LINUX.ORG.RU

OpenGL/GLSL: glLinkProgram не линкует шейдеры

 ,


0

2

$subj. glGetProgramiv() после glLinkProgram() возращает GL_FALSE, при этом лог, полученный glGetProgramInfoLog(), пустой (и логи даже после успешной компиляции шейдеров тоже - нет даже warning-ов).

thetailgunner@aileron:~$ glxinfo | grep -i version
server glx version string: 1.4
client glx version string: 1.4
GLX version: 1.4
OpenGL core profile version string: 3.3 (Core Profile) Mesa 10.3.2
OpenGL core profile shading language version string: 3.30
OpenGL version string: 3.0 Mesa 10.3.2
OpenGL shading language version string: 1.30
OpenGL ES profile version string: OpenGL ES 3.0 Mesa 10.3.2
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.0

#include <GL/gl3w.h>
#include <GL/glu.h>
#include <glm/glm.hpp>
#include <GLFW/glfw3.h>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>
#include <iostream>
#include <stdexcept>
#include <vector>

static const GLfloat globVertexBufferData[] = {
  -1.0f, -1.0f,  0.0f,
   1.0f, -1.0f,  0.0f,
   0.0f,  1.0f,  0.0f,
};

void getShaderCompileLog(GLuint sId, std::string& outLogStr) {
    GLint logLen;
    glGetShaderiv(sId, GL_INFO_LOG_LENGTH, &logLen);
    outLogStr.resize((unsigned long)logLen);
    glGetShaderInfoLog(sId, logLen, &logLen, &outLogStr[0]);
}

void getProgramCompileLog(GLuint pId, std::string& outLog) {
    GLint logLen;
    glGetProgramiv(pId, GL_INFO_LOG_LENGTH, &logLen);
    outLog.resize((unsigned long)logLen);
    glGetProgramInfoLog(pId, logLen, &logLen, &outLog[0]);
}

bool shaderCompiled(GLuint id) {
    GLint status;
    glGetShaderiv(id, GL_COMPILE_STATUS, &status);
    if (GL_FALSE == status)
        return false;
    return true;
}

bool programCompiled(GLuint pId) {
    GLint status;
    glGetProgramiv(pId, GL_COMPILE_STATUS, &status);
    if (GL_FALSE == status)
        return false;
    return true;
}

GLuint prepareShaders() {
    const GLchar* const vertexShaderStr = "#version 330 \n"
                               "layout(location = 0) in vec3 vertexPos;\n"
                               "void main() {\n"
                               "gl_Position.xyz = vertexPos;\n"
                               "gl_Position.w = 1.0;\n"
                               "}";
    GLuint vertexShaderId = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShaderId, 1, &vertexShaderStr, nullptr);
    glCompileShader(vertexShaderId);

    if (!shaderCompiled(vertexShaderId)) {
        std::string log;
        getShaderCompileLog(vertexShaderId, log);
        std::cerr << log;
        throw std::runtime_error("unable to compile shader");
    }

    const GLchar* const  fragmentShaderStr = "#version 330 \n"
                                             "precisison mediump float;\n"
                                             "out vec3 color;\n"
                                             "void main() { color = vec3(0, 0, 1); }";
    GLuint frShaderId = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(frShaderId, 1, &fragmentShaderStr, nullptr);
    glCompileShader(frShaderId);

    if (!shaderCompiled(frShaderId)) {
        std::string log;
        getShaderCompileLog(frShaderId, log);
        std::cerr << log;
        throw std::runtime_error("unable to compile shader");
    }
    GLuint pId = glCreateProgram();
    glAttachShader(pId, vertexShaderId);
    glAttachShader(pId, frShaderId);
    glLinkProgram(pId);
    if (!programCompiled(pId)) {
        std::string log;
        getProgramCompileLog(pId, log);
        std::cerr << &log[0];
        throw std::runtime_error("unable to compile program");
    }
    glDeleteShader(vertexShaderId);
    glDeleteShader(frShaderId);
    return pId;
}

void resizeCallback(GLFWwindow*, int w, int h) {
    glViewport(0, 0, w, h);
}

