Webgl:不同格式的颜色附件在Windows

时间:2015-05-26 16:40:58

标签: javascript webgl

我正在尝试使用带有OES_texture_float的WEBGL_draw_buffers,这有效。但是,当使用两个具有不同类型的渲染目标时,这不适用于我的Windows机器(amd)。但它可以在我的linux机器上运行(开源radeon驱动程序)。

所以带有以下颜色附件的帧缓冲区在Windows上不起作用:

  

附件0:rgb *无符号字节

     

附件1:rgb * float

但以下布局确实有效:

  

附件0:rgb * float

     

附件1:rgb * float

我写了一个小测试程序来说明问题:

<!DOCTYPE html>
<html>

<head>
</head>

<body>
  <script type="text/javascript">
    var canvas = document.createElement('canvas');
    var gl = canvas.getContext("webgl");

    var WEBGL_draw_buffers = gl.getExtension("WEBGL_draw_buffers") || gl.getExtension("GL_EXT_draw_buffers") || gl.getExtension("EXT_draw_buffers");
    gl.getExtension("OES_texture_float");
    gl.getExtension("WEBGL_depth_texture");



    var result = "";
    result += "UNSIGNED_BYTE, FLOAT: " + test(gl.UNSIGNED_BYTE, gl.FLOAT) + "<br />";
    result += "FLOAT, FLOAT: " + test(gl.FLOAT, gl.FLOAT);

    var div = document.createElement('div');
    div.innerHTML = result;
    document.body.appendChild(div);


    function setParams() {
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    }

    function test(type1, type2) {
      var w = 2, h = 2;

      var t1 = gl.createTexture();
      gl.bindTexture(gl.TEXTURE_2D, t1);
      setParams();
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, w, h, 0, gl.RGB, type1, null);


      var t2 = gl.createTexture();
      gl.bindTexture(gl.TEXTURE_2D, t2);
      setParams();
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, w, h, 0, gl.RGB, type2, null);


      var framebuffer = gl.createFramebuffer();
      gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);

      WEBGL_draw_buffers.drawBuffersWEBGL([WEBGL_draw_buffers.COLOR_ATTACHMENT0_WEBGL, WEBGL_draw_buffers.COLOR_ATTACHMENT1_WEBGL]);


      gl.framebufferTexture2D(gl.FRAMEBUFFER, WEBGL_draw_buffers.COLOR_ATTACHMENT0_WEBGL, gl.TEXTURE_2D, t1, 0);
      gl.framebufferTexture2D(gl.FRAMEBUFFER, WEBGL_draw_buffers.COLOR_ATTACHMENT1_WEBGL, gl.TEXTURE_2D, t2, 0);

      var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);


      gl.bindFramebuffer(gl.FRAMEBUFFER, null);


      switch (status) {
        case gl.FRAMEBUFFER_COMPLETE:
          return "FRAMEBUFFER_COMPLETE";
        case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
          return "FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
        case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
          return "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
        case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
          return "FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
        case gl.FRAMEBUFFER_UNSUPPORTED:
          return "FRAMEBUFFER_UNSUPPORTED";
        default:
          return "Error: " + status;
      }
    }
  </script>
</body>

</html>

在Windows上输出:

UNSIGNED_BYTE, FLOAT: FRAMEBUFFER_UNSUPPORTED
FLOAT, FLOAT: FRAMEBUFFER_COMPLETE

并在linux上输出:

UNSIGNED_BYTE, FLOAT: FRAMEBUFFER_COMPLETE
FLOAT, FLOAT: FRAMEBUFFER_COMPLETE

我想知道原因。请注意,我的结果在firefox和chrome中是相同的。

更新:当在Windows上禁用angle时,它的行为就像linux一样。

2 个答案:

答案 0 :(得分:0)

我在reddit上回复,但我会在这里复制一遍:

据我所知,驱动程序拒绝多个颜色缓冲区是“正确的”,这些颜色缓冲区的所有颜色的位平面数不同(参见https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_buffers.txt第5期),并且根据4.0节OpenGLES2规范: “附加到应用程序创建的帧缓冲区对象的所有颜色缓冲区必须具有相同数量的位平面”

