如果没有错误,为什么 GL 函数调用返回的位置是 -1?

Why is the location returned by GL function call -1 if there's no error?

在下面的程序中,最后一个打印函数打印 -1,这是名为 num 的制服的位置。我为函数 glGetUniformLocation() 提供了正确的参数,但结果却得到了 -1,不知道为什么?

P.S。着色器编译成功。

        GLuint program = glCreateProgram();
        GLuint computeShader = glCreateShader(GL_COMPUTE_SHADER);

        const GLchar* const shaderSrc = {
            "#version 310 es\n"
            "\n"
            "// Input layout qualifier declaring a 16 x 16 (x 1) local\n" "// workgroup size\n"
            "layout (local_size_x = 16, local_size_y = 16) in;\n"
            "uniform int num;\n"
            "\n"
            "void main(void)\n"
            "{\n"
            "//Do Nothing \n"
            "}\n"
        };

        glShaderSource(computeShader, 1, &shaderSrc, NULL);
        glCompileShader(computeShader);
        int result;
        glGetShaderiv(computeShader, GL_COMPILE_STATUS, &result);

        if(result == GL_FALSE){
            int length;
            glGetShaderiv(computeShader, GL_INFO_LOG_LENGTH, &length);
            char* message = static_cast<char*>(malloc(length));
            glGetShaderInfoLog(computeShader, length, &length, message);
            __android_log_print(ANDROID_LOG_INFO, "MyLog", "Shader Compile Error:  %s", message);
            free(message);
        }

        GL_CALL(glAttachShader(program, computeShader));
        GL_CALL(glLinkProgram(program));
        GL_CALL(glValidateProgram(program));
        GL_CALL(glUseProgram(program));
        auto location = glGetUniformLocation(program, "num");
        __android_log_print(ANDROID_LOG_INFO, "MyLog", "Location %d", location);

统一变量num不是活动的程序资源,因为它没有在着色器程序中使用。编译器和链接器优化代码并确定不需要该变量。因此,您将无法获得有效的统一位置。

此外@Rabbid76's answer我想具体解决一下你标题中的问题:

Why is the location returned by GL function call -1 if there's no error?

因为没有错误,位置-1 不是错误条件

只有 active 制服有位置。查询非活动制服的位置定义为 return -1。另请注意以下内容:

glUniform1f(-1, someValue)

在 GL 中完全有效,也不会根据规范产生任何错误。它只会被默默地忽略。

因为对于一个 non-active uniform 变量来说,不可能 影响你的着色器程序的输出,它的值是无关紧要的,而且 GL 没有打扰。

请注意,API中的这种设计选择是相当合理的。在客户端,您可以使用一组要提供给着色器的制服。但是您可以为这些着色器提供不同的替代方案,每个替代方案都访问这些制服中的特定 sub-set。客户端代码可以相同地对待每个变体,它不必知道(或查询)每个变体使用哪个制服。它只是不能将位置 -1 视为错误,因为它不是错误。至少如果您的客户端代码不能绝对确定此变量 必须 处于活动状态。

警告:查询non-active制服的值实际上是一个错误!

如果您使用 glGetUniformfv(program,location,params) 之类的函数并将 location 设置为 -1,这实际上 一个错误条件。该调用只会 return GL_INVALID_OPERATION 并且没有其他影响(这也意味着 params 指向的内存内容不会被修改 - 它不会 return此类事物的任何默认值)。这种行为也很合理,因为 non-active 统一变量不能有值,你不能查询它们,试图这样做是错误的。

警告:顶点属性的情况略有不同

对于顶点属性,有glGetAttribLocation,这也会return GLint,对于不存在或不活跃的属性使用-1 .查询这些也没有错误。但是采用这些属性位置(如 glVertexAttribPointerglEnableVertexAttribPointer)的 GL 函数通常使用 GLuint 类型,并且

glVertexAttribPointer(-1, ...);

生成一个GL_INALID_VALUE GL错误,因为(GLuint)-1最有可能大于您实现的GL_MAX_VERTEX_ATTRIBS值(即使它你不是没有得到你想要的结果吗。

因此对于属性位置,您的客户端代码必须检查 -1...