I'm using a shader transpiler tool called 'glslcc' and it supports transpiling into glsl. However I think the GLSL outputs are Vulkan GLSL since it contains things like the following but I might be wrong.
layout(std140) uniform u_Test
{
vec4 test;
} _34;
Will this shader work in OpenGL? If not is there a way to convert from this format to something else so it can be loaded in OpenGL?
This is a Uniform Block that can of course be used with OpenGL (see also Uniform Buffer Object). There is no Vulkan exclusive declaration in this code. The Layout Qualifier std140 was introduced with OpenGL 3.1. See The OpenGLĀ® Shading Language, Version 4.60.7.
Related
I did a glsl -> metal parser that works pretty well if the glsl code is not using very old features.
The biggest issue I'm facing is when a glsl code does not explicitly define a texture binding location, like:
uniform layout(binding = 0) sampler2D myTexture; // this is fine
uniform sampler2D myTexture2; // this is the problem
In metal you have to define a texture index on compile time. While in glsl you are allowed to specify (and change) it on run-time.
I believe this is not possible, specially because I can't find it on the spec, but does anyone know if it's possible to specify (or change) a texture index of a metal shader on the fly in CPU side?
texture2d < half > myTexture[[ texture(IDX) ]] // where IDX is not constexpr?
Is there any way to automatically compile OpenGL shaders for Vulkan? The problem is with the uniforms.
'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan
I have tried compiling for OpenGL, then decompiling with spirv-cross with --vulkan-semantics, but it still has non-opaque uniforms.
spirv-cross seems to only have tools for compiling Vulkan shaders for OpenGL.
[--glsl-emit-push-constant-as-ubo]
[--glsl-emit-ubo-as-plain-uniforms]
A shader meant for OpenGL consumption will not work on Vulkan. Even ignoring the difference in how they consider uniforms, they have very different resource models. Vulkan uses descriptor sets and binding points, with all resources using the same binding indices (set+binding). By contrast, OpenGL gives each kind of resource its own unique set of indices. So a GLSL shader meant for OpenGL consumption might assign a texture uniform and a uniform block to the same binding index. But you can't do that in a GLSL shader meant for Vulkan, not unless the two resources are in different descriptor sets.
If you want to share shaders, you're going to need to employ pre-processor trickery to make sure that the shader assigns resources (including how it apportions uniforms) for the specific target that the shader is being compiled for.
There seems to be a lot of ambiguity about gl_FragColor being deprecated. For example, it is missing in the GLSL 4.40 specification, but it is included in the GLSL 4.60 specification.
What is the safest, most compatible, most supported strategy? Using gl_FragColor or defining a shader output like out vec4 color?
Yes, gl_FragColor is deprecated. You should use the following syntax:
layout(location = 0) out vec4 diffuseColor;
It is included in the GLSL 4.60 spec under the section 7.1.7. Compatibility Profile Built-In Language Variables. That means, if you create a core context this variable will not be available.
If you would read the the GLSL 4.40 specification carefully, then you would find gl_FragCoord in chapter "7.1.1 Compatibility Profile Built-In Language Variables", as it is in the GLSL 4.60 specification.
The following fragment output variables are available in a fragment shader when using the compatibility profile:
out vec4 gl_FragColor;
out vec4 gl_FragData[gl_MaxDrawBuffers];
Writing to gl_FragColor specifies the fragment color that will be used by the subsequent fixed functionality pipeline. If subsequent fixed functionality consumes fragment color and an execution of the fragment shader executable does not write a value to gl_FragColor then the fragment color consumed is undefined.
This means you can't use gl_FragColor, in an OpenGL Core profile Context, because it is deprecated, but it would still be available in a compatibility profile.
The modern way of writing to the output buffers from a fragment shader, is to declare user-defined output variables and to use Layout Qualifiers.
Most GLSL shaders are using a attribute for the color in the vertex shader, which will be forwarded as varying to the fragment shader. Like this:
attribute vec4 position;
attribute vec4 color;
uniform mat4 mvp;
varying vec4 destinationColor;
void main(){
destinationColor = color;
gl_Position = mvp * position;
};
Setting the color can be done with glVertexAtribPointer() to pass one color per vertex or with glVertexAttrib4fv() to pass a global color for all vertexes. I try to understand the difference to the predefined variable gl_Color in the vertex shader (if there is any difference at all). i.e.
attribute vec4 position;
uniform mat4 mvp;
varying vec4 destinationColor;
void main(){
destinationColor = gl_Color;
gl_Position = mvp * position;
};
and using glColorPointer() to pass one color per vertex or glColor4fv() to use a global color for all vertexes. To me the second shader looks better (= more efficient?), because it uses less attributes. But all tutorials & online resources are using the first approach - so I wonder if I missed anything or if there is no difference at all.
What is better practice when writing GLSL shaders?
To me the second shader looks better (= more efficient?), because it uses less attributes.
It does not use fewer attributes. It just uses fewer explicit attribute declarations. All of the work needed to get that color value to OpenGL is still there. It's still being done. The hardware is still fetching data from a buffer object or getting it from the glColor context value or whatever.
You just don't see it in your shader's text. But just because you don't see it doesn't mean that it happens for free.
User-defined attributes are preferred for the following reasons:
User-defined attributes make it clear how many resources your shaders are using. If you want to know how many attributes you need to provide to a shader, just look at the global declarations. But with predefined attributes, you can't do this; you have to scan through the entire vertex shader for any gl_* names that name a predefined attribute.
User-defined attributes can do more things. If you want to pass integer values as integers to the vertex shader, you must use a user-defined attribute. If you need to pass a double-precision float to the vertex shader, again, a predefined attribute cannot help you.
Predefined attributes were removed from core OpenGL contexts. OSX, for example, does not allow the compatibility profile. You can still use OpenGL 2.1, but if you want to use any OpenGL version 3.2 or greater on OSX, you cannot use removed functionality. And the built-in vertex attributes were removed in OpenGL 3.1.
Predefined attributes were never a part of OpenGL ES 2.0+. So if you want to write shaders that can work in OpenGL ES, you again cannot use them.
So basically, there's no reason to use them these days.
if I remember correctly gl_Color is deprecated remnant from the old style API without VAO/VBO using glBegin() ... glEnd(). If you go to core profile there is no gl_Color anymore ... so I assume you use old OpenGL version or compatibility profile.
If you try to use gl_Color in core profile (for example 4.00) you got:
0(35) : error C7616: global variable gl_Color is removed after version 140
Which means gl_Color was removed from GLSL 1.4
It is not entirely matter of performance but the change in graphic rendering SW architecture or hierarchy of the GL calls if you want.
I am trying to get UBOs working, however I get a compilation error in the fragment shader:
ERROR 0:5:"(": synrax error.
Fragment Shader:
layout(std140) uniform Colors
{
vec3 SCol;
vec3 WCol;
float DCool;
float DWarm;
}colors;
Where am I going wrong?
At the begining of your fragment shader source file (the very first line) put this:
#version 140
This means that you are telling the GLSL compiler that you use the version 1.40 of the shading language (you can, of course, use a higher version - see Wikipedia for details).
Alternatively, if your OpenGL driver (and/or hardware) doesn't support GLSL 1.40 fully (which is part of OpenGL 3.1), but only GLSL 1.30 (OpenGL 3.0), you can try the following:
#version 130
#extension GL_ARB_uniform_buffer_object : require
However, this one will work only if your OpenGL 3.0 driver supports the GL_ARB_uniform_buffer_object extension.
Hope this helps.