diff --git a/src/libs/agc.cpp b/src/libs/agc.cpp index cbf5b730d..dbe00bd74 100644 --- a/src/libs/agc.cpp +++ b/src/libs/agc.cpp @@ -57,7 +57,6 @@ struct DriverDmem { }; static DriverDmem g_driver_dmem; -static int InitializeDmem(); static void ReleaseDmem(); } // namespace Gen5Driver @@ -82,6 +81,8 @@ void Initialize() { auto& video_out = VideoOut::VideoOutInit(width, height, presenter); g_renderer = &presenter.Renderer(); g_renderer->InitializeGpu(&video_out); + // Native driver module startup reserves its DMEM before the guest can allocate it. + EXIT_IF(Gen5Driver::Initialize() != OK); ShaderInit(); } @@ -356,38 +357,6 @@ int KYTY_SYSV_ABI AgcInit(uint32_t* state, uint32_t ver) { } printf("version = %u\n", ver); - std::scoped_lock lock {Gen5Driver::g_driver_dmem.mutex}; - if (Gen5Driver::g_driver_dmem.physical_offset >= 0) { - return OK; - } - if (const auto result = Gen5Driver::InitializeDmem(); result != OK) { - return result; - } - struct FunctionShaderBindings { - uint64_t code; - uint32_t user_data[2]; - }; - static_assert(sizeof(FunctionShaderBindings) == 16); - // Ordered-count queue validator, including its return to the caller. - static constexpr std::array validator { - 0xbeeb03ff, 0x00000021, 0xb96a1818, 0xbf06106a, - 0xbf800000, 0x8590807e, 0xb96a0a18, 0xbf066a80, - 0xbf800000, 0x85ea807e, 0x88ea106a, 0xbf870003, - 0xbefc03ff, 0x8a6ca000, 0xbf920009, 0xbefd210e, - }; - const auto base = Gen5Driver::DriverDmemBase + Gen5Driver::AgcDmemOffset; - const auto function_table = base + 0x60; - const auto code_address = base + 0x100; // Shader code requires 256-byte alignment. - std::array functions {}; - functions[2].code = code_address; - const std::array descriptor { - static_cast(function_table), - static_cast(function_table >> 32u) | 0x00100000u, - static_cast(functions.size()), 0x5204u, - }; - std::memcpy(reinterpret_cast(function_table), functions.data(), sizeof(functions)); - std::memcpy(reinterpret_cast(code_address), validator.data(), sizeof(validator)); - std::memcpy(reinterpret_cast(base), descriptor.data(), sizeof(descriptor)); return OK; } @@ -4275,7 +4244,11 @@ namespace Gen5Driver { LIB_NAME("Graphics5Driver", "Graphics5Driver"); -static int InitializeDmem() { +int Initialize() { + std::scoped_lock lock {g_driver_dmem.mutex}; + if (g_driver_dmem.physical_offset >= 0) { + return OK; + } int64_t physical_offset = -1; auto result = LibKernel::Memory::KernelAllocateDirectMemory( 0, LibKernel::Memory::KernelGetDirectMemorySize(), DriverDmemSize, DriverDmemSize, @@ -4292,6 +4265,31 @@ static int InitializeDmem() { } EXIT_IF(reinterpret_cast(address) != DriverDmemBase); std::memset(address, 0, DriverDmemSize); + struct FunctionShaderBindings { + uint64_t code; + uint32_t user_data[2]; + }; + static_assert(sizeof(FunctionShaderBindings) == 16); + // Ordered-count queue validator, including its return to the caller. + static constexpr std::array validator { + 0xbeeb03ff, 0x00000021, 0xb96a1818, 0xbf06106a, + 0xbf800000, 0x8590807e, 0xb96a0a18, 0xbf066a80, + 0xbf800000, 0x85ea807e, 0x88ea106a, 0xbf870003, + 0xbefc03ff, 0x8a6ca000, 0xbf920009, 0xbefd210e, + }; + const auto base = DriverDmemBase + AgcDmemOffset; + const auto function_table = base + 0x60; + const auto code_address = base + 0x100; // Shader code requires 256-byte alignment. + std::array functions {}; + functions[2].code = code_address; + const std::array descriptor { + static_cast(function_table), + static_cast(function_table >> 32u) | 0x00100000u, + static_cast(functions.size()), 0x5204u, + }; + std::memcpy(reinterpret_cast(function_table), functions.data(), sizeof(functions)); + std::memcpy(reinterpret_cast(code_address), validator.data(), sizeof(validator)); + std::memcpy(reinterpret_cast(base), descriptor.data(), sizeof(descriptor)); g_driver_dmem.physical_offset = physical_offset; return OK; } diff --git a/src/libs/agc.h b/src/libs/agc.h index 712bf1ad9..bac31c03a 100644 --- a/src/libs/agc.h +++ b/src/libs/agc.h @@ -307,6 +307,8 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetFlip(CommandBuffer* buf, uint32_t video_out_han namespace Gen5Driver { +int Initialize(); + struct Packet { uint32_t* addr; uint32_t dw_num; diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index c34db80fd..e8aa0e559 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -41903,9 +41903,24 @@ void CheckAgcSystemTable(RenderContext &renderer) { 0xbf800000, 0x85ea807e, 0x88ea106a, 0xbf870003, 0xbefc03ff, 0x8a6ca000, 0xbf920009, 0xbefd210e}; LibKernel::Memory::InstallGpuResources(&renderer); + Require(name, "driver module startup", Gen5Driver::Initialize() == 0, + "driver module startup failed before guest initialization"); + const auto direct_memory_size = LibKernel::Memory::KernelGetDirectMemorySize(); + int64_t available_offset = -1; + size_t available_size = 0; + Require(name, "remaining direct pool", + LibKernel::Memory::KernelAvailableDirectMemorySize( + 0, direct_memory_size, 0, &available_offset, &available_size) == 0 && + available_size == direct_memory_size - 0x200000, + "driver startup did not reserve its backing in the reported direct pool"); + int64_t guest_allocation = -1; + Require(name, "guest consumes remaining direct pool", + LibKernel::Memory::KernelAllocateDirectMemory( + 0, direct_memory_size, available_size, 0x4000, 0, &guest_allocation) == 0, + "guest could not allocate all remaining direct memory"); uint32_t state = 0xabcdef01u; Require(name, "driver startup", Gen5::AgcInit(&state, 13) == 0 && state == 0xabcdef01u, - "Agc startup failed or changed its ignored public state pointer"); + "Agc startup required free guest memory or changed its ignored public state pointer"); LibKernel::Memory::VirtualQueryInfo mapping{}; Require(name, "shared driver backing", LibKernel::Memory::KernelVirtualQuery(reinterpret_cast(driver_base), 0, @@ -41932,10 +41947,14 @@ void CheckAgcSystemTable(RenderContext &renderer) { Require(name, "default instrumentation", *instrumentation == 0, "unused vertex validation was enabled at startup"); *instrumentation = 0x12340000u; - Require(name, "repeat startup", Gen5::AgcInit(nullptr, 13) == 0 && + Require(name, "repeat startup", Gen5Driver::Initialize() == 0 && + Gen5::AgcInit(nullptr, 13) == 0 && *instrumentation == 0x12340000u, "repeat Agc initialization reset existing system state"); *instrumentation = 0; + Require(name, "release guest allocation", + LibKernel::Memory::KernelCheckedReleaseDirectMemory(guest_allocation, available_size) == 0, + "guest allocation release failed"); LibKernel::Memory::InstallGpuResources(nullptr); std::printf("[host] %-32s ok\n", name); }