From d093d3b520aa53f4e3cd9418aca2841ad78dab67 Mon Sep 17 00:00:00 2001 From: PYTHONRETARDE <152398455+PYTHONRETARDE@users.noreply.github.com> Date: Thu, 15 Oct 2026 00:59:52 +0000 Subject: [PATCH 1/3] fix(agc): key shader modules by the pipeline library mode AMD's Windows driver compiles pipelines differently when VK_EXT_graphics_pipeline_library is enabled on the device, but its on-disk cache (%LOCALAPPDATA%\AMD\VkCache) does not key on it. A process in one mode is then served pipelines compiled in the other, and their writes never land (#4768, #5271). With the library feature off, every module now flips bit 15 of the SPIR-V generator word, which no driver interprets, so the two modes hash to separate cache entries. Co-Authored-By: Claude Opus 5.5 --- .../Execution/src/PresentationPass.cpp | 10 ++++++---- .../Execution/src/VulkanDevice.cpp | 7 ++++++- .../libSceAgcDriver/Graphics/include/Context.hpp | 6 ++++++ .../Graphics/src/GpuColorTransfer.cpp | 5 +++-- .../prx/libSceAgcDriver/Graphics/src/Pipeline.cpp | 7 ++++++- .../prx/libSceAgcDriver/Graphics/src/Recorder.cpp | 15 +++++++++------ .../Graphics/src/TextureDetiler.cpp | 15 +++++++++------ 7 files changed, 45 insertions(+), 20 deletions(-) diff --git a/core/libs/prx/libSceAgcDriver/Execution/src/PresentationPass.cpp b/core/libs/prx/libSceAgcDriver/Execution/src/PresentationPass.cpp index ecaa69ff9c..e246000759 100644 --- a/core/libs/prx/libSceAgcDriver/Execution/src/PresentationPass.cpp +++ b/core/libs/prx/libSceAgcDriver/Execution/src/PresentationPass.cpp @@ -72,11 +72,13 @@ PresentationPass::PresentationPass(const Graphics::Context& context, std::size_t context.Function("vkUpdateDescriptorSets")(context.device, static_cast(tableWrites.size()), tableWrites.data(), 0, nullptr); const auto createModule = context.Function("vkCreateShaderModule"); VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - moduleInfo.codeSize = sizeof(PRESENTATION_PASS_VERT_SPV); - moduleInfo.pCode = PRESENTATION_PASS_VERT_SPV; + const auto presentationPassVertCode = Graphics::CacheKeyedSpirv(context.graphicsPipelineLibrary, PRESENTATION_PASS_VERT_SPV, sizeof(PRESENTATION_PASS_VERT_SPV)); + moduleInfo.codeSize = presentationPassVertCode.size() * sizeof(std::uint32_t); + moduleInfo.pCode = presentationPassVertCode.data(); Graphics::Check(createModule(context.device, &moduleInfo, nullptr, &vertex), "vkCreateShaderModule presentation vertex"); - moduleInfo.codeSize = sizeof(PRESENTATION_PASS_FRAG_SPV); - moduleInfo.pCode = PRESENTATION_PASS_FRAG_SPV; + const auto presentationPassFragCode = Graphics::CacheKeyedSpirv(context.graphicsPipelineLibrary, PRESENTATION_PASS_FRAG_SPV, sizeof(PRESENTATION_PASS_FRAG_SPV)); + moduleInfo.codeSize = presentationPassFragCode.size() * sizeof(std::uint32_t); + moduleInfo.pCode = presentationPassFragCode.data(); Graphics::Check(createModule(context.device, &moduleInfo, nullptr, &fragment), "vkCreateShaderModule presentation fragment"); } catch (...) { release(); diff --git a/core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp b/core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp index c19c2efa29..d634b9356c 100644 --- a/core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp +++ b/core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp @@ -4872,9 +4872,14 @@ std::shared_ptr VulkanDevice::createComputePipeline(cons objects->destroyModule = state->DeviceFunction("vkDestroyShaderModule"); objects->destroyLayout = state->DeviceFunction("vkDestroyPipelineLayout"); objects->destroyPipeline = state->DeviceFunction("vkDestroyPipeline"); + std::vector keyed; + if (!state->graphicsPipelineLibrary && shader.spirv.size() > 2) { + keyed.assign(shader.spirv.data(), shader.spirv.data() + shader.spirv.size()); + keyed[2] ^= 0x8000u; + } VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; moduleInfo.codeSize = shader.spirv.size() * sizeof(std::uint32_t); - moduleInfo.pCode = shader.spirv.data(); + moduleInfo.pCode = keyed.empty() ? shader.spirv.data() : keyed.data(); check(state->DeviceFunction("vkCreateShaderModule")(state->device, &moduleInfo, nullptr, &objects->module), "vkCreateShaderModule"); objects->resourcesLayout = setLayout; const std::array setLayouts{setLayout, shader.workgroupMemoryDwords != 0 ? state->workgroupMemoryLayout : VK_NULL_HANDLE}; diff --git a/core/libs/prx/libSceAgcDriver/Graphics/include/Context.hpp b/core/libs/prx/libSceAgcDriver/Graphics/include/Context.hpp index c73dcc10bb..e8a03e46e5 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/include/Context.hpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/include/Context.hpp @@ -20,6 +20,12 @@ namespace AgcDriver::Graphics { +inline std::vector CacheKeyedSpirv(bool graphicsPipelineLibrary, const std::uint32_t* code, std::size_t bytes) { + std::vector keyed(code, code + bytes / sizeof(std::uint32_t)); + if (!graphicsPipelineLibrary && keyed.size() > 2) keyed[2] ^= 0x8000u; + return keyed; +} + class TextureDetiler; class GpuColorTransfer; class BufferPool; diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/GpuColorTransfer.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/GpuColorTransfer.cpp index 973aff1e34..c29c7e941b 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/GpuColorTransfer.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/GpuColorTransfer.cpp @@ -29,8 +29,9 @@ GpuColorTransfer::GpuColorTransfer(const Context& context) : context(context) { layoutInfo.pPushConstantRanges = &push; Check(context.Function("vkCreatePipelineLayout")(context.device, &layoutInfo, nullptr, &pipelineLayout), "vkCreatePipelineLayout color transfer"); VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - moduleInfo.codeSize = sizeof(COLOR_TRANSFER_SPV); - moduleInfo.pCode = COLOR_TRANSFER_SPV; + const auto colorTransferCode = CacheKeyedSpirv(context.graphicsPipelineLibrary, COLOR_TRANSFER_SPV, sizeof(COLOR_TRANSFER_SPV)); + moduleInfo.codeSize = colorTransferCode.size() * sizeof(std::uint32_t); + moduleInfo.pCode = colorTransferCode.data(); Check(context.Function("vkCreateShaderModule")(context.device, &moduleInfo, nullptr, &module), "vkCreateShaderModule color transfer"); VkComputePipelineCreateInfo pipelineInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; pipelineInfo.stage = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp index eaca4be3f4..4979c76e21 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp @@ -359,9 +359,14 @@ Pipeline::Pipeline(const Context& context, const State& state, const VertexInput const VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT meshSubgroup{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT, nullptr, 32u}; for (std::uint32_t i = 0; i < shaders.size(); ++i) { const auto& shader = *shaders[i].program; + std::vector keyed; + if (!context.graphicsPipelineLibrary && shader.spirv.size() > 2) { + keyed.assign(shader.spirv.data(), shader.spirv.data() + shader.spirv.size()); + keyed[2] ^= 0x8000u; + } VkShaderModuleCreateInfo module{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; module.codeSize = shader.spirv.size() * sizeof(std::uint32_t); - module.pCode = shader.spirv.data(); + module.pCode = keyed.empty() ? shader.spirv.data() : keyed.data(); Check(context.Function("vkCreateShaderModule")(context.device, &module, nullptr, &_modules[i]), "vkCreateShaderModule graphics"); const auto stage = VulkanStage(shaders[i].stage); stages[i].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp index a4dfce1f09..e33db0d231 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp @@ -2076,8 +2076,9 @@ bool Recorder::gpuSampleCounter() { layoutInfo.pPushConstantRanges = &push; Check(context.Function("vkCreatePipelineLayout")(context.device, &layoutInfo, nullptr, &sampleLayout), "vkCreatePipelineLayout sample counter"); VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - moduleInfo.codeSize = sizeof(SAMPLE_COUNTER_SPV); - moduleInfo.pCode = SAMPLE_COUNTER_SPV; + const auto sampleCounterCode = CacheKeyedSpirv(context.graphicsPipelineLibrary, SAMPLE_COUNTER_SPV, sizeof(SAMPLE_COUNTER_SPV)); + moduleInfo.codeSize = sampleCounterCode.size() * sizeof(std::uint32_t); + moduleInfo.pCode = sampleCounterCode.data(); Check(context.Function("vkCreateShaderModule")(context.device, &moduleInfo, nullptr, &module), "vkCreateShaderModule sample counter"); VkComputePipelineCreateInfo pipelineInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; pipelineInfo.stage = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; @@ -2094,8 +2095,9 @@ bool Recorder::gpuSampleCounter() { const VkPushConstantRange dumpPush{VK_SHADER_STAGE_COMPUTE_BIT, 0, SampleDumpPushBytes}; layoutInfo.pPushConstantRanges = &dumpPush; Check(context.Function("vkCreatePipelineLayout")(context.device, &layoutInfo, nullptr, &dumpLayout), "vkCreatePipelineLayout sample dumps"); - moduleInfo.codeSize = sizeof(SAMPLE_DUMPS_SPV); - moduleInfo.pCode = SAMPLE_DUMPS_SPV; + const auto sampleDumpsCode = CacheKeyedSpirv(context.graphicsPipelineLibrary, SAMPLE_DUMPS_SPV, sizeof(SAMPLE_DUMPS_SPV)); + moduleInfo.codeSize = sampleDumpsCode.size() * sizeof(std::uint32_t); + moduleInfo.pCode = sampleDumpsCode.data(); Check(context.Function("vkCreateShaderModule")(context.device, &moduleInfo, nullptr, &module), "vkCreateShaderModule sample dumps"); pipelineInfo.stage.module = module; pipelineInfo.layout = dumpLayout; @@ -2392,8 +2394,9 @@ bool Recorder::RecordMeshArguments(VkCommandBuffer commands, VkDeviceAddress rec layoutInfo.pPushConstantRanges = &push; Check(context.Function("vkCreatePipelineLayout")(context.device, &layoutInfo, nullptr, &meshArgumentLayout), "vkCreatePipelineLayout mesh arguments"); VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - moduleInfo.codeSize = sizeof(MESH_ARGUMENTS_SPV); - moduleInfo.pCode = MESH_ARGUMENTS_SPV; + const auto meshArgumentsCode = CacheKeyedSpirv(context.graphicsPipelineLibrary, MESH_ARGUMENTS_SPV, sizeof(MESH_ARGUMENTS_SPV)); + moduleInfo.codeSize = meshArgumentsCode.size() * sizeof(std::uint32_t); + moduleInfo.pCode = meshArgumentsCode.data(); Check(context.Function("vkCreateShaderModule")(context.device, &moduleInfo, nullptr, &module), "vkCreateShaderModule mesh arguments"); VkComputePipelineCreateInfo pipelineInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; pipelineInfo.stage = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp index 0bd34f6890..4063f8fb02 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp @@ -90,8 +90,9 @@ TextureDetiler::TextureDetiler(const Context& context) : context(context) { pipelineLayoutInfo.pPushConstantRanges = &pushRange; Check(context.Function("vkCreatePipelineLayout")(context.device, &pipelineLayoutInfo, nullptr, &pipelineLayout), "vkCreatePipelineLayout"); VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - moduleInfo.codeSize = sizeof(TEXTURE_DETILE_SPV); - moduleInfo.pCode = TEXTURE_DETILE_SPV; + const auto textureDetileCode = CacheKeyedSpirv(context.graphicsPipelineLibrary, TEXTURE_DETILE_SPV, sizeof(TEXTURE_DETILE_SPV)); + moduleInfo.codeSize = textureDetileCode.size() * sizeof(std::uint32_t); + moduleInfo.pCode = textureDetileCode.data(); Check(context.Function("vkCreateShaderModule")(context.device, &moduleInfo, nullptr, &module), "vkCreateShaderModule"); bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; Check(context.Function("vkCreateDescriptorSetLayout")(context.device, &layoutInfo, nullptr, &imageDescriptorLayout), "vkCreateDescriptorSetLayout"); @@ -169,8 +170,9 @@ VkPipeline TextureDetiler::pipeline(TextureTileMode tileMode, std::uint32_t elem } if (image && imageModule == VK_NULL_HANDLE) { VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - moduleInfo.codeSize = sizeof(TEXTURE_DETILE_IMAGE_SPV); - moduleInfo.pCode = TEXTURE_DETILE_IMAGE_SPV; + const auto textureDetileImageCode = CacheKeyedSpirv(context.graphicsPipelineLibrary, TEXTURE_DETILE_IMAGE_SPV, sizeof(TEXTURE_DETILE_IMAGE_SPV)); + moduleInfo.codeSize = textureDetileImageCode.size() * sizeof(std::uint32_t); + moduleInfo.pCode = textureDetileImageCode.data(); Check(context.Function("vkCreateShaderModule")(context.device, &moduleInfo, nullptr, &imageModule), "vkCreateShaderModule"); } std::array entries{}; @@ -348,8 +350,9 @@ void TextureDetiler::DispatchCmaskClear(VkCommandBuffer commands, VkBuffer cmask pipelineLayoutInfo.pPushConstantRanges = &pushRange; Check(context.Function("vkCreatePipelineLayout")(context.device, &pipelineLayoutInfo, nullptr, &cmaskPipelineLayout), "vkCreatePipelineLayout CMASK clear"); VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - moduleInfo.codeSize = sizeof(CMASK_CLEAR_SPV); - moduleInfo.pCode = CMASK_CLEAR_SPV; + const auto cmaskClearCode = CacheKeyedSpirv(context.graphicsPipelineLibrary, CMASK_CLEAR_SPV, sizeof(CMASK_CLEAR_SPV)); + moduleInfo.codeSize = cmaskClearCode.size() * sizeof(std::uint32_t); + moduleInfo.pCode = cmaskClearCode.data(); VkShaderModule cmaskModule = VK_NULL_HANDLE; Check(context.Function("vkCreateShaderModule")(context.device, &moduleInfo, nullptr, &cmaskModule), "vkCreateShaderModule CMASK clear"); VkComputePipelineCreateInfo pipelineInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; From f161a741db0b2fcb8baee2b79437a7a3b75b8a9d Mon Sep 17 00:00:00 2001 From: LeandroLP23 Date: Thu, 15 Oct 2026 17:03:51 +0200 Subject: [PATCH 2/3] fix(agc): key the compute pipeline replay's module by the pipeline library mode The replay rebuilds a captured compute pipeline to time it. With the library feature off, production now flips the SPIR-V generator word before vkCreateShaderModule. The replay creates the same module, so it hits the same AMD driver cache entries as the run it reproduces. Co-Authored-By: Claude Opus 5.5 --- core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp b/core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp index d634b9356c..681e8e0952 100644 --- a/core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp +++ b/core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp @@ -914,9 +914,10 @@ ComputePipelineReplayResult VulkanDevice::ReplayComputePipeline(const ComputePip check(state->DeviceFunction("vkCreatePipelineCache")(state->device, &cacheInfo, nullptr, &replay.cache), "vkCreatePipelineCache replay"); result.cacheMilliseconds = elapsed(phase); phase = std::chrono::steady_clock::now(); + const auto replayCode = Graphics::CacheKeyedSpirv(state->graphicsPipelineLibrary, capture.spirv.data(), capture.spirv.size() * sizeof(std::uint32_t)); VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - moduleInfo.codeSize = capture.spirv.size() * sizeof(std::uint32_t); - moduleInfo.pCode = capture.spirv.data(); + moduleInfo.codeSize = replayCode.size() * sizeof(std::uint32_t); + moduleInfo.pCode = replayCode.data(); check(state->DeviceFunction("vkCreateShaderModule")(state->device, &moduleInfo, nullptr, &objects.module), "vkCreateShaderModule replay"); result.moduleMilliseconds = elapsed(phase); phase = std::chrono::steady_clock::now(); From 28ce7bc0b82004899266a7af281c926afa08a9fe Mon Sep 17 00:00:00 2001 From: LeandroLP23 Date: Tue, 20 Oct 2026 18:12:06 +0200 Subject: [PATCH 3/3] fix(agc): create every shader module through the pipeline-library cache key Six vkCreateShaderModule calls added to main since this branch's base still passed their SPIR-V unchanged, so on AMD's Windows driver they shared on-disk cache entries across the two pipeline library modes: splitComputePipeline's recompiled compute programs, the multisample readback modules, the dispatch-arguments module, the texture repack module and the two performance overlay modules. Graphics::CreateShaderModule now keys the generator word and creates the module in one place. Every module the driver creates goes through it, including the recompiled graphics and compute programs that copied the key inline, so new call sites can't skip it. Co-Authored-By: Claude Opus 5.5 --- .../Execution/src/PerformanceOverlay.cpp | 10 ++------ .../Execution/src/PresentationPass.cpp | 12 ++-------- .../Execution/src/VulkanDevice.cpp | 22 +++-------------- .../Graphics/include/Context.hpp | 20 ++++++++++++---- .../Graphics/src/GpuColorTransfer.cpp | 6 +---- .../Graphics/src/MultisampleReadback.cpp | 6 ++--- .../libSceAgcDriver/Graphics/src/Pipeline.cpp | 10 +------- .../libSceAgcDriver/Graphics/src/Recorder.cpp | 22 ++++------------- .../Graphics/src/TextureDetiler.cpp | 24 ++++--------------- .../prx/libSceAgcDriver/tests/Graphics.cpp | 20 ++++++++++++++++ 10 files changed, 54 insertions(+), 98 deletions(-) diff --git a/core/libs/prx/libSceAgcDriver/Execution/src/PerformanceOverlay.cpp b/core/libs/prx/libSceAgcDriver/Execution/src/PerformanceOverlay.cpp index e21ddf0599..ca74a794d9 100644 --- a/core/libs/prx/libSceAgcDriver/Execution/src/PerformanceOverlay.cpp +++ b/core/libs/prx/libSceAgcDriver/Execution/src/PerformanceOverlay.cpp @@ -538,14 +538,8 @@ PerformanceOverlay::PerformanceOverlay(const Graphics::Context& context, std::si layoutInfo.pushConstantRangeCount = 1; layoutInfo.pPushConstantRanges = &push; Graphics::Check(context.Function("vkCreatePipelineLayout")(context.device, &layoutInfo, nullptr, &pipelineLayout), "vkCreatePipelineLayout performance overlay"); - const auto createModule = context.Function("vkCreateShaderModule"); - VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - moduleInfo.codeSize = sizeof(PERFORMANCE_OVERLAY_VERT_SPV); - moduleInfo.pCode = PERFORMANCE_OVERLAY_VERT_SPV; - Graphics::Check(createModule(context.device, &moduleInfo, nullptr, &vertex), "vkCreateShaderModule performance overlay vertex"); - moduleInfo.codeSize = sizeof(PERFORMANCE_OVERLAY_FRAG_SPV); - moduleInfo.pCode = PERFORMANCE_OVERLAY_FRAG_SPV; - Graphics::Check(createModule(context.device, &moduleInfo, nullptr, &fragment), "vkCreateShaderModule performance overlay fragment"); + vertex = Graphics::CreateShaderModule(context, PERFORMANCE_OVERLAY_VERT_SPV, sizeof(PERFORMANCE_OVERLAY_VERT_SPV), "vkCreateShaderModule performance overlay vertex"); + fragment = Graphics::CreateShaderModule(context, PERFORMANCE_OVERLAY_FRAG_SPV, sizeof(PERFORMANCE_OVERLAY_FRAG_SPV), "vkCreateShaderModule performance overlay fragment"); } catch (...) { release(); throw; diff --git a/core/libs/prx/libSceAgcDriver/Execution/src/PresentationPass.cpp b/core/libs/prx/libSceAgcDriver/Execution/src/PresentationPass.cpp index e246000759..e42e4e2b03 100644 --- a/core/libs/prx/libSceAgcDriver/Execution/src/PresentationPass.cpp +++ b/core/libs/prx/libSceAgcDriver/Execution/src/PresentationPass.cpp @@ -70,16 +70,8 @@ PresentationPass::PresentationPass(const Graphics::Context& context, std::size_t tableWrites[i].pBufferInfo = &tableInfo; } context.Function("vkUpdateDescriptorSets")(context.device, static_cast(tableWrites.size()), tableWrites.data(), 0, nullptr); - const auto createModule = context.Function("vkCreateShaderModule"); - VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - const auto presentationPassVertCode = Graphics::CacheKeyedSpirv(context.graphicsPipelineLibrary, PRESENTATION_PASS_VERT_SPV, sizeof(PRESENTATION_PASS_VERT_SPV)); - moduleInfo.codeSize = presentationPassVertCode.size() * sizeof(std::uint32_t); - moduleInfo.pCode = presentationPassVertCode.data(); - Graphics::Check(createModule(context.device, &moduleInfo, nullptr, &vertex), "vkCreateShaderModule presentation vertex"); - const auto presentationPassFragCode = Graphics::CacheKeyedSpirv(context.graphicsPipelineLibrary, PRESENTATION_PASS_FRAG_SPV, sizeof(PRESENTATION_PASS_FRAG_SPV)); - moduleInfo.codeSize = presentationPassFragCode.size() * sizeof(std::uint32_t); - moduleInfo.pCode = presentationPassFragCode.data(); - Graphics::Check(createModule(context.device, &moduleInfo, nullptr, &fragment), "vkCreateShaderModule presentation fragment"); + vertex = Graphics::CreateShaderModule(context, PRESENTATION_PASS_VERT_SPV, sizeof(PRESENTATION_PASS_VERT_SPV), "vkCreateShaderModule presentation vertex"); + fragment = Graphics::CreateShaderModule(context, PRESENTATION_PASS_FRAG_SPV, sizeof(PRESENTATION_PASS_FRAG_SPV), "vkCreateShaderModule presentation fragment"); } catch (...) { release(); throw; diff --git a/core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp b/core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp index 681e8e0952..66da673ed8 100644 --- a/core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp +++ b/core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp @@ -914,11 +914,7 @@ ComputePipelineReplayResult VulkanDevice::ReplayComputePipeline(const ComputePip check(state->DeviceFunction("vkCreatePipelineCache")(state->device, &cacheInfo, nullptr, &replay.cache), "vkCreatePipelineCache replay"); result.cacheMilliseconds = elapsed(phase); phase = std::chrono::steady_clock::now(); - const auto replayCode = Graphics::CacheKeyedSpirv(state->graphicsPipelineLibrary, capture.spirv.data(), capture.spirv.size() * sizeof(std::uint32_t)); - VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - moduleInfo.codeSize = replayCode.size() * sizeof(std::uint32_t); - moduleInfo.pCode = replayCode.data(); - check(state->DeviceFunction("vkCreateShaderModule")(state->device, &moduleInfo, nullptr, &objects.module), "vkCreateShaderModule replay"); + objects.module = Graphics::CreateShaderModule(state->DeviceFunction("vkCreateShaderModule"), state->device, state->graphicsPipelineLibrary, capture.spirv.data(), capture.spirv.size() * sizeof(std::uint32_t), "vkCreateShaderModule replay"); result.moduleMilliseconds = elapsed(phase); phase = std::chrono::steady_clock::now(); std::array, 2> descriptorCounts{}; @@ -4873,15 +4869,7 @@ std::shared_ptr VulkanDevice::createComputePipeline(cons objects->destroyModule = state->DeviceFunction("vkDestroyShaderModule"); objects->destroyLayout = state->DeviceFunction("vkDestroyPipelineLayout"); objects->destroyPipeline = state->DeviceFunction("vkDestroyPipeline"); - std::vector keyed; - if (!state->graphicsPipelineLibrary && shader.spirv.size() > 2) { - keyed.assign(shader.spirv.data(), shader.spirv.data() + shader.spirv.size()); - keyed[2] ^= 0x8000u; - } - VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - moduleInfo.codeSize = shader.spirv.size() * sizeof(std::uint32_t); - moduleInfo.pCode = keyed.empty() ? shader.spirv.data() : keyed.data(); - check(state->DeviceFunction("vkCreateShaderModule")(state->device, &moduleInfo, nullptr, &objects->module), "vkCreateShaderModule"); + objects->module = Graphics::CreateShaderModule(state->DeviceFunction("vkCreateShaderModule"), state->device, state->graphicsPipelineLibrary, shader.spirv.data(), shader.spirv.size() * sizeof(std::uint32_t), "vkCreateShaderModule"); objects->resourcesLayout = setLayout; const std::array setLayouts{setLayout, shader.workgroupMemoryDwords != 0 ? state->workgroupMemoryLayout : VK_NULL_HANDLE}; const VkPushConstantRange push{VK_SHADER_STAGE_COMPUTE_BIT, 0, Graphics::ComputePushConstantBytes}; @@ -4941,11 +4929,7 @@ VkPipeline VulkanDevice::splitComputePipeline(const Graphics::Context& context, std::array offsets{}; for (std::uint32_t component = 0; component < offsets.size(); ++component) offsets[component] = {ShaderRecompiler::PipelineSpecialization::WorkgroupOffsetBase + component, base[component]}; const Graphics::PipelineSpecialization specialization(shader, offsets); - VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - moduleInfo.codeSize = shader.spirv.size() * sizeof(std::uint32_t); - moduleInfo.pCode = shader.spirv.data(); - VkShaderModule module = VK_NULL_HANDLE; - check(state->DeviceFunction("vkCreateShaderModule")(state->device, &moduleInfo, nullptr, &module), "vkCreateShaderModule"); + VkShaderModule module = Graphics::CreateShaderModule(state->DeviceFunction("vkCreateShaderModule"), state->device, state->graphicsPipelineLibrary, shader.spirv.data(), shader.spirv.size() * sizeof(std::uint32_t), "vkCreateShaderModule"); VkPipeline pipeline = VK_NULL_HANDLE; try { CreateComputePipeline(state->device, state->DeviceFunction("vkCreateComputePipelines"), context.pipelineCache, module, objects.layout, computePipelineFlags(), computeStageFlags(shader), specialization.Info(), computeSubgroupSize(shader), &pipeline, context.pipelineCacheSynchronization); diff --git a/core/libs/prx/libSceAgcDriver/Graphics/include/Context.hpp b/core/libs/prx/libSceAgcDriver/Graphics/include/Context.hpp index e8a03e46e5..b4c113d749 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/include/Context.hpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/include/Context.hpp @@ -20,11 +20,6 @@ namespace AgcDriver::Graphics { -inline std::vector CacheKeyedSpirv(bool graphicsPipelineLibrary, const std::uint32_t* code, std::size_t bytes) { - std::vector keyed(code, code + bytes / sizeof(std::uint32_t)); - if (!graphicsPipelineLibrary && keyed.size() > 2) keyed[2] ^= 0x8000u; - return keyed; -} class TextureDetiler; class GpuColorTransfer; @@ -77,6 +72,17 @@ inline void Check(VkResult result, const char* operation) { if (result != VK_SUCCESS) throw std::runtime_error(std::string("AGC graphics: ") + operation + ": Vulkan result " + std::to_string(result)); } +inline VkShaderModule CreateShaderModule(PFN_vkCreateShaderModule create, VkDevice device, bool graphicsPipelineLibrary, const std::uint32_t* code, std::size_t bytes, const char* operation) { + std::vector keyed(code, code + bytes / sizeof(std::uint32_t)); + if (!graphicsPipelineLibrary && keyed.size() > 2) keyed[2] ^= 0x8000u; + VkShaderModuleCreateInfo info{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; + info.codeSize = keyed.size() * sizeof(std::uint32_t); + info.pCode = keyed.data(); + VkShaderModule module = VK_NULL_HANDLE; + Check(create(device, &info, nullptr, &module), operation); + return module; +} + inline void Require(bool condition, const char* reason) { if (!condition) throw std::runtime_error(std::string("AGC graphics: ") + reason); } @@ -343,6 +349,10 @@ struct Context { } }; +inline VkShaderModule CreateShaderModule(const Context& context, const std::uint32_t* code, std::size_t bytes, const char* operation) { + return CreateShaderModule(context.Function("vkCreateShaderModule"), context.device, context.graphicsPipelineLibrary, code, bytes, operation); +} + inline void EndRenderPass(const Context& context, VkCommandBuffer commands) { if (context.graphicsPipelineLibrary) context.Resolved(&DeviceFunctions::cmdEndRendering, "vkCmdEndRenderingKHR")(commands); else context.Resolved(&DeviceFunctions::cmdEndRenderPass, "vkCmdEndRenderPass")(commands); diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/GpuColorTransfer.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/GpuColorTransfer.cpp index c29c7e941b..9881ba2473 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/GpuColorTransfer.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/GpuColorTransfer.cpp @@ -28,11 +28,7 @@ GpuColorTransfer::GpuColorTransfer(const Context& context) : context(context) { layoutInfo.pushConstantRangeCount = 1; layoutInfo.pPushConstantRanges = &push; Check(context.Function("vkCreatePipelineLayout")(context.device, &layoutInfo, nullptr, &pipelineLayout), "vkCreatePipelineLayout color transfer"); - VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - const auto colorTransferCode = CacheKeyedSpirv(context.graphicsPipelineLibrary, COLOR_TRANSFER_SPV, sizeof(COLOR_TRANSFER_SPV)); - moduleInfo.codeSize = colorTransferCode.size() * sizeof(std::uint32_t); - moduleInfo.pCode = colorTransferCode.data(); - Check(context.Function("vkCreateShaderModule")(context.device, &moduleInfo, nullptr, &module), "vkCreateShaderModule color transfer"); + module = CreateShaderModule(context, COLOR_TRANSFER_SPV, sizeof(COLOR_TRANSFER_SPV), "vkCreateShaderModule color transfer"); VkComputePipelineCreateInfo pipelineInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; pipelineInfo.stage = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; pipelineInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/MultisampleReadback.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/MultisampleReadback.cpp index 8f731eb881..fe92fa1b97 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/MultisampleReadback.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/MultisampleReadback.cpp @@ -46,10 +46,8 @@ VkPipeline TextureDetiler::multisampleReadbackPipeline(std::uint32_t elementByte } auto& module = readbackModules[depth ? 1u : 0u]; if (module == VK_NULL_HANDLE) { - VkShaderModuleCreateInfo info{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - info.codeSize = depth ? sizeof(MULTISAMPLE_READBACK_DEPTH_SPV) : sizeof(MULTISAMPLE_READBACK_UINT_SPV); - info.pCode = depth ? MULTISAMPLE_READBACK_DEPTH_SPV : MULTISAMPLE_READBACK_UINT_SPV; - Check(context.Function("vkCreateShaderModule")(context.device, &info, nullptr, &module), "vkCreateShaderModule multisample readback"); + module = depth ? CreateShaderModule(context, MULTISAMPLE_READBACK_DEPTH_SPV, sizeof(MULTISAMPLE_READBACK_DEPTH_SPV), "vkCreateShaderModule multisample readback") + : CreateShaderModule(context, MULTISAMPLE_READBACK_UINT_SPV, sizeof(MULTISAMPLE_READBACK_UINT_SPV), "vkCreateShaderModule multisample readback"); } const VkSpecializationMapEntry entry{0u, 0u, sizeof(elementBytes)}; const VkSpecializationInfo specialization{1u, &entry, sizeof(elementBytes), &elementBytes}; diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp index 4979c76e21..1eaef4b7ac 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp @@ -359,15 +359,7 @@ Pipeline::Pipeline(const Context& context, const State& state, const VertexInput const VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT meshSubgroup{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT, nullptr, 32u}; for (std::uint32_t i = 0; i < shaders.size(); ++i) { const auto& shader = *shaders[i].program; - std::vector keyed; - if (!context.graphicsPipelineLibrary && shader.spirv.size() > 2) { - keyed.assign(shader.spirv.data(), shader.spirv.data() + shader.spirv.size()); - keyed[2] ^= 0x8000u; - } - VkShaderModuleCreateInfo module{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - module.codeSize = shader.spirv.size() * sizeof(std::uint32_t); - module.pCode = keyed.empty() ? shader.spirv.data() : keyed.data(); - Check(context.Function("vkCreateShaderModule")(context.device, &module, nullptr, &_modules[i]), "vkCreateShaderModule graphics"); + _modules[i] = CreateShaderModule(context, shader.spirv.data(), shader.spirv.size() * sizeof(std::uint32_t), "vkCreateShaderModule graphics"); const auto stage = VulkanStage(shaders[i].stage); stages[i].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; stages[i].stage = stage; diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp index e33db0d231..45b109c2c8 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp @@ -1992,10 +1992,7 @@ bool Recorder::RecordDispatchArguments(VkCommandBuffer commands, VkDeviceAddress layoutInfo.pushConstantRangeCount = 1; layoutInfo.pPushConstantRanges = &push; Check(context.Function("vkCreatePipelineLayout")(context.device, &layoutInfo, nullptr, &dispatchArgumentLayout), "vkCreatePipelineLayout dispatch arguments"); - VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - moduleInfo.codeSize = sizeof(DISPATCH_ARGUMENTS_SPV); - moduleInfo.pCode = DISPATCH_ARGUMENTS_SPV; - Check(context.Function("vkCreateShaderModule")(context.device, &moduleInfo, nullptr, &module), "vkCreateShaderModule dispatch arguments"); + module = CreateShaderModule(context, DISPATCH_ARGUMENTS_SPV, sizeof(DISPATCH_ARGUMENTS_SPV), "vkCreateShaderModule dispatch arguments"); VkComputePipelineCreateInfo pipelineInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; pipelineInfo.stage = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; pipelineInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; @@ -2075,11 +2072,7 @@ bool Recorder::gpuSampleCounter() { layoutInfo.pushConstantRangeCount = 1; layoutInfo.pPushConstantRanges = &push; Check(context.Function("vkCreatePipelineLayout")(context.device, &layoutInfo, nullptr, &sampleLayout), "vkCreatePipelineLayout sample counter"); - VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - const auto sampleCounterCode = CacheKeyedSpirv(context.graphicsPipelineLibrary, SAMPLE_COUNTER_SPV, sizeof(SAMPLE_COUNTER_SPV)); - moduleInfo.codeSize = sampleCounterCode.size() * sizeof(std::uint32_t); - moduleInfo.pCode = sampleCounterCode.data(); - Check(context.Function("vkCreateShaderModule")(context.device, &moduleInfo, nullptr, &module), "vkCreateShaderModule sample counter"); + module = CreateShaderModule(context, SAMPLE_COUNTER_SPV, sizeof(SAMPLE_COUNTER_SPV), "vkCreateShaderModule sample counter"); VkComputePipelineCreateInfo pipelineInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; pipelineInfo.stage = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; pipelineInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; @@ -2095,10 +2088,7 @@ bool Recorder::gpuSampleCounter() { const VkPushConstantRange dumpPush{VK_SHADER_STAGE_COMPUTE_BIT, 0, SampleDumpPushBytes}; layoutInfo.pPushConstantRanges = &dumpPush; Check(context.Function("vkCreatePipelineLayout")(context.device, &layoutInfo, nullptr, &dumpLayout), "vkCreatePipelineLayout sample dumps"); - const auto sampleDumpsCode = CacheKeyedSpirv(context.graphicsPipelineLibrary, SAMPLE_DUMPS_SPV, sizeof(SAMPLE_DUMPS_SPV)); - moduleInfo.codeSize = sampleDumpsCode.size() * sizeof(std::uint32_t); - moduleInfo.pCode = sampleDumpsCode.data(); - Check(context.Function("vkCreateShaderModule")(context.device, &moduleInfo, nullptr, &module), "vkCreateShaderModule sample dumps"); + module = CreateShaderModule(context, SAMPLE_DUMPS_SPV, sizeof(SAMPLE_DUMPS_SPV), "vkCreateShaderModule sample dumps"); pipelineInfo.stage.module = module; pipelineInfo.layout = dumpLayout; { @@ -2393,11 +2383,7 @@ bool Recorder::RecordMeshArguments(VkCommandBuffer commands, VkDeviceAddress rec layoutInfo.pushConstantRangeCount = 1; layoutInfo.pPushConstantRanges = &push; Check(context.Function("vkCreatePipelineLayout")(context.device, &layoutInfo, nullptr, &meshArgumentLayout), "vkCreatePipelineLayout mesh arguments"); - VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - const auto meshArgumentsCode = CacheKeyedSpirv(context.graphicsPipelineLibrary, MESH_ARGUMENTS_SPV, sizeof(MESH_ARGUMENTS_SPV)); - moduleInfo.codeSize = meshArgumentsCode.size() * sizeof(std::uint32_t); - moduleInfo.pCode = meshArgumentsCode.data(); - Check(context.Function("vkCreateShaderModule")(context.device, &moduleInfo, nullptr, &module), "vkCreateShaderModule mesh arguments"); + module = CreateShaderModule(context, MESH_ARGUMENTS_SPV, sizeof(MESH_ARGUMENTS_SPV), "vkCreateShaderModule mesh arguments"); VkComputePipelineCreateInfo pipelineInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; pipelineInfo.stage = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; pipelineInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp index 4063f8fb02..74621bdba1 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp @@ -89,11 +89,7 @@ TextureDetiler::TextureDetiler(const Context& context) : context(context) { pipelineLayoutInfo.pushConstantRangeCount = 1; pipelineLayoutInfo.pPushConstantRanges = &pushRange; Check(context.Function("vkCreatePipelineLayout")(context.device, &pipelineLayoutInfo, nullptr, &pipelineLayout), "vkCreatePipelineLayout"); - VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - const auto textureDetileCode = CacheKeyedSpirv(context.graphicsPipelineLibrary, TEXTURE_DETILE_SPV, sizeof(TEXTURE_DETILE_SPV)); - moduleInfo.codeSize = textureDetileCode.size() * sizeof(std::uint32_t); - moduleInfo.pCode = textureDetileCode.data(); - Check(context.Function("vkCreateShaderModule")(context.device, &moduleInfo, nullptr, &module), "vkCreateShaderModule"); + module = CreateShaderModule(context, TEXTURE_DETILE_SPV, sizeof(TEXTURE_DETILE_SPV), "vkCreateShaderModule"); bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; Check(context.Function("vkCreateDescriptorSetLayout")(context.device, &layoutInfo, nullptr, &imageDescriptorLayout), "vkCreateDescriptorSetLayout"); pipelineLayoutInfo.pSetLayouts = &imageDescriptorLayout; @@ -169,11 +165,7 @@ VkPipeline TextureDetiler::pipeline(TextureTileMode tileMode, std::uint32_t elem std::copy(equation->bits.begin(), equation->bits.end(), values.begin() + 4); } if (image && imageModule == VK_NULL_HANDLE) { - VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - const auto textureDetileImageCode = CacheKeyedSpirv(context.graphicsPipelineLibrary, TEXTURE_DETILE_IMAGE_SPV, sizeof(TEXTURE_DETILE_IMAGE_SPV)); - moduleInfo.codeSize = textureDetileImageCode.size() * sizeof(std::uint32_t); - moduleInfo.pCode = textureDetileImageCode.data(); - Check(context.Function("vkCreateShaderModule")(context.device, &moduleInfo, nullptr, &imageModule), "vkCreateShaderModule"); + imageModule = CreateShaderModule(context, TEXTURE_DETILE_IMAGE_SPV, sizeof(TEXTURE_DETILE_IMAGE_SPV), "vkCreateShaderModule"); } std::array entries{}; for (std::uint32_t index = 0; index < entries.size(); ++index) entries[index] = {index, index * 4u, 4}; @@ -275,10 +267,7 @@ void TextureDetiler::DispatchRepack(VkCommandBuffer commands, VkBuffer source, s Require(commands != VK_NULL_HANDLE && source != VK_NULL_HANDLE && destination != VK_NULL_HANDLE, "a texel repack needs a command buffer and its buffers"); Require(bytes != 0 && bytes % 4u == 0 && sourceOffset % 4u == 0 && destinationOffset % 4u == 0, "a texel repack needs whole aligned words"); if (repackPipeline == VK_NULL_HANDLE) { - VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - moduleInfo.codeSize = sizeof(TEXTURE_REPACK_SPV); - moduleInfo.pCode = TEXTURE_REPACK_SPV; - Check(context.Function("vkCreateShaderModule")(context.device, &moduleInfo, nullptr, &repackModule), "vkCreateShaderModule repack"); + repackModule = CreateShaderModule(context, TEXTURE_REPACK_SPV, sizeof(TEXTURE_REPACK_SPV), "vkCreateShaderModule repack"); VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; stage.module = repackModule; @@ -349,12 +338,7 @@ void TextureDetiler::DispatchCmaskClear(VkCommandBuffer commands, VkBuffer cmask pipelineLayoutInfo.pushConstantRangeCount = 1; pipelineLayoutInfo.pPushConstantRanges = &pushRange; Check(context.Function("vkCreatePipelineLayout")(context.device, &pipelineLayoutInfo, nullptr, &cmaskPipelineLayout), "vkCreatePipelineLayout CMASK clear"); - VkShaderModuleCreateInfo moduleInfo{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - const auto cmaskClearCode = CacheKeyedSpirv(context.graphicsPipelineLibrary, CMASK_CLEAR_SPV, sizeof(CMASK_CLEAR_SPV)); - moduleInfo.codeSize = cmaskClearCode.size() * sizeof(std::uint32_t); - moduleInfo.pCode = cmaskClearCode.data(); - VkShaderModule cmaskModule = VK_NULL_HANDLE; - Check(context.Function("vkCreateShaderModule")(context.device, &moduleInfo, nullptr, &cmaskModule), "vkCreateShaderModule CMASK clear"); + VkShaderModule cmaskModule = CreateShaderModule(context, CMASK_CLEAR_SPV, sizeof(CMASK_CLEAR_SPV), "vkCreateShaderModule CMASK clear"); VkComputePipelineCreateInfo pipelineInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; pipelineInfo.stage = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; pipelineInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; diff --git a/core/libs/prx/libSceAgcDriver/tests/Graphics.cpp b/core/libs/prx/libSceAgcDriver/tests/Graphics.cpp index e28a78b241..92e2141a31 100644 --- a/core/libs/prx/libSceAgcDriver/tests/Graphics.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/Graphics.cpp @@ -8393,6 +8393,25 @@ void LineStripTests() { Require(rejection.empty(), "the draw precheck rejected an indexed line strip with primitive restart: " + rejection); } +std::uint32_t keyedGenerator = 0; +std::size_t keyedWords = 0; + +VKAPI_ATTR VkResult VKAPI_CALL keyedCreateShaderModule(VkDevice, const VkShaderModuleCreateInfo* info, const VkAllocationCallbacks*, VkShaderModule* module) { + keyedWords = info->codeSize / sizeof(std::uint32_t); + keyedGenerator = info->pCode[2]; + *module = makeHandle(); + return VK_SUCCESS; +} + +void ShaderModuleKeyTests() { + const std::array code{0x07230203u, 0x00010300u, 0x00080001u, 8u, 0u}; + static_cast(AgcDriver::Graphics::CreateShaderModule(keyedCreateShaderModule, VK_NULL_HANDLE, true, code.data(), sizeof(code), "keyed module")); + Require(keyedWords == code.size() && keyedGenerator == 0x00080001u, "a shader module with graphics pipeline libraries changed its generator word"); + static_cast(AgcDriver::Graphics::CreateShaderModule(keyedCreateShaderModule, VK_NULL_HANDLE, false, code.data(), sizeof(code), "keyed module")); + Require(keyedWords == code.size() && keyedGenerator == (0x00080001u ^ 0x8000u), "a shader module without graphics pipeline libraries kept the generator word of the other mode"); + Require(code[2] == 0x00080001u, "keying a shader module changed its source words"); +} + void ProvokingVertexTests() { using namespace AgcDriver::Graphics; constexpr std::uint32_t lastVertex = 1u << 19u; @@ -10391,6 +10410,7 @@ int main(int argc, char** argv) { stencilReferenceUnusedTests(); aliasedBufferViewTests(); LineStripTests(); + ShaderModuleKeyTests(); ProvokingVertexTests(); ProvokingVertexRenderPassTests(); ConservativeRasterizationTests();