|
@@ -1,4 +1,4 @@
|
|
|
-import { GPUIndexFormat, GPUTextureFormat, GPUFeatureName } from './constants.js';
|
|
|
+import { GPUIndexFormat, GPUTextureFormat, GPUFeatureName, GPULoadOp } from './constants.js';
|
|
|
import WebGPUAnimation from './WebGPUAnimation.js';
|
|
|
import WebGPURenderObjects from './WebGPURenderObjects.js';
|
|
|
import WebGPUAttributes from './WebGPUAttributes.js';
|
|
@@ -14,7 +14,6 @@ import WebGPUTextures from './WebGPUTextures.js';
|
|
|
import WebGPUBackground from './WebGPUBackground.js';
|
|
|
import WebGPUNodes from './nodes/WebGPUNodes.js';
|
|
|
import WebGPUUtils from './WebGPUUtils.js';
|
|
|
-
|
|
|
import { Frustum, Matrix4, Vector3, Color, SRGBColorSpace, NoToneMapping, DepthFormat } from 'three';
|
|
|
|
|
|
console.info( 'THREE.WebGPURenderer: Modified Matrix4.makePerspective() and Matrix4.makeOrtographic() to work with WebGPU, see https://github.com/mrdoob/three.js/issues/20276.' );
|
|
@@ -140,7 +139,6 @@ class WebGPURenderer {
|
|
|
|
|
|
this._currentRenderState = null;
|
|
|
|
|
|
- this._currentRenderList = null;
|
|
|
this._opaqueSort = null;
|
|
|
this._transparentSort = null;
|
|
|
|
|
@@ -224,16 +222,12 @@ class WebGPURenderer {
|
|
|
|
|
|
const context = ( parameters.context !== undefined ) ? parameters.context : this.domElement.getContext( 'webgpu' );
|
|
|
|
|
|
- context.configure( {
|
|
|
- device,
|
|
|
- format: GPUTextureFormat.BGRA8Unorm, // this is the only valid context format right now (r121)
|
|
|
- alphaMode: 'premultiplied'
|
|
|
- } );
|
|
|
-
|
|
|
this._adapter = adapter;
|
|
|
this._device = device;
|
|
|
this._context = context;
|
|
|
|
|
|
+ this._configureContext();
|
|
|
+
|
|
|
this._info = new WebGPUInfo();
|
|
|
this._properties = new WebGPUProperties();
|
|
|
this._attributes = new WebGPUAttributes( device );
|
|
@@ -265,13 +259,24 @@ class WebGPURenderer {
|
|
|
|
|
|
if ( this._initialized === false ) await this.init();
|
|
|
|
|
|
- //
|
|
|
+ // preserve render tree
|
|
|
|
|
|
const nodeFrame = this._nodes.nodeFrame;
|
|
|
|
|
|
const previousRenderId = nodeFrame.renderId;
|
|
|
+ const previousRenderState = this._currentRenderState;
|
|
|
+
|
|
|
+ //
|
|
|
+
|
|
|
+ const renderState = this._renderStates.get( scene, camera );
|
|
|
+ const renderTarget = this._renderTarget;
|
|
|
+
|
|
|
+ this._currentRenderState = renderState;
|
|
|
+
|
|
|
nodeFrame.renderId ++;
|
|
|
|
|
|
+ //
|
|
|
+
|
|
|
if ( this._animation.isAnimating === false ) nodeFrame.update();
|
|
|
|
|
|
if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();
|
|
@@ -283,25 +288,22 @@ class WebGPURenderer {
|
|
|
_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
|
|
|
_frustum.setFromProjectionMatrix( _projScreenMatrix );
|
|
|
|
|
|
- this._currentRenderList = this._renderLists.get( scene, camera );
|
|
|
- this._currentRenderList.init();
|
|
|
-
|
|
|
- this._currentRenderState = this._renderStates.get( scene, camera );
|
|
|
- this._currentRenderState.init();
|
|
|
+ const renderList = this._renderLists.get( scene, camera );
|
|
|
+ renderList.init();
|
|
|
|
|
|
- this._projectObject( scene, camera, 0 );
|
|
|
+ this._projectObject( scene, camera, 0, renderList );
|
|
|
|
|
|
- this._currentRenderList.finish();
|
|
|
+ renderList.finish();
|
|
|
|
|
|
if ( this.sortObjects === true ) {
|
|
|
|
|
|
- this._currentRenderList.sort( this._opaqueSort, this._transparentSort );
|
|
|
+ renderList.sort( this._opaqueSort, this._transparentSort );
|
|
|
|
|
|
}
|
|
|
|
|
|
// prepare render pass descriptor
|
|
|
|
|
|
- const renderPassDescriptor = {
|
|
|
+ renderState.descriptorGPU = {
|
|
|
colorAttachments: [ {
|
|
|
view: null
|
|
|
} ],
|
|
@@ -310,15 +312,8 @@ class WebGPURenderer {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- const renderAttachments = {
|
|
|
- depth: true,
|
|
|
- stencil: true
|
|
|
- };
|
|
|
-
|
|
|
- const colorAttachment = renderPassDescriptor.colorAttachments[ 0 ];
|
|
|
- const depthStencilAttachment = renderPassDescriptor.depthStencilAttachment;
|
|
|
-
|
|
|
- const renderTarget = this._renderTarget;
|
|
|
+ const colorAttachment = renderState.descriptorGPU.colorAttachments[ 0 ];
|
|
|
+ const depthStencilAttachment = renderState.descriptorGPU.depthStencilAttachment;
|
|
|
|
|
|
if ( renderTarget !== null ) {
|
|
|
|
|
@@ -331,7 +326,7 @@ class WebGPURenderer {
|
|
|
colorAttachment.view = renderTargetProperties.colorTextureGPU.createView();
|
|
|
depthStencilAttachment.view = renderTargetProperties.depthTextureGPU.createView();
|
|
|
|
|
|
- renderAttachments.stencil = renderTarget.depthTexture ? renderTarget.depthTexture.format !== DepthFormat : true;
|
|
|
+ renderState.stencil = renderTarget.depthTexture ? renderTarget.depthTexture.format !== DepthFormat : true;
|
|
|
|
|
|
} else {
|
|
|
|
|
@@ -360,13 +355,14 @@ class WebGPURenderer {
|
|
|
|
|
|
//
|
|
|
|
|
|
- this._background.update( this._currentRenderList, scene, renderPassDescriptor, renderAttachments );
|
|
|
+ this._background.update( scene, renderList, renderState );
|
|
|
|
|
|
// start render pass
|
|
|
|
|
|
const device = this._device;
|
|
|
- const cmdEncoder = device.createCommandEncoder( {} );
|
|
|
- const passEncoder = cmdEncoder.beginRenderPass( renderPassDescriptor );
|
|
|
+
|
|
|
+ renderState.encoderGPU = device.createCommandEncoder( {} );
|
|
|
+ renderState.currentPassGPU = renderState.encoderGPU.beginRenderPass( renderState.descriptorGPU );
|
|
|
|
|
|
// global rasterization settings for all renderable objects
|
|
|
|
|
@@ -377,7 +373,7 @@ class WebGPURenderer {
|
|
|
const width = Math.floor( vp.width * this._pixelRatio );
|
|
|
const height = Math.floor( vp.height * this._pixelRatio );
|
|
|
|
|
|
- passEncoder.setViewport( vp.x, vp.y, width, height, vp.minDepth, vp.maxDepth );
|
|
|
+ renderState.currentPassGPU.setViewport( vp.x, vp.y, width, height, vp.minDepth, vp.maxDepth );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -388,28 +384,29 @@ class WebGPURenderer {
|
|
|
const width = Math.floor( sc.width * this._pixelRatio );
|
|
|
const height = Math.floor( sc.height * this._pixelRatio );
|
|
|
|
|
|
- passEncoder.setScissorRect( sc.x, sc.y, width, height );
|
|
|
+ renderState.currentPassGPU.setScissorRect( sc.x, sc.y, width, height );
|
|
|
|
|
|
}
|
|
|
|
|
|
- // lights node
|
|
|
-
|
|
|
- const lightsNode = this._currentRenderState.getLightsNode();
|
|
|
-
|
|
|
// process render lists
|
|
|
|
|
|
- const opaqueObjects = this._currentRenderList.opaque;
|
|
|
- const transparentObjects = this._currentRenderList.transparent;
|
|
|
+ const opaqueObjects = renderList.opaque;
|
|
|
+ const transparentObjects = renderList.transparent;
|
|
|
+ const lightsNode = renderList.lightsNode;
|
|
|
|
|
|
- if ( opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, scene, lightsNode, passEncoder );
|
|
|
- if ( transparentObjects.length > 0 ) this._renderObjects( transparentObjects, camera, scene, lightsNode, passEncoder );
|
|
|
+ if ( opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, scene, lightsNode, renderState );
|
|
|
+ if ( transparentObjects.length > 0 ) this._renderObjects( transparentObjects, camera, scene, lightsNode, renderState );
|
|
|
|
|
|
// finish render pass
|
|
|
|
|
|
- passEncoder.end();
|
|
|
- device.queue.submit( [ cmdEncoder.finish() ] );
|
|
|
+ renderState.currentPassGPU.end();
|
|
|
+
|
|
|
+ device.queue.submit( [ renderState.encoderGPU.finish() ] );
|
|
|
+
|
|
|
+ // restore render tree
|
|
|
|
|
|
nodeFrame.renderId = previousRenderId;
|
|
|
+ this._currentRenderState = previousRenderState;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -544,6 +541,42 @@ class WebGPURenderer {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ copyFramebufferToRenderTarget( renderTarget ) {
|
|
|
+
|
|
|
+ const renderState = this._currentRenderState;
|
|
|
+ const { encoderGPU, descriptorGPU } = renderState;
|
|
|
+
|
|
|
+ const texture = renderTarget.texture;
|
|
|
+ texture.internalFormat = GPUTextureFormat.BGRA8Unorm;
|
|
|
+
|
|
|
+ this._textures.initRenderTarget( renderTarget );
|
|
|
+
|
|
|
+ const sourceGPU = this._context.getCurrentTexture();
|
|
|
+ const destinationGPU = this._textures.getTextureGPU( texture );
|
|
|
+
|
|
|
+ renderState.currentPassGPU.end();
|
|
|
+
|
|
|
+ encoderGPU.copyTextureToTexture(
|
|
|
+ {
|
|
|
+ texture: sourceGPU
|
|
|
+ },
|
|
|
+ {
|
|
|
+ texture: destinationGPU
|
|
|
+ },
|
|
|
+ [
|
|
|
+ texture.image.width,
|
|
|
+ texture.image.height
|
|
|
+ ]
|
|
|
+ );
|
|
|
+
|
|
|
+ descriptorGPU.colorAttachments[ 0 ].loadOp = GPULoadOp.Load;
|
|
|
+ if ( renderState.depth ) descriptorGPU.depthStencilAttachment.depthLoadOp = GPULoadOp.Load;
|
|
|
+ if ( renderState.stencil ) descriptorGPU.depthStencilAttachment.stencilLoadOp = GPULoadOp.Load;
|
|
|
+
|
|
|
+ renderState.currentPassGPU = encoderGPU.beginRenderPass( descriptorGPU );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
getViewport( target ) {
|
|
|
|
|
|
const viewport = this._viewport;
|
|
@@ -733,10 +766,7 @@ class WebGPURenderer {
|
|
|
|
|
|
}
|
|
|
|
|
|
- _projectObject( object, camera, groupOrder ) {
|
|
|
-
|
|
|
- const currentRenderList = this._currentRenderList;
|
|
|
- const currentRenderState = this._currentRenderState;
|
|
|
+ _projectObject( object, camera, groupOrder, renderList ) {
|
|
|
|
|
|
if ( object.visible === false ) return;
|
|
|
|
|
@@ -754,13 +784,7 @@ class WebGPURenderer {
|
|
|
|
|
|
} else if ( object.isLight ) {
|
|
|
|
|
|
- currentRenderState.pushLight( object );
|
|
|
-
|
|
|
- if ( object.castShadow ) {
|
|
|
-
|
|
|
- //currentRenderState.pushShadow( object );
|
|
|
-
|
|
|
- }
|
|
|
+ renderList.pushLight( object );
|
|
|
|
|
|
} else if ( object.isSprite ) {
|
|
|
|
|
@@ -777,7 +801,7 @@ class WebGPURenderer {
|
|
|
|
|
|
if ( material.visible ) {
|
|
|
|
|
|
- currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
|
|
|
+ renderList.push( object, geometry, material, groupOrder, _vector3.z, null );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -811,7 +835,7 @@ class WebGPURenderer {
|
|
|
|
|
|
if ( groupMaterial && groupMaterial.visible ) {
|
|
|
|
|
|
- currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group );
|
|
|
+ renderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -819,7 +843,7 @@ class WebGPURenderer {
|
|
|
|
|
|
} else if ( material.visible ) {
|
|
|
|
|
|
- currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
|
|
|
+ renderList.push( object, geometry, material, groupOrder, _vector3.z, null );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -833,13 +857,13 @@ class WebGPURenderer {
|
|
|
|
|
|
for ( let i = 0, l = children.length; i < l; i ++ ) {
|
|
|
|
|
|
- this._projectObject( children[ i ], camera, groupOrder );
|
|
|
+ this._projectObject( children[ i ], camera, groupOrder, renderList );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
- _renderObjects( renderList, camera, scene, lightsNode, passEncoder ) {
|
|
|
+ _renderObjects( renderList, camera, scene, lightsNode ) {
|
|
|
|
|
|
// process renderable objects
|
|
|
|
|
@@ -866,9 +890,9 @@ class WebGPURenderer {
|
|
|
const minDepth = ( vp.minDepth === undefined ) ? 0 : vp.minDepth;
|
|
|
const maxDepth = ( vp.maxDepth === undefined ) ? 1 : vp.maxDepth;
|
|
|
|
|
|
- passEncoder.setViewport( vp.x, vp.y, vp.width, vp.height, minDepth, maxDepth );
|
|
|
+ this._currentRenderState.currentPassGPU.setViewport( vp.x, vp.y, vp.width, vp.height, minDepth, maxDepth );
|
|
|
|
|
|
- this._renderObject( object, scene, camera2, geometry, material, group, lightsNode, passEncoder );
|
|
|
+ this._renderObject( object, scene, camera2, geometry, material, group, lightsNode );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -876,7 +900,7 @@ class WebGPURenderer {
|
|
|
|
|
|
} else {
|
|
|
|
|
|
- this._renderObject( object, scene, camera, geometry, material, group, lightsNode, passEncoder );
|
|
|
+ this._renderObject( object, scene, camera, geometry, material, group, lightsNode );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -884,9 +908,7 @@ class WebGPURenderer {
|
|
|
|
|
|
}
|
|
|
|
|
|
- _renderObject( object, scene, camera, geometry, material, group, lightsNode, passEncoder ) {
|
|
|
-
|
|
|
- const info = this._info;
|
|
|
+ _renderObject( object, scene, camera, geometry, material, group, lightsNode ) {
|
|
|
|
|
|
material = scene.overrideMaterial !== null ? scene.overrideMaterial : material;
|
|
|
|
|
@@ -904,6 +926,11 @@ class WebGPURenderer {
|
|
|
|
|
|
//
|
|
|
|
|
|
+ const passEncoder = this._currentRenderState.currentPassGPU;
|
|
|
+ const info = this._info;
|
|
|
+
|
|
|
+ //
|
|
|
+
|
|
|
object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
|
|
|
object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
|
|
|
|
|
@@ -1055,7 +1082,7 @@ class WebGPURenderer {
|
|
|
},
|
|
|
sampleCount: this._parameters.sampleCount,
|
|
|
format: GPUTextureFormat.BGRA8Unorm,
|
|
|
- usage: GPUTextureUsage.RENDER_ATTACHMENT
|
|
|
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC
|
|
|
} );
|
|
|
|
|
|
}
|
|
@@ -1079,7 +1106,7 @@ class WebGPURenderer {
|
|
|
},
|
|
|
sampleCount: this._parameters.sampleCount,
|
|
|
format: GPUTextureFormat.Depth24PlusStencil8,
|
|
|
- usage: GPUTextureUsage.RENDER_ATTACHMENT
|
|
|
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC
|
|
|
} );
|
|
|
|
|
|
}
|
|
@@ -1095,7 +1122,7 @@ class WebGPURenderer {
|
|
|
this._context.configure( {
|
|
|
device: device,
|
|
|
format: GPUTextureFormat.BGRA8Unorm,
|
|
|
- usage: GPUTextureUsage.RENDER_ATTACHMENT,
|
|
|
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,
|
|
|
alphaMode: 'premultiplied'
|
|
|
} );
|
|
|
|