FRAMEBUFFER_INCOMPLETE_ATTACHMENT 只发生在 Android w/ Firefox

FRAMEBUFFER_INCOMPLETE_ATTACHMENT only happens on Android w/ Firefox

我有一些 javascript/webgl 代码可以在我尝试过的所有浏览器上运行,但 Android 上的移动版 firefox 运行 除外。问题与“framebuffer complete”有关,但我不知道具体是什么问题。

这是我能制作的最小的复制品。它应该只是创建一个纹理和一个帧缓冲区,设置一些属性,然后检查帧缓冲区是 'complete':

var canvas = document.createElement('canvas');
var gl = canvas.getContext('webgl');
var GL = WebGLRenderingContext;
if (gl.getExtension('OES_texture_float') === null) {
    alert("No float support.");
}

var texture = gl.createTexture();
var frameBuffer = gl.createFramebuffer();
gl.bindTexture(GL.TEXTURE_2D, texture);
gl.bindFramebuffer(GL.FRAMEBUFFER, frameBuffer);

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);
gl.texImage2D(
    GL.TEXTURE_2D, //target
    0,             //level
    GL.RGBA,       //internalformat
    2,             //width
    2,             //height
    0,             //border
    GL.RGBA,       //format
    GL.FLOAT,      // type [changing to UNSIGNED_BYTE "fixes" the failure...?]
    null           // pixels
);
gl.framebufferTexture2D(
    GL.FRAMEBUFFER,
    GL.COLOR_ATTACHMENT0,
    GL.TEXTURE_2D,
    texture,
    0);

var result = gl.checkFramebufferStatus(GL.FRAMEBUFFER);
if (result === GL.FRAMEBUFFER_COMPLETE) {
    alert("success (FRAMEBUFFER_COMPLETE)");
} else {
    alert("ERROR " + ({
        [0]: "Argument wasn't a frame buffer",
        [GL.INVALID_ENUM]: "INVALID_ENUM",
        [GL.FRAMEBUFFER_INCOMPLETE_ATTACHMENT]: "FRAMEBUFFER_INCOMPLETE_ATTACHMENT",
        [GL.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT]:
            "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT",
        [GL.FRAMEBUFFER_INCOMPLETE_DIMENSIONS]: "FRAMEBUFFER_INCOMPLETE_DIMENSIONS",
        [GL.FRAMEBUFFER_UNSUPPORTED]: "FRAMEBUFFER_UNSUPPORTED"
    }[result] || result));
}

在我的测试中,此代码在 Windows+Firefox-44、Windows+Chrome-49、Android+Chrome 和Ubuntu+火狐。但在 Android+Firefox 上 FRAMEBUFFER_INCOMPLETE_ATTACHMENT 失败。

此外,我发现它似乎只影响 FLOAT 纹理。如果我将类型更改为 UNSIGNED_BYTE,它会通过。

因为我一般不熟悉 opengl,所以我可能做了一些明显的疏忽(例如,没有绑定必需的 属性),而移动版 firefox 是唯一没有静默的浏览器纠正我的错误。

另一个可能相关的事情是必须将 GL.FRAMEBUFFER 传递给 gl.checkFramebufferStatus,而不是实际的 frameBuffer 实例。当我传递 frameBuffer 时,结果总是 0。通常 0 表示成功,但是 the mdn docs 甚至没有将 0 列为此函数的可能 return 值;他们说好的结果是 FRAMEBUFFER_COMPLETE.

如果它在其他浏览器中 在完全相同的 phone 上工作,那么我会 file a bug with Mozilla.

但一般来说,将浮点纹理附加到帧缓冲区的功能并未得到普遍支持。在 OpenGL ES 2.0 中,任何格式都不能保证有效:(

在 WebGL 中,只有 3 种格式可以保证有效。 From the spec:

The following combinations of framebuffer object attachments, when all of the attachments are framebuffer attachment complete, non-zero, and have the same width and height, must result in the framebuffer being framebuffer complete:

  • COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture
  • COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16 renderbuffer
  • COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL renderbuffer

所有其他附件组合最多为 GPU/driver/browser。