I am a newbie following the book <OpenGL ES 3.0 cookbook> chapter2, but I get stuck with this error during installing the demo APP with this:
2020-12-06 16:16:10.888 7549-7578/com.demo.hellosquare E/glOpenGLES3Native: Could not compile shader 35633:
ERROR: 0:6: 'RadianAngle' : Only consts can be used in a global initializer
ERROR: 0:6: 'RadianAngle' : Only consts can be used in a global initializer
ERROR: 0:6: 'RadianAngle' : Only consts can be used in a global initializer
ERROR: 0:6: 'RadianAngle' : Only consts can be used in a global initializer
ERROR: 4 compilation errors. No code generated.
The problem is, I don't understand what is that message trying to tell me(Google has no relevant results).
The code involves "RadianAngle" are the following places:
In the top of my single CPP file, I declared:
GLuint radianAngle;
And then with my shader also in top the same file:
static const char vertexShader[] =
"#version 300 es \n"
"in vec4 VertexPosition; \n"
"in vec4 VertexColor; \n"
"uniform float RadianAngle; \n"
"out vec4 TriangleColor; \n"
"mat2 rotation = mat2(cos(RadianAngle),sin(RadianAngle), \
-sin(RadianAngle),cos(RadianAngle)); \n"
"void main() { \n"
" gl_Position = mat4(rotation)*VertexPosition; \n"
" TriangleColor = VertexColor; \n"
"}\n";
Finally inside my render function(will be called through JNI) in same file:
radianAngle = glGetUniformLocation(programID, "RadianAngle");
glUniform1f(radianAngle, radian);
Strangely, I copied exactly from the book, sigh..
The issue is related to the line:
mat2 rotation = mat2(cos(RadianAngle),sin(RadianAngle),
-sin(RadianAngle),cos(RadianAngle));
rotation is a variable in global scope. Global variables can only be initialized with constant expressions. RadianAngle is not constant because it is a uniform variable. This causes the error:
ERROR: 0:6: 'RadianAngle' : Only consts can be used in a global initializer
The error occurs 4 times, because RadianAngle is used 4 times in the initializer of rotation.
You have to set the value of rotation in main:
mat2 rotation;
void main()
{
rotation = mat2(cos(RadianAngle),sin(RadianAngle),
-sin(RadianAngle),cos(RadianAngle));
// [...]
}
Related
I'm trying out the ARB_fragment_shader_interlock extension in OpenGL 4.5 and am failing to get the shader to compile when trying to use pixel_interlock_ordered.
#version 430
#extension GL_ARB_shading_language_420pack : require
#extension GL_ARB_shader_image_load_store : require
#extension GL_ARB_fragment_shader_interlock : require
layout(location = 0, rg8, pixel_interlock_ordered) uniform image2D image1;
void main()
{
beginInvocationInterlockARB();
ivec2 coords = ivec2(gl_FragCoord.xy);
vec4 pixel = imageLoad(image1, coords);
pixel.g = pixel.g + 0.01;
if (pixel.g > 0.5)
pixel.r = pixel.r + 0.01;
else
pixel.r = pixel.r + 0.02;
imageStore(image1, coords, pixel);
endInvocationInterlockARB();
}
The following shader fails compilation with:
0(6) : error C7600: no value specified for layout qualifier 'pixel_interlock_ordered'
Which is the same error you would get for any random name instead of pixel_interlock_ordered. I guess the syntax is different somehow, but the spec (https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_fragment_shader_interlock.txt) refer to it as a "layout qualifier".
Googling "pixel_interlock_ordered" comes up short with just links to the official specs, so I can't find an example. What is the correct syntax?
Layout qualifiers in GLSL are a bit weird. They usually apply to declarations, but some of them effectively apply to the shader as a whole. Such qualifiers are basically shader-specific options you set from within the shader.
The interlock qualifiers are those kinds of qualifiers. You're not saying that this variable will be accessed via interlocking, because that's not what interlocking means. It means that the execution of the interlock-bound code will have a certain property, relative to executing interlock-bound code on other invocations of the same shader. The qualifier specifies the details of the execution restriction.
Qualifiers that apply to the shader as a whole are grammatically specified as qualifiers on in or out (most such qualifiers use in, but a few use out):
layout(pixel_interlock_ordered) in;
The issue I'm going to write about can only be reproduced with some hardware and drivers.
I managed to reproduce it on GeForce GTX 760 with 399.24 driver and GeForce 950M with 416.34. The issue does not show up on GTX650 with 390.87 driver. All these GPUs return 1024 for GL_MAX_VERTEX_UNIFORM_VECTORS, so I hardcoded 1000 as vec4 array size in vertex shader.
I try to compile and link the following shader program.
Vertex shader:
#version 330
uniform vec4 vs[1000];
uniform sampler2D tex;
void main()
{
gl_Position = vs[42];
//gl_Position += texture(tex, vs[0].xy); // (1)
}
Fragment shader:
#version 330
out vec4 outFragColor;
void main()
{
outFragColor = vec4(0.0);
}
Everything is OK while line (1) is commented and thus tex sampler is optimized out. But if we uncomment it, link fails with the following log:
-----------
Internal error: assembly compile error for vertex shader at offset 427:
-- error message --
line 16, column 9: error: invalid parameter array size
line 20, column 16: error: out of bounds array access
line 22, column 30: error: out of bounds array access
-- internal assembly text --
!!NVvp5.0
OPTION NV_internal;
OPTION NV_gpu_program_fp64;
OPTION NV_bindless_texture;
Error: could not link.
# cgc version 3.4.0001, build date Oct 10 2018
# command line args:
#vendor NVIDIA Corporation
#version 3.4.0.1 COP Build Date Oct 10 2018
#profile gp5vp
#program main
#semantic vs
#semantic tex
#var float4 gl_Position : $vout.POSITION : HPOS : -1 : 1
#var float4 vs[0] : : c[0], 1000 : -1 : 1
#var ulong tex : : c[1000] : -1 : 1
PARAM c[2002] = { program.local[0..2001] };
TEMP R0;
LONG TEMP D0;
TEMP T;
PK64.U D0.x, c[1000];
TEX.F R0, c[0], handle(D0.x), 2D;
ADD.F result.position, R0, c[42];
END
# 3 instructions, 1 R-regs, 1 D-regs
Here we see that the array takes registers 0..999, and the sampler takes register 1000. Elements above 1000 are not referenced anywhere except line PARAM c[2002] = { program.local[0..2001] };.
Further experiments with array size showed that 2002 is not a constant, but a doubled amount of registers required.
I remember that
OpenGL implementations are allowed to reject shaders for
implementation-dependent reasons.
So is there a workaround to use all available registers along with a sampler in a vertex shader?
If not, what might be the rationale behind this behavior? Obviously, this shader does not use any registers for temporary computation results.
Is it a misoptimization in shader compiler?
UPD: a quick-n-diry reproduction example is here.
UPD2: Webgl repro with workaround description.
I'm currently developing an OpenGL-Widget in Qt, based on the QOpenGLWidget. I followed some examples and used the GLSL-Wrapper for Demo purposes. The application itself should be as independent as possible for compatibility purposes, like changing the GUI framework.
When the Qt code takes care of the shader, the app works fine:
QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
const char *vsrc =
"uniform mediump mat4 matrix;\n"
"void main(void)\n"
"{\n"
" gl_Position = matrix * gl_Vertex;\n"
" gl_FrontColor = gl_Color;\n"
"}\n";
bool success = vshader->compileSourceCode(vsrc);
program = new QOpenGLShaderProgram();
program->addShader(vshader);
program->link();
Next, I upload and compile the shader on my own:
const char *vsrc =
"uniform mediump mat4 matrix;\n"
"void main(void)\n"
"{\n"
" gl_Position = matrix * gl_Vertex;\n"
" gl_FrontColor = gl_Color;\n"
"}\n";
GLuint programmID = glCreateProgram();
GLuint shaderID = glCreateShader(GL_VERTEX_SHADER);
int length =(int) std::char_traits<char>::length(vsrc);
glShaderSource(shaderID, 1, &vsrc, &length);
glCompileShader(shaderID);
char *error = new char[1000];
int* messagelength = new int;
glGetShaderInfoLog(shaderID, (GLsizei)1000, messagelength, error);
string str = string(error, *messagelength);
std::cout << str << std::endl << std::flush;
delete error;
delete messagelength;
glAttachShader(programmID, shaderID);
glDeleteShader(shaderID);
glLinkProgram(programmID);
glUseProgram(programmID);
However, this results in the following errors:
0(1) : error C0000: syntax error, unexpected type identifier, expecting '{' at token "mat4"
0(4) : warning C7506: OpenGL does not define the global type matrix
0(4) : warning C7531: pointers requires "#extension GL_NV_shader_buffer_load : enable" before use
0(4) : error C0000: syntax error, unexpected identifier, expecting '(' at token "gl_Vertex"
How do I make this work?
Well, your code is invalid in desktop GL. Since your shader does not contain a #version directive, it is to be interpreted as GLSL 1.10. And that version does not know of the precision qualifiers like mediump. (Later just accept that keywords, for improved compatibility with GLSL ES).
Note that Qt might very well use GL ES 2.0 as default (and not desktop GL), depending on your local configuration and also on how the qt libs were built.
Also note that your shader is totally invalid in a modern core profile of desktop GL.
The only recommendation I can give you is to first decide which version (or versions) of OpenGL you want/have to target.
I am attempting to create a tessellation shader:
#version 410 core
// define the number of CPs in the output patch
layout (vertices = 3) out;
uniform vec3 gEyeWorldPos;
// attributes of the input CPs
in vec3 WorldPos_CS_in[];
in vec2 TexCoord_CS_in[];
in vec3 Normal_CS_in[];
// attributes of the output CPs
out vec3 WorldPos_ES_in[];
out vec2 TexCoord_ES_in[];
out vec3 Normal_ES_in[];
float GetTessLevel(float Distance0, float Distance1)
{
float AvgDistance = (Distance0 + Distance1) / 2.0;
if (AvgDistance <= 2.0) {
return 10.0;
}
else if (AvgDistance <= 5.0) {
return 7.0;
}
else {
return 3.0;
}
}
void main()
{
// Set the control points of the output patch
TexCoord_ES_in[gl_InvocationID] = TexCoord_CS_in[gl_InvocationID];
Normal_ES_in[gl_InvocationID] = Normal_CS_in[gl_InvocationID];
WorldPos_ES_in[gl_InvocationID] = WorldPos_CS_in[gl_InvocationID];
// Calculate the distance from the camera to the three control points
float EyeToVertexDistance0 = distance(gEyeWorldPos, WorldPos_ES_in[0]);
float EyeToVertexDistance1 = distance(gEyeWorldPos, WorldPos_ES_in[1]);
float EyeToVertexDistance2 = distance(gEyeWorldPos, WorldPos_ES_in[2]);
// Calculate the tessellation levels
gl_TessLevelOuter[0] = GetTessLevel(EyeToVertexDistance1, EyeToVertexDistance2);
gl_TessLevelOuter[1] = GetTessLevel(EyeToVertexDistance2, EyeToVertexDistance0);
gl_TessLevelOuter[2] = GetTessLevel(EyeToVertexDistance0, EyeToVertexDistance1);
gl_TessLevelInner[0] = gl_TessLevelOuter[2];
}
However, when I run my game, I get the following error:
Error: 1281
Tessellation shader wasn't able to be compiled correctly. Error log:
ERROR: 0:? : '' : Incorrect GLSL version: 410
WARNING: -1:65535: 'GL_ARB_explicit_attrib_location' : extension is not available in current GLSL version
WARNING: 0:4: 'vertices' : symbol not available in current GLSL version
WARNING: 0:? : 'gl_InvocationID' : variable is not available in current GLSL version
WARNING: 0:? : 'gl_InvocationID' : variable is not available in current GLSL version
WARNING: 0:? : 'gl_InvocationID' : variable is not available in current GLSL version
WARNING: 0:? : 'gl_InvocationID' : variable is not available in current GLSL version
WARNING: 0:? : 'gl_InvocationID' : variable is not available in current GLSL version
WARNING: 0:? : 'gl_InvocationID' : variable is not available in current GLSL version
WARNING: 0:? : 'gl_TessLevelOuter' : variable is not available in current GLSL version
WARNING: 0:? : 'gl_TessLevelOuter' : variable is not available in current GLSL version
WARNING: 0:? : 'gl_TessLevelOuter' : variable is not available in current GLSL version
WARNING: 0:? : '
My game appears to be ignoring the shaders, but I guess that is expected with so many errors?
I have already tried googling the error, however I am unable to find any solution or even information on why this is happening.
How can I fix the above errors so my shader can run correctly?
Well, you probably don't have a OpenGL-4.1 core context to begin with, and thus your shaders won't compile. Instead of debugging the shaders, I suggest you look at your context creation code and double check your system is cabable of giving you a 4.1 version context.
when i load my tessellation control shader it ouputs:
0(7) : error C3008: unknown layout specifier 'vertices'
0(15) : error C7565: assignment to varying in gl_TessLevelOuterIn
0(16) : error C7565: assignment to varying in gl_TessLevelOuterIn
my shader looks like this
#version 400
layout(vertices = 2) out;
void main( )
{
gl_out[ gl_InvocationID ].gl_Position = gl_in[ gl_InvocationID ].gl_Position;
gl_TessLevelOuter[0] = float( 1 );
gl_TessLevelOuter[1] = float( 5 );
}
what i am doing wrong here?
the qualifier 'vertices' should be visible with #version 400 ?
the specs say:
Layout Qualifiers
layout(layout-qualifiers) in/out/uniform
Output Layout Qualifiers
For tessellation control shaders:
vertices = integer-constant
also my tessellation evaluation shader says:
0(5) : error C3008: unknown layout specifier 'equal_spacing'
0(5) : error C3008: unknown layout specifier 'isolines'
do i missing something?
regards,
peter