I'm having trouble getting OpenGL to work properly. It fails on all shaders and simply returns an info log with the length of 0.
To see if it was in fact OpenGL, I created a little piece of code to test it:
GLuint s = glCreateShader(GL_VERTEX_SHADER);
const char *src = "bad\nsource\ncode";
glShaderSource(s, 1, &src, 0);
GLint len;
glGetShaderiv(s, GL_INFO_LOG_LENGTH, &len);
std::vector<char> buffer(len+1);
glGetShaderInfoLog(s, len, 0, buffer.data());
buffer[len] = '\0';
std::cout << len << std::endl;
std::cout << buffer.data() << std::endl;
And when ran, it simply prints 0 to the console.
What's happening?
You need to compile your shader in order to get an errorlog.
Pseudo Code:
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if(status == GL_FALSE) {
GLint infolog_length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infolog_length);
GLchar[] infolog = new GLchar[infolog_length+1];
glGetShaderInfoLog(shader, infolog_length, null, infolog.ptr);
// print infolog etc.
}
From The Documentation:
glGetShaderInfoLog returns the information log for the specified shader object. The information log for a shader object is modified when the shader is compiled. The string that is returned will be null terminated.
Related
I am currently working on a OpenGL Shader class, that uses SPIR-V to compile the shaders. Getting the compiled binaries from SPIR-V works fine, the problem is, that my program crashes with the OpenGL exception GL_INVALID_OPERATION error generated. <program> has not been linked, or is not a program object. when trying to bind the Shader with glUseProgram(m_RendererID).
This is my shader creation function:
void OpenGLShader::LoadAndCreateShaders(const std::unordered_map<GLenum, std::vector<uint32>> &shaderData)
{
if (m_RendererID)
glDeleteProgram(m_RendererID);
GLuint program = glCreateProgram();
m_RendererID = program;
std::vector<GLuint> shaderRendererIds;
shaderRendererIds.reserve(shaderData.size());
for (auto &[stage, data] : shaderData)
{
GLuint shaderId = glCreateShader(stage);
glShaderBinary(1, &shaderId, GL_SHADER_BINARY_FORMAT_SPIR_V, data.data(), (uint32)data.size());
glSpecializeShader(shaderId, "main", 0, nullptr, nullptr);
glAttachShader(program, shaderId);
GLint status;
glGetShaderiv(shaderId, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
std::cout << "Shader compilation failed" << std::endl;
}
shaderRendererIds.emplace_back(shaderId);
}
// Link shader program
glLinkProgram(program);
int32 isLinked = 0;
glGetProgramiv(program, GL_LINK_STATUS, (int32*)&isLinked);
if (isLinked == GL_FALSE)
{
int32 maxLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
if (maxLength > 0)
{
std::vector<GLchar> infoLog(maxLength);
glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
std::cout << "Shader linking failed: " << &infoLog[0] << std::endl;
glDeleteProgram(program);
for (auto id : shaderRendererIds)
glDeleteShader(id);
}
}
for (auto id : shaderRendererIds)
glDetachShader(program, id);
}
This function basically takes in the compiled sources from SPIR-V and tries to create the OpenGL shader. When I debugged the program, I found out that after glLinkProgram() isLinked stays 0, but the maxLength variable stays also 0. So the linking process failed, but didn't give an error. Did anyone have the same issue before?
I'm working off a code base that I know compiles correctly. Currently, I've introduced a purposeful spelling mistake into my shader to simulate an error. At this point, the code refuses to compile. I can then call
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, ¶ms);
to find that params is now 108 where is was previously 0, so I know that there is a log associated with this shader (which I have tried to compile). However, when I call
glGetProgramInfoLog(shader, 512, &size, ErrorLog);
size returns 0, and ErrorLog is still empty.
Here's the important code in this situation:
void Shader::AddShader(GLuint ShaderProgram, const char* pShaderText, GLenum ShaderType)
{
GLuint ShaderObj = glCreateShader(ShaderType);
if (ShaderObj == 0) {
fprintf(stderr, "Error creating shader type %d\n", ShaderType);
exit(1);
}
const char* pShaderSource = readShaderSource(pShaderText);
glShaderSource(ShaderObj, 1, (const GLchar**)&pShaderSource, NULL);
glCompileShader(ShaderObj);
checkCompileError(ShaderObj, ShaderType);
glAttachShader(ShaderProgram, ShaderObj);
}
bool Shader::checkCompileError(GLuint shader, GLenum ShaderType)
{
GLint params = -1;
GLchar ErrorLog[512] = { 0 };
GLint size = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, ¶ms);
if (GL_TRUE != params) {
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, ¶ms);
glGetProgramInfoLog(shader, 512, &size, ErrorLog);
fprintf(stderr, "Error compiling shader type %d: '%s'\n", ShaderType, ErrorLog);
exit(1);
}
return true;
}
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, ¶ms);
glGetProgramInfoLog(shader, 512, &size, ErrorLog);
^^^^^^^ should be Shader
You're compiling & checking a shader so you should use glGetShaderInfoLog().
glGetProgramInfoLog() is for grabbing the link log of the complete shader program object you get from glCreateProgram()
when I call glCompileShader() for the vertex shader, and use glGetShaderiv to get the status, it returns a false. However when I look at the log, it is empty. I'm new to shaders so I'm sure i've done something wrong. Here is my code:
void GLSLProgram::compileShader(const std::string& filePath, GLuint id)
{
/*Shader Program Reading*/
//don't worry about this \/, it just loads my shader program from the file.
std::string shader = gdcUtil::implode(gdcFile::readBlock(filePath, 0, 0, '\n', 0, true), true);
const char* shaderPtr = shader.c_str();
/*Shader Source Refering*/
glShaderSource(id, 1, &shaderPtr, nullptr);
/*Shader Compiling*/
glCompileShader(id);
GLint success = 0;
glGetShaderiv(id, GL_COMPILE_STATUS, &success);
if (success == GL_FALSE) {
//Setup Error Log
GLint maxLength = 0;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &maxLength);
std::vector<char> errorLog(maxLength);
glGetShaderInfoLog(id, maxLength, &maxLength, &errorLog[0]);
std::string log;
for (int i = 0; i < errorLog.size(); i++) {
log += errorLog[i];
}
gdcUtil::error(log, "GD_GLSL");
glDeleteShader(id);
gdcUtil::quit();
}
}
Vertex Shader Program:
#version 130
in vec2 vertexPosition;
void main() {
gl_Position.xy = vertexPosition;
gl_Position.z = 0.0;
gl_Position.w = 1.0;
}
I know for a fact that it loads the shader program correctly, just fails upon compilation.
EDIT: Here is the code that calls compileShader
//Create Shaders
_vertID = glCreateShader(GL_VERTEX_SHADER);
bool shaderValid = glIsShader(_vertID);
if (_vertID = 0) {
gdcUtil::error("Could not create Vertex Shader", "GD_GLSL");
gdcUtil::quit();
}
_fragID = glCreateShader(GL_FRAGMENT_SHADER);
if (_fragID = 0) {
gdcUtil::error("Could not create Fragment Shader", "GD_GLSL");
gdcUtil::quit();
}
//Compile Shaders
compileShader(vertFilePath, _vertID);
compileShader(fragFilePath, _fragID);
I've seen other similar questions, and I now that it's usually due to wrong shader loading code, but I've tried with lots of different ways to load them, and I always get this error. Here is the loading code I'm currently using (for the Vertex shader, i do the same for the fragment shader):
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
std::string VertexShaderCode;
std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
if(VertexShaderStream.is_open()){
std::string Line = "";
while(getline(VertexShaderStream, Line))
VertexShaderCode += "\n" + Line;
VertexShaderStream.close();
}
GLint Result = GL_FALSE;
int InfoLogLength;
// Compile Vertex Shader
printf("Compiling shader : %s\n", vertex_file_path);
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
glCompileShader(VertexShaderID);
// Check Vertex Shader
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> VertexShaderErrorMessage(InfoLogLength);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);
I've also tried this:
GLuint VertexShaderID = glCreateShader(GL_FRAGMENT_SHADER);
std::ifstream shaderFile(vertex_file_path);
//Error out here.
stringstream shaderData;
shaderData << shaderFile.rdbuf(); //Loads the entire string into a string stream.
shaderFile.close();
const std::string &VertexShaderCode = shaderData.str(); //Get the string stream as a std::string.
GLint Result = GL_FALSE;
int InfoLogLength;
printf("Compiling shader : %s\n", vertex_file_path);
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
glCompileShader(VertexShaderID);
// Check Vertex Shader
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> VertexShaderErrorMessage(InfoLogLength);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);
And this is the linking code:
// Link the program
fprintf(stdout, "Linking program\n");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);
// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> ProgramErrorMessage( max(InfoLogLength, int(1)) );
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);
I have also tried passing (GLint *)VertexShaderCode.size() instead of NULL to the length parameter of glShaderSource(), but I get the same errors. I get those errors both when compiling and when linking
In case it helps, I'm using Opengl 3.3, GLEW, GLFW, Visual c++ 2010, and windows 7 64 bits
How did you pass the length parameter to glShaderSource. The typecast you performed should trigger you a thick fat warning. The proper way would have been to put the result of size() into a variable. And then you give the pointer to that variable to glShaderSource.
I am trying to experiment using basic shaders in my program, I came across a nice tutorial that talks you through writing a basic shader "util class" i guess you would call it? Which should allow me to apply a vertex and fragment shader...So I linked glew to my project (i have also glu, glut and glaux included) and inserted the following into a header file
#include "include\gl\glew.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
static struct {
/* ... fields for buffer and texture objects */
GLuint vertex_shader, fragment_shader, program;
struct {
GLint fade_factor;
GLint textures[2];
} uniforms;
struct {
GLint position;
} attributes;
GLfloat fade_factor;
} g_resources;
static GLuint make_shader(GLenum type, const char *filename)
{
GLint length;
char *source = file_content(filename, &length);
GLuint shader;
GLint shader_ok;
if (!source)
return 0;
shader = glCreateShader(type);
glShaderSource(shader, 1, (const GLchar**)&source, &length);
free(source);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok);
if (!shader_ok) {
fprintf(stderr, "Failed to compile %s:\n", filename);
show_info_log(shader, glGetShaderiv, glGetShaderInfoLog);
glDeleteShader(shader);
return 0;
}
return shader;
}
static void show_info_log(
GLuint object,
PFNGLGETSHADERIVPROC glGet__iv,
PFNGLGETSHADERINFOLOGPROC glGet__InfoLog)
{
GLint log_length;
char *log;
glGet__iv(object, GL_INFO_LOG_LENGTH, &log_length);
log = malloc(log_length);
glGet__InfoLog(object, log_length, NULL, log);
fprintf(stderr, "%s", log);
free(log);
}
static GLuint make_program(GLuint vertex_shader, GLuint fragment_shader)
{
GLint program_ok;
GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &program_ok);
if (!program_ok) {
fprintf(stderr, "Failed to link shader program:\n");
show_info_log(program, glGetProgramiv, glGetProgramInfoLog);
glDeleteProgram(program);
return 0;
}
return program;
}
static int make_resources(void)
{
/* make buffers and textures ... */
g_resources.vertex_shader = make_shader(
GL_VERTEX_SHADER,
"hello-gl.v.glsl"
);
if (g_resources.vertex_shader == 0)
return 0;
g_resources.fragment_shader = make_shader(
GL_FRAGMENT_SHADER,
"hello-gl.f.glsl"
);
if (g_resources.fragment_shader == 0)
return 0;
g_resources.program = make_program(
g_resources.vertex_shader,
g_resources.fragment_shader
);
if (g_resources.program == 0)
return 0;
g_resources.uniforms.fade_factor
= glGetUniformLocation(g_resources.program, "fade_factor");
g_resources.uniforms.textures[0]
= glGetUniformLocation(g_resources.program, "textures[0]");
g_resources.uniforms.textures[1]
= glGetUniformLocation(g_resources.program, "textures[1]");
g_resources.attributes.position
= glGetAttribLocation(g_resources.program, "position");
return 1;
}
But my compiler complains about the following:
9 IntelliSense: "GLchar" is not a type name
11 IntelliSense: a value of type "void *" cannot be assigned to an entity of type "char *"
7 IntelliSense: identifier "file_contents" is undefined
5 IntelliSense: identifier "GLchar" is undefined
Am I missing something? I searched the internet and it seems like GLchar and the file_contents function do exist?
The error line you gave is the compiler telling you, that it doesn't know about the type GLchar, which is defined in GL/gl.h – or GL/glew.h in your case, which also defines it. But it seems to be not properly included.
Your first line should be
#include <GL/glew.h>
i.e. uppercae GL, a forward slash (backslashes are a Microsoaft addition, but forwards are accepted just fine), and the whole thing in angle brackets, as you want to include from the standard includes.
Next you should not link against glaux. That one is so outdated that it's become toxic.
If you want a working OpenGL shader example program, I prepared one at https://github.com/datenwolf/codesamples/tree/master/samples/OpenGL/minimal_glsl