为啥 OpenGL 的 glDrawArrays() 在核心配置文件 3.2 下失败并显示 GL_INVALID_OPERATION 而不是 3.3 或 4.2?

Posted

技术标签:

【中文标题】为啥 OpenGL 的 glDrawArrays() 在核心配置文件 3.2 下失败并显示 GL_INVALID_OPERATION 而不是 3.3 或 4.2?【英文标题】:Why does OpenGL's glDrawArrays() fail with GL_INVALID_OPERATION under Core Profile 3.2, but not 3.3 or 4.2?为什么 OpenGL 的 glDrawArrays() 在核心配置文件 3.2 下失败并显示 GL_INVALID_OPERATION 而不是 3.3 或 4.2? 【发布时间】:2012-10-14 15:11:42 【问题描述】:

我有调用 glDrawArrays 的 OpenGL 渲染代码,当 OpenGL 上下文为(自动/隐式获得)4.2 时,它可以完美运行,但在明确请求 OpenGL 核心上下文 3.2 时始终失败(GL_INVALID_OPERATION)。 (在这两种情况下,着色器总是设置为#version 150,但我怀疑这不是重点。)

根据规范,当 glDrawArrays() 因 GL_INVALID_OPERATION 失败时,只有两个实例:

“如果非零缓冲区对象名称绑定到启用的数组并且缓冲区对象的数据存储当前已映射”——我此时没有进行任何缓冲区映射

李>

“如果几何着色器处于活动状态且模式与 [...] 不兼容”——不,目前没有几何着色器。

此外:

    我已经验证并仔细检查了它只是 glDrawArrays() 调用失败。还仔细检查了在两个 GL 版本下传递给 glDrawArrays() 的所有参数是否相同,缓冲区绑定也是如此。

    这发生在 3 个不同的 nvidia GPU 和 2 个不同的操作系统(Win7 和 OSX,都是 64 位)中——当然,在 OSX 中我们只有 3.2 上下文,反正没有 4.2 )。

    集成的“Intel HD”GPU 不会发生这种情况,但对于那个,我只得到一个自动隐式 3.3 上下文(尝试通过 GLFW 显式强制使用此 GPU 的 3.2 核心配置文件,窗口创建失败但这是一个完全不同的问题...)

对于它的价值,这里是从渲染循环中摘录的相关例程,在 Golang 中:

func (me *TMesh) render () 
    curMesh = me
    curTechnique.OnRenderMesh()
    gl.BindBuffer(gl.ARRAY_BUFFER, me.glVertBuf)
    if me.glElemBuf > 0 
        gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, me.glElemBuf)
        gl.VertexAttribPointer(curProg.AttrLocs["aPos"], 3, gl.FLOAT, gl.FALSE, 0, gl.Pointer(nil))
        gl.DrawElements(me.glMode, me.glNumIndices, gl.UNSIGNED_INT, gl.Pointer(nil))
        gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0)
     else 
        gl.VertexAttribPointer(curProg.AttrLocs["aPos"], 3, gl.FLOAT, gl.FALSE, 0, gl.Pointer(nil))
        /* BOOM! */
        gl.DrawArrays(me.glMode, 0, me.glNumVerts)
    
    gl.BindBuffer(gl.ARRAY_BUFFER, 0)

所以这当然是更大的渲染循环的一部分,尽管现在整个“*TMesh”结构只是两个实例,一个是简单的立方体,另一个是简单的金字塔。重要的是整个绘图循环完美无缺,当查询 GL 是否存在 3.3 和 4.2 下的错误时,没有报告任何错误,但在 3 个具有显式 3.2 核心配置文件的 nvidia GPU 上失败,错误代码根据规范仅在两种具体情况,据我所知,没有一种适用于此。

这里可能有什么问题?你遇到过这种情况吗?有什么想法是我遗漏的吗?

【问题讨论】:

有什么问题吗?听起来更像是一个错误报告。 "根据规范,只有两个 glDrawArrays() 因 GL_INVALID_OPERATION 失败的情况:" 一个美好的幻想,但不是真的。所有glDraw* 调用都可能以多种 方式失败。它们只是没有全部列在每个绘制调用下。我试过collate many of them here,但可能还有更多。 @jnml 啊,是的......当然,这些线程中隐含的问题总是“这里可能出了什么问题?你有没有遇到过这个问题?我错过了什么?”。会相应更新...... @NicolBolas 有趣...似乎您可以在该列表中添加另一个可能的原因:“在 Nvidia GL 驱动程序上具有强制 3.2 核心配置文件的天真简单的普通 DrawArrays,否则在 3.3 和 4.2" 下运行良好... ;) 问题更新:***.com/questions/13062149/… 【参考方案1】:

我有一个疯狂的猜测。

据我了解,所有 OpenGL 调用都必须发生在同一个线程上。这种限制不能很好地与 goroutine 混合,因为同一个 goroutine 可以在其执行的不同点上的不同线程上运行。

要解决这个问题,您需要在主 goroutine(或任何执行 OpenGL 调用的 goroutine)启动后立即将其锁定到当前线程,然后再初始化 OpenGL。

import "runtime"

func main() 
    runtime.LockOSThread()

    ...

您看到不一致结果的原因可能是实施差异。

【讨论】:

Goroutines 和 LockOSThread,这已经被处理了...... :) 问题更新:***.com/questions/13062149/…【参考方案2】:

这不是只是 DrawArrays,我在这里弄错了。不知何故,我调用 glVertexAttribPointer 的方式是这里的问题:在 any 严格的核心配置文件中,无论是 3.2 还是 4.2... 都将进一步调查。在 4.2 非严格的上下文中,没问题。

【讨论】:

问题更新:***.com/questions/13062149/…

以上是关于为啥 OpenGL 的 glDrawArrays() 在核心配置文件 3.2 下失败并显示 GL_INVALID_OPERATION 而不是 3.3 或 4.2?的主要内容,如果未能解决你的问题,请参考以下文章

我可以在调用 glDrawArrays 后删除 OpenGL 顶点数组吗?

调用 glDrawArrays() 时的 OpenGL VBO Segfault

glDrawArrays上的OpenGL Segfaulting

不同形状的OpenGL glDrawArrays

OpenGL - 为 glDrawArrays 自动生成索引/步幅参数

OpenGL 3.3 - glDrawArrays 后的无效操作错误 (1282)