So we have in C:
auto if break int case long char register
continue return default short do sizeof
double static else struct entry switch extern
typedef float union for unsigned
goto while enum void const signed volatile
What new keywords OpenGL (ES) Shader Language provide to us?
I am new to GLSL and I want to create some highlight editing util for ease of use.
Math words included into GLSL will count as keywords..?
New ones (excluding the ones you listed above) according to the latest spec document:
attribute uniform varying
layout
centroid flat smooth noperspective
patch sample
subroutine
in out inout
invariant
discard
mat2 mat3 mat4 dmat2 dmat3 dmat4
mat2x2 mat2x3 mat2x4 dmat2x2 dmat2x3 dmat2x4
mat3x2 mat3x3 mat3x4 dmat3x2 dmat3x3 dmat3x4
mat4x2 mat4x3 mat4x4 dmat4x2 dmat4x3 dmat4x4
vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 dvec2 dvec3 dvec4
uvec2 uvec3 uvec4
lowp mediump highp precision
sampler1D sampler2D sampler3D samplerCube
sampler1DShadow sampler2DShadow samplerCubeShadow
sampler1DArray sampler2DArray
sampler1DArrayShadow sampler2DArrayShadow
isampler1D isampler2D isampler3D isamplerCube
isampler1DArray isampler2DArray
usampler1D usampler2D usampler3D usamplerCube
usampler1DArray usampler2DArray
sampler2DRect sampler2DRectShadow isampler2DRect usampler2DRect
samplerBuffer isamplerBuffer usamplerBuffer
sampler2DMS isampler2DMS usampler2DMS
sampler2DMSArray isampler2DMSArray usampler2DMSArray
samplerCubeArray samplerCubeArrayShadow isamplerCubeArray usamplerCubeArray
Reserved for future use (will cause error at the moment):
common partition active
asm
class union enum typedef template this packed
goto
inline noinline volatile public static extern external interface
long short half fixed unsigned superp
input output
hvec2 hvec3 hvec4 fvec2 fvec3 fvec4
sampler3DRect
filter
image1D image2D image3D imageCube
iimage1D iimage2D iimage3D iimageCube
uimage1D uimage2D uimage3D uimageCube
image1DArray image2DArray
iimage1DArray iimage2DArray uimage1DArray uimage2DArray
image1DShadow image2DShadow
image1DArrayShadow image2DArrayShadow
imageBuffer iimageBuffer uimageBuffer
sizeof cast
namespace using
row_major
You probably want to get the OpenGL ES GLSL language specification. §3.6 lists the keywords (plus a number of reserved words that aren't keywords, but you're not supposed to use anyway, so they probably merit some sort of color coding as well).
Edit: Oops, I grabbed the wrong link there. My apologies. The current specs are:
OpenGL 4.1 GLSL
OpenGL ES 2.0 GLSL
Besides the above answers, there are also reserved identifiers, eg. in GLSL ES 3.0 spec:
Identifiers starting with gl_ are reserved for use by OpenGL ES, and may not be declared in a shader as either a variable or a function. It is an error to redeclare a variable, including those starting “gl_”.
And other things beyond these are reserved:
In addition, all identifiers containing two consecutive underscores (__) are reserved for use by underlying software layers. Defining such a name in a shader does not itself result in an error, but may result in unintended behaviors that stem from having multiple definitions of the same name.
It is relevant for syntax coloring and correctness checking.
Similarly, macros starting with GL_, and a bunch of things with __.
Related
SPIR-V allows for very verbose data formats.
GLSL has only basic data types (Chapter 4) that do not specify bit length.
As far as I am aware the most convenient way to program shaders for Vulkan is to program them in GLSL, then use the Vulkan SDK provided compiler (glslc.exe) to convert the file into a SPIR-V binary.
My question is how does one use these verbose data formats such as the VK_FORMAT_R4G4_UNORM_PACK8 (found in the SPIR-V link above) In GLSL while using glslc.exe to compile our shader code. Are there special data types that the compiler allows for? If not is there an alternative higher level language that one could use and then compile into the binary?
For example if this was the attribute descriptions used in the graphics pipeline:
struct Attributes {
vec2 pos;
char flags;
};
static inline std::array<VkVertexInputAttributeDescription, 3> getAttributeDescriptions() {
std::array<VkVertexInputAttributeDescription, 3> attributeDescriptions{};
attributeDescriptions[0].binding = 0;
attributeDescriptions[0].location = 0;
attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
attributeDescriptions[0].offset = offsetof(Attributes, pos);
attributeDescriptions[1].binding = 0;
attributeDescriptions[1].location = 1;
attributeDescriptions[1].format = VK_FORMAT_R4G4_UNORM_PACK8;
attributeDescriptions[1].offset = offsetof(Attributes, flags);
return attributeDescriptions;
The proceeding GLSL shader code would look something like this:
#version 450
#extension GL_ARB_separate_shader_objects : enable
//Instance Attributes
layout(location = 0) in vec2 pos;
layout(location = 1) in 4BitVec2DataType flags;
//4BitVec2DataType is a placeholder for whatever GLSL's equivalent of SPIR-V's VK_FORMAT_R4G4_UNORM_PACK8 would be
void main() {
...
}
The proceeding GLSL shader code would look something like this:
No, it wouldn't. You would receive a vec2 in the shader, because that's how vertex attributes work. The vertex format is not meant to exactly match the data format; the data will be converted from that format to the shader-expected bitdepth. Unsigned normalized values are floating-point data, so a 2-vector UNORM maps to a GLSL vec2.
And BTW, SPIR-V does not change this. The shader's input size need not exactly match the given data size; any conversion is just baked into the shader (this is also part of why the vertex format is part of the pipeline).
The GL_EXT_shader_16bit_storage extension offers more flexibility in GLSL for creating unusual sizes of data types within buffer-backed interface blocks. But these are specifically for data in UBOs/SSBOs, not vertex formats. However, this extension requires the SPV_KHR_16bit_storage and SPV_KHR_8bit_storage SPIR-V extensions.
I want to use bindless textures, but spirv does not support it. I found here: https://www.khronos.org/opengl/wiki/Bindless_Texture that uint64_t can be converted to a sampler2D.
uint64_t values can be converted to any sampler or image type using constructors: sampler2DArray(some_uint64). They can also be converted back to 64-bit integers.
and I thought that I could upload a bindless handle as the uint64_t and then convert it to the sampler2D.
spir-v compiler gives me them errors:
error: 'sampler/image' : cannot construct this type
error: 'sampler2D' : sampler-constructor requires two arguments
error: 'constructor' : too many arguments
error: 'assign' : cannot convert from ' const float' to 'layout( location=0) out highp 4-component vector of float'
shader code
#version 460 core
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#extension GL_EXT_scalar_block_layout : require
layout(location = 0) out vec4 f_color;
layout(location = 0) in vec2 v_uv;
layout(std430, binding = 5) uniform Textures
{
uint64_t albedo;
};
void main()
{
f_color = texture(sampler2D(albedo), v_uv);
}
is it possible to convert uint64_t to sampler2D? How to do it?
As with all GLSL extensions, you must explicitly enable them. However, you have a more interesting problem: bindless texturing cannot be used with SPIR-V. What you want to do is only possible if you feed the GLSL directly to OpenGL, without the SPIR-V intermediary.
Vulkan does not support bindless textures; you need to use arrays of samplers to get an equivalent effect. And OpenGL doesn't support GL_EXT_scalar_block_layout. So the code you're writing cannot be used by any graphics system.
I am experiencing the following error in GLSL. Here is the fragment shader:
#version 450 core
#define DIFFUSE_TEX_UNIT 0
#define INDEX_UNIFORM_LOC 0
layout(binding = DIFFUSE_TEX_UNIT) uniform sampler2D colorTex;
#ifdef SOME_SPECIAL_CASE
layout (location = INDEX_UNIFORM_LOC) uniform uint u_blendMode;
//...more code here related to the case
#endif
//... rest of the code(not important)
Now,when I compile this shader into program without declaring SOME_SPECIAL_CASE,and still set u_blendMode uniform during runtime,I am getting the following error from driver:
GL_INVALID_OPERATION error generated. value is
invalid; expected GL_INT or GL_UNSIGNED_INT64_NV.
But I would expect to get an error like this:
GL_INVALID_OPERATION error generated. ' location ' is invalid.
Because there is no location with such an index (0) if I don't set SOME_SPECIAL_CASE preprocessor flag. Then I decided to check what uniform I have got, which requires GL_INT or GL_UNSIGNED_INT64_NV,so I queried uniform name based on its location (zero):
char buff[20];
GLsizei len = 0;
glGetActiveUniformName(prog.progHandle, 0, 20, &len, buff);
And got the name 'colorTex',which is the name of sampler2D uniform that has binding index DIFFUSE_TEX_UNIT ,that is also zero.
Untill now,I believed uniform location and binding points do not use same indices and I still believe they don't,because otherwise this shader,when compiled with SOME_SPECIAL_CASE active would fail,as well as many other shaders I have written thru my work history.Hence it looks utterly weird why that sampler2D uniform binding index is affected when I am setting non-existing uniform location,and I also use specific type (GLSL - uint)
glProgramUniform1ui(prog, location, (GLuint)value);
Which also doesn't match the type of sampler2D (so the error is kinda right at least about type mismatch).
Is it a driver bug?
One more thing,I tried to check in docs if binding and location indices really overlap and found this statement:
It is illegal to assign the same uniform location to two uniforms in
the same shader or the same program. Even if those two uniforms have
the same name and type, and are defined in different shader stages, it
is not legal to explicitly assign them the same uniform location; a
linker error will occur.
This is just absolutely wrong! I have been doing this for years. And tried that again after reading those lines. Having same uniform,with same location in both vertex and fragment shader compiles and works fine.
My setup:
NVIDIA Quadro P2000, driver 419.17
OpenGL 4.5
Windows 10 64bit
Regarding the ability to use same uniform on same location,at least on NVIDIA GPU the following compiles and runs fine:
Vertex shader
#version 450 core
#define MVP_UNIFORM_LOC 2
layout(location = 0) in vec2 v_Position;
layout(location = MVP_UNIFORM_LOC) uniform mat4 u_MVP;
smooth out vec2 texCoord;
void main()
{
texCoord = v_Position;
gl_Position = u_MVP * vec4(v_Position,0.0,1.0);
}
Fragment shader:
#version 450 core
#define MVP_UNIFORM_LOC 2
#define TEX_MAP_UNIT 5
layout(binding = TEX_MAP_UNIT ) uniform sampler2D texMap;
layout(location = MVP_UNIFORM_LOC) uniform mat4 u_MVP;
smooth in vec2 texCoord;
out vec4 OUTPUT;
void main()
{
vec4 tex = texture(texMap, texCoord);
OUTPUT = u_MVP * tex;
}
Is it a driver bug?
No. glGetActiveUniformName takes uniform indices, not uniform locations. Indices cannot be set from the shader; they're just all of the uniform variables, from 0 to the number of active uniforms. Indices are only used for introspecting properties of uniforms.
There's no way to take a uniform location and ask for the uniform index (or name) of the uniform variable.
But I would expect to get an error like this:
...
Because there is no location with such an index (0) if I don't set SOME_SPECIAL_CASE preprocessor flag.
Sure there is. Uniform variables which do not use explicit locations will never have the same location as a uniform variable that does have an explicit location. However, that's not what's happening here.
If SOME_SPECIAL_CASE is not defined, then the declaration of u_blendMode does not exist. Since location 0 was never used by an explicit uniform variable, it is now available for implicit location assignment.
So the implementation can assign the location of colorTex to zero (note that this is different from assigning the binding to zero).
If you want to reserve location 0 always, then the declaration of u_blendMode must always be visible, even if you never use it. The specification allows implementations to still optimize away such declarations, but the explicit location itself is not optimized away. So if you use location = 0 for a uniform that goes unused, then location 0 may or may not be a valid location. But if it is valid, it will always refer to u_blendMode.
Regarding the ability to use same uniform on same location,at least on NVIDIA GPU the following compiles and runs fine:
The GLSL specification has worked this out, and it is now OK to have two explicit uniform locations that are the same, so long as the two declarations are themselves identical. So cross-shader-stage uniform locations are supposed to work.
My vertex shader is ,
uniform Block1{ vec4 offset_x1; vec4 offset_x2;}block1;
out float value;
in vec4 position;
void main()
{
value = block1.offset_x1.x + block1.offset_x2.x;
gl_Position = position;
}
The code I am using to pass values is :
GLfloat color_values[8];// contains valid values
glGenBuffers(1,&buffer_object);
glBindBuffer(GL_UNIFORM_BUFFER,buffer_object);
glBufferData(GL_UNIFORM_BUFFER,sizeof(color_values),color_values,GL_STATIC_DRAW);
glUniformBlockBinding(psId,blockIndex,0);
glBindBufferRange(GL_UNIFORM_BUFFER,0,buffer_object,0,16);
glBindBufferRange(GL_UNIFORM_BUFFER,0,buffer_object,16,16);
Here what I am expecting is, to pass 16 bytes for each vec4 uniform. I get GL_INVALID_VALUE error for offset=16 , size = 16.
I am confused with offset value. Spec says it is corresponding to "buffer_object".
There is an alignment restriction for UBOs when binding. Any glBindBufferRange/Base's offset must be a multiple of GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT. This alignment could be anything, so you have to query it before building your array of uniform buffers. That means you can't do it directly in compile-time C++ logic; it has to be runtime logic.
Speaking of querying things at runtime, your code is horribly broken in many other ways. You did not define a layout qualifier for your uniform block; therefore, the default is used: shared. And you cannot use `shared* layout without querying the layout of each block's members from OpenGL. Ever.
If you had done a query, you would have quickly discovered that your uniform block is at least 32 bytes in size, not 16. And since you only provided 16 bytes in your range, undefined behavior (which includes the possibility of program termination) results.
If you want to be able to define C/C++ objects that map exactly to the uniform block definition, you need to use std140 layout and follow the rules of std140's layout in your C/C++ object.
Does the variable that you're stuffing values into dictate what precision you're working with, to the right of the equals sign?
For example, is there any difference, of meaning, to the precision specifier here:
gl_FragColor = lowp vec4(1);
Here's another example:
lowp float floaty = 1. * 2.;
floaty = lowp 1. * lowp 2.;
And if you take some floats, and create a vector or matrix from them, will that vector or matrix take on the precision of the values you stuff it with, or will those values transform into another precision level?
I think optimizing this would best answer the question:
dot(gl_LightSource[0].position.xyz, gl_NormalMatrix * gl_Normal)
I mean, does it need to go this far, if you want it as fast as possible, or is some of it useless?
lowp dot(lowp gl_LightSource[0].position.xyz, lowp gl_NormalMatrix * lowp gl_Normal)
I know you can define the default precision for float, and that this supposedly is used for vectors and matrices afterwards. Assume for the purpose of education, that we had defined this previously:
precision highp float;
You don't need precision specifiers on constants/literals since those get compile time evaluated to whatever they are being assigned to.
In vertex shaders, the following precisions are declared by default: ( 4.5.3 Default Precision Qualifiers)
precision highp float;
precision highp int;
precision lowp sampler2D;
precision lowp samplerCube;
And in fragment shaders you get:
precision mediump int;
precision lowp sampler2D;
precision lowp samplerCube;
This means that if you declare a float in a fragment shader, you have to say whether it is a lowp or a mediump. The default float/int precisions also extend to matrices/vectors.
highp is only supported on systems that have the GL_FRAGMENT_PRECISION_HIGH macro defined to 1; on the rest you'll get a compiler error. (4.5.4 Available Precision Qualifiers)
The rule for precision in an expression is that they get cast automatically to the type of the assignment / parameter they are bound to. So for your dot, it would use the precision of the input types by default and the additional lowp's are unnecessary (and syntactically incorrect). If you want to down-cast a type to a lower precision, the only way to do it is to explicitly assign it to a lower precision.
These answers are all from the Khronos GLSL spec, which you can find here (relevant sections are 4.5.2 and 4.5.3): https://www.khronos.org/registry/OpenGL/specs/es/2.0/GLSL_ES_Specification_1.00.pdf
In more recent versions of the spec, those sections are 4.7.3 and 4.7.4. Nothing has changed, except adding a default precision highp atomic_uint; to both lists. See https://www.khronos.org/registry/OpenGL/specs/es/3.2/GLSL_ES_Specification_3.20.pdf