Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compiling GLSL written for OpenGL ES versions to Vulkan

Tags:

vulkan

My question is similar to this one but part of the (useful) given answer isn't compatible with compiling GLSL for vulkan based on OpenGL ES ESSL 3.10.

In order to use a separate section of the push constant memory in the vertex shader and the fragment shader, the suggested solution is to use layout(offset = #) before the first member of the push constant structure.

Attempting to do this in GLSL ES 310 code leads to the error "'offset on block member': not supported with this profile: es".

Is there a supported way to declare such an offset that is compatible with es?

The only workaround I've found is to declare a bunch of dummy variables in the fragment shader. When I do so, I get validation layer errors if I don't declare the full range of the fragment shader's push constant buffer in VkPipelineLayoutCreateInfo. After fixing that, I get validation layer warnings about "vkCreatePipelineLayout() call has push constants with overlapping ranges".

Obviously I can ignore warnings, but if there's a tidier solution, then that would be much more preferable.

Simple example, this compiles successfully with VulkanSDK\1.0.13.0\Bin\glslangValidator.exe:

#version 430
#extension GL_ARB_enhanced_layouts: enable

layout(std140, push_constant) uniform PushConstants
{
        layout(offset=64) mat4 matWorldViewProj;
} ubuf;

layout(location = 0) in vec4 i_Position;

void main() {
    gl_Position = ubuf.matWorldViewProj * i_Position;
}

Whereas this does not:

#version 310 es
#extension GL_ARB_enhanced_layouts: enable

layout(std140, push_constant) uniform PushConstants
{
        layout(offset=64) mat4 matWorldViewProj;
} ubuf;

layout(location = 0) in vec4 i_Position;

void main() {
    gl_Position = ubuf.matWorldViewProj * i_Position;
}

Converting all my 310 ES shader code to 430 would solve my problem, but that wouldn't be ideal. GL_ARB_enhanced_layouts doesn't apply to 310 ES code, so my question is not about why it doesn't work, but rather, do I have any options in ES to achieve the same goal?

like image 847
Columbo Avatar asked Jun 17 '16 15:06

Columbo


People also ask

Can Vulkan use GLSL?

OpenGL Shading Language (GLSL) is the standard shader programming language for Khronos APIs such as Vulkan, OpenGL 4.

Does Vulkan use GLSL or HLSL?

With a few exceptions, all Vulkan features and shader stages available with GLSL can be used with HLSL too, including recent Vulkan additions like hardware accelerated ray tracing.

How do you compile shaders in Vulkan?

Double click the file to run it. Replace the path to glslc with the path to where you installed the Vulkan SDK. Make the script executable with chmod +x compile.sh and run it. These two commands tell the compiler to read the GLSL source file and output a SPIR-V bytecode file using the -o (output) flag.

What does GLSL compile to?

Now, GLSL code can be pre-compiled to SPIR-V offline using the shaderc toolchain. The developers would do this ahead of time and ship the SPIR-V bytecode with their app. Then at runtime the SPIR-V gets submitted to the Vulkan driver and compiled the rest of the way to GPU machine code.


2 Answers

I would consider this an error in the GLSL compiler.

What's happening is this. There are some things which compiling GLSL for Vulkan adds to the language, as defined by KHR_vulkan_glsl. The push_constant layout, for example, is explicitly added to GLSL syntax.

However, there are certain things which it does not add to the language. Important to your use case is the ability to apply offsets to members of uniform blocks. Oh yes, KHR_vulkan_glsl uses that information when building the shader's block layout. But the grammar that allows you to say layout(offset=#) is defined by GLSL, not by KHR_vulkan_glsl.

And that grammar is not a part of any version of GLSL-ES. Nor is it provided by any ES extension I am aware of. So you can't use it.

I would say that the reference compiler should, when compiling a shader for Vulkan, either fail to compile any GLSL-ES-based version, or silently ignore any version and extension declarations, and just assume desktop GLSL 4.50.

As for what you can do about it... nothing. Short of hacking that solution into the compiler yourself, your primary solution is to write your code against versions of desktop OpenGL. Like 4.50.

like image 199
Nicol Bolas Avatar answered Sep 22 '22 13:09

Nicol Bolas


If you compile SPIR-V for Vulkan there is a "VULKAN" define set in your shaders (see GL_KHR_VULKAN_glsl), so you could do something like this:

#ifdef VULKAN
    layout(push_constant) uniform pushConstants {
        vec4 (offset = 12) pos;
    } pushConstBlock;
#else
    // GLES stuff
#endif
like image 24
Sascha Willems Avatar answered Sep 21 '22 13:09

Sascha Willems