glCreateShader崩溃了

24

我应该拥有最新版本的Glew和Glut,所以那不应该是问题。一切都应该已经链接好了,我正在使用MS Visual Studio 2010。

我的程序可以编译,但是当我执行glCreateShader(GL_FRAGMENT_SHADER)时,它显示一个错误:"0xC0000005:访问冲突"。

#include <GL\glew.h>
#include <GL\glut.h>
#include <stdio.h>
#include <stdlib.h>

GLuint program;

static char* readShaderSource(const char * shaderFile)
{
    FILE* fp = fopen(shaderFile, "r");
    char* buf;
    long size;

    if (fp == NULL) return NULL; 
    fseek(fp, 0L, SEEK_END);//go to end
    size = ftell(fp);       //get size
    fseek(fp, 0L, SEEK_SET);//go to begining

    buf = (char*) malloc((size +1) * sizeof(char));
    fread(buf, 1, size, fp);
    buf[size] = NULL;
    fclose(fp);
    return buf;
}

static void initShader(const GLchar * fsFile)
{
    GLint status;
    GLchar * fSource;
    GLuint fShader;
    GLuint fShader2;

    //read file
    fSource = readShaderSource(fsFile);
    if (fSource == NULL)
    {
        printf("Fail to load file");
        exit(EXIT_FAILURE);
    }

    //Create program and shader object
    fShader2 = glCreateShader(GL_VERTEX_SHADER);
    fShader = glCreateShader(GL_FRAGMENT_SHADER);
    program = glCreateProgram();

    //Attach shaders to program
    glAttachShader(program, fShader);

    //read shaders
    glShaderSource(fShader, 1, (const GLchar**) &fSource, NULL);

    //compile fragment shader
    glCompileShader(fShader);

    //error check
    glGetShaderiv(fShader, GL_COMPILE_STATUS, &status);
    if (status == GL_FALSE)
    {
        printf("Failed to compile the fragment shader.");
        exit(EXIT_FAILURE);
    }

    //link and error check
    glLinkProgram(program);
    glGetProgramiv(program, GL_LINK_STATUS, &status);
    if (status == GL_FALSE)
    {
        printf("program error");
        exit(EXIT_FAILURE);
    }

    //use program object
    glUseProgram(program);

    //set up uniform parameter
    //skipped for now
}

int main(int argc, char ** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(500,500);
    glutCreateWindow("Matrix Fractal");
    glClearColor(1.0, 1.0, 1.0, 1.0);
    gluOrtho2D(0.0,0.0,(GLfloat) 500, (GLfloat) 500);

    glutDisplayFunc(draw);
    glutReshapeFunc(reshape);

    initShader("fsFractal.glsl");

    glutMainLoop();
}
5个回答

58

在使用 GLEW 之前,您必须进行初始化:

GLenum err = glewInit();


1
谢谢Ben。它起作用了。但是为了清晰起见,我使用了另一种变体,我将其作为下面的答案发布。 - sinner

6

还有一种情况可能会导致这种问题的发生,而且条件并不明显。 如果你决定在应用程序中同时使用glfw和glew,如果你写下以下代码:

glCreateShader(shaderType);

那么你也可能遇到ACCESS_VIOLATION问题。

glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

如果你把这一行改成
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);

由于空函数指针glCreateShader(),ACCESS_VIOLATION已经消失。

不要问我,glew和glfw这两个库是如何相互干扰的...巫术警告!


5
我通过在glfwMakeContextCurrent()后调用glewInit()解决了那个问题。 - jimvonmoon
除了 @jimvonmoon 的建议之外,shader所属的窗口在shader创建时必须是当前窗口。这是我的错误。 - scones
谢谢,你让我省去了10天的调试时间。 - Matth

4

以下是我基于 @BenRujil 上面的回答后续组成的变体。

   glewExperimental = GL_TRUE;
    if(glewInit() != GLEW_OK)
        throw std::runtime_error("glewInit failed");

3
如果您正在使用GLFW和GLEW/GLXW,则在使用GLFW创建有效的openGL上下文之前尝试初始化GLEW/GLXW可能会导致访问地址0的访问冲突。请注意,保持正确的顺序很重要。
if (!glfwInit()) {
  std::cerr << "GL initialization failed" << std::endl;
  return 1;
}
// Setup the openGL profile you need - we're going with a 4.3 core profile
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Context creation happens in the line below
GLFWwindow *window = glfwCreateWindow(800, 600, "text", NULL, NULL);
if (!window) {
  std::cerr << "Window or GL initialization failed";
  glfwTerminate();
  return 1;
}
glfwMakeContextCurrent(window);
if (glxwInit()) { // Now it's a good time to initialize Xtension wranglers
  std::cerr << "Failed to initialize GLXW" << std::endl;
  return 1;
}

在创建上下文之前调用glxwInit()将会选择设置的默认上下文,并可能触发访问冲突(可能需要在运行时捕获)。

2
如果是GLFW的问题,您可以在程序崩溃之前向他们请求错误信息。
Windows示例:
创建一个回调函数:
#include <windows.h>
void glfw_onError(int error, const char* description)
{
    // print message in Windows popup dialog box
    MessageBox(NULL, description, "GLFW error", MB_OK);
}

并将其放置在代码的开头位置。
glfwSetErrorCallback(glfw_onError);

我这样做后出现了“The GLFW library is not initialized.”的错误提示。原来我的GLFW库没有初始化。结果发现Ben的回答是正确的。我只是把glfwInit()放在类似这样的断言中:assert(glfwInit());所以当我为程序进行发布编译时,它被剥离了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接