Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SPIR-V] Multiple variables with TaskPayloadWorkgroupEXT in task/amplification shaders #5981

Closed
godlikepanos opened this issue Nov 6, 2023 · 6 comments · Fixed by #6526
Closed
Assignees
Labels
bug Bug, regression, crash spirv Work related to SPIR-V

Comments

@godlikepanos
Copy link
Contributor

godlikepanos commented Nov 6, 2023

Description
When the task payload is a struct the SPIR-V backend generates multiple variables with TaskPayloadWorkgroupEXT (one variable per member of the struct actually). The spec states that only a single TaskPayloadWorkgroupEXT variable can exist.

Each OpEntryPoint with the MeshEXT or TaskEXT Execution Models can have at most one global OpVariable of storage class TaskPayloadWorkgroupEXT.

Steps to Reproduce
Here is a simple task shader:

struct Payload
{
    uint index1;
    uint index2;
};

groupshared Payload s_payload;

[numthreads(16, 1, 1)]
void main(uint svGroupId : SV_GROUPID) 
{
    s_payload.index1 = svGroupId;
    s_payload.index2 = svGroupId * 100;

    DispatchMesh(svGroupId, 1, 1, s_payload);
}

Compiling with -T as_6_7 -E main -spirv -fspv-target-env=vulkan1.1spirv1.4 it gives the following SPIR-V:

               OpCapability MeshShadingEXT
               OpExtension "SPV_EXT_mesh_shader"
               OpMemoryModel Logical GLSL450
               OpEntryPoint TaskEXT %main "main" %gl_WorkGroupID %out_var_index1 %out_var_index2 %s_payload
               OpExecutionMode %main LocalSize 16 1 1
               OpMemberName %Payload 0 "index1"
               OpMemberName %Payload 1 "index2"
               OpModuleProcessed "dxc-commit-hash: 05094636"
               OpModuleProcessed "dxc-cl-option: /app/example.hlsl -E main -T as_6_7 -Zi -Qembed_debug -spirv -fspv-target-env=vulkan1.1spirv1.4"
               OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId
        %int = OpTypeInt 32 1
      %int_0 = OpConstant %int 0
       %uint = OpTypeInt 32 0
   %uint_100 = OpConstant %uint 100
      %int_1 = OpConstant %int 1
     %uint_1 = OpConstant %uint 1
    %Payload = OpTypeStruct %uint %uint
%_ptr_Workgroup_Payload = OpTypePointer Workgroup %Payload
     %v3uint = OpTypeVector %uint 3
%_ptr_Input_v3uint = OpTypePointer Input %v3uint
%_ptr_TaskPayloadWorkgroupEXT_uint = OpTypePointer TaskPayloadWorkgroupEXT %uint
       %void = OpTypeVoid
         %20 = OpTypeFunction %void
%_ptr_Function_uint = OpTypePointer Function %uint
         %22 = OpTypeFunction %void %_ptr_Function_uint
%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
     %uint_2 = OpConstant %uint 2
   %uint_264 = OpConstant %uint 264
  %s_payload = OpVariable %_ptr_Workgroup_Payload Workgroup
%gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input
%out_var_index1 = OpVariable %_ptr_TaskPayloadWorkgroupEXT_uint TaskPayloadWorkgroupEXT
%out_var_index2 = OpVariable %_ptr_TaskPayloadWorkgroupEXT_uint TaskPayloadWorkgroupEXT
       %main = OpFunction %void None %20
         %26 = OpLabel
%param_var_svGroupId = OpVariable %_ptr_Function_uint Function
         %27 = OpLoad %v3uint %gl_WorkGroupID
         %28 = OpCompositeExtract %uint %27 0
               OpStore %param_var_svGroupId %28
         %29 = OpAccessChain %_ptr_Workgroup_uint %s_payload %int_0
               OpStore %29 %28
         %30 = OpIMul %uint %28 %uint_100
         %31 = OpAccessChain %_ptr_Workgroup_uint %s_payload %int_1
               OpStore %31 %30
               OpControlBarrier %uint_2 %uint_2 %uint_264
         %32 = OpLoad %Payload %s_payload
         %33 = OpCompositeExtract %uint %32 0
               OpStore %out_var_index1 %33
         %34 = OpCompositeExtract %uint %32 1
               OpStore %out_var_index2 %34
               OpEmitMeshTasksEXT %28 %uint_1 %uint_1
               OpFunctionEnd

You can play with the shader in compiler explorer: https://godbolt.org/z/hPEnx68E3

As you can see there are two TaskPayloadWorkgroupEXT variables (out_var_index1 and out_var_index2) which is wrong.