我读到了,因为附加到片段输出的所有颜色应该具有相同的位深度,如果有些具有8位(无符号字节)而其他有32位(浮点数)则不是这种情况。

Linux驱动程序可能不是严格符合规范,或实现放宽此限制的扩展。换句话说 - 您不能依赖支持不同位深度的多个颜色输出的驱动程序。

答案 1 :(得分:0)

WebGL只需要3种附件组合即可工作。

From the spec

  

以下帧缓冲对象附件的组合,当所有附件都是帧缓冲附件完成,非零且具有相同的宽度和高度时,必须导致帧缓冲完成帧缓冲:

     
      
  • COLOR_ATTACHMENT0 = RGBA / UNSIGNED_BYTE纹理
  •   
  • COLOR_ATTACHMENT0 = RGBA / UNSIGNED_BYTE纹理+ DEPTH_ATTACHMENT = DEPTH_COMPONENT16渲染缓冲区
  •   
  • COLOR_ATTACHMENT0 = RGBA / UNSIGNED_BYTE纹理+ DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL渲染缓冲区
  •   

WEBGL_draw_buffers扩展程序会增加一些内容。 From that spec

  

如果:   帧缓冲区的颜色附件是使用格式RGBA和类型UNSIGNED_BYTE分配的所有纹理,以及   帧缓冲区具有:

     
      
  • 无深度或模板附件

  •   
  • 有效的DEPTHDEPTH_STENCIL附件

  •   
     

然后针对此帧缓冲区调用checkFramebufferStatus不得返回FRAMEBUFFER_UNSUPPORTED。 (换句话说,实现必须支持使用RGBA / UNSIGNED_BYTE纹理作为颜色附件,加上DEPTHDEPTH_STENCIL附件。)

     

COLOR_ATTACHMENT0_WEBGL开始附加n个连续的颜色附件,其中n介于1和MAX_DRAW_BUFFERS_WEBGL之间,不得在调用checkFramebufferStatus时返回FRAMEBUFFER_UNSUPPORTED。换句话说,如果MAX_DRAW_BUFFERS_WEBGL为4,那么需要实现以支持以下颜色附件组合:

     
      
  • COLOR_ATTACHMENT0_WEBGL = RGBA / UNSIGNED_BYTE

  •   
  • COLOR_ATTACHMENT0_WEBGL = RGBA / UNSIGNED_BYTE   COLOR_ATTACHMENT1_WEBGL = RGBA / UNSIGNED_BYTE

  •   
  • COLOR_ATTACHMENT0_WEBGL = RGBA / UNSIGNED_BYTE   COLOR_ATTACHMENT1_WEBGL = RGBA / UNSIGNED_BYTE   COLOR_ATTACHMENT2_WEBGL = RGBA / UNSIGNED_BYTE

  •   
  • COLOR_ATTACHMENT0_WEBGL = RGBA / UNSIGNED_BYTE   COLOR_ATTACHMENT1_WEBGL = RGBA / UNSIGNED_BYTE   COLOR_ATTACHMENT2_WEBGL = RGBA / UNSIGNED_BYTE   COLOR_ATTACHMENT3_WEBGL = RGBA / UNSIGNED_BYTE

  •   

所有其他组合与驱动程序有关。

正如@Kimixa所提到的那样,规范列表组合不起作用,但相反规范也说明哪些组合工作是100%依赖于驱动程序。事实上,在OpenGL ES 2.0中,即使是上面提到的那些也不需要工作。 WebGL在OpenGL ES 2.0之上添加了该要求

这也是某些GPU上未启用WEBGL_draw_buffers的原因之一。 Chrome首次初始化时会测试所有必需的组合。如果驱动程序未针对每个必需组合返回FRAMEBUFFER_COMPLETE,则Chrome不会启用WEBGL_draw_buffers扩展名。

除了所需的组合之外,了解特定组合是否有效的唯一方法是设置它们,然后使用gl.checkFramebufferStatus进行检查。