я адаптировал код из OpenGL учебника кода компаньона Антона найти здесь: https://github.com/capnramses/antons_opengl_tutorials_book/blob/master/02_shaders/main.cПочему glGetProgramiv GL_ACTIVE_UNIFORMS иногда возвращает мусор и разбивает мою программу?
При тестировании print_all или dump_all функции, чтобы напечатать все о шейдере, я заметил в моем журнале, что glGetProgramiv(shader_program, GL_ACTIVE_UNIFORMS, ¶ms)
поместит значение мусора, что (или ничего не делает из-за проверки цикла), или чрезвычайно положителен, и сбой моей программы на glGetActiveUniform(shader_program, i, MAX_LENGTH, &actual_length, &size, &type, name)
, поскольку он должен обрабатывать только значения i
до NUM_ACTIVE_UNIFORMS - 1
; и я уверен, что он не ожидает, что число превысит 1 миллион. Я также проверил результат 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);
}
Мой журнал, когда отрицательное значение: h_ttp: //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)
аварий в первой итерации для цикла ниже его со значением, равным нулю для i
. Однако, когда glGetProgramiv
возвращает 0 для активной формы, как это должно быть, вызов glGetActiveUniform
с 0 для i
не сбой (я жестко закодировал цикл for, чтобы обойти один раз). Это заставляет меня чувствовать, что здесь происходит больше, чем просто неинициализированные данные, которые мне возвращают.
EDIT 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;
}
Я хотел бы добавить, что я, не зная о драйверах, думал, что если диспетчер устройств Microsoft сказал, что мой драйвер обновлен, все было в порядке. Это, по-видимому, не совсем так; проконсультируйтесь с продавцом, как и все. – rationalcoder