KhronosGroup / glslang

Khronos-reference front end for GLSL/ESSL, partial front end for HLSL, and a SPIR-V generator.
Other
2.95k stars 819 forks source link

In Vulkan, OpTypeStruct must not contain an opaque type. #2931

Open vbachet opened 2 years ago

vbachet commented 2 years ago

Hello,

We have a fair amount of shader code running on OpenGL, that we want to reuse on our Vulkan backend. The Vulkan relaxed rules help a lot, but we have a remaining issue with texture samplers declared in a structure. For example:

`struct TexUnit { sampler2D smp; vec4 blah; };

uniform TexUnit myTex;`

is valid in OpenGL, but not in Vulkan.

While I fully understand the rationale behind this limitation, I would be interested to know if there is a way to get a valid Vulkan SPIRV binary out of this GLSL code, without touching shader code.

Thanks a lot for your help.

greg-lunarg commented 2 years ago

I think so.

This is similar to a problem that HLSL has: HLSL also allows opaques in structs but Vulkan does not.

The way this was fixed for HLSL was to use the spirv-opt optimizer to "legalize" the invalid SPIR-V coming out of the HLSL front-end. Essentially, scalar replacement (SROA) would break these structs up and create standalone variables from their components, which Vulkan would accept.

I will quick run an experiment and see if this fix could work for GLSL.

greg-lunarg commented 2 years ago

Sorry, unfortunately the HLSL solution only addressed and eliminated local variable structs with opaque types.

I will take a look at the resulting SPIR-V and see what might be done.

greg-lunarg commented 2 years ago

What version shaders are you using?

vbachet commented 2 years ago

We are using GLSL #version 450, Vulkan 1.1 and SPIRV 1.3. For the record we build our shaders using glslang with automap bindings, automap locations, and Vulkan relaxed rules. We don't get any compilation errors from glslang but the resulting SPIRV is not considered valid by spirv-opt or Vulkan.

greg-lunarg commented 2 years ago

I was trying to find a version of GLSL where it was valid to have an opaque in a struct, but I couldn't find one. What were the "original" versions of your shaders?

vbachet commented 2 years ago

Thank you very much for taking the time to look at our problem.

The original version is 330, and as long as we target OpenGL it works fine on all vendors/platforms.

I've found in the GLSL Vulkan specification (GL_KHR_vulkan_glsl) the following sentence indicating that it is a limitation specific to Vulkan: Remove "structure member selection" from 4.1.7 and instead add a sentence "Opaque types cannot be declared or nested in a structure (struct)."