可能滥用WGL,glDrawArrays崩溃

时间:2014-07-30 05:29:21

标签: windows opengl wgl

下面的代码创建一个窗口,使用wglGetProcAddress加载一些OpenGL过程,然后在绿色背景的中心绘制一个红色方块。在我的机器上程序工作正常,但在朋友的笔记本电脑上,它在调用xglDrawArrays()时崩溃,并抱怨该函数试图取消引用0x00000000。请注意,我在朋友的机器上的xglDrawArrays指针本身是非NULL的,正如我在调试器中验证的那样。让我再次强调,错误不是由于xglDrawArrays为NULL,而是由于xglDrawArrays在内部访问NULL数据。

现在,最奇怪的是,当我改变" xglDrawArrays" to" glDrawArrays"在他的机器上,代码突然起作用。这让我怀疑这个错误是由于一些误用WGL造成的。

相关的顶点和片段着色器非常简单:

/* Vertex Shader */
attribute vec2 pos;
void main() {
    gl_Position = vec4(pos.x, pos.y, 0, 1)
}

/* Fragment Shader */
void main() {
    gl_FragColor = vec4(1, 0, 0, 1)
}

相关代码在这里:

#include <windows.h>
#include <stdlib.h>
#include <conio.h>
#include <gl/gl.h>
#include "glext.h"

typedef void (__stdcall *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count);

PFNGLCREATESHADERPROC            xglCreateShader;
PFNGLSHADERSOURCEPROC            xglShaderSource;
PFNGLCOMPILESHADERPROC           xglCompileShader;
PFNGLGETSHADERIVPROC             xglGetShaderiv;
PFNGLGETSHADERINFOLOGPROC        xglGetShaderInfoLog;
PFNGLCREATEPROGRAMPROC           xglCreateProgram;
PFNGLATTACHSHADERPROC            xglAttachShader;
PFNGLLINKPROGRAMPROC             xglLinkProgram;
PFNGLGETPROGRAMIVPROC            xglGetProgramiv;
PFNGLUSEPROGRAMPROC              xglUseProgram;
PFNGLGENBUFFERSPROC              xglGenBuffers;
PFNGLBUFFERDATAPROC              xglBufferData;
PFNGLVERTEXATTRIBPOINTERPROC     xglVertexAttribPointer;
PFNGLGETATTRIBLOCATIONPROC       xglGetAttribLocation;
PFNGLENABLEVERTEXATTRIBARRAYPROC xglEnableVertexAttribArray;
PFNGLDRAWARRAYSPROC              xglDrawArrays;
PFNGLBINDBUFFERPROC              xglBindBuffer;

void
LoadOpenGLProcs(void)
{
    xglCreateShader            = (void*)wglGetProcAddress("glCreateShader");
    xglShaderSource            = (void*)wglGetProcAddress("glShaderSource");
    xglCompileShader           = (void*)wglGetProcAddress("glCompileShader");
    xglGetShaderiv             = (void*)wglGetProcAddress("glGetShaderiv");
    xglGetShaderInfoLog        = (void*)wglGetProcAddress("glGetShaderInfoLog");
    xglCreateProgram           = (void*)wglGetProcAddress("glCreateProgram");
    xglAttachShader            = (void*)wglGetProcAddress("glAttachShader");
    xglLinkProgram             = (void*)wglGetProcAddress("glLinkProgram");
    xglGetProgramiv            = (void*)wglGetProcAddress("glGetProgramiv");
    xglUseProgram              = (void*)wglGetProcAddress("glUseProgram");
    xglGenBuffers              = (void*)wglGetProcAddress("glGenBuffers");
    xglBufferData              = (void*)wglGetProcAddress("glBufferData");
    xglVertexAttribPointer     = (void*)wglGetProcAddress("glVertexAttribPointer");
    xglGetAttribLocation       = (void*)wglGetProcAddress("glGetAttribLocation");
    xglEnableVertexAttribArray = (void*)wglGetProcAddress("glEnableVertexAttribArray");
    xglDrawArrays              = (void*)wglGetProcAddress("glDrawArrays");
    xglBindBuffer              = (void*)wglGetProcAddress("glBindBuffer");
}

HGLRC openglContext;
GLuint programID;
GLint posID;
GLuint bufferID;

