OpenGL:缓冲区对象/着色器超出范围

Posted

技术标签:

【中文标题】OpenGL:缓冲区对象/着色器超出范围【英文标题】:OpenGL: Buffer Objects/Shaders going out of scope 【发布时间】:2017-03-25 17:36:31 【问题描述】:

我正在学习 OpenGL,但遇到了问题。

我知道所有内存都是由 OpenGL 分配到 GPU 上的,所以从技术上讲范围应该不是问题吗?但是,当我尝试这样做时:

int SetUpVertexShader()
    glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

    //BUILD AND COMPILE SHADER
    //VERTEX SHADER
    GLuint vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    //snip - code to compile shader, etc etc
    


;

int SetUpFragmentShaderandLink()
    //BUILD AND COMPILE SHADER
    //FRAGMENT SHADER
    GLint success;
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    //snip - code to compile shader, etc etc

;

int linkShaders()
    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader); //this line has complaints saying vertexShader is an undeclared identifier
    glAttachShader(shaderProgram, fragmentShader); // this line also has complaints saying fragmentShader is an undeclared identifier
    //the rest of the lines all have undeclared identifier complaints
    glLinkProgram(shaderProgram);
    //check linking errors
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if(!success)
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED" << infoLog << std::endl;
    
;

然后,一旦我到达链接着色器和程序函数 linkShaders,我就会收到抱怨说顶点着色器和片段着色器超出了范围(更具体地说,我被告知这两个是“未声明的标识符”)。如果这些是在 GPU 上而不是在堆栈上分配的,那么为什么我被告知它们超出了范围?我做错了吗?

【问题讨论】:

文件分配在磁盘上,但如果您声明FILE* foo = fopen ("foo.txt", "w"),然后尝试在其范围之外使用foo,则会出现错误。是不是让你想起了什么? 请显示linkShaders 使用的vertexShaderfragmentShader 的声明/定义(提示:您显示的定义分别是SetUpVertexShaderSetUpFragmentShaderandLink 的本地定义)。跨度> @n.m.你能进一步解释一下吗? FILE* foo 是一个文件句柄。 GLuint fragmentShader 是一个着色器句柄。两者都是遵循正常范围规则的正常 C 变量。它们代表的东西,文件和着色器,不是 C 对象,它们与范围规则或 C 语言中的任何其他内容无关。回顾一下,着色器是在 GPU 上分配的,它们的句柄不是。句柄是普通的 C 对象。您的程序只看到句柄,而不是着色器本身。 【参考方案1】:

您的变量需要在范围内才能使用它们(无论是否涉及 OpenGL,这都是正确的)。

glCreateShaderglCreateProgram 返回以及 glAttachShaderglLinkProgram 使用的是 OpenGL 对象的句柄(用于特定目的的唯一标识符)。确保将它们保存在您可以在需要将它们提供给其他 OpenGL 调用时访问它们的地方(尤其是在您不再需要最初请求的资源时用于清理函数)。

【讨论】:

那么这是否意味着像 GLuint vertexShader 这样的东西是句柄? 是的,vertexShader是 OpenGL 内部处理的对象的 句柄,可以通过提供它的 OpenGL 调用进行操作。【参考方案2】:

问题不在于内存本身超出范围,因为 GPU 内存遵循堆模式,而超出范围的变量只能发生在堆栈模式中。

问题是指向此内存的指针(存储在 CPU 内存中)位于堆栈上并且超出范围。所以你只需要在函数体之外声明你的 GLuint 指针。

【讨论】:

您在那里写的内容实际上不准确且具有误导性。它比有用更令人困惑。请参阅上面@n.m. 的评论,了解正确的方向。 @datenwolf 你能解释一下不准确的地方吗?它肯定是正确的,并且不像上面的评论那样依赖于完全不相关的类比,而是实际上给出了问题的正确名称以供进一步研究和理解,以及一个转述的解决方案,而不是问“它记得你吗东西?”。所以我真的很想知道为什么这值得一票否决,以及为什么你不给出更好的替代答案。 Tl;博士:到底是什么问题?? 第一个错误:内存没有范围。符号有。内存管理中没有“堆模式”之类的东西。某些操作系统和/或运行时环境在地址空间中定义了“堆内存”的概念,但这只是严格定义的东西。同样在 C/C++ 中根本没有“堆”。有静态 自动动态存储。最后但同样重要的是,OpenGL 纹理和缓冲区名称/ID不是 指针,它们是句柄! OpenGL 纹理或缓冲区 ID 甚至根本不引用特定的内存位置。 @datenwolf 恐怕这完全是错误的。动态存储通常称为“堆分配”、“堆内存模式”或“堆模式”,而静态自动存储通常称为“堆栈分配”、“堆栈内存模式”或“堆栈模式”。另外,OpenGL句柄和其他任意句柄一样,可以看作是某个内存空间中的内存指针,这里是OpenGL接口,不一定是物理地址。为了进一步解释,我很乐意提供一些讲座书籍的参考链接。 请告诉我“堆”一词在 C 语言标准(此处可免费访问的草案:open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf)中出现的位置。然后对 POSIX 标准重复此操作 (pubs.opengroup.org/onlinepubs/9699919799)。把所有你需要的时间。 堆内存是一个非常模糊的术语,据我所知,Microsoft Windows 是唯一明确使用“堆”一词的操作系统。

以上是关于OpenGL:缓冲区对象/着色器超出范围的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL坐标系统

Qt中的OpengL glDrawBuffers()?

具有动态数组的 SwiftUI 多个选择器,索引超出范围错误

“IndexError:位置索引器超出范围”,当它们明显不是时

ORA-22835: 缓冲区太小和 ORA-25137: 数据值超出范围

Sapera++ 与 Qt LNK2019 GetOptionsFromQuestions 和没有关联的缓冲区和索引超出范围