1

注意:我将首先具体吐出我的问题,然后我会更好地解释我的场景。

在我的窗户上,使用我的英特尔驱动程序。我可以编译这两个(分别是顶点和片段着色器),但不能链接它们:

attribute vec4 vertex;
void main(void) {
       gl_Position = vertex;
}

,

uniform sampler2D textures[2];
vec4 third(sampler2D texture) {
       return texture2D(texture,vec2(0.5,0.5));
}
vec4 second(float a) {
       return third(textures[0]);
}

void main(void) {
       gl_FragColor = second(0.0);
}

我在链接时收到错误消息(链接状态为假),但信息日志为空。

问题是这个着色器在我的 Linux 中使用相同的 GPU 运行良好,并且在我的 NVIDIA 中运行良好。只有在使用英特尔驱动程序的 Windows 中,我才会遇到这个问题。我的 OpenGL 通知以下有关驱动程序的信息:

GL_VENDOR Intel
GL_RENDERER Intel(R) HD Graphics Family
GL_VERSION 3.0.0 - Build 8.15.10.2253
GL_SHADING_LANGUAGE_VERSION 1.30  - Intel Build 8.15.10.2253

有趣的是,看起来无关紧要的修改使程序能够正确链接,到目前为止我发现了一些:

  1. 如果第二个函数没有接收到任何参数,它就会起作用。
  2. 如果 main() 直接调用第三个,它可以工作。
  3. 如果制服不是数组,它是单个元素,它可以工作。
  4. 如果不是将 sampler2D 从第二个传递到第三个,而是传递一个索引,第三个将用于访问纹理,它可以工作。

我的问题是如何使它工作但保持相同的语义?我需要三个函数,我需要thirdmain函数不使用制服,我需要只有second函数知道制服。另外,我需要secondandthird函数接收参数。在我的真实世界场景中,第二个和第三个函数用它收到的值做了很多事情。

只是为了澄清,我在做什么需要这个:

在我正在开发的框架中,使用了三种不同的片段着色器。第一个(main在我的参考代码中)是用户提供的,这个可以调用second框架中定义的函数(在我的参考代码中)。第三级也是用户提供的,但着色器只编译一次,不知道它会被使用多少次以及它的哪些值,它second负责分配正确数量的缓冲区并third为每个缓冲区调用。

这是我用来测试着色器的代码:

#include <SDL.h>
#include <GL/glew.h>
#include <iostream>
#include <vector>
#include <cassert>
#include <sstream>
#include <stdexcept>

#define WIDTH 800
#define HEIGHT 640

void warn(const std::exception& e) {
#ifndef NDEBUG
    std::cerr << "Warning: " << e.what() << std::endl;
#endif
};

namespace {
std::string tostr(unsigned a) { 
    std::stringstream ss;
    ss << a;
    return ss.str();
}

std::string errorname(unsigned a) {
    switch(a) {
    case GL_NO_ERROR:                      return "GL_NO_ERROR";
    case GL_INVALID_ENUM:                  return "GL_INVALID_ENUM";
    case GL_INVALID_VALUE:                 return "GL_INVALID_VALUE";
    case GL_INVALID_OPERATION:             return "GL_INVALID_OPERATION";
    case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION";
    case GL_OUT_OF_MEMORY:                 return "GL_OUT_OF_MEMORY";
    }
    return "";
}

}

void checkGlErrorImpl(unsigned line, const char* file) {
    GLenum curerr = glGetError();
    if( curerr == GL_NO_ERROR )
        return;

    auto err = std::runtime_error(std::string("OpenGL ")+errorname(curerr)+" error on "+file+":"+tostr(line));
    warn(err);
    throw err;
}

#define checkGlError() checkGlErrorImpl(__LINE__,__FILE__)

int create_shader(unsigned type, const char* shaderSource) {
    unsigned id = glCreateShader(type);

    const char* shaderSources[2] = {"#version 130\n",shaderSource};
    glShaderSource(id,2,shaderSources,NULL);

    glCompileShader(id);
    GLint compileStatus;
    glGetShaderiv(id, GL_COMPILE_STATUS, &compileStatus);
        int msgLength;
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &msgLength);

        char* msg = new char[msgLength];
        glGetShaderInfoLog(id, msgLength, &msgLength, msg);

        std::cout << "(" << id << ") " << msg << std::endl;

        std::runtime_error except(std::string("Error on compiling shader:\n")+msg);
        delete[] msg;
        if( compileStatus == GL_FALSE ) {
            warn(except);
            throw except;
        }

    checkGlError();

    return id;
};

int create_program(const std::vector<int>& shaders) {
    int id = glCreateProgram();
    checkGlError();
    for( unsigned int i=0; i< shaders.size(); ++i ) {
        glAttachShader(id,shaders[i]);
    }

    glLinkProgram(id);
    GLint linkStatus=-1;
    glGetProgramiv(id, GL_LINK_STATUS, &linkStatus);
    assert(linkStatus != -1);
    checkGlError();
    if( linkStatus == GL_FALSE ) {
        int msgLength=-1;
        glGetProgramiv(id, GL_INFO_LOG_LENGTH, &msgLength);
        assert( msgLength != -1 );

        char* msg = new char[msgLength+1];
        msg[0] = '\0';
        std::cout << "Buffer(" << msgLength+1 << ")" << msg << std::endl;
        glGetProgramInfoLog(id, msgLength+1, &msgLength, msg);
        std::cout << "Second length " << msgLength << std::endl;
        std::cout << "Log " << msg << std::endl;
        std::string errormsg("Error on linking shader: ");
        errormsg += msg;
//      delete[] msg;

        auto err = std::runtime_error(errormsg);
        warn(err);
        throw err;
    }

    checkGlError();

    return id;
}

int main(int argc, char** argv) {
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
        throw __LINE__;
    }

    int video_flags;
    video_flags = SDL_OPENGL;
    video_flags |= SDL_GL_DOUBLEBUFFER;
    video_flags |= SDL_HWSURFACE;
    video_flags |= SDL_HWACCEL;
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
    SDL_Surface* surface = SDL_SetVideoMode( WIDTH, HEIGHT, 24, video_flags );
    if( surface == NULL )
        throw __LINE__;

    unsigned width = WIDTH;
    unsigned height = HEIGHT;

    GLenum err = glewInit();
    if (GLEW_OK != err) {
        std::cerr << "Error: " << glewGetErrorString(err) << std::endl;
        throw __LINE__;
    }

    std::vector<int> shaders;
    shaders.push_back( create_shader(GL_VERTEX_SHADER,
        "attribute vec4 vertex;\n"
        "void main(void) {\n"
        "   gl_Position = vertex;\n"
        "}\n"
    ));
    shaders.push_back( create_shader(GL_FRAGMENT_SHADER,
        "uniform sampler2D textures[2];\n"
        "vec4 third(sampler2D texture) {\n"
        "   return texture2D(texture,vec2(0.5,0.5));\n"
        "}\n"
        "vec4 second(float a) {\n"
        "   return third(textures[0]);\n"
        "}\n"
        "\n"
        "void main(void) {\n"
        "   gl_FragColor = second(0.0);\n"
        "}\n"
    ));

    int program = create_program(shaders);

    try {
        while( true ) {
            SDL_Event event;
            while( SDL_PollEvent(&event) ) {
                switch( event.type ) {
                case SDL_QUIT:
                    throw 0;
                break;
                }
            }
            SDL_Delay(10);
        }
    } catch( int returnal) {
        return returnal;
    }
    return 0;
};

它依赖于 GLEW、SDL、OpenGL 和 C++11。

4

0 回答 0