仅在删除/ realloc纹理之后来自glFramebufferTexture2DEXT的GL_INVALID_VALUE

时间:2012-11-29 19:25:31

标签: windows opengl textures framebuffer fbo

我有一些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配置文件。

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

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

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

1 个答案:

答案 0 :(得分:1)

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

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

  

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

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