2015-03-07 4 views
0

я адаптировал код из 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, &params) поместит значение мусора, что (или ничего не делает из-за проверки цикла), или чрезвычайно положителен, и сбой моей программы на 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, &params); 
    fprintf(file, "GL_LINK_STATUS = %i\n", params); 

    glGetProgramiv (shader_program, GL_ATTACHED_SHADERS, &params); 
    fprintf(file,"GL_ATTACHED_SHADERS = %i\n", params); 

    glGetProgramiv (shader_program, GL_ACTIVE_ATTRIBUTES, &params); 
    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, &params); 
    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, &params) возвращает огромное количество, вызов 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; 
} 

ответ

1

Выполнение запроса в системе GL, касающееся количества униформ (или любого другого состояния) программы, которая не удалось связать, действительна.В OpenGL 4.3 core profile specification состоянии в разделе 7.3.1:

Если программа связана неудачно, ссылка может не работать на ряд причин, в том числе в случаях, когда программа требуется больше ресурсов, чем поддерживается реализацией. Реализации: разрешено, но не обязательно, для записи списков ресурсов, которые были считаться активными, если бы программа была успешно связана. Если реализация не записывает информацию для любого данного интерфейса, соответствующий список активных ресурсов считается пустым. Если программа никогда не была связана, все списки активных ресурсов считаются пустыми.

вместе с разделом 7.13 о glGetProgramiv():

Если pnam е ACTIVE_ATTRIBUTES, количество активных атрибутов (см раздел 7.3.1) в программе возвращается. Если активных атрибутов нет, возвращается . Если pname - ACTIVE_UNIFORMS, возвращается количество активных униформ в программе. Если активных форм не существует, ноль возвращается .

Обратите внимание, что раздел 7.3.1 упоминается только один раз в этой цитате, но он определяет «ресурсы» для включения униформ, а также атрибутов (среди прочих).

В общем, GL никогда не вернет вам неинициализированные данные, за исключением случаев, когда вы запрашиваете вещи, за которые вы сами несете ответственность за заполнение (например, буферы, фреймбуферы и т. Д.). A glGet*() вызывает либо успешное выполнение (и возвращает действительные данные), либо сбой с некоторой ошибкой GL (и ничего не записывает в память, на которую указывают аргументы).

Если вы видите какое-то неинициализированное состояние GL, это, скорее всего, ошибка драйвера. Обратите внимание, что запрос к ресурсам программы, которая не удалось связать, является необычно необычной (и в сущности тоже бесполезной) операцией (я никогда не пытался это сделать), поэтому это, возможно, не проверенный код, и я могу представить, что вы можете поразить некоторые ошибки драйверов.

Поскольку у вас есть минимальная тестовая программа, способная воспроизвести проблему, единственной рекомендацией, которую я могу дать, является: обновите свои драйверы. Если это не поможет, напишите отчет об ошибке.

+0

Я хотел бы добавить, что я, не зная о драйверах, думал, что если диспетчер устройств Microsoft сказал, что мой драйвер обновлен, все было в порядке. Это, по-видимому, не совсем так; проконсультируйтесь с продавцом, как и все. – rationalcoder

0

Вызывающие glGetProgramiv (GL_ACTIVE_UNIFORMS) на программу, которая не смогла связать это очень плохая идея.

Коэффициенты в том, что драйвер никогда не достигал точки в процессе, когда это значение установлено, и просто возвращает вам неинициализированную память.

Уэтер это ошибка драйвера, неопределенно спорная, так как программа находится в недействительном состоянии.

+0

Хорошо, обсуждать нечего. Спецификация GL четко указывает, что запрос активных атрибутов программы, для которой неудача ссылок является совершенно законной. – derhass

+0

Он возвращает неинициализированную память? Почему это 0, как должно быть около 17 раз из двадцати? Что мне интересно, так это то, что когда возвращаемое значение является сумасшедшим большим, вызов glGetActiveUniform() в первой итерации цикла for (когда i равен нулю) падает. Однако, когда я вручную ставил нуль для этого параметра, когда вызов glGetProgramiv() возвращает 0, как и следовало ожидать, вызов прекрасен и ничего не происходит. Это говорит мне о том, что это не просто возвращение неинициализированной памяти. мысли? PS: @derhass Вот что я говорю! lol – rationalcoder

+0

@noobEqualsBlake: Ну, сложно сказать, что именно происходит. На вашей стороне все еще может быть неопределенное поведение. Если, например, вы каким-то образом можете повредить кучу или стек, это также может повлиять на драйвер. Вы можете создать минимальный пример, который просто создает контекст GL и некоторую программу, которая не связывается, и попытайтесь воспроизвести там поведение. Кроме того, какую реализацию GL вы используете? – derhass