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: RenderBundle #28347

Merged
merged 39 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
b5e90f1
wip
RenaudRohlinger May 2, 2024
9581a48
add demo
RenaudRohlinger May 2, 2024
601829e
add gpu metrics
RenaudRohlinger May 2, 2024
f0a0f7d
Merge remote-tracking branch 'upstream/dev' into utsubo/feat/render-b…
RenaudRohlinger May 6, 2024
4d45eeb
fix bundeType condition
RenaudRohlinger May 6, 2024
f980c88
cleanup
RenaudRohlinger May 6, 2024
a108cc2
refactor and cleanup
RenaudRohlinger May 6, 2024
cbd2952
support postprocess and multisample
RenaudRohlinger May 6, 2024
6e7c6be
update
RenaudRohlinger May 6, 2024
da2c578
cache and pbr on bundle example
RenaudRohlinger May 6, 2024
8416940
wip static mode
RenaudRohlinger May 12, 2024
4117374
update
RenaudRohlinger May 12, 2024
e35068c
update
RenaudRohlinger May 12, 2024
36450f6
Merge branch 'dev' into utsubo/feat/render-bundles
RenaudRohlinger May 12, 2024
78554d0
revert shared
RenaudRohlinger May 12, 2024
03974d6
ci
RenaudRohlinger May 12, 2024
3c0547b
circular dep
RenaudRohlinger May 12, 2024
ad881a6
move the logic to the renderContext
RenaudRohlinger May 12, 2024
e114f30
add screenshot for ci
RenaudRohlinger May 12, 2024
453c9d9
cleanup
RenaudRohlinger May 13, 2024
0aa652c
Merge remote-tracking branch 'upstream/dev' into utsubo/feat/render-b…
RenaudRohlinger May 13, 2024
a58f07b
merge with dev
RenaudRohlinger May 19, 2024
5d7e2e3
merge with upstream
RenaudRohlinger May 19, 2024
0837566
new RenderBundle API
RenaudRohlinger May 19, 2024
fa28f29
TODO: Need to handle FBO too
RenaudRohlinger May 19, 2024
84ed55d
cleanup
RenaudRohlinger May 19, 2024
cc65c9c
more cleanup
RenaudRohlinger May 19, 2024
9b53b73
fix deepscan
RenaudRohlinger May 19, 2024
9d26c2b
fix framebuffer
RenaudRohlinger May 20, 2024
978fb04
update example
RenaudRohlinger May 20, 2024
ab55f96
update scene too
RenaudRohlinger May 20, 2024
61b6697
reuse correct scene for update matrices
RenaudRohlinger May 20, 2024
b832ce7
merge with upstream
RenaudRohlinger May 23, 2024
b65317d
introduce renderBundle.needsUpdate and rename to private _renderBundle()
RenaudRohlinger May 23, 2024
e19de5f
cleanup
RenaudRohlinger May 23, 2024
8a193ef
improve example
RenaudRohlinger May 23, 2024
74aca82
fix capsule constructor
RenaudRohlinger May 23, 2024
1a46e3d
remove confusing gui in example
RenaudRohlinger May 23, 2024
777d2ee
Adding RenderBundles and Group.static
sunag May 23, 2024
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 @@ -386,7 +386,8 @@
"webgpu_instancing_morph",
"webgpu_texturegrad",
"webgpu_volume_cloud",
"webgpu_volume_perlin"
"webgpu_volume_perlin",
"webgpu_renderbundle"
],
"webaudio": [
"webaudio_orientation",
Expand Down
18 changes: 18 additions & 0 deletions examples/jsm/renderers/common/RenderBundle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class RenderBundle {

constructor( scene, camera ) {

this.scene = scene;
this.camera = camera;

}

clone() {

return Object.assign( new this.constructor(), this );

}

}

export default RenderBundle;
38 changes: 38 additions & 0 deletions examples/jsm/renderers/common/RenderBundles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import ChainMap from './ChainMap.js';
import RenderBundle from './RenderBundle.js';

class RenderBundles {

constructor() {

this.lists = new ChainMap();

}

get( scene, camera ) {

const lists = this.lists;
const keys = [ scene, camera ];

let list = lists.get( keys );

if ( list === undefined ) {

list = new RenderBundle( scene, camera );
lists.set( keys, list );

}

return list;

}

dispose() {

this.lists = new ChainMap();

}

}

export default RenderBundles;
9 changes: 9 additions & 0 deletions examples/jsm/renderers/common/RenderList.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class RenderList {

this.opaque = [];
this.transparent = [];
this.bundles = [];

this.lightsNode = new LightsNode( [] );
this.lightsArray = [];
Expand All @@ -71,6 +72,8 @@ class RenderList {

this.opaque.length = 0;
this.transparent.length = 0;
this.bundles.length = 0;

this.lightsArray.length = 0;

this.occlusionQueryCount = 0;
Expand Down Expand Up @@ -135,6 +138,12 @@ class RenderList {

}

pushBundle( group ) {

this.bundles.push( group );

}

pushLight( light ) {

this.lightsArray.push( light );
Expand Down
128 changes: 127 additions & 1 deletion examples/jsm/renderers/common/Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import ClippingContext from './ClippingContext.js';
import { Scene, Frustum, Matrix4, Vector2, Vector3, Vector4, DoubleSide, BackSide, FrontSide, SRGBColorSpace, NoColorSpace, NoToneMapping, LinearFilter, LinearSRGBColorSpace, RenderTarget, HalfFloatType, RGBAFormat } from 'three';
import { NodeMaterial } from '../../nodes/Nodes.js';
import QuadMesh from '../../objects/QuadMesh.js';
import RenderBundles from './RenderBundles.js';

const _scene = new Scene();
const _drawingBufferSize = new Vector2();
Expand Down Expand Up @@ -87,6 +88,7 @@ class Renderer {
this._bindings = null;
this._objects = null;
this._pipelines = null;
this._bundles = null;
this._renderLists = null;
this._renderContexts = null;
this._textures = null;
Expand All @@ -111,6 +113,7 @@ class Renderer {

this._renderObjectFunction = null;
this._currentRenderObjectFunction = null;
this._currentRenderBundle = null;

this._handleObjectFunction = this._renderObjectDirect;

Expand Down Expand Up @@ -171,6 +174,7 @@ class Renderer {
this._bindings = new Bindings( backend, this._nodes, this._textures, this._attributes, this._pipelines, this.info );
this._objects = new RenderObjects( this, this._nodes, this._geometries, this._pipelines, this._bindings, this.info );
this._renderLists = new RenderLists();
this._bundles = new RenderBundles();
this._renderContexts = new RenderContexts();

//
Expand Down Expand Up @@ -326,6 +330,81 @@ class Renderer {

}

_renderBundle( bundle, sceneRef, lightsNode ) {

const { object, camera, renderList } = bundle;

const renderContext = this._currentRenderContext;
const renderContextData = this.backend.get( renderContext );

//

const renderBundle = this._bundles.get( object, camera );

const renderBundleData = this.backend.get( renderBundle );
if ( renderBundleData.renderContexts === undefined ) renderBundleData.renderContexts = new Set();

//

const renderBundleNeedsUpdate = renderBundleData.renderContexts.has( renderContext ) === false || object.needsUpdate === true;

renderBundleData.renderContexts.add( renderContext );

if ( renderBundleNeedsUpdate ) {

if ( renderContextData.renderObjects === undefined || object.needsUpdate === true ) {

const nodeFrame = this._nodes.nodeFrame;

renderContextData.renderObjects = [];
renderContextData.renderBundles = [];
renderContextData.scene = sceneRef;
renderContextData.camera = camera;
renderContextData.renderId = nodeFrame.renderId;

renderContextData.registerBundlesPhase = true;

}

this._currentRenderBundle = renderBundle;

const opaqueObjects = renderList.opaque;

if ( opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, sceneRef, lightsNode );

this._currentRenderBundle = null;

//

object.needsUpdate = false;

} else {

const renderContext = this._currentRenderContext;
const renderContextData = this.backend.get( renderContext );

for ( let i = 0, l = renderContextData.renderObjects.length; i < l; i ++ ) {

const renderObject = renderContextData.renderObjects[ i ];

this._nodes.updateBefore( renderObject );

//

renderObject.object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, renderObject.object.matrixWorld );
renderObject.object.normalMatrix.getNormalMatrix( renderObject.object.modelViewMatrix );

this._nodes.updateForRender( renderObject );
this._bindings.updateForRender( renderObject );

this.backend.draw( renderObject, this.info );

}

}

}

render( scene, camera ) {

if ( this._initialized === false ) {
Expand Down Expand Up @@ -456,7 +535,6 @@ class Renderer {

if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();


//

let viewport = this._viewport;
Expand Down Expand Up @@ -564,8 +642,10 @@ class Renderer {

const opaqueObjects = renderList.opaque;
const transparentObjects = renderList.transparent;
const bundles = renderList.bundles;
const lightsNode = renderList.lightsNode;

if ( bundles.length > 0 ) this._renderBundles( bundles, sceneRef, lightsNode );
if ( opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, sceneRef, lightsNode );
if ( transparentObjects.length > 0 ) this._renderObjects( transparentObjects, camera, sceneRef, lightsNode );

Expand Down Expand Up @@ -1194,6 +1274,25 @@ class Renderer {

}

if ( object.static === true ) {

const baseRenderList = renderList;

// replace render list
renderList = this._renderLists.get( object, camera );

renderList.begin();

baseRenderList.pushBundle( {
object,
camera,
renderList,
} );

renderList.finish();

}

const children = object.children;

for ( let i = 0, l = children.length; i < l; i ++ ) {
Expand All @@ -1204,6 +1303,16 @@ class Renderer {

}

_renderBundles( bundles, sceneRef, lightsNode ) {

for ( const bundle of bundles ) {

this._renderBundle( bundle, sceneRef, lightsNode );

}

}

_renderObjects( renderList, camera, scene, lightsNode ) {

// process renderable objects
Expand Down Expand Up @@ -1397,8 +1506,25 @@ class Renderer {

//

if ( this._currentRenderBundle !== null && this._currentRenderBundle.needsUpdate === true ) {

const renderObjectData = this.backend.get( renderObject );

renderObjectData.bundleEncoder = undefined;
renderObjectData.lastPipelineGPU = undefined;

}

this.backend.draw( renderObject, this.info );

if ( this._currentRenderBundle !== null ) {

const renderContextData = this.backend.get( this._currentRenderContext );

renderContextData.renderObjects.push( renderObject );

}

}

_createObjectPipeline( object, material, scene, camera, lightsNode, passId ) {
Expand Down
40 changes: 38 additions & 2 deletions examples/jsm/renderers/webgpu/WebGPUBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,13 @@ class WebGPUBackend extends Backend {
const renderContextData = this.get( renderContext );
const occlusionQueryCount = renderContext.occlusionQueryCount;

if ( renderContextData.renderBundles !== undefined && renderContextData.renderBundles.length > 0 ) {

renderContextData.registerBundlesPhase = false;
renderContextData.currentPass.executeBundles( renderContextData.renderBundles );

}

if ( occlusionQueryCount > renderContextData.occlusionQueryIndex ) {

renderContextData.currentPass.endOcclusionQuery();
Expand Down Expand Up @@ -791,9 +798,22 @@ class WebGPUBackend extends Backend {
const pipelineGPU = this.get( pipeline ).pipeline;
const currentSets = contextData.currentSets;

// pipeline
const renderObjectData = this.get( renderObject );

const { bundleEncoder, renderBundle, lastPipelineGPU } = renderObjectData;

const renderContextData = this.get( context );

if ( renderContextData.registerBundlesPhase === true && bundleEncoder !== undefined && lastPipelineGPU === pipelineGPU ) {

renderContextData.renderBundles.push( renderBundle );
return;

}

const passEncoderGPU = contextData.currentPass;
const passEncoderGPU = this.renderer._currentRenderBundle ? this.createBundleEncoder( context, renderObject ) : contextData.currentPass;

// pipeline

if ( currentSets.pipeline !== pipelineGPU ) {

Expand Down Expand Up @@ -905,6 +925,16 @@ class WebGPUBackend extends Backend {

}


if ( this.renderer._currentRenderBundle ) {

const renderBundle = passEncoderGPU.finish();
renderObjectData.lastPipelineGPU = pipelineGPU;
renderObjectData.renderBundle = renderBundle;
renderObjectData.bundleEncoder = passEncoderGPU;

}

}

// cache key
Expand Down Expand Up @@ -1160,6 +1190,12 @@ class WebGPUBackend extends Backend {

}

createBundleEncoder( renderContext, renderObject ) {

return this.pipelineUtils.createBundleEncoder( renderContext, renderObject );

}

// bindings

createBindings( bindings ) {
Expand Down
Loading