Description
Description
In task shaders, the OpEmitMeshTasksEXT
will never have a payload attached even when it should. This is possibly leftover from the NV extension where the payload was implicit and not a parameter to the emit instruction.
Steps to Reproduce
You can compile the test shader from this repository ./tools/clang/test/CodeGenSPIRV/meshshading.ext.amplification.hlsl to see the problem.
The checks there are not complete (I'm not sure if they're intended to be a partial match or not) but the OpEmitMeshTasksEXT produced does not reference the payload when it should. This is not completely invalid but it doesn't match the HLSL which is outputting a payload.
On godbolt here is a shorter example: https://godbolt.org/z/6ajvse7jW
struct payloadType { uint a; };
groupshared payloadType payload;
[numthreads(1, 1, 1)]
void main()
{
payload.a = 12;
DispatchMesh(1, 1, 1, payload);
}
; ...
%payload = OpVariable %_ptr_TaskPayloadWorkgroupEXT_payloadType TaskPayloadWorkgroupEXT
; ...
%18 = OpLoad %payloadType %payload
OpStore %payload %18
OpEmitMeshTasksEXT %uint_1 %uint_1 %uint_1
OpFunctionEnd
Actual Behavior
OpEmitMeshTasksEXT
is always produced without a payload regardless of whether the HLSL shader used one or not.
Environment
dxcompiler.dll: 1.8 - 1.8.2407.7 (416fab6b5); dxil.dll: 1.8(101.8.2407.12)
&libdxcompiler.so: 1.8(dev;1-e4636f06); libdxil.so: 1.8
- Windows 10 22H2
Theory
The code in SpirvEmitter::processDispatchMesh
seems to do most of the work of declaring the payload but doesn't associate it with the emit, instead always passing NULL. This patch fixes it for me though I don't know if it's complete:
diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp
index 94952b3c3..9ae16619e 100644
--- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp
+++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp
@@ -12593,7 +12593,7 @@ void SpirvEmitter::processDispatchMesh(const CallExpr *callExpr) {
: spv::StorageClass::Output;
auto *payloadArg = doExpr(args[3]);
bool isValid = false;
- const VarDecl *param = nullptr;
+ SpirvInstruction *param = nullptr;
if (const auto *implCastExpr = dyn_cast<CastExpr>(args[3])) {
if (const auto *arg = dyn_cast<DeclRefExpr>(implCastExpr->getSubExpr())) {
if (const auto *paramDecl = dyn_cast<VarDecl>(arg->getDecl())) {
@@ -12601,7 +12601,8 @@ void SpirvEmitter::processDispatchMesh(const CallExpr *callExpr) {
isValid = declIdMapper.createPayloadStageVars(
sigPoint, sc, paramDecl, /*asInput=*/false, paramDecl->getType(),
"out.var", &payloadArg);
- param = paramDecl;
+ param =
+ declIdMapper.getDeclEvalInfo(paramDecl, paramDecl->getLocation());
}
}
}
@@ -12618,7 +12619,7 @@ void SpirvEmitter::processDispatchMesh(const CallExpr *callExpr) {
if (featureManager.isExtensionEnabled(Extension::EXT_mesh_shader)) {
// for EXT_mesh_shader, create opEmitMeshTasksEXT.
- spvBuilder.createEmitMeshTasksEXT(threadX, threadY, threadZ, loc, nullptr,
+ spvBuilder.createEmitMeshTasksEXT(threadX, threadY, threadZ, loc, param,
range);
} else {
// for NV_mesh_shader, set TaskCountNV = threadX * threadY * threadZ.
Metadata
Metadata
Assignees
Type
Projects
Status
Status