尝试使用glReadPixels从FBO读回深度在AMD卡上失败

时间:2014-01-21 09:59:12

标签: opengl fbo

我在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卡上读取深度吗?

0 个答案:

没有答案