我有一些 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() 检查纹理大小;它确实存在。