Open Bug 1581171 Opened 6 years ago Updated 3 years ago

WebGL2 renderbufferStorage() breaks depth blitting to framebuffer by selecting incompatible internal format.

Categories

(Core :: Graphics: CanvasWebGL, defect, P3)

defect

Tracking

()

UNCONFIRMED

People

(Reporter: f.meyer, Unassigned)

Details

Attachments

(1 file)

Attached image gecko_webgl_bug.png

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36

Steps to reproduce:

I am attempting to blit the depth information from one framebuffer to another framebuffer while the source depth buffer is implemented as a render buffer and the destination depth buffer as a texture. The first depth buffer has to be a render buffer as it must be multisampled.

I created a simple demo based on WebGL2 samples in order to make the issue easier to debug. It can be accessed here: http://clients.viscircle.com/WebGL2Samples/samples/fbo_multisample_depth_blit.html

This rendering works like this:

  1. Create a read framebuffer with two attached (multisampled) render buffers for COLOR_ATTACHMENT0 and DEPTH_ATTACHMENT. The internal format specified for the depth render buffer is DEPTH_COMPONENT16.

  2. Create a draw framebuffer with two attached textures for COLOR_ATTACHMENT0 and DEPTH_ATTACHMENT. The internal format specified for the depth texture is DEPTH_COMPONENT16 too.

  3. Render a circle to the read framebuffer.

  4. Blit the read framebuffer to the draw framebuffer specifying both COLOR_BUFFER_BIT and DEPTH_BUFFER_BIT.

  5. Render the draw framebuffer on the screen.

I don't think the color attachment is strictly required to reproduce the bug, but it made it easier for me to immediately see whether the combined blit operation succeeds or not.
When using two separate blits for color and depth, the color will of course be blitted, but the depth blit in isolation still does not work.

Actual results:

The canvas on the demo page is blank.

The cause of this bug is that DoRenderbufferStorageMaybeMultisample(...), corresponding to gl.renderbufferStorageMultisample(), decides to use an incompatible internal depth format.

In dom/canvas/WebGLRenderbuffer.cpp, line 88 Gecko will, when possible, always pick DEPTH_COMPONENT24 or DEPTH24_STENCIL8 as internal format for a render buffer that was specified to be DEPTH_COMPONENT16. This renders the render buffer completely incompatible with the destination texture it's supposed to be blitted on.

The blit to the draw framebuffer then fails silently in the gl::GLContext, because the internal formats don't match. This results in a black/empty canvas.
WebGLFramebuffer::BlitFramebuffer, which invokes fBlitFramebuffer on the gl::GLContext, also still thinks that the underlying render buffer is encoded as DEPTH_COMPONENT16 and thus does not throw an error regarding the inconsistency.

Expected results:

The website should show an orange, pixelated circle on a black background.

On the technical side, Gecko ideally of course shouldn't have to tamper the internal format. However, from the source code comments I understand that this is sometimes required, as not all GL contexts support OpenGL ES specific formats like DEPTH_COMPONENT16.

But currently Gecko will always select 24-bit depth if it can, even though the GL context implements OpenGL ES.
I suggest that the logic should be modified so that the internal format is only altered when the context is not for OpenGL ES.

I will submit a patch for my proposed solution.

Bugbug thinks this bug should belong to this component, but please revert this change in case of error.

Component: Untriaged → Canvas: WebGL
Product: Firefox → Core

The priority flag is not set for this bug.
:jgilbert, could you have a look please?

For more information, please visit auto_nag documentation.

Flags: needinfo?(jgilbert)
Flags: needinfo?(jgilbert)
Priority: -- → P3
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: