123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- import WebGPURenderPipeline from './WebGPURenderPipeline.js';
- import WebGPUProgrammableStage from './WebGPUProgrammableStage.js';
- class WebGPURenderPipelines {
- constructor( renderer, properties, device, sampleCount, nodes ) {
- this.renderer = renderer;
- this.properties = properties;
- this.device = device;
- this.sampleCount = sampleCount;
- this.nodes = nodes;
- this.pipelines = [];
- this.objectCache = new WeakMap();
- this.stages = {
- vertex: new Map(),
- fragment: new Map()
- };
- }
- get( object ) {
- const device = this.device;
- const properties = this.properties;
- const material = object.material;
- const materialProperties = properties.get( material );
- const cache = this._getCache( object );
- let currentPipeline;
- if ( this._needsUpdate( object, cache ) ) {
- // get shader
- const nodeBuilder = this.nodes.get( object );
- // programmable stages
- let stageVertex = this.stages.vertex.get( nodeBuilder.vertexShader );
- if ( stageVertex === undefined ) {
- stageVertex = new WebGPUProgrammableStage( device, nodeBuilder.vertexShader, 'vertex' );
- this.stages.vertex.set( nodeBuilder.vertexShader, stageVertex );
- }
- let stageFragment = this.stages.fragment.get( nodeBuilder.fragmentShader );
- if ( stageFragment === undefined ) {
- stageFragment = new WebGPUProgrammableStage( device, nodeBuilder.fragmentShader, 'fragment' );
- this.stages.fragment.set( nodeBuilder.fragmentShader, stageFragment );
- }
- // determine render pipeline
- currentPipeline = this._acquirePipeline( stageVertex, stageFragment, object, nodeBuilder );
- cache.currentPipeline = currentPipeline;
- // keep track of all pipelines which are used by a material
- let materialPipelines = materialProperties.pipelines;
- if ( materialPipelines === undefined ) {
- materialPipelines = new Set();
- materialProperties.pipelines = materialPipelines;
- }
- if ( materialPipelines.has( currentPipeline ) === false ) {
- materialPipelines.add( currentPipeline );
- currentPipeline.usedTimes ++;
- stageVertex.usedTimes ++;
- stageFragment.usedTimes ++;
- }
- // dispose
- if ( materialProperties.disposeCallback === undefined ) {
- const disposeCallback = onMaterialDispose.bind( this );
- materialProperties.disposeCallback = disposeCallback;
- material.addEventListener( 'dispose', disposeCallback );
- }
- } else {
- currentPipeline = cache.currentPipeline;
- }
- return currentPipeline;
- }
- dispose() {
- this.pipelines = [];
- this.objectCache = new WeakMap();
- this.shaderModules = {
- vertex: new Map(),
- fragment: new Map()
- };
- }
- _acquirePipeline( stageVertex, stageFragment, object, nodeBuilder ) {
- let pipeline;
- const pipelines = this.pipelines;
- // check for existing pipeline
- const cacheKey = this._computeCacheKey( stageVertex, stageFragment, object );
- for ( let i = 0, il = pipelines.length; i < il; i ++ ) {
- const preexistingPipeline = pipelines[ i ];
- if ( preexistingPipeline.cacheKey === cacheKey ) {
- pipeline = preexistingPipeline;
- break;
- }
- }
- if ( pipeline === undefined ) {
- pipeline = new WebGPURenderPipeline( this.device, this.renderer, this.sampleCount );
- pipeline.init( cacheKey, stageVertex, stageFragment, object, nodeBuilder );
- pipelines.push( pipeline );
- }
- return pipeline;
- }
- _computeCacheKey( stageVertex, stageFragment, object ) {
- const material = object.material;
- const renderer = this.renderer;
- const parameters = [
- stageVertex.id, stageFragment.id,
- material.transparent, material.blending, material.premultipliedAlpha,
- material.blendSrc, material.blendDst, material.blendEquation,
- material.blendSrcAlpha, material.blendDstAlpha, material.blendEquationAlpha,
- material.colorWrite,
- material.depthWrite, material.depthTest, material.depthFunc,
- material.stencilWrite, material.stencilFunc,
- material.stencilFail, material.stencilZFail, material.stencilZPass,
- material.stencilFuncMask, material.stencilWriteMask,
- material.side,
- this.sampleCount,
- renderer.getCurrentEncoding(), renderer.getCurrentColorFormat(), renderer.getCurrentDepthStencilFormat()
- ];
- return parameters.join();
- }
- _getCache( object ) {
- let cache = this.objectCache.get( object );
- if ( cache === undefined ) {
- cache = {};
- this.objectCache.set( object, cache );
- }
- return cache;
- }
- _releasePipeline( pipeline ) {
- if ( -- pipeline.usedTimes === 0 ) {
- const pipelines = this.pipelines;
- const i = pipelines.indexOf( pipeline );
- pipelines[ i ] = pipelines[ pipelines.length - 1 ];
- pipelines.pop();
- this._releaseStage( pipeline.stageVertex );
- this._releaseStage( pipeline.stageFragment );
- }
- }
- _releaseStage( stage ) {
- if ( -- stage.usedTimes === 0 ) {
- const code = stage.code;
- const type = stage.type;
- this.stages[ type ].delete( code );
- }
- }
- _needsUpdate( object, cache ) {
- const material = object.material;
- let needsUpdate = false;
- // check material state
- if ( cache.material !== material || cache.materialVersion !== material.version ||
- cache.transparent !== material.transparent || cache.blending !== material.blending || cache.premultipliedAlpha !== material.premultipliedAlpha ||
- cache.blendSrc !== material.blendSrc || cache.blendDst !== material.blendDst || cache.blendEquation !== material.blendEquation ||
- cache.blendSrcAlpha !== material.blendSrcAlpha || cache.blendDstAlpha !== material.blendDstAlpha || cache.blendEquationAlpha !== material.blendEquationAlpha ||
- cache.colorWrite !== material.colorWrite ||
- cache.depthWrite !== material.depthWrite || cache.depthTest !== material.depthTest || cache.depthFunc !== material.depthFunc ||
- cache.stencilWrite !== material.stencilWrite || cache.stencilFunc !== material.stencilFunc ||
- cache.stencilFail !== material.stencilFail || cache.stencilZFail !== material.stencilZFail || cache.stencilZPass !== material.stencilZPass ||
- cache.stencilFuncMask !== material.stencilFuncMask || cache.stencilWriteMask !== material.stencilWriteMask ||
- cache.side !== material.side
- ) {
- cache.material = material; cache.materialVersion = material.version;
- cache.transparent = material.transparent; cache.blending = material.blending; cache.premultipliedAlpha = material.premultipliedAlpha;
- cache.blendSrc = material.blendSrc; cache.blendDst = material.blendDst; cache.blendEquation = material.blendEquation;
- cache.blendSrcAlpha = material.blendSrcAlpha; cache.blendDstAlpha = material.blendDstAlpha; cache.blendEquationAlpha = material.blendEquationAlpha;
- cache.colorWrite = material.colorWrite;
- cache.depthWrite = material.depthWrite; cache.depthTest = material.depthTest; cache.depthFunc = material.depthFunc;
- cache.stencilWrite = material.stencilWrite; cache.stencilFunc = material.stencilFunc;
- cache.stencilFail = material.stencilFail; cache.stencilZFail = material.stencilZFail; cache.stencilZPass = material.stencilZPass;
- cache.stencilFuncMask = material.stencilFuncMask; cache.stencilWriteMask = material.stencilWriteMask;
- cache.side = material.side;
- needsUpdate = true;
- }
- // check renderer state
- const renderer = this.renderer;
- const encoding = renderer.getCurrentEncoding();
- const colorFormat = renderer.getCurrentColorFormat();
- const depthStencilFormat = renderer.getCurrentDepthStencilFormat();
- if ( cache.sampleCount !== this.sampleCount || cache.encoding !== encoding ||
- cache.colorFormat !== colorFormat || cache.depthStencilFormat !== depthStencilFormat ) {
- cache.sampleCount = this.sampleCount;
- cache.encoding = encoding;
- cache.colorFormat = colorFormat;
- cache.depthStencilFormat = depthStencilFormat;
- needsUpdate = true;
- }
- return needsUpdate;
- }
- }
- function onMaterialDispose( event ) {
- const properties = this.properties;
- const material = event.target;
- const materialProperties = properties.get( material );
- material.removeEventListener( 'dispose', materialProperties.disposeCallback );
- properties.remove( material );
- // remove references to pipelines
- const pipelines = materialProperties.pipelines;
- if ( pipelines !== undefined ) {
- for ( const pipeline of pipelines ) {
- this._releasePipeline( pipeline );
- }
- }
- }
- export default WebGPURenderPipelines;
|