我有一些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()检查纹理大小;确实存在。
答案 0 :(得分:1)
这听起来像是NVIDIA OpenGL实现中的一个错误。删除对象名称后,该对象名称将变为无效,因此应该是glGen*
返回的合法候选对象。
您应该提交一份错误报告,其中包含一个可以重现问题的最小案例。
我不想这样做,因为它是一个愚蠢的kluge并增加了内存错误的机会。
不,它没有。 glGenTextures
没有为纹理分配存储(这可能是任何真正的OOM错误)。它只创建纹理名称。不幸的是,你必须使用一种解决方法,但这并不是真正的问题。