int main() {
  if(!glfwInit()) {
    std::cerr << "Failed to initialize GLFW" << std::endl;
    return -1;
  }

  glfwDefaultWindowHints();

  GLFWwindow* window = glfwCreateWindow(300, 300, "Test",
                                        nullptr, nullptr);
  if(window == nullptr) {
    std::cerr << "Failed to open GLFW window" << std::endl;
    glfwTerminate();
    return -1;
  }

  glfwMakeContextCurrent(window);
  if (gl3wInit()) {
      return -1;
  }
  glfwSwapInterval(1);
  glfwSetWindowSizeCallback(window, resizeCallback);
  glfwShowWindow(window);
  glEnable(GL_DOUBLEBUFFER);
  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LESS);

  glClearColor(0, 0, 0, 1);

  GLuint pId;

  try {
      pId = prepareShaders();
  } catch (...) {
      glfwDestroyWindow(window);
      glfwTerminate();
      return -1;
  }

  GLuint vbo;
  glGenBuffers(1, &vbo);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  glBufferData(GL_ARRAY_BUFFER, sizeof(globVertexBufferData), globVertexBufferData, GL_STATIC_DRAW);

  GLuint vao;
  glGenVertexArrays(1, &vao);
  glBindVertexArray(vao);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
  glBindBuffer(GL_ARRAY_BUFFER, 0);
  glBindVertexArray(0);

  while (glfwWindowShouldClose(window) != GL_FALSE) {
       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

       glUseProgram(pId);
       glBindVertexArray(0);
       glEnableVertexAttribArray(0);
       glDrawArrays(GL_TRIANGLES, 0 ,3);
       glDisableVertexAttribArray(0);

       glfwSwapBuffers(window);
       glfwPollEvents();
  }

  glfwDestroyWindow(window);
  glfwTerminate();
  return 0;
}

Ответ на: комментарий от ckotinko

Либо я запутался, либо одно из двух. При компиляции шейдера теперь говорит, что GLSL version 3.30 is not supported (каюсь - возможно, показал нетронутую версию - в более поздних, кажется, менял версию на поддерживаемую 130). Тогда вопрос в другом - почему 3.30 не поддерживается?

out vec4 color;

Поправил, но не совсем понимаю, чем должно помочь.

cypherpunks01
() автор топика

И все равно, даже если сменить версию на 130 и не компилировать vertex shader вообще (1.30 не умеет layout(location=...)), в резульатте glLinkProgram - ошибка и пустой лог.

cypherpunks01
() автор топика

Выхлоп

lspci -k | egrep 'VGA|3D' -A2
В студию.
PS
Твою портянку не читал, как ты её компилируешь тоже. Так что в коде сам ищи ошибки.

peregrine ★★★★★
()

«out vec3 color;\n»
«void main() { color = vec3(0, 0, 1); }»

Наизусть спеку GLSL не знаю, но догадываюсь, что это не работает на всех версиях. Пробуй:

«void main() { gl_FragColor = vec4(0, 0, 1.0, 1.0); }»

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

Dendy ★★★★★
()
Ответ на: комментарий от cypherpunks01

Kernel driver in use: nouveau

Ну не умеет он в OpenGL (точнее умеет, но как-то так), чего вы от него хотите. Думаешь игры под ним просто так не идут? Ставь блоб нужной версии для твоей видяхи.

peregrine ★★★★★
()

А шейдеры точно все компилируются? В OpenGL 3.3 нету спецификаторов для точности, они появляются в каком-то из OpenGL 4.x либо через GL_ARB_gpu_shader5

oh-la-la
()
Последнее исправление: oh-la-la (всего исправлений: 1)
Ответ на: комментарий от oh-la-la

Если закомментировать vertex shader (3.30 не поддерживается, 1.30 не умеет layout) и у fragment shader сменить версию на 130, компилируется.

cypherpunks01
() автор топика
Ответ на: комментарий от oh-la-la

С glfwDefaultWindowHints() да, говорит, что 3.0 Mesa 10.3.2. Если указать

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
, то 3.3 (Core Profile) Mesa 10.3.2, но glLinkProgram яснее вести себя не начал.

cypherpunks01
() автор топика
Ответ на: комментарий от cypherpunks01
bool programCompiled(GLuint pId) {
    GLint status;
    glGetProgramiv(pId, GL_COMPILE_STATUS, &status);
    if (GL_FALSE == status)
        return false;
    return true;
}

Программа не компилируется, она линкуется. Здесь должна быть проверка на GL_LINK_STATUS.

oh-la-la
()

Попробуй использовать расширение ARB_debug_support.

O02eg ★★★★★
()
Ответ на: комментарий от oh-la-la

Вот теперь (со включенным core profile и GL_LINK_STATUS), шейдеры 330 собираются и линкуются в программу. Правда, ожидаемого треугольника там не видно.

cypherpunks01
() автор топика

glGetProgramInfoLog(pId, logLen, &logLen, &outLog[0]);

А если так:

outLog.resize((unsigned long)logLen + 1);
glGetProgramInfoLog(pId, logLen, nullptr, &outLog[0]);

andreyu ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.