Skip to content

WebGLRenderer: Better support for blitFramebuffer #33161

@vanruesc

Description

@vanruesc

Description

Related: #21734, #29772

It's sometimes necessary to copy the contents of a render target or a depth texture into another one to avoid feedback loops.

Three offers the Renderer.copyTextureToTexture method which supports copying render target textures as well as depth textures. However, this method has a noticable impact on performance when used inside an animation loop because it can't use blitFramebuffer in those cases. It's more suited for infrequent copy operations.

The faster alternative is to use a fullscreen copy pass, but this adds unnecesssary overhead. It's also possible to use blitFramebuffer directly as shown below, but this requires accessing private data and raw gl values.

const gl = renderer.getContext();
const props = renderer.properties;

let blitMask = 0;
if(color) { blitMask |= gl.COLOR_BUFFER_BIT; }
if(depth) { blitMask |= gl.DEPTH_BUFFER_BIT ; }
if(stencil) { blitMask |= gl.STENCIL_BUFFER_BIT; }

const srcFBO = props.get(renderTargetA).__webglFramebuffer;
const dstFBO = props.get(renderTargetB).__webglFramebuffer;

gl.bindFramebuffer(gl.READ_FRAMEBUFFER, srcFBO);
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, dstFBO);

gl.blitFramebuffer(
	0, 0, renderTargetA.width, renderTargetA.height,
	0, 0, renderTargetB.width, renderTargetB.height,
	blitMask, gl.NEAREST
);

gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);

I've done some testing and found that blitFramebuffer is on par with a copy shader while copyTextureToTexture is much slower:

Performance Tests

copy shader

Image

blitFramebuffer

Image

copyTextureToTexture

Image
Image

Solution

It would be great if three had a method equivalent to blitFramebuffer for fast framebuffer copy operations so that users don't have to access internals and use direct gl calls.

Alternatives

copyTextureToTexture could be changed to also accept RenderTarget arguments so that blitFramebuffer can be used internally.

Additional context

I tried using copyTextureToTexture under the assumption that it would use blitFramebuffer internally, but I had to disable it when I noticed the performance degradation.

The use of blitFramebuffer came up again in pmndrs/postprocessing#740.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions