fix(agc): validate a mesh stage's push block when it has no push data of its own
A mesh-stage program reads its draw parameters from the end of the pipeline's push block (MeshDrawPushOffsetBytes), so its SPIR-V always declares the push-constant variable. When its user data do not fit the push range it has no push data of its own and RecompileResult::pushConstants is empty, and validation refused the draw with "invalid push constant interface". Validation now expects the push block of every mesh-stage program and still requires it to match the recompiler's metadata for the other stages. agc_driver_mesh_tests draws the triangle list with a geometry program given no push range for its own data.
This commit is contained in:
parent
33f9109999
commit
13aecb4f7c
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ struct MeshDraw {
|
|||
ShaderRecompiler::MeshConfiguration mesh;
|
||||
AgcDriver::Pm4::DrawParameters draw;
|
||||
std::array<std::uint32_t, 4> 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<std::uintptr_t>(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<std::uint32_t>(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<std::uint32_t>(Ordered.size()), 0, 1, 0, false}, VertexBufferDescriptor(Ordered.data(), static_cast<std::uint32_t>(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<std::uint32_t>(Strip.size()), 0, 1, 0, false}, VertexBufferDescriptor(Strip.data(), static_cast<std::uint32_t>(Strip.size()))});
|
||||
|
|
|
|||
Loading…
Reference in New Issue