Note no1: It seems the code generated is not generally optimal. The s_payload is decorated as groupshared in SPIR-V and at DispatchMesh() the compiler will emit copies from s_payload to a new set of TaskPayloadWorkgroupEXT variables. It would have been preferable if s_payload was decorated as TaskPayloadWorkgroupEXT and the extra copies are removed.

Note no2: Similar problem exists in the mesh shaders where DXC will take the struct of a payload and create multiple global TaskPayloadWorkgroupEXT variables.

Actual Behavior
Ideally the s_payload is not decorated as groupshared but as TaskPayloadWorkgroupEXT and the copies from groupshared to TaskPayloadWorkgroupEXT are removed.

Environment

  • DXC version: trunk & 1.7.2207
  • Host Operating System: Linux & Windows
@godlikepanos godlikepanos added bug Bug, regression, crash needs-triage Awaiting triage spirv Work related to SPIR-V labels Nov 6, 2023
@godlikepanos
Copy link
Contributor Author

cc @tywuAMD

@sudonatalie
Copy link
Collaborator

Thanks for identifying this @godlikepanos . @cassiebeckley Can you look into this?

Relevant spec: https://htmlpreview.github.io/?https://github.com/KhronosGroup/SPIRV-Registry/blob/master/extensions/EXT/SPV_EXT_mesh_shader.html

And it looks like adding this to spirv-val is already being tracked here: KhronosGroup/SPIRV-Tools#4919

@sudonatalie sudonatalie removed the needs-triage Awaiting triage label Nov 21, 2023
@sudonatalie sudonatalie moved this from For Google to Done in HLSL Triage Nov 21, 2023
@spencer-lunarg
Copy link

this seems like a related problem to KhronosGroup/SPIRV-Tools#4969 (comment) where there are more than 1 RayTracing StorageClass Variable

@godlikepanos
Copy link
Contributor Author

godlikepanos commented Mar 23, 2024

Hi. Is there a chance this can be prioritized? On top of the problems it causes on RenderDoc (the mesh view in RenderDoc doesn't work when there are multiple TaskPayloadWorkgroupEXT) it also causes issues on AMD. AMD confirmed that their driver's compiler fails to link the task and mesh shaders because of the issue

@spencer-lunarg
Copy link

for notes, I think this was added already for Ray Tracing shaders
#6268

@sudonatalie
Copy link
Collaborator

@cassiebeckley feel free to re-assign this to me if you don't have bandwidth for it right now.

sudonatalie added a commit to sudonatalie/DirectXShaderCompiler that referenced this issue Apr 12, 2024
The existing logic from VK_NV_mesh_shader was incorrectly adapted
for the VK_EXT_mesh_shader implementation when it comes to the handling
of mesh payloads as in/out variables. Because TaskPayloadWorkgroupEXT
must be applied to a single global OpVariable for each Task/Mesh shader,
the struct should not be flattened. Further, as far as I can tell,
Location assignment is not necessary for these input and output
variables, so the usual reason for flattening structs does not apply.

This change now removes the inner struct member global variables and
ensures the parent payload is decorated with TaskPayloadWorkgroupEXT.
Note that for amplification/task shaders, the payload variable is
created with the groupshared decl, and then it's storage class needs to
be updated when that variable is used as a parameter to the DispatchMesh
call, as described in: https://docs.vulkan.org/spec/latest/proposals/proposals/VK_EXT_mesh_shader.html#_hlsl_changes

Tested with updated spirv-val from: KhronosGroup/SPIRV-Tools#5640

Fixes microsoft#5981
sudonatalie added a commit that referenced this issue Apr 17, 2024
)

The existing logic from `VK_NV_mesh_shader` was incorrectly adapted for
the `VK_EXT_mesh_shader` implementation when it comes to the handling of
payloads as in/out variables. Because `TaskPayloadWorkgroupEXT` must be
applied to a single global `OpVariable` for each task/mesh shader, the
struct should not be flattened. Further, Location assignment is not
necessary for these input and output variables, so the usual reason for
flattening structs does not apply.

This change now removes the inner struct member global variables and
ensures the parent payload is decorated with `TaskPayloadWorkgroupEXT`.
Note that for amplification/task shaders, the payload variable is
created with the `groupshared` decl, and then its storage class needs to
be updated when that variable is used as a parameter to the
`DispatchMesh` call, as described in:
https://docs.vulkan.org/spec/latest/proposals/proposals/VK_EXT_mesh_shader.html#_hlsl_changes

Tested with new validation checks from:
KhronosGroup/SPIRV-Tools#5640

Fixes #5981
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Bug, regression, crash spirv Work related to SPIR-V
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

5 participants