【发布时间】:2020-05-29 08:55:38
【问题描述】:
我正在用 C 语言学习带有 Win32 的 OpenGL,并且我已经到了想要实现着色器的地步。我这样做更多的是作为一种学习经验而不是一个项目,所以我决定不使用像 glew 之类的典型扩展牧马人库。这是我的扩展抓取头文件:
glExtensions.h:
#include <windows.h>
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
#define WGL_ACCELERATION_ARB 0x2003
#define WGL_SWAP_METHOD_ARB 0x2007
#define WGL_SUPPORT_OPENGL_ARB 0x2010
#define WGL_DOUBLE_BUFFER_ARB 0x2011
#define WGL_PIXEL_TYPE_ARB 0x2013
#define WGL_COLOR_BITS_ARB 0x2014
#define WGL_DEPTH_BITS_ARB 0x2022
#define WGL_STENCIL_BITS_ARB 0x2023
#define WGL_FULL_ACCELERATION_ARB 0x2027
#define WGL_SWAP_EXCHANGE_ARB 0x2028
#define WGL_TYPE_RGBA_ARB 0x202B
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
#define GL_ARRAY_BUFFER 0x8892
#define GL_STATIC_DRAW 0x88E4
#define GL_FRAGMENT_SHADER 0x8B30
#define GL_VERTEX_SHADER 0x8B31
#define GL_COMPILE_STATUS 0x8B81
#define GL_LINK_STATUS 0x8B82
#define GL_INFO_LOG_LENGTH 0x8B84
#define GL_TEXTURE0 0x84C0
#define GL_BGRA 0x80E1
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
PROC glCreateProgram;
PROC glCreateShader;
PROC glShaderSource;
PROC glCompileShader;
PROC glAttachShader;
PROC glLinkProgram;
PROC glUseProgram;
PROC glGetShaderInfoLog;
PROC glDeleteShader;
PROC glDetachShader;
PROC glIsProgram;
PROC glGenBuffers;
PROC glBindBuffer;
PROC glBufferData;
PROC glEnableVertexAttribArray;
PROC glVertexAttribPointer;
PROC glGenVertexArrays;
PROC glBindVertexArray;
void GLEInit(int);
这里是c文件, glExtionsions.c
#include "glExtensions.h"
#include <windows.h>
#include <gl/gl.h>
#include "consoleUtil.h"
extern PROC glCreateProgram;
extern PROC glCreateShader;
extern PROC glShaderSource;
extern PROC glCompileShader;
extern PROC glAttachShader;
extern PROC glLinkProgram;
extern PROC glUseProgram;
extern PROC glGetShaderInfoLog;
extern PROC glDeleteShader;
extern PROC glDetachShader;
extern PROC glIsProgram;
extern PROC glGenBuffers;
extern PROC glBindBuffer;
extern PROC glBufferData;
extern PROC glEnableVertexAttribArray;
extern PROC glVertexAttribPointer;
extern PROC glGenVertexArrays;
extern PROC glBindVertexArray;
PROC getProc(int hOut, const char* name) {
PROC p = wglGetProcAddress(name);
if(p == 0 ||
(p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) ||
(p == (void*)-1) )
{
HMODULE module = LoadLibraryA("opengl32.dll");
p = GetProcAddress(module, name);
}
return p;
}
void GLEInit(int hOut) {
glCreateProgram = getProc(hOut, "glCreateProgram");
glCreateShader = getProc(hOut, "glCreateShader");
glShaderSource = getProc(hOut, "glShaderSource");
glCompileShader = getProc(hOut, "glCompileShader");
glAttachShader = getProc(hOut, "glAttachShader");
glLinkProgram = getProc(hOut, "glLinkProgram");
glUseProgram = getProc(hOut, "glUseProgram");
glGetShaderInfoLog = getProc(hOut, "glGetShaderInfoLog");
glDeleteShader = getProc(hOut, "glDeleteShader");
glDetachShader = getProc(hOut, "glDetachShader");
glIsProgram = getProc(hOut, "glIsProgram");
glGenBuffers = getProc(hOut, "glGenBuffers");
glBindBuffer = getProc(hOut, "glBindBuffer");
glBufferData = getProc(hOut, "glBufferData");
glEnableVertexAttribArray = getProc(hOut, "glEnableVertexAttribArray");
glVertexAttribPointer = getProc(hOut, "glVertexAttribPointer");
glGenVertexArrays = getProc(hOut, "glGenVertexArrays");
glBindVertexArray = getProc(hOut, "glBindVertexArray");
}
GLEInit 在窗口创建后运行,然后我运行这段代码
int createBasicProgram(int hOut) {
//vertex shader bullcrap
FILE* basicVSFile = getFile("shaders/basic.vs");
FILEDATA* vsfd = getFileData(hOut, basicVSFile);
close(basicVSFile);
int vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, vsfd->numLines, vsfd->lines, vsfd->lengths);
glCompileShader(vs);
int actualLength = 0;
glGetShaderInfoLog(vs, ERROR_BUFFER_SIZE, &actualLength, errorBuffer);
if (actualLength > 0) {
print(hOut, "deleting vertex shader\n");
glDeleteShader(vs);
print(hOut, errorBuffer);
return -1;
}
freeFileData(vsfd);
//fragment shader bullcrap
FILE* basicFSFile = getFile("shaders/basic.fs");
FILEDATA* fsfd = getFileData(hOut, basicFSFile);
int fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, fsfd->numLines, fsfd->lines, fsfd->lengths);
glCompileShader(fs);
glGetShaderInfoLog(fs, ERROR_BUFFER_SIZE, &actualLength, errorBuffer);
if (actualLength > 0) {
print(hOut, "deleting fragment shader\n");
glDeleteShader(fs);
print(hOut, errorBuffer);
return -1;
}
freeFileData(fsfd);
int progId = glCreateProgram();
glAttachShader(progId, vs);
glAttachShader(progId, fs);
glLinkProgram(progId);
glGetShaderInfoLog(progId, ERROR_BUFFER_SIZE, &actualLength, errorBuffer);
if (actualLength > 0) {
print(hOut, errorBuffer);
}
glDetachShader(progId, vs);
glDetachShader(progId, fs);
glDeleteShader(vs);
glDeleteShader(fs);
return progId;
}
void init(hOut) {
bp = createBasicProgram(hOut);
glGenVertexArrays(1, &vaoId);
glBindVertexArray(vaoId);
glGenBuffers(1, &vboId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
}
此代码不会导致错误,但是当我添加简单语句时:
glUseProgram(bp);
进入显示函数,每帧调用一次,程序运行一秒钟,控制台和程序窗口打开并黑屏大约 3 秒钟,然后崩溃,没有构建错误或输出错误可跟踪。这个 glUseProgram 是否有任何原因会导致我的程序崩溃?
堆栈转储显示:“Exception: STATUS_ACCESS_VIOLATION at rip=001004016E6”,其中包含一堆内存位置和我不理解的内容。
【问题讨论】:
-
你肯定在链接后查询了错误的错误日志。应该是
glGetProgramInfoLog而不是glGetShaderInfoLog。 -
好吧,这些疯狂的东西是干什么用的?
if(p == 0 || (p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) || (p == (void*)-1) )。请注意,void 指针和函数指针不能可靠地混合使用。 -
请在您的上下文中描述“崩溃”的含义。该程序是否只是在没有任何消息的情况下自行关闭?没有“无法执行位置...”错误?
-
@Lundin: "这个疯狂的东西是干什么用的?" WGL 函数指针检索函数不能可靠地为实现未提供的函数返回
nullptr。它可以返回过多的无效指针值,因此您必须根据所有这些值检查指针。现在,这几乎可以肯定是从另一个加载器复制而来的,后者从另一个加载器复制了它,等等,所以目前尚不清楚这在今天的实现中是否仍然需要,但在某些时候需要它。 -
How to debug small programs。如果您正在学习,请花时间学习如何使用调试器。这段时间花得很值。这是您将比任何其他工具使用得更多的工具。