diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/ShaderValidation.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/ShaderValidation.cpp index 76b3f374d..413860f9a 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/ShaderValidation.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/ShaderValidation.cpp @@ -421,7 +421,7 @@ Module Inspect(const CompiledShader& compiled, const State& state, const VkPhysi } } } else if (variable.storage == spv::StorageClassPushConstant) { - Require(!push && !shader.pushConstants.empty() && (type[0] & 0xffffu) == spv::OpTypeStruct, "invalid push constant interface"); + Require(!push && (!shader.pushConstants.empty() || mesh) && (type[0] & 0xffffu) == spv::OpTypeStruct, "invalid push constant interface"); push = true; Require(type.size() == 3 && module.decorations[typeId].block, "push constant variable must be a Block struct with exactly one member"); const auto offset = module.offsets.find({typeId, 0}); @@ -480,7 +480,7 @@ Module Inspect(const CompiledShader& compiled, const State& state, const VkPhysi Require(shader.vertexAttributes.empty(), "vertex attribute metadata is invalid for this stage"); } Require(descriptors.size() == shader.bindings.size(), "recompiler binding metadata contains undeclared resources"); - Require(push == !shader.pushConstants.empty(), "recompiler push constant metadata disagrees with SPIR-V"); + Require(push == (!shader.pushConstants.empty() || mesh), "recompiler push constant metadata disagrees with SPIR-V"); for (const auto id : module.interface) Require(module.variables.contains(id), "entry point interface contains an unknown variable"); if (mesh) Require(module.primitiveIndices, "mesh shader does not export primitive indices"); if (stage == Stage::Vertex || mesh || evaluation) Require(module.position, "vertex shader does not export position"); diff --git a/core/libs/prx/libSceAgcDriver/tests/Mesh.cpp b/core/libs/prx/libSceAgcDriver/tests/Mesh.cpp index 129df2015..4808e4e13 100644 --- a/core/libs/prx/libSceAgcDriver/tests/Mesh.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/Mesh.cpp @@ -106,6 +106,7 @@ struct MeshDraw { ShaderRecompiler::MeshConfiguration mesh; AgcDriver::Pm4::DrawParameters draw; std::array vertexBuffer; + std::uint32_t geometryPushBytes = ShaderRecompiler::MeshDrawPushOffsetBytes; }; void DrawMesh(AgcDriver::VulkanDevice& device, const MeshDraw& setup) { @@ -119,11 +120,12 @@ void DrawMesh(AgcDriver::VulkanDevice& device, const MeshDraw& setup) { {ShaderStage::Mesh, reinterpret_cast(GeometryCode.data()), GeometryCode, 0, {}}, {64, 0, userData, std::nullopt, std::nullopt, ShaderRecompiler::ShaderVertexStageInfo{}, geometryMemory}, target, - {0, 0, 0, ShaderRecompiler::MeshDrawPushOffsetBytes}, + {0, 0, 0, setup.geometryPushBytes}, ShaderRecompiler::GraphicsCompileContext{0, {}, setup.mesh, std::nullopt, {setup.draw.indexAddress, setup.draw.indexCount, setup.draw.indexSize, setup.draw.instanceCount}} }; const auto meshResult = ShaderRecompiler::Recompile(geometry); const auto meshPush = static_cast(meshResult.pushConstants.size()); + Require((meshPush == 0) == (setup.geometryPushBytes == 0), "the geometry program's push data does not follow its layout"); ShaderRecompiler::ShaderPixelStageInfo pixel{}; pixel.interpolatorCount = 1; @@ -212,6 +214,10 @@ int main() { CheckTriangles((std::string("non-indexed triangle list, ") + name).c_str()); } + ClearPixels(); + DrawMesh(device, {SmallSubgroup, {0, static_cast(Ordered.size()), 0, 1, 0, false}, VertexBufferDescriptor(Ordered.data(), static_cast(Ordered.size())), 0}); + CheckTriangles("mesh program without push data"); + ClearPixels(); const ShaderRecompiler::MeshConfiguration strip{6u, 3u, 5u, 9u, 3u, 64u, 1024u, 0u, 4u}; DrawMesh(device, {strip, {0, static_cast(Strip.size()), 0, 1, 0, false}, VertexBufferDescriptor(Strip.data(), static_cast(Strip.size()))});