-
Notifications
You must be signed in to change notification settings - Fork 367
Alignment error compiling HLSL to SPIR-V. #334
-
I am a long-time programmer, mostly back-end-stuff, but new to Vulkan and Diligent. I created a fairly simple app to generate and dispaly a Fibonacci Sphere with a compute shader, and it worked fine. Now, I am trying something more ambitious.
I have a HLSL compute shader that I am cross-compiling using:
Diligent::IRenderDevice::CreateShader(ShaderCreateInfo, RefCntAutoPtr)
This shader has multiple entry points. When I invoke CreateShader, I get an error about structure alignment:
Diligent Engine: ERROR: Spirv optimizer error: Structure id 390 decorated as BufferBlock for variable in Uniform storage class must follow standard storage buffer layout rules: member 1 at offset 20 overlaps previous member ending at offset 31 %Cell = OpTypeStruct %_arr_uint_uint_8 %_arr_uint_uint_4
The ShaderCreateInfo is configured as follows:
ShaderCreateInfo shaderCI;
shaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;
shaderCI.ShaderCompiler = SHADER_COMPILER_DEFAULT;
shaderCI.EntryPoint = entryPoints[stageIdx];
shaderCI.Source = shaderSource.c_str();
shaderCI.Desc.ShaderType = SHADER_TYPE_COMPUTE;
shaderCI.Desc.Name = (std::string("Shader CS - ") + entryPoints[stageIdx]).c_str();
And the problem structure is:
struct Cell {
uint ids[8]; // Store up to 8 different IDs per cell
uint count[4]; // Number IDs in this cell
};
I have no idea how this manages to violate SPIR-V alignment rules, and even less idea why the offset of member 1 would be 20, as opposed to 31. Can anybody explain this to me?
Beta Was this translation helpful? Give feedback.
All reactions
First of all, in this line:
shaderCI.Desc.Name = (std::string("Shader CS - ") + entryPoints[stageIdx]).c_str();You create a temporary string on stack, which is immediately destroyed, so shaderCI.Desc.Name is a pointer to dead memory.
Note that Core Diligent API is c-compatible, so shaderCI.Desc.Name is a pointer, not std::string
There is GraphicsTypesX.hpp header that contains C++ wrappers, which are easier and safer to use.
As to the topic, this appears to be an issue in GLSLang - it generates the code that does not pass validation by SPIRV-Tools.
Note that indexing in Shaders can only be done on 4-vectors (e.g. float4, uint4). As a rule of thumb, always align you struct members by 4-ve...
Replies: 3 comments 3 replies
-
First of all, in this line:
shaderCI.Desc.Name = (std::string("Shader CS - ") + entryPoints[stageIdx]).c_str();You create a temporary string on stack, which is immediately destroyed, so shaderCI.Desc.Name is a pointer to dead memory.
Note that Core Diligent API is c-compatible, so shaderCI.Desc.Name is a pointer, not std::string
There is GraphicsTypesX.hpp header that contains C++ wrappers, which are easier and safer to use.
As to the topic, this appears to be an issue in GLSLang - it generates the code that does not pass validation by SPIRV-Tools.
Note that indexing in Shaders can only be done on 4-vectors (e.g. float4, uint4). As a rule of thumb, always align you struct members by 4-vectors to avoid hard-to-debug problems caused by mismatch between CPU and GPU layouts.
For example, struct like this will cause a lot of pain:
struct Bad { float3 f3; float4 f4; };
As the shader will add padding between f3 and f4. Also, never use float3 in constant buffers.
Going back to your question, try
struct Cell { uint4 ids[2]; // Store up to 8 different IDs per cell uint4 count; // Number IDs in this cell };
If the problem was indeed in this struct, this most likely should fix it.
Beta Was this translation helpful? Give feedback.
All reactions
-
Beta Was this translation helpful? Give feedback.
All reactions
-
Did you manage to fix the shader issue?
Beta Was this translation helpful? Give feedback.
All reactions
-
Yes, Assiduous' suggestion did resolve the problem. Indexing into the resulting array is awkward, but it does work.
I still don't understand why this is necessary, but it appears to be some quirk of GLSLang?
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
This may be a bug in GLSLang. The SPIRV must be valid, or the shader should not compile.
It should be possible to use some math tricks to get the index from the vector, for example, use dot with mask vector (such as uint4(0, 0, 1, 0))
Beta Was this translation helpful? Give feedback.
All reactions
-
The term "mask vector" is new to me. I will do some research.
Update:
I am currently using:
int vecIdx = idIdx / 4;
uint compIdx = idIdx % 4;
vec[cellIdx].ids[vecIdx][compIdx];
Which at least compiles. You are suggesting something like
dot(vec[vecIdx], mask[compIdx])
where
uint4 mask[4] = {{1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1}};
?
Beta Was this translation helpful? Give feedback.