char*
ReadEntireFile(const wchar_t* path)
{
    char* buff = malloc(1);
    size_t buffSize = 1;

    HANDLE fileHandle = CreateFile(
        path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

    if( fileHandle == INVALID_HANDLE_VALUE )
    {
        MessageBox(NULL, L"CreateFile failed", L"ERROR", MB_OK);
        exit(0);
    }

    while(1)
    {
        char ch;
        BOOL success;
        DWORD numBytesRead;

        success = ReadFile(fileHandle, &ch, 1, &numBytesRead, NULL);

        if( ! success ) {
            MessageBox(NULL, L"ReadFile failed", L"ERROR", MB_OK);
            exit(0);
        }

        if( numBytesRead == 0 )
            break;

        buff[buffSize-1] = ch;
        buffSize++;
        buff = realloc(buff, buffSize);
    }

    buff[buffSize-1] = 0;
    return buff;
}

void
DieUponGLError(void)
{
    if( glGetError() != GL_NO_ERROR )
    {
        MessageBox(NULL, L"glGetError returned an error", L"ERROR", MB_OK);
        exit(0);
    }
}

void
LoadShaders(void)
{
    const char* fileData;
    GLint compileStatus;
    GLint linkStatus;
    char errorString[1024];

    GLuint vertShaderID = xglCreateShader(GL_VERTEX_SHADER);
    GLuint fragShaderID = xglCreateShader(GL_FRAGMENT_SHADER);
    _cprintf("vert shader id: %d\n", vertShaderID);
    _cprintf("frag shader id: %d\n", fragShaderID);

    fileData = ReadEntireFile(
        L"C:\\Users\\myname\\Desktop\\simple.vs");
    xglShaderSource(vertShaderID, 1, &fileData, NULL);
    DieUponGLError();
    free((void*)fileData);

    fileData = ReadEntireFile(
        L"C:\\Users\\myname\\Desktop\\simple.fs");
    xglShaderSource(fragShaderID, 1, &fileData, NULL);
    DieUponGLError();
    free((void*)fileData);

    xglCompileShader(vertShaderID);
    xglGetShaderiv(vertShaderID, GL_COMPILE_STATUS, &compileStatus);
    if( compileStatus != GL_TRUE )
    {
        xglGetShaderInfoLog(vertShaderID, 1024, NULL, errorString);
        _cprintf("[SHADER COMPILE ERROR]\n");
        _cprintf("%s\n", errorString);
        MessageBox(
            NULL, L"glCompileShader(vertShaderID) failed", L"ERROR", MB_OK);
        exit(0);
    }

    xglCompileShader(fragShaderID);
    xglGetShaderiv(fragShaderID, GL_COMPILE_STATUS, &compileStatus);
    if( compileStatus != GL_TRUE )
    {
        MessageBox(
            NULL, L"glCompileShader(fragShaderID) failed", L"ERROR", MB_OK);
        exit(0);
    }

    _cprintf("vert shader compile status: %d\n", compileStatus);
    _cprintf("frag shader compile status: %d\n", compileStatus);

    programID = xglCreateProgram();
    xglAttachShader(programID, vertShaderID);
    xglAttachShader(programID, fragShaderID);

    xglLinkProgram(programID);
    xglGetProgramiv(programID, GL_LINK_STATUS, &linkStatus);
    if( linkStatus != GL_TRUE )
    {
        MessageBox(
            NULL, L"glLinkShader(programID) failed", L"ERROR", MB_OK);
        exit(0);
    }

    xglUseProgram(programID);
    DieUponGLError();
    _cprintf("Shader program successfully linked and installed\n");

    posID = xglGetAttribLocation(programID, "pos");
    if( posID == -1 )
    {
        MessageBox(
            NULL, L"glGetAttribLocation(\"pos\") failed", L"ERROR", MB_OK);
        exit(0);
    }
}

void
LoadGeometry(void)
{

    GLfloat squarePoints[] =
    {
        -0.5, +0.5,
        -0.5, -0.5,
        +0.5, +0.5,
        +0.5, -0.5
    };

    xglGenBuffers(1, &bufferID);

    xglBindBuffer(GL_ARRAY_BUFFER, bufferID);

    xglBufferData(
        GL_ARRAY_BUFFER, sizeof(squarePoints), squarePoints, GL_STATIC_DRAW);
}

void
DrawGeometry(void)
{
    xglBindBuffer(GL_ARRAY_BUFFER, bufferID);
    xglVertexAttribPointer(posID, 2, GL_FLOAT, GL_FALSE, 0, 0);
    xglEnableVertexAttribArray(posID);
    xglDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}

double
TimeSec(void)
{
    LARGE_INTEGER value;

    static LARGE_INTEGER freq;
    static BOOL firstRun = TRUE;
    if( firstRun )
    {
        firstRun = FALSE;
        QueryPerformanceFrequency(&freq);
    }

    QueryPerformanceCounter(&value);
    return (double)value.QuadPart / (double)freq.QuadPart;
}

LRESULT CALLBACK MainWindowProc(
    HWND hwnd,
    UINT msg,
    WPARAM wparam,
    LPARAM lparam)
{
    if( msg == WM_DESTROY )
    {
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hwnd, msg, wparam, lparam);
}

int
WINAPI
WinMain(
    HINSTANCE appInstance,
    HINSTANCE prevAppInstance,
    LPSTR lpCmdLine,
    int showCmd)
{
    MSG msg;
    HWND win;
    WNDCLASSEX cls;
    HDC dc;
    GLuint pixelFormatID;
    PIXELFORMATDESCRIPTOR pixelFormatDescriptor =
    {
        sizeof(PIXELFORMATDESCRIPTOR),
        1,
        PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
        PFD_TYPE_RGBA,
        32, // cColorBits
        0,  // cRedBits
        0,  // cRedShift
        0,  // cGreenBits
        0,  // cGreenShift
        0,  // cBlueBits
        0,  // cBlueShift
        0,  // cAlphaBits
        0,  // cAlphaShift
        0,  // cAccumBits
        0,  // cAccumRedBits
        0,  // cAccumGreenBits
        0,  // cAccumBlueBits
        0,  // cAccumAlphaBits
        24, // Size of the depth buffer (in bits)
        0,  // Size of stencil buffer (in bits)
        0,  // Number of aux buffers
        0,  // iLayerType (ignored)
        0,  // bReserved
        0,  // dwLayerMask (ignored)
        0,  // dwVisibleMask (0 means black)
        0   // dwDamageMask (ignored)
    };

    cls.cbSize        = sizeof(cls);
    cls.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    cls.lpfnWndProc   = MainWindowProc;
    cls.cbClsExtra    = 0;
    cls.cbWndExtra    = 0;
    cls.hInstance     = appInstance;
    cls.hIcon         = NULL;
    cls.hCursor       = LoadCursor(NULL, IDC_ARROW);
    cls.hbrBackground = GetStockObject(WHITE_BRUSH);
    cls.lpszMenuName  = L"MainMenu";
    cls.lpszClassName = L"MainWindowClass";
    cls.hIconSm       = NULL;

    if( RegisterClassEx(&cls) == 0 )
    {
        MessageBox(NULL, L"RegisterClassEx failed", L"ERROR", MB_OK);
        return 0;
    }

    win = CreateWindowEx(
        0,
        L"MainWindowClass",
        L"Main Window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        500,
        500,
        NULL,
        NULL,
        appInstance,
        NULL);

    if( win == NULL )
    {
        MessageBox(NULL, L"CreateWindowEx failed", L"ERROR", MB_OK);
        return 0;
    }

    dc = GetDC(win);
    if( dc == NULL )
    {
        MessageBox(NULL, L"GetDC() failed", L"ERROR", MB_OK);
        return 0;
    }

    pixelFormatID = ChoosePixelFormat(dc, &pixelFormatDescriptor);

    if (pixelFormatID == 0 )
    {
        MessageBox(NULL, L"ChoosePixelFormat() failed", L"ERROR", MB_OK);
        return 0;
    }

    if( ! SetPixelFormat(dc, pixelFormatID, &pixelFormatDescriptor) )
    {
        MessageBox(NULL, L"SetPixelFormat", L"ERROR", MB_OK);
        return 0;
    }

    openglContext = wglCreateContext(dc);
    if( openglContext == NULL )
    {
        MessageBox(NULL, L"wglCreateContext() failed", L"ERROR", MB_OK);
        return 0;
    }

    if( ! wglMakeCurrent(dc, openglContext) )
    {
        MessageBox(NULL, L"wglMakeCurrent() failed", L"ERROR", MB_OK);
        return 0;
    }

    ShowWindow(win, showCmd);

    AllocConsole();
    _cprintf("GL_VERSION: %s\n", glGetString(GL_VERSION));

    LoadOpenGLProcs();
    LoadShaders();
    LoadGeometry();
    DieUponGLError();

    while(1)
    {
        while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
        {
            TranslateMessage(&msg); 
            DispatchMessage(&msg); 
        }

        glClearColor(0, 1, 0, 1);
        glClear(GL_COLOR_BUFFER_BIT);
        DrawGeometry();
        SwapBuffers(dc);
    }

    return 0;
}

最后,我使用的glext.h文件就在这里:glxext.h

1 个答案:

答案 0 :(得分:0)

首先,wglGetProcAddress如果你要求的功能不是微软软件的'扩展',那么DrawElements可能会返回NULL(这是 - 高于GL 1.1的所有内容; APIENTRY不在上面)。

其次,您需要将函数类型定义为typedef void (APIENTRY *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); ,例如:

{{1}}

最后,如果你有权访问调试器,为什么不至少附加stacktrace?