glShaderSource导致段错误

时间:2013-12-24 21:42:06

标签: c opengl

我正在尝试学习图形编程,我编写了一个简单的OpenGL程序,它绘制了一个三角形并且应该将其涂成红色,但是当我为片段着色器调用函数glShaderSource时会导致段错误。

我不知道它为什么会导致段错误,因为spec page没有说明导致段错误的函数,并且任何关于着色器被加载到内存中的错误都不是它,因为顶点着色器以相同的方式加载,当我调用glGetShaderInfoLog并打印日志时,它表示顶点着色器编译正常。

无论如何,我的代码加载着色器并链接着色程序......

int LoadShader(char* Filename, GLchar* ShaderSource) //dont call this function by itself as it doesnt free its own memory
{
FILE* z;
z = fopen(Filename, "rb");

if(z == NULL) {printf("Error: file \"%s\" does not exist...\n", Filename); return -1;}

unsigned long len = 0;

//get file length
fseek(z, 0, SEEK_END);
len = ftell(z);
rewind(z);

if(len == 0) {printf("Error reading file \"%s\"\n", Filename); return -1;}


ShaderSource = (char*)malloc((sizeof(char)) * len + 1); //allocate enough bytes for the file
if(ShaderSource == NULL) {puts("Memory Error"); return -1;}

size_t result = fread(ShaderSource, 1, len, z);
if( result != len) 
{
    puts("Reading Error"); 
    free(ShaderSource);
    ShaderSource = NULL;
    return -1;
}

ShaderSource[len] = 0; //make it null terminated

puts(ShaderSource); //debbugging

fclose(z);

return 1;
}

//----------------------------------------------------------------------
GLuint MakeProgram(char* VSpath, char* FSpath){

GLuint  VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint  FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

GLchar* VSsource; 
GLchar* FSsource;

if(!LoadShader(VSpath, VSsource))
    return -1;


if(!LoadShader(FSpath, FSsource))
    return -1;


GLint Result = GL_FALSE;
int InfoLogLength;

//compile shaders
const char* VS = VSsource; // glShaderSource needs a const char
glShaderSource(VertexShaderID, 1, &VS, NULL); //we use NULL for length becuase the source is null-terminated
glCompileShader(VertexShaderID);
//check
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
char* VSerr;
VSerr = (char*)malloc(sizeof(char) * InfoLogLength);

glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VSerr[0]);
printf("%s\n", VSerr);

free(VSerr);
VSerr = NULL;


//fragment shader
const char* FS = FSsource;
glShaderSource(FragmentShaderID, 1, &FS, NULL);
glCompileShader(FragmentShaderID);
//check
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
char* FSerr;
FSerr = (char*)malloc(sizeof(char) * InfoLogLength);

glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FSerr[0]);
printf("%s\n", FSerr);

free(FSerr);
FSerr = NULL;


//link program
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);
//check program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
char* err;
err = (char*)malloc(sizeof(char) * InfoLogLength);

glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &err[0]);
printf("%s\n", err);

free(err);

//free the shaders
free(VSsource);
VSsource = NULL;

free(FSsource);
FSsource = NULL;

glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);

return ProgramID;
}

1 个答案:

答案 0 :(得分:2)

仔细查看您对VSsource(未初始化),FSsource(未初始化)和LoadShader (...)实施的实际声明。因为这是C并且您没有通过引用传递任何内容,所以对ShaderSource函数内的LoadShader (...)指针所做的任何更改都不会在函数外部传播。

简而言之,您错误地实施了LoadShader (...)。你需要实际更改存储在传递它的指针中的地址(因为你在函数内部分配了这个内存),但你不能这样做,因为你当前传递的是GLchar*

至于为什么GL接受第一次拨打glShaderSource (...)的未初始化指针,我不能说。也许你非常幸运?无论如何,您可以通过更改LoadShader代替GLchar**来更正您的问题。我将在下面说明必要的更改:

/* Originally, you made a copy of an uninitialized pointer and then proceeded to
   re-assign this copy a value when you called malloc (...) - you actually need
   to pass a pointer to your pointer so you can update the address outside of
   this function!
*/
int LoadShader(char* Filename, GLchar** pShaderSource) //dont call this function by itself as it doesnt free its own memory
{
  [...]
  *pShaderSource = (GLchar *)malloc((sizeof(GLchar)) * len + 1); //allocate enough bytes for the file

  GLchar* ShaderSource = *pShaderSource;
  [...]
}

GLuint MakeProgram(char* VSpath, char* FSpath){
  [...]
  GLchar* VSsource; /* Uninitialized */
  GLchar* FSsource; /* Uninitialized */

  if(!LoadShader(VSpath, &VSsource)) /* Pass the address of your pointer */
    return -1;

  if(!LoadShader(FSpath, &FSsource)) /* Pass the address of your pointer */
    return -1;

  /*
   * Now, since you did not pass copies of your pointers, you actually have
   *   *VALID* initialized memory addresses !
   */
  [...]
}

或者,您可以简单地修改函数以返回您分配的字符串的地址。您可以返回 NULL ,而不是像现在一样在失败时返回 -1 。如果您选择走这条路线,您的功能界面就会如此简单:GLchar* LoadShader (char* Filename)