我在AMD Radeon 7750(驱动程序Catalyst 13.12)上从FBO读回深度值时遇到问题该代码适用于我尝试过的所有nVidia卡(主钻机有一个GTX 680运行驱动程序332.21)但是我知道,对于OpenGL规范的一致性,AMD通常会对细节更加挑剔。两台机器都运行Windows 7。
代码在Delphi中,但是应该非常简单地移植到任何其他语言。 (我尝试移植到C ++,但我发现的过剩并不能让我创建核心配置文件上下文。)
procedure TForm2.Button_CombinedWithDepthClick(Sender: TObject);
var
VFBOId: Cardinal;
VFBOSTatus: Cardinal;
VErrString: string;
VCol0TexId: Cardinal;
VDepthRenderBufferId: Cardinal;
VR16UIColorVals: array of Word;
VRGBA32FColorVals: array of Single;
VDepthValsFloats: array of Single;
VDepthValsInt32s: array of Integer;
VDepthValsUInt32s: array of Cardinal;
VDepthValsUInt16s: array of Word;
i: Integer;
begin
// Init and setup FBO
glGenFramebuffers(1, @VFBOId);
glBindFramebuffer(GL_FRAMEBUFFER, VFBOId);
glGenTextures(1, @VCol0TexId);
glBindTexture(GL_TEXTURE_2D, VCol0TexId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
if CheckBox_R16UI.Checked then
glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, Panel_1.Width, Panel_1.Height, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, nil)
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, Panel_1.Width, Panel_1.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
glFrameBufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, VCol0TexId, 0);
glGenRenderbuffers(1, @VDepthRenderBufferId);
glBindRenderbuffer(GL_RENDERBUFFER, VDepthRenderBufferId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, Panel_1.Width, Panel_1.Height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, VDepthRenderBufferId);
VFBOstatus := glCheckFramebufferStatus(GL_FRAMEBUFFER);
if VFBOstatus <> GL_FRAMEBUFFER_COMPLETE then
begin
if VFBOstatus = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT then
VErrString := 'FBO Error: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT'
else if VFBOstatus = GL_FRAMEBUFFER_UNSUPPORTED then
VErrString := 'FBO Error: GL_FRAMEBUFFER_UNSUPPORTED'
else if VFBOStatus = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER then
VErrString := 'FBO Error: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER'
else if VFBOStatus = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER then
VErrString := 'FBO Error: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER'
else if VFBOStatus = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT then
VErrString := 'FBO Error: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT';
raise Exception.Create(VErrString);
end;
glBindRenderbuffer(GL_RENDERBUFFER, 0);
//Clear color
if CheckBox_R16UI.Checked then
begin
glClearColorIuiEXT(590, 200, 314, 147);
glClearDepth(0.69);
end
else
begin
glClearColor(0.5, 0.25, 0.125, 0.0625);
glClearDepth(0.27);
end;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
//Read back
GlError;
glPixelStorei(GL_PACK_ALIGNMENT, 2);
if CheckBox_R16UI.Checked then
begin
SetLength(VR16UIColorVals, Panel_1.Width * Panel_1.Height);
for i := 0 to High(VR16UIColorVals) do
VR16UIColorVals[i] := 123;
glReadPixels(0, 0, Panel_1.Width, Panel_1.Height, GL_RED_INTEGER, GL_UNSIGNED_SHORT, @VR16UIColorVals[0]);
end
else
begin
SetLength(VRGBA32FColorVals, Panel_1.Width * Panel_1.Height * 4);
for i := 0 to High(VRGBA32FColorVals) do
VRGBA32FColorVals[i] := 0.3;
glReadPixels(0, 0, Panel_1.Width, Panel_1.Height, GL_RGBA, GL_FLOAT, @VRGBA32FColorVals[0]);
end;
GlError;
SetLength(VDepthValsFloats, Panel_1.Width * Panel_1.Height);
for i := 0 to High(VDepthValsFloats) do
VDepthValsFloats[i] := 123.074;
glReadPixels(0, 0, Panel_1.Width, Panel_1.Height, GL_DEPTH_COMPONENT, GL_FLOAT, @VDepthValsFloats[0]);
GlError;
SetLength(VDepthValsInt32s, Panel_1.Width * Panel_1.Height);
for i := 0 to High(VDepthValsInt32s) do
VDepthValsInt32s[i] := 456;
glReadPixels(0, 0, Panel_1.Width, Panel_1.Height, GL_DEPTH_COMPONENT, GL_INT, @VDepthValsInt32s[0]);
GlError;
SetLength(VDepthValsUInt32s, Panel_1.Width * Panel_1.Height);
for i := 0 to High(VDepthValsUInt32s) do
VDepthValsUInt32s[i] := 2378;
glReadPixels(0, 0, Panel_1.Width, Panel_1.Height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, @VDepthValsUInt32s[0]);
GlError;
SetLength(VDepthValsUInt16s, Panel_1.Width * Panel_1.Height);
for i := 0 to High(VDepthValsUInt16s) do
VDepthValsUInt16s[i] := 961;
glReadPixels(0, 0, Panel_1.Width, Panel_1.Height, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, @VDepthValsUInt16s[0]);
GlError;
glPixelStorei(GL_PACK_ALIGNMENT, 4);
SetLength(VDepthValsFloats, 0);
SetLength(VDepthValsInt32s, 0);
SetLength(VDepthValsUInt16s, 0);
SetLength(VDepthValsUInt32s, 0);
// Clean up
glDeleteRenderbuffers(1, @VDepthRenderBufferId);
glBindTexture(GL_TEXTURE_2D, 0);
glDeleteTextures(1, @VCol0TexId);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, @VFBOId);
end;
该开关是一个复选框,这里唯一没有包含的是创建一个OpenGL 3.3 Core Profile上下文,其中定义了调试标志和调试回调函数。在nVidia卡上,两个代码路径都正常工作,当R16UI颜色缓冲区绑定到COLOR_ATTACHMENT0时从FBO读取的深度值是正确的。当RGBA32F颜色缓冲区绑定到FBO的COLOR_ATTACHMENT0但AMD Radeon 7750在尝试读取深度时失败,并且glReadPixels调用导致OpenGL错误时,两个卡都有效。
OpenGL Debug回调提供了有关错误的一些其他信息:
调试输出:OpenGLDebugCallback。来源:SOURCE_API类型: TYPE_ERROR严重性:SEVERITY_HIGH消息:&#39; glReadPixels失败 因为操作需要源和目标 内部格式必须共享相同的数字类型(整数, 单精度浮子或双精度浮子) (GL_INVALID_OPERATION)&#39;处理ReadDepthSimple.exe
我无法在glReadPixels页面上将此视为GL_INVALID_OPERATION的有效原因。如果我注释掉连接深度缓冲区的行,两种情况下nVidia卡上的行为和RGBA32F颜色附加情况下的AMD卡都给出了
调试输出:OpenGLDebugCallback。来源:SOURCE_API类型: TYPE_ERROR严重性:SEVERITY_HIGH消息:&#39; GL_INVALID_OPERATION 生成错误。 Drawable没有深度缓冲区。&#39;处理 ReadDepthSimple.exe
然而,当在AMD卡上使用R16UI颜色缓冲区时,我之前得到了相同的错误,抱怨不同的数据类型。
我喜欢指向&#34;驱动程序错误!&#34;在墙上签名,但也许我做错了什么。我需要这个以某种方式工作,渲染到R16UI颜色附件和深度并读回它们。
有什么想法吗?任何人都可以使用带有R16UI颜色缓冲区的FBO在AMD卡上读取深度吗?