I'm experiencing a strange behaviour in my OpenGL application. I generate a number of GLSL programs during the initialization of the program. The shader programs are read from text files and the programs are compiled and linked. However, I randomly encounter compilation errors for one of the shader programs (a pass-through vertex shader). I cannot understand why the program loads perfectly fine and the shader program successfully compiles several times but fails to do in other times!
Here is the shader code:
#version 330
// vertex position in the model space
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec2 inTexCoord;
// will be interporlated for each fragment
smooth out vec2 vTexCoord;
// uniforms
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
void main(void) {
gl_Position = projectionMatrix * modelViewMatrix * vec4(inPosition, 1.0);
vTexCoord = inTexCoord;
}
And here is the code for compiling the shader (passThroughVertShader is a QString):
this->passThroughVertShader = glCreateShader(GL_VERTEX_SHADER);
const char *passThroughVertShaderCodeC = passThroughVertShaderCode.toStdString().c_str();
sourceCode = passThroughVertShaderCodeC;
glShaderSource(this->passThroughVertShader, 1, &sourceCode, NULL);
glCompileShader(this->passThroughVertShader);
glGetShaderiv(this->passThroughVertShader, GL_COMPILE_STATUS, &isCompiled);
if(isCompiled == GL_FALSE)
{
qDebug("ERROR compiling pass-through vertex shader..");
exit(-1);
}
glAttachShader(this->shaderProgram, this->passThroughVertShader);
And the function that loads it:
QString MyClass::readShaderFile(const QString &filename) {
QString content;
QFile file(filename);
if (file.open(QIODevice::ReadOnly)) {
QTextStream tStream(&file);
content = tStream.readAll();
}
return content;
}
Update:
Following Andon's suggestion, I double checked and I wasn't checking the log after failure. Here is what the log says:
Error: 0(17) : error C0000: syntax error, unexpected '!', expecting "::" at token "!"
Ok, answering myself here. Thanks to AndonM.Coleman for pointing out that I should check the error log. The output was not clear, but it lead me to another SO question that shed some light on a bug I had in the code. Apparently I was doing the right thing for compiling all other shaders in the program and somehow forgot one line when I was writing the code for this one. What I should have been doing was the following:
string passThroughVertShaderCodeS = passThroughVertShaderCode.toStdString();
const char *passThroughVertShaderCodeC = passThroughVertShaderCodeS.c_str();
In short, the toStdString() method was returning a temporary copy of the buffer. Since I'm calling c_str() on that temporary copy which gets destroyed after that line, that pointer becomes invalid. I'm not sure why it occasionally succeeded though.
Related
I try to follow the tutorial on YT on 'The Cherno' channel about OpenGL (you can find my code here). I have two uniforms u_Color and u_Texture that I load using glUniform1i function called from Shader.cpp file. For u_Color everything's alright but when I try to load u_Texture I obtain error code
0x502 (GL_INVALID_OPERATION; Qt debugging stops printing out "Illegal operation" error).
I tried to remove unused calls to "u_Color" uniform in shader AND cpp code, I've tried to use the function outside of GLCall macro and some other stuff but it simply doesn't want to work. I am sure location of the texture is alright (unsigned int) and I think my code looks exactly the same as the one from tutorial that actually works!
I work on Linux system (18.04), with Intel graphic card, and I'm using Qt Creator (Qt Creator 4.11.2 based on Qt 5.14.2) with g++ compiler (7.5.0).
If somebody could check it out I'd really appreciate it.
That's the problematic part of the code from "Shader.cpp"
GLuint uniformlocation = static_cast<GLuint>(glGetUniformLocation(m_rendererID, "u_Texture"));
glUniform1f(uniformLocation, value);
And here's fragment shader that uses u_Texture
#version 330 core
layout(location = 0) out vec4 color;
in vec2 v_TexCoord;
uniform vec4 u_Color;
uniform sampler2D u_Texture;
void main()
{
vec4 texColor = texture2D(u_Texture, v_TexCoord);
color = texColor;
}
glUniform1f sets a value of a uniform of the currently installed program, thus the program has to be installed by glUseProgram, before:
GLuint uniformlocation = static_cast<GLuint>(glGetUniformLocation(m_rendererID, "u_Texture"));
glUseProgram(m_rendererID);
glUniform1f(uniformLocation, value);
respectively:
shader.bind();
shader.setUniform1i("u_Texture", 0);
The GL_INVALID_OPERATION is caused, by the fact, that there is no current program object.
Alternatively you can use glProgramUniform to specify the value of a uniform variable for a specified program object
When I try to compile this GLSL code in OpenGL 4.0 I get error 1282
Vertex shader:
#version 330 core
layout(location = 0) in vec2 aPos;
uniform mat4 model[100];
uniform mat4 projection;
out int instanceID;
void main()
{
instanceID = gl_InstanceID;
gl_Position = projection * model[gl_InstanceID] * vec4(aPos.x, aPos.y, 0.0, 1.0);
}
Fragment shader:
#version 330 core
in int instanceID;
out vec4 FragColor;
uniform vec4 color[100];
void main()
{
FragColor = color[instanceID];
}
The code is regular ShaderProgram creation because I get the error before drawing or anything like that but just in case here is the code:
unsigned int vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
std::string vShaderCode = ReadEntireTextFile(vertPath);
const char* c_vShaderCode = vShaderCode.c_str();
glShaderSource(vertex, 1, &c_vShaderCode, NULL);
glCompileShader(vertex);
std::string fShaderCode = ReadEntireTextFile(fragPath);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
const char* c_fShaderCode = fShaderCode.c_str();
glShaderSource(fragment, 1, &c_fShaderCode, NULL);
glCompileShader(fragment);
// shader Program
m_RendererID = glCreateProgram();
glAttachShader(m_RendererID, vertex);
glAttachShader(m_RendererID, fragment);
glLinkProgram(m_RendererID);
// delete the shaders as they're linked into our program now and no longer necessery
glDeleteShader(vertex);
glDeleteShader(fragment);
glUseProgram(m_RendererID);
I know for sure that the error is because of instanceID because it worked when the shader didn't have that. but I tried to find where the problem is exactly with no luck.
UPDATE:
Made sure shaders were compiled successfully. and turns out they are compiled successfully.
I was able to pinpoint where the error occurs and it was the glUseProgram funtion.
I think the error is because of instanceID because when I change:
FragColor = color[instanceID];
to
FragColor = color[0];
the program works.
UPDATE(2):
I solved the problem.
Turns out I had 2 problems one being that I had too many components and I fixed that thanks to one of the answers alerting me.
The other was that I can't put uniforms directly in the fragment shader which I thought you could do.So I put the colors in the vertex shader and passed the one color I needed for the fragment shader.
Thanks for the help!
uniform mat4 model[100];
That is way outside of what is guaranteed by the spec. The limit here is GL_MAX_VERTEX_UNIFORM_COMPONENTS, which the spec guarantees to be at least 1024. Since a mat4 consumes 16 components, that's 64 matrices at most. Now your particular limit might be higher, but you also have the other uniforms in your program, like color[100].
(from comments):
It does not return anything for both fragment and vertex shaders and glGetShaderiv(shader, GL_COMPILE_STATUS, &output); returns true for both shaders.
But that does not imply that the program object linked successfully. Such ressource limits are usually enforced during linking.
I'm pretty sure program is an object created by openGL successfully, I'm not really sure about the others though. you see if i change the fragment shader main function to FragColor = color[0]; it will work so the issue is with instanceID I think.
That conclusion does not follow. If you write color[0], it will optimize your vec4r[100] array to vec4[1], and you might get below your particular limit.
I'm building a game using OpenGL and C++. I'm using GLFW and GLAD. I'm currently in the process of setting up simple shaders, but I'm completely roadblocked by a compilation problem. In a nutshell, shader compilation fails with no error message.
Here's my vertex shader (it's meant to draw 2D images and text):
#version 330 core
layout (location = 0) in vec2 vPosition;
layout (location = 1) in vec2 vTexCoords;
layout (location = 2) in vec4 vColor;
out vec4 fColor;
out vec2 fTexCoords;
uniform mat4 mvp;
void main()
{
vec4 position = mvp * vec4(vPosition, 0, 1);
position.y *= -1;
gl_Position = position;
fColor = vColor;
fTexCoords = vTexCoords;
}
And here's the relevant code to create the shader, load the shader source, compile the shader, and check for errors.
GLuint shaderId = glCreateShader(GL_VERTEX_SHADER);
std::string source = FileUtilities::ReadAllText(Paths::Shaders + filename);
GLchar const* file = source.c_str();
GLint length = static_cast<GLint>(source.size());
glShaderSource(shaderId, 0, &file, &length);
glCompileShader(shaderId);
GLint status;
glGetShaderiv(shaderId, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
GLint logSize = 0;
glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &logSize);
std::vector<GLchar> message = std::vector<GLchar>(logSize);
glGetShaderInfoLog(shaderId, logSize, nullptr, &message[0]);
glDeleteShader(shaderId);
std::cout << std::string(message.begin(), message.end());
}
Using that code, logSize is returned as 1, meaning that I'm unable to access the error message provided by GL. From what I can tell, the message doesn't exist at all. I've already seen the question posted here, in which the issue was a missing call to glCompileShader. As you can see, my code does call that function.
In attempting to solve this problem, I've already confirmed a few things.
My shader source (a string) is being read correctly. The source is a single string that, as far as I can tell, exactly matches the actual shader file.
There are no casting issues from the string source to GLchar const* or GLint (the variables file and length). Both look correct.
If I artificially inflate the value of logSize (to, say, 1000), the resulting message is nothing but zeroes. No error message exists.
I am calling glfwInit() and related functions before reaching this point in the code. Querying glGetString(GL_VERSION) does correctly return the target version (3.3.0).
Does anyone know how to fix this? As I said, my progress is completely blocked since I can't render anything (2D or 3D) without working shaders.
Thank you!
The problem is that you never upload any shader source to the shader.
The second parameter in this line:
glShaderSource(shaderId, 0, &file, &length);
tells OpenGL to load 0 code strings to the shader (nothing). Change this to 1, and it should work.
I see very weird behavior:
Vertex shader:
in vec2 vTextCoord;
in vec3 vPosition; //model coordinates
out vec2 texCoord_;
void main()
{
texCoord_ = vTextCoord;
}
Fragment shader:
in vec2 texCoord_;
layout(location = 0) out vec4 fColor;
void main()
{
fColor = vec4(texCoord_.x,1,1,1); //when using this line I get image 1
//fColor = vec4(1,1,1,1); // when using this line I get image 2
}
These shaders do nothing, and they are not called. Images are generated by other shaders.
The only interaction these shaders has with opengl, is that I compile and link them into a program.
Still:
When using (in the fragment shader) the line:
fColor = vec4(texCoord_.x,1,1,1);
I get the following buggy rendering:
And when using the line:
fColor = vec4(1,1,1,1);
I get the following correct rendering:
Now, there are other shaders in the system, particularly, I have another shader that also have an attribute by the name of:
vTextCoord
However, that shader is not linked together with the problematic shader.
I know it is related to the fact another shader that share the attribute name exists on the system (because if I change the name the issue disappears).
Am I doing something terribly wrong?
Did anyone encounter something similar in the past?
Are there known issues with the GLSL compiler that can relate to this?
Finally isolated the issue of my shader not being able to be used to it failing to compile.
Here is my shader loading routine. The first part reads in the shader:
void GLSLShader::LoadFromFile(GLenum whichShader, const string filename)
{
ifstream fp;
// Attempt to open the shader
fp.open(filename.c_str(), ios_base::in);
// If the file exists, load it
if(fp)
{
// Copy the shader into the buffer
string buffer(std::istreambuf_iterator<char>(fp), (std::istreambuf_iterator<char>()));
// Debug output to show full text of shader
errorLog.writeSuccess("Shader debug: %s", buffer.c_str());
LoadFromString(whichShader, buffer);
}
else
{
errorLog.writeError("Could not load the shader %s", filename.c_str());
}
}
After it has loaded it into a string, it sends it to be loaded:
void GLSLShader::LoadFromString(GLenum type, const string source)
{
// Create the shader
GLuint shader = glCreateShader(type);
// Convert the string
const char * ptmp = source.c_str();
glShaderSource(shader, 1, &ptmp, NULL);
// Compile the shader
glCompileShader(shader);
// Check to see if the shader has loaded
GLint status;
glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
GLint infoLogLength;
glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *infoLog= new GLchar[infoLogLength];
glGetShaderInfoLog (shader, infoLogLength, NULL, infoLog);
errorLog.writeError("could not compile: %s", infoLog);
delete [] infoLog;
}
_shaders[_totalShaders++]=shader;
}
I am getting the debug output "could not compile: " and it seems that the error buffer is empty. This has been driving me crazy for the past 3 days. Does anyone see my error?
Here are the very simple shaders:
#version 330
layout (location = 0) in vec4 position;
layout (location = 1) in vec4 color;
smooth out vec4 theColor;
void main()
{
gl_Position = position;
theColor = color;
}
#version 330
smooth in vec4 theColor;
out vec4 outputColor;
void main()
{
outputColor = theColor;
}
UPDATE
It looks like for some reason there is crap being added to the end of the shader in memory. I am not sure why. I have tried reading it in to a char* and a string. Here is the output:
<-!-> Shader: #version 330
layout (location = 0) in vec4 position;
layout (location = 1) in vec4 color;
smooth out vec4 theColor;
void main()
{
gl_Position = position;
theColor = color;
}
n
<-!-> Shader: #version 330
smooth in vec4 theColor;
out vec4 outputColor;
void main()
{
outputColor = theColor;
}
nts/Resources
Notice the 'n' at the end of the first shader and the 'nts/Resources' at the end of the second one. Any idea why?
ANOTHER UPDATE
The crap at the end was caused by an extra line at the end. I removed it and it is back to outputting the correct shader text. Still no luck thought with compiling.
I am at a loss here. The Superbible has their extensive libraries that are unoptimized and I don't need. There doesn't seem to be a damn decent shader compiler for Mac. I really don't mind how simple it is. It just needs to work with shaders. Does anyone have an example?
You're calling glShaderSource without supplying the length of each string in the sources array. Hence the string supplied is assumed to be terminated by a null byte ('\0'). The way you're reading the file into memory does not terminate the shader source with an additional null byte. So the GLSL compiler will read beyond the end of the shader source into random memory, where it finds… garbage.
Solution: Either add a terminating null byte, or supply the shader text lengths parameter.