我已经修改了Anton在这里找到的opengl教程伴随代码中的一些代码: https://github.com/capnramses/antons_opengl_tutorials_book/blob/master/02_shaders/main.c
在测试print_all或dump_all函数以打印着色器的所有内容时,我在日志中注意到glGetProgramiv(shader_program, GL_ACTIVE_UNIFORMS, ¶ms)
会产生非常消极的垃圾值(并且由于以下情况而无法执行任何操作for循环检查)或非常积极,并在glGetActiveUniform(shader_program, i, MAX_LENGTH, &actual_length, &size, &type, name)
崩溃我的程序,因为它只应处理i
到NUM_ACTIVE_UNIFORMS - 1
的值;我相信它不会超过100万。我在调用之后还检查了glGetError的结果,并且没有设置错误标志。
这是我的转储功能和我日志的图片:
void dump_all(FILE* file, GLuint shader_program)
{
int params = -1;
fprintf(file, "--------------------\nshader program %i info:\n", shader_program);
glGetProgramiv (shader_program, GL_LINK_STATUS, ¶ms);
fprintf(file, "GL_LINK_STATUS = %i\n", params);
glGetProgramiv (shader_program, GL_ATTACHED_SHADERS, ¶ms);
fprintf(file,"GL_ATTACHED_SHADERS = %i\n", params);
glGetProgramiv (shader_program, GL_ACTIVE_ATTRIBUTES, ¶ms);
fprintf(file, "GL_ACTIVE_ATTRIBUTES = %i\n", params);
const int MAX_LENGTH = 64;
int i;
for (i = 0; i < params; i++)
{
char name[MAX_LENGTH];
int actual_length = 0; // not used atm.
int size = 0;
GLenum type;
glGetActiveAttrib (shader_program, i, MAX_LENGTH, &actual_length, &size, &type, name);
if (size > 1)
{
int j;
for (j = 0; j < size; j++)
{
char long_name[MAX_LENGTH];
int location;
sprintf (long_name, "%s[%i]", name, j);
location = glGetAttribLocation (shader_program, long_name);
fprintf (file, " %i) type:%s name:%s location:%i\n",
i, gl_type_to_string(type), long_name, location);
}
}
else
{
int location = glGetAttribLocation (shader_program, name);
fprintf(file, " %i) type:%s name:%s location:%i\n", i, gl_type_to_string (type), name, location);
}
}
printf("\nbefore the active uniform call\n");
glGetProgramiv (shader_program, GL_ACTIVE_UNIFORMS, ¶ms);
GLenum error = glGetError();
printf("\nThere is an error (0 for no error and 1 for an error): %d\n", error != GL_NO_ERROR);
printf("\nglGetError: %d\n", error);
printf("\nafter the get active uniform call\n");
fprintf(file, "GL_ACTIVE_UNIFORMS = %i\n", params);
for (i = 0; i < params; i++)
{
char name[MAX_LENGTH];
int actual_length = 0; // not used atm.
int size = 0;
GLenum type;
printf("\nright before the thing\n");
glGetActiveUniform (shader_program, i, MAX_LENGTH, &actual_length, &size, &type, name);
printf("\nright after the thign\n");
if (size > 1)
{
printf("\nin the if block\n");
int j;
for (j = 0; j < size; j++)
{
char long_name[MAX_LENGTH];
int location;
sprintf (long_name, "%s[%i]", name, j);
location = glGetUniformLocation (shader_program, long_name);
fprintf(file, " %i) type:%s name:%s location:%i\n",
i, gl_type_to_string (type), long_name, location);
}
}
else
{
printf("\nin the else block\n");
int location = glGetUniformLocation (shader_program, name);
fprintf(file, " %i) type:%s name:%s location:%i\n",
i, gl_type_to_string (type), name, location);
}
}
print_program_info_log(file, shader_program);
}
当值为负时我的日志:http://i.stack.imgur.com/Xu9nq.png
当值很大并且崩溃程序时我的日志:http://i.stack.imgur.com/QBP1o.png
注意:我从无法找到文件的目录中运行应用程序。另外,我还没有在任何地方调用glUseProgram()。因此,我正在转储未成功链接的着色器的内容,或者甚至连接了任何成功编译的着色器。
这是一个间歇性的问题;大多数情况下,日志将正确打印0表示活动制服。到目前为止,我已经看到了三个结果; 1.)数字太大而且崩溃了。 2.)这个数字是疯狂的负面而且没有崩溃。 3.)数字很大但不是太大,并且在崩溃调用下方的循环中花费了大量时间,只是打印出垃圾。
这是一个驱动程序错误,还是我在做一些固有的未定义的东西?
编辑1:
如果对glGetProgramiv(shader_program, GL_ACTIVE_UNIFORMS, ¶ms)
的调用返回一个庞大的数字,则glGetActiveUniform (shader_program, i, MAX_LENGTH, &actual_length, &size, &type, name)
的调用会在其下方for循环的第一次迭代中崩溃,i
的值为零。但是,当glGetProgramiv
为活动制服返回0时,对glGetActiveUniform
的调用i
为0并不会崩溃(我对for循环进行了硬编码)一旦)。这让我觉得这里还有更多的内容,而不仅仅是未经初始化的数据会返回给我。
编辑2 根据要求,这是一个提供奇怪值的最小示例程序:
#include <stdio.h>
#undef main
int main(int argc, char ** argv)
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_Window *window = SDL_CreateWindow("Example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL);
if(!window)
{
printf("no window created : %s\n", SDL_GetError());
}
SDL_GLContext context = SDL_GL_CreateContext(window);
SDL_GL_MakeCurrent(window, context);
SDL_GL_SetSwapInterval(1);
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if(err != GLEW_OK)
{
printf("glew failed to init: %s", glewGetErrorString(err));
return -1;
}
GLuint program = glCreateProgram();
glLinkProgram(program); // I can create and attach shaders, compile them, or whatever; I get the same result.
GLint num;
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &num);
printf("NUM UNIFORMS: %d", num);
int run_loop = 1;
while(run_loop)
{
SDL_Event event;
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_QUIT:
SDL_Quit();
run_loop = 0;
break;
default:
break;
}
}
SDL_GL_SwapWindow(window);
}
return 0;
}
答案 0 :(得分:1)
查询无法链接的程序的制服(或任何其他状态)的数量在GL中有效。第7.3.1节中的OpenGL 4.3 core profile specification状态:
如果程序链接失败,则链接可能失败了 原因的数量,包括程序需要更多的情况 资源比实施支持的资源。实施是 允许但不要求记录可能的资源列表 如果程序成功链接,则被认为是活跃的。如果 实现不记录任何给定接口的信息, 相应的活动资源列表被视为空。如果一个 程序从未被链接,所有活动资源列表都是 被认为是空的。
与第7.13节一起讨论glGetProgramiv():
如果
pnam
e是ACTIVE_ATTRIBUTES
,则活动属性的数量(请参阅 程序中的第7.3.1节返回。如果不存在活动属性, 返回零。如果pname是ACTIVE_UNIFORMS
,则为活动数 程序中的制服被退回。如果没有活动的制服,则为零 返回。
请注意,第7.3.1节仅在此引文中引用一次,但它定义了&#34;资源&#34;包括制服和属性(以及其他)。
一般情况下,GL永远不会向您返回未初始化的数据 - 除非您查询自己负责填充的内容(如缓冲区,帧缓冲区等)。 glGet*()
调用成功(并返回有效数据),或者因GL错误而失败(并且不会向参数指向的内存写入任何内容)。
如果你看到一些未初始化的GL状态,那很可能是一个驱动程序错误。请注意,查询无法链接的程序的资源是一个特别不寻常(实际上也是无用的)操作(我从未尝试过这样做),所以这可能是一个没有经过良好测试的代码路径,我可以想象你可能会遇到一些驱动程序错误。
由于您有一个能够重现问题的最小测试程序,我可以给出的唯一建议是:更新您的驱动程序。如果这没有帮助,请提交错误报告。
答案 1 :(得分:0)
在无法链接的程序上调用glGetProgramiv(GL_ACTIVE_UNIFORMS)是一个非常糟糕的主意。
可能的情况是,驱动程序从未达到设置该值的过程中的点,并且只是将未初始化的内存返回给您。
由于程序处于无效状态,因此构成驱动程序错误的问题含糊不清。