Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebGPURenderer: MSAA, Postprocessing and Wireframe support in the WebGL Backend #27473

Merged
merged 16 commits into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion examples/files.json
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,8 @@
"webgpu_tsl_editor",
"webgpu_tsl_transpiler",
"webgpu_video_panorama",
"webgpu_postprocessing_afterimage"
"webgpu_postprocessing_afterimage",
"webgpu_multisampled_renderbuffers"
],
"webaudio": [
"webaudio_orientation",
Expand Down
3 changes: 3 additions & 0 deletions examples/jsm/nodes/display/AfterImageNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ class AfterImageNode extends TempNode {
this.damp = uniform( damp );

this._compRT = new RenderTarget();
this._compRT.texture.name = 'AfterImageNode.comp';

this._oldRT = new RenderTarget();
this._oldRT.texture.name = 'AfterImageNode.old';

this.updateBeforeType = NodeUpdateType.RENDER;

Expand Down
2 changes: 2 additions & 0 deletions examples/jsm/nodes/display/GaussianBlurNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ class GaussianBlurNode extends TempNode {
this._passDirection = uniform( new Vector2() );

this._horizontalRT = new RenderTarget();
this._horizontalRT.texture.name = 'GaussianBlurNode.horizontal';
this._verticalRT = new RenderTarget();
this._verticalRT.texture.name = 'GaussianBlurNode.vertical';

this.updateBeforeType = NodeUpdateType.RENDER;

Expand Down
172 changes: 121 additions & 51 deletions examples/jsm/renderers/webgl/WebGLBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class WebGLBackend extends Backend {

//

//

renderContextData.previousContext = this._currentContext;
this._currentContext = renderContext;

Expand All @@ -79,7 +81,6 @@ class WebGLBackend extends Backend {
this.clear( renderContext.clearColor, renderContext.clearDepth, renderContext.clearStencil, renderContext );

//

if ( renderContext.viewport ) {

this.updateViewport( renderContext );
Expand Down Expand Up @@ -110,11 +111,49 @@ class WebGLBackend extends Backend {

finishRender( renderContext ) {

const { gl } = this;
const renderContextData = this.get( renderContext );
const previousContext = renderContextData.previousContext;

this._currentContext = previousContext;


if ( renderContext.textures !== null && renderContext.renderTarget ) {

const renderTargetContextData = this.get( renderContext.renderTarget );

const { samples, stencilBuffer } = renderContext.renderTarget;
const fb = renderTargetContextData.framebuffer;

if ( samples > 0 ) {

const invalidationArray = [];
const depthStyle = stencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT;

invalidationArray.push( gl.COLOR_ATTACHMENT0 );

if ( renderTargetContextData.depthBuffer ) {

invalidationArray.push( depthStyle );

}

// TODO For loop support MRT
const msaaFrameBuffer = renderTargetContextData.msaaFrameBuffer;

gl.bindFramebuffer( gl.READ_FRAMEBUFFER, msaaFrameBuffer );
gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb );


gl.blitFramebuffer( 0, 0, renderContext.width, renderContext.height, 0, 0, renderContext.width, renderContext.height, gl.COLOR_BUFFER_BIT, gl.NEAREST );

gl.invalidateFramebuffer( gl.READ_FRAMEBUFFER, invalidationArray );

}


}

if ( previousContext !== null ) {

this._setFramebuffer( previousContext );
Expand All @@ -133,6 +172,9 @@ class WebGLBackend extends Backend {

}


this._currentContext = renderContext;

const occlusionQueryCount = renderContext.occlusionQueryCount;

if ( occlusionQueryCount > 0 ) {
Expand All @@ -151,6 +193,7 @@ class WebGLBackend extends Backend {

}


}

resolveOccludedAsync( renderContext ) {
Expand Down Expand Up @@ -312,7 +355,7 @@ class WebGLBackend extends Backend {

draw( renderObject, info ) {

const { pipeline, material, context } = renderObject;
const { pipeline, material, context, isRenderObject } = renderObject;
const { programGPU, vaoGPU } = this.get( pipeline );

const { gl, state } = this;
Expand All @@ -321,6 +364,13 @@ class WebGLBackend extends Backend {

//

if ( isRenderObject ) {

// we need to bind the framebuffer per object in multi pass pipeline
this._setFramebuffer( context );

}

const bindings = renderObject.getBindings();

for ( const binding of bindings ) {
Expand All @@ -334,8 +384,7 @@ class WebGLBackend extends Backend {

} else if ( binding.isSampledTexture ) {

gl.activeTexture( gl.TEXTURE0 + index );
gl.bindTexture( bindingData.glTextureType, bindingData.textureGPU );
state.bindTexture( bindingData.glTextureType, bindingData.textureGPU, gl.TEXTURE0 + index );

}

Expand Down Expand Up @@ -391,7 +440,20 @@ class WebGLBackend extends Backend {
else if ( object.isLineSegments ) mode = gl.LINES;
else if ( object.isLine ) mode = gl.LINE_STRIP;
else if ( object.isLineLoop ) mode = gl.LINE_LOOP;
else mode = gl.TRIANGLES;
else {

if ( material.wireframe === true ) {
sunag marked this conversation as resolved.
Show resolved Hide resolved

state.setLineWidth( material.wireframeLinewidth * this.renderer.getPixelRatio() );
mode = gl.LINES;

} else {

mode = gl.TRIANGLES;

}

}

//

Expand Down Expand Up @@ -482,6 +544,7 @@ class WebGLBackend extends Backend {

}


destroyTexture( texture ) {

this.textureUtils.destroyTexture( texture );
Expand Down Expand Up @@ -794,100 +857,107 @@ class WebGLBackend extends Backend {

copyFramebufferToTexture( texture, renderContext ) {

const { gl } = this;
this.textureUtils.copyFramebufferToTexture( texture, renderContext );

const { textureGPU } = this.get( texture );
}

const width = texture.image.width;
const height = texture.image.height;
_setFramebuffer( renderContext ) {

gl.bindFramebuffer( gl.READ_FRAMEBUFFER, null );
const { gl, state } = this;

if ( texture.isDepthTexture ) {
let fb = null;
let currentFrameBuffer = null;

const fb = gl.createFramebuffer();
if ( renderContext.textures !== null ) {

gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb );
const renderTargetContextData = this.get( renderContext.renderTarget );
const { samples } = renderContext.renderTarget;

gl.framebufferTexture2D( gl.DRAW_FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, textureGPU, 0 );
fb = renderTargetContextData.framebuffer;
let msaaFb = renderTargetContextData.msaaFrameBuffer;
let depthRenderbuffer = renderTargetContextData.depthRenderbuffer;

gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, gl.DEPTH_BUFFER_BIT, gl.NEAREST );

gl.deleteFramebuffer( fb );
if ( fb === undefined ) {

fb = gl.createFramebuffer();

} else {
state.bindFramebuffer( gl.FRAMEBUFFER, fb );

gl.bindTexture( gl.TEXTURE_2D, textureGPU );
gl.copyTexSubImage2D( gl.TEXTURE_2D, 0, 0, 0, 0, 0, width, height );
const textures = renderContext.textures;

gl.bindTexture( gl.TEXTURE_2D, null );
for ( let i = 0; i < textures.length; i ++ ) {

}
const texture = textures[ i ];
const textureData = this.get( texture );
textureData.renderTarget = renderContext.renderTarget;

if ( texture.generateMipmaps ) this.generateMipmaps( texture );
const attachment = gl.COLOR_ATTACHMENT0 + i;

this._setFramebuffer( renderContext );

}
gl.framebufferTexture2D( gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureData.textureGPU, 0 );

_setFramebuffer( renderContext ) {
}

const { gl } = this;
if ( renderContext.depthTexture !== null ) {

if ( renderContext.textures !== null ) {
const textureData = this.get( renderContext.depthTexture );

const renderContextData = this.get( renderContext.renderTarget );
gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, textureData.textureGPU, 0 );

let fb = renderContextData.framebuffer;
}

if ( fb === undefined ) {

fb = gl.createFramebuffer();
renderTargetContextData.framebuffer = fb;

gl.bindFramebuffer( gl.FRAMEBUFFER, fb );
state.drawBuffers( renderContext, fb );

const textures = renderContext.textures;
}

const drawBuffers = [];
if ( samples > 0 ) {

for ( let i = 0; i < textures.length; i ++ ) {
if ( msaaFb === undefined ) {

const texture = textures[ i ];
const { textureGPU } = this.get( texture );
msaaFb = gl.createFramebuffer();

const attachment = gl.COLOR_ATTACHMENT0 + i;
state.bindFramebuffer( gl.FRAMEBUFFER, msaaFb );

gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.TEXTURE_2D, textureGPU, 0 );
// TODO For loop support MRT
const msaaRenderbuffer = gl.createRenderbuffer();
gl.bindRenderbuffer( gl.RENDERBUFFER, msaaRenderbuffer );

drawBuffers.push( attachment );
const texture = renderContext.textures[ 0 ];
const textureData = this.get( texture );

}
gl.renderbufferStorageMultisample( gl.RENDERBUFFER, samples, textureData.glInternalFormat, renderContext.width, renderContext.height );
gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, msaaRenderbuffer );

gl.drawBuffers( drawBuffers );
renderTargetContextData.msaaRenderbuffer = msaaRenderbuffer;
renderTargetContextData.msaaFrameBuffer = msaaFb;

if ( renderContext.depthTexture !== null ) {
if ( depthRenderbuffer === undefined ) {

const { textureGPU } = this.get( renderContext.depthTexture );
depthRenderbuffer = gl.createRenderbuffer();
this.textureUtils.setupRenderBufferStorage( depthRenderbuffer, renderContext );

gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, textureGPU, 0 );
renderTargetContextData.depthRenderbuffer = depthRenderbuffer;

}

}

renderContextData.framebuffer = fb;
currentFrameBuffer = renderTargetContextData.msaaFrameBuffer;

} else {

gl.bindFramebuffer( gl.FRAMEBUFFER, fb );
currentFrameBuffer = fb;

}

} else {

gl.bindFramebuffer( gl.FRAMEBUFFER, null );

}

state.bindFramebuffer( gl.FRAMEBUFFER, currentFrameBuffer );

}

}
Expand Down
Loading