0

我有一些 C#(SharpGL-esque)代码将 OpenGL 帧缓冲区处理抽象为简单的“将此纹理设置为'渲染目标'”调用。当纹理第一次设置为渲染目标时,我为该纹理大小创建了一个具有匹配深度缓冲区的 FBO;然后,FBO/深度缓冲区组合将被重新用于所有相同大小的纹理。

我有一个奇怪的错误如下。

最初,该应用程序运行并呈现良好。但是如果我增加我的窗口大小,这可能会导致一些代码需要调整其“渲染目标”纹理的大小,它通过 glDeleteTextures() 和 glGenTextures() (然后绑定、glTexImage2D 和 texparams 所以 MIN_FILTER 和 MAG_FILTER 都是 GL_NEAREST )。我观察到这样做时我倾向于返回相同的名称(ID)(因为 GL 重用了刚刚释放的名称)。

然后我们点击下面的代码(对稍微有点混蛋的 GL 式语法表示歉意):

    void SetRenderTarget(Texture texture)
    {
        if (texture != null)
        {
            var size = (texture.Width << 16) | texture.Height;
            FrameBufferInfo info;
            if (!_mapSizeToFrameBufferInfo.TryGetValue(size, out info))
            {
                info = new FrameBufferInfo();
                info.Width = texture.Width;
                info.Height = texture.Height;

                GL.GenFramebuffersEXT(1, _buffer);
                info.FrameBuffer = _buffer[0];

                GL.BindFramebufferEXT(GL.FRAMEBUFFER_EXT, info.FrameBuffer);
                GL.FramebufferTexture2DEXT(GL.FRAMEBUFFER_EXT, GL.COLOR_ATTACHMENT0_EXT, GL.TEXTURE_2D, texture.InternalID, 0);

                GL.GenRenderbuffersEXT(1, _buffer);
                info.DepthBuffer = _buffer[0];
                GL.BindRenderBufferEXT(GL.RENDERBUFFER_EXT, info.DepthBuffer);
                GL.RenderbufferStorageEXT(GL.RENDERBUFFER_EXT, GL.DEPTH_COMPONENT16, texture.Width, texture.Height);
                GL.BindRenderBufferEXT(GL.RENDERBUFFER_EXT, 0);
                GL.FramebufferRenderbufferEXT(GL.FRAMEBUFFER_EXT, GL.DEPTH_ATTACHMENT_EXT, GL.RENDERBUFFER_EXT, info.DepthBuffer);
                _mapSizeToFrameBufferInfo.Add(size, info);
            }
            else
            {
                GL.BindFramebufferEXT(GL.FRAMEBUFFER_EXT, info.FrameBuffer);
                GL.FramebufferTexture2DEXT(GL.FRAMEBUFFER_EXT, GL.COLOR_ATTACHMENT0_EXT, GL.TEXTURE_2D, texture.InternalID, 0);
            }
            GL.CheckFrameBufferStatus(GL.FRAMEBUFFER_EXT);
        }
        else
        {
            GL.FramebufferTexture2DEXT(GL.FRAMEBUFFER_EXT, GL.COLOR_ATTACHMENT0_EXT, GL.TEXTURE_2D, 0, 0);
            GL.BindFramebufferEXT(GL.FRAMEBUFFER_EXT, 0);
        }

        ProjectStandardOrthographic();
    }

在所述窗口调整大小之后,GL 从 glFramebufferTexture2DEXT() 调用返回一个 GL_INVALID_VALUE 错误(用 glGetError() 和 gDEBugger 标识)。如果我忽略这一点,glCheckFrameBufferStatus() 稍后会失败并显示 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT。如果我也忽略这一点,如果我检查它们,我会看到预期的“帧缓冲区可疑做任何事情”错误,如果我不检查它们,则会看到黑屏。

我在 NVidia GeForce GTX 550 Ti、Vista 64(32 位应用程序)、306.97 驱动程序上运行。我将 GL 3.3 与 Core 配置文件一起使用。

解决方法和好奇心:如果在重新分配纹理时我 glGenTextures() 在 glDeleteTextures() 之前 - 为了避免取回相同的 ID - 问题就消失了。我不想这样做,因为它是一个愚蠢的 kluge 并增加了我的内存不足错误的机会。我推测这是因为 GL 在最近的 FBO 中曾经/正在使用纹理,现在已经确定纹理 ID 正在使用或以某种方式不再有效,因此不可接受?也许?

问题后 gDEBugger 显示两个 FBO(原始的具有较小的深度缓冲区和先前的纹理,以及具有较大组合的新的)都附加了相同的纹理 ID。

我尝试在释放之前将纹理从帧缓冲区中分离(再次通过 glFramebufferTexture2DEXT),但无济于事(gDEBuffer 反映了更改,但问题仍然存在)。我已经尝试完全取出深度缓冲区。在使用之前,我尝试通过 glGetTexLevelParameter() 检查纹理大小;它确实存在。

4

1 回答 1

1

这听起来像是 NVIDIA 的 OpenGL 实现中的一个错误。删除对象名称后,该对象名称将变为无效,因此应该是glGen*返回的合法候选对象。

您应该提交一份错误报告,其中包含重现问题的最小案例。

我不想这样做,因为它是一个愚蠢的 kluge 并增加了我的内存不足错误的机会。

不,它没有。glGenTextures不为纹理分配存储空间(这可能是任何真正的 OOM 错误的来源)。它只创建纹理名称。不幸的是,您必须使用一种解决方法,但这并不是真正的问题。

于 2012-11-29T20:06:30.563 回答