|
@@ -1,6 +1,5 @@
|
|
import WebGPURenderPipeline from './WebGPURenderPipeline.js';
|
|
import WebGPURenderPipeline from './WebGPURenderPipeline.js';
|
|
-
|
|
|
|
-let _id = 0;
|
|
|
|
|
|
+import WebGPUProgrammableStage from './WebGPUProgrammableStage.js';
|
|
|
|
|
|
class WebGPURenderPipelines {
|
|
class WebGPURenderPipelines {
|
|
|
|
|
|
@@ -16,7 +15,7 @@ class WebGPURenderPipelines {
|
|
this.pipelines = [];
|
|
this.pipelines = [];
|
|
this.objectCache = new WeakMap();
|
|
this.objectCache = new WeakMap();
|
|
|
|
|
|
- this.shaderModules = {
|
|
|
|
|
|
+ this.stages = {
|
|
vertex: new Map(),
|
|
vertex: new Map(),
|
|
fragment: new Map()
|
|
fragment: new Map()
|
|
};
|
|
};
|
|
@@ -26,6 +25,7 @@ class WebGPURenderPipelines {
|
|
get( object ) {
|
|
get( object ) {
|
|
|
|
|
|
const device = this.device;
|
|
const device = this.device;
|
|
|
|
+ const glslang = this.glslang;
|
|
const properties = this.properties;
|
|
const properties = this.properties;
|
|
|
|
|
|
const material = object.material;
|
|
const material = object.material;
|
|
@@ -41,45 +41,32 @@ class WebGPURenderPipelines {
|
|
|
|
|
|
const nodeBuilder = this.nodes.get( object );
|
|
const nodeBuilder = this.nodes.get( object );
|
|
|
|
|
|
- // shader modules
|
|
|
|
-
|
|
|
|
- const glslang = this.glslang;
|
|
|
|
-
|
|
|
|
- let moduleVertex = this.shaderModules.vertex.get( nodeBuilder.vertexShader );
|
|
|
|
-
|
|
|
|
- if ( moduleVertex === undefined ) {
|
|
|
|
|
|
+ // programmable stages
|
|
|
|
|
|
- const byteCodeVertex = glslang.compileGLSL( nodeBuilder.vertexShader, 'vertex' );
|
|
|
|
|
|
+ let stageVertex = this.stages.vertex.get( nodeBuilder.vertexShader );
|
|
|
|
|
|
- moduleVertex = {
|
|
|
|
- module: device.createShaderModule( { code: byteCodeVertex } ),
|
|
|
|
- entryPoint: 'main',
|
|
|
|
- id: _id ++
|
|
|
|
- };
|
|
|
|
|
|
+ if ( stageVertex === undefined ) {
|
|
|
|
|
|
- this.shaderModules.vertex.set( nodeBuilder.vertexShader, moduleVertex );
|
|
|
|
|
|
+ stageVertex = new WebGPUProgrammableStage( device, glslang, nodeBuilder.vertexShader, 'vertex' );
|
|
|
|
+ this.stages.vertex.set( nodeBuilder.vertexShader, stageVertex );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- let moduleFragment = this.shaderModules.fragment.get( nodeBuilder.fragmentShader );
|
|
|
|
|
|
+ let stageFragment = this.stages.fragment.get( nodeBuilder.fragmentShader );
|
|
|
|
|
|
- if ( moduleFragment === undefined ) {
|
|
|
|
|
|
+ if ( stageFragment === undefined ) {
|
|
|
|
|
|
- const byteCodeFragment = glslang.compileGLSL( nodeBuilder.fragmentShader, 'fragment' );
|
|
|
|
-
|
|
|
|
- moduleFragment = {
|
|
|
|
- module: device.createShaderModule( { code: byteCodeFragment } ),
|
|
|
|
- entryPoint: 'main',
|
|
|
|
- id: _id ++
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- this.shaderModules.fragment.set( nodeBuilder.fragmentShader, moduleFragment );
|
|
|
|
|
|
+ stageFragment = new WebGPUProgrammableStage( device, glslang, nodeBuilder.fragmentShader, 'fragment' );
|
|
|
|
+ this.stages.fragment.set( nodeBuilder.fragmentShader, stageFragment );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ stageVertex.usedTimes ++;
|
|
|
|
+ stageFragment.usedTimes ++;
|
|
|
|
+
|
|
// determine render pipeline
|
|
// determine render pipeline
|
|
|
|
|
|
- currentPipeline = this._acquirePipeline( moduleVertex, moduleFragment, object, nodeBuilder );
|
|
|
|
|
|
+ currentPipeline = this._acquirePipeline( stageVertex, stageFragment, object, nodeBuilder );
|
|
objectProperties.currentPipeline = currentPipeline;
|
|
objectProperties.currentPipeline = currentPipeline;
|
|
|
|
|
|
// keep track of all pipelines which are used by a material
|
|
// keep track of all pipelines which are used by a material
|
|
@@ -128,14 +115,14 @@ class WebGPURenderPipelines {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- _acquirePipeline( moduleVertex, moduleFragment, object, nodeBuilder ) {
|
|
|
|
|
|
+ _acquirePipeline( stageVertex, stageFragment, object, nodeBuilder ) {
|
|
|
|
|
|
let pipeline;
|
|
let pipeline;
|
|
const pipelines = this.pipelines;
|
|
const pipelines = this.pipelines;
|
|
|
|
|
|
// check for existing pipeline
|
|
// check for existing pipeline
|
|
|
|
|
|
- const cacheKey = this._computeCacheKey( moduleVertex, moduleFragment, object );
|
|
|
|
|
|
+ const cacheKey = this._computeCacheKey( stageVertex, stageFragment, object );
|
|
|
|
|
|
for ( let i = 0, il = pipelines.length; i < il; i ++ ) {
|
|
for ( let i = 0, il = pipelines.length; i < il; i ++ ) {
|
|
|
|
|
|
@@ -152,8 +139,9 @@ class WebGPURenderPipelines {
|
|
|
|
|
|
if ( pipeline === undefined ) {
|
|
if ( pipeline === undefined ) {
|
|
|
|
|
|
- pipeline = new WebGPURenderPipeline( cacheKey, this.device, this.renderer, this.sampleCount );
|
|
|
|
- pipeline.init( moduleVertex, moduleFragment, object, nodeBuilder );
|
|
|
|
|
|
+ pipeline = new WebGPURenderPipeline( this.device, this.renderer, this.sampleCount );
|
|
|
|
+ pipeline.init( cacheKey, stageVertex, stageFragment, object, nodeBuilder );
|
|
|
|
+
|
|
pipelines.push( pipeline );
|
|
pipelines.push( pipeline );
|
|
|
|
|
|
}
|
|
}
|
|
@@ -162,13 +150,13 @@ class WebGPURenderPipelines {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- _computeCacheKey( moduleVertex, moduleFragment, object ) {
|
|
|
|
|
|
+ _computeCacheKey( stageVertex, stageFragment, object ) {
|
|
|
|
|
|
const material = object.material;
|
|
const material = object.material;
|
|
const renderer = this.renderer;
|
|
const renderer = this.renderer;
|
|
|
|
|
|
const parameters = [
|
|
const parameters = [
|
|
- moduleVertex.id, moduleFragment.id,
|
|
|
|
|
|
+ stageVertex.id, stageFragment.id,
|
|
material.transparent, material.blending, material.premultipliedAlpha,
|
|
material.transparent, material.blending, material.premultipliedAlpha,
|
|
material.blendSrc, material.blendDst, material.blendEquation,
|
|
material.blendSrc, material.blendDst, material.blendEquation,
|
|
material.blendSrcAlpha, material.blendDstAlpha, material.blendEquationAlpha,
|
|
material.blendSrcAlpha, material.blendDstAlpha, material.blendEquationAlpha,
|
|
@@ -196,6 +184,22 @@ class WebGPURenderPipelines {
|
|
pipelines[ i ] = pipelines[ pipelines.length - 1 ];
|
|
pipelines[ i ] = pipelines[ pipelines.length - 1 ];
|
|
pipelines.pop();
|
|
pipelines.pop();
|
|
|
|
|
|
|
|
+ this._relaseStage( pipeline.stageVertex );
|
|
|
|
+ this._relaseStage( pipeline.stageFragment );
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ _relaseStage( stage ) {
|
|
|
|
+
|
|
|
|
+ if ( -- stage.usedTimes === 0 ) {
|
|
|
|
+
|
|
|
|
+ const code = stage.code;
|
|
|
|
+ const type = stage.type;
|
|
|
|
+
|
|
|
|
+ this.stages[ type ].delete( code );
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
@@ -283,20 +287,18 @@ function onMaterialDispose( event ) {
|
|
|
|
|
|
// remove references to pipelines
|
|
// remove references to pipelines
|
|
|
|
|
|
- const pipelines = properties.get( material ).pipelines;
|
|
|
|
|
|
+ const pipelines = materialProperties.pipelines;
|
|
|
|
|
|
if ( pipelines !== undefined ) {
|
|
if ( pipelines !== undefined ) {
|
|
|
|
|
|
- pipelines.forEach( function ( pipeline ) {
|
|
|
|
|
|
+ for ( const pipeline of pipelines ) {
|
|
|
|
|
|
this._releasePipeline( pipeline );
|
|
this._releasePipeline( pipeline );
|
|
|
|
|
|
- } );
|
|
|
|
|
|
+ }
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- // @TODO: still need remove nodes and bindings
|
|
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
|
|
export default WebGPURenderPipelines;
|
|
export default WebGPURenderPipelines;
|