first commit
This commit is contained in:
		
							
								
								
									
										322
									
								
								public/sdk/three/jsm/renderers/common/Pipelines.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								public/sdk/three/jsm/renderers/common/Pipelines.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,322 @@ | ||||
| import DataMap from './DataMap.js'; | ||||
| import RenderPipeline from './RenderPipeline.js'; | ||||
| import ComputePipeline from './ComputePipeline.js'; | ||||
| import ProgrammableStage from './ProgrammableStage.js'; | ||||
|  | ||||
| class Pipelines extends DataMap { | ||||
|  | ||||
| 	constructor( backend, nodes ) { | ||||
|  | ||||
| 		super(); | ||||
|  | ||||
| 		this.backend = backend; | ||||
| 		this.nodes = nodes; | ||||
|  | ||||
| 		this.bindings = null; // set by the bindings | ||||
|  | ||||
| 		this.caches = new Map(); | ||||
| 		this.programs = { | ||||
| 			vertex: new Map(), | ||||
| 			fragment: new Map(), | ||||
| 			compute: new Map() | ||||
| 		}; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	getForCompute( computeNode, bindings ) { | ||||
|  | ||||
| 		const { backend } = this; | ||||
|  | ||||
| 		const data = this.get( computeNode ); | ||||
|  | ||||
| 		if ( this._needsComputeUpdate( computeNode ) ) { | ||||
|  | ||||
| 			const previousPipeline = data.pipeline; | ||||
|  | ||||
| 			if ( previousPipeline ) { | ||||
|  | ||||
| 				previousPipeline.usedTimes --; | ||||
| 				previousPipeline.computeProgram.usedTimes --; | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 			// get shader | ||||
|  | ||||
| 			const nodeBuilderState = this.nodes.getForCompute( computeNode ); | ||||
|  | ||||
| 			// programmable stage | ||||
|  | ||||
| 			let stageCompute = this.programs.compute.get( nodeBuilderState.computeShader ); | ||||
|  | ||||
| 			if ( stageCompute === undefined ) { | ||||
|  | ||||
| 				if ( previousPipeline && previousPipeline.computeProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.computeProgram ); | ||||
|  | ||||
| 				stageCompute = new ProgrammableStage( nodeBuilderState.computeShader, 'compute', nodeBuilderState.transforms, nodeBuilderState.nodeAttributes ); | ||||
| 				this.programs.compute.set( nodeBuilderState.computeShader, stageCompute ); | ||||
|  | ||||
| 				backend.createProgram( stageCompute ); | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 			// determine compute pipeline | ||||
|  | ||||
| 			const cacheKey = this._getComputeCacheKey( computeNode, stageCompute ); | ||||
|  | ||||
| 			let pipeline = this.caches.get( cacheKey ); | ||||
|  | ||||
| 			if ( pipeline === undefined ) { | ||||
|  | ||||
| 				if ( previousPipeline && previousPipeline.usedTimes === 0 ) this._releasePipeline( computeNode ); | ||||
|  | ||||
| 				pipeline = this._getComputePipeline( computeNode, stageCompute, cacheKey, bindings ); | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 			// keep track of all used times | ||||
|  | ||||
| 			pipeline.usedTimes ++; | ||||
| 			stageCompute.usedTimes ++; | ||||
|  | ||||
| 			// | ||||
|  | ||||
| 			data.version = computeNode.version; | ||||
| 			data.pipeline = pipeline; | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		return data.pipeline; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	getForRender( renderObject, promises = null ) { | ||||
|  | ||||
| 		const { backend } = this; | ||||
|  | ||||
| 		const data = this.get( renderObject ); | ||||
|  | ||||
| 		if ( this._needsRenderUpdate( renderObject ) ) { | ||||
|  | ||||
| 			const previousPipeline = data.pipeline; | ||||
|  | ||||
| 			if ( previousPipeline ) { | ||||
|  | ||||
| 				previousPipeline.usedTimes --; | ||||
| 				previousPipeline.vertexProgram.usedTimes --; | ||||
| 				previousPipeline.fragmentProgram.usedTimes --; | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 			// get shader | ||||
|  | ||||
| 			const nodeBuilderState = renderObject.getNodeBuilderState(); | ||||
|  | ||||
| 			// programmable stages | ||||
|  | ||||
| 			let stageVertex = this.programs.vertex.get( nodeBuilderState.vertexShader ); | ||||
|  | ||||
| 			if ( stageVertex === undefined ) { | ||||
|  | ||||
| 				if ( previousPipeline && previousPipeline.vertexProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.vertexProgram ); | ||||
|  | ||||
| 				stageVertex = new ProgrammableStage( nodeBuilderState.vertexShader, 'vertex' ); | ||||
| 				this.programs.vertex.set( nodeBuilderState.vertexShader, stageVertex ); | ||||
|  | ||||
| 				backend.createProgram( stageVertex ); | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 			let stageFragment = this.programs.fragment.get( nodeBuilderState.fragmentShader ); | ||||
|  | ||||
| 			if ( stageFragment === undefined ) { | ||||
|  | ||||
| 				if ( previousPipeline && previousPipeline.fragmentProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.fragmentProgram ); | ||||
|  | ||||
| 				stageFragment = new ProgrammableStage( nodeBuilderState.fragmentShader, 'fragment' ); | ||||
| 				this.programs.fragment.set( nodeBuilderState.fragmentShader, stageFragment ); | ||||
|  | ||||
| 				backend.createProgram( stageFragment ); | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 			// determine render pipeline | ||||
|  | ||||
| 			const cacheKey = this._getRenderCacheKey( renderObject, stageVertex, stageFragment ); | ||||
|  | ||||
| 			let pipeline = this.caches.get( cacheKey ); | ||||
|  | ||||
| 			if ( pipeline === undefined ) { | ||||
|  | ||||
| 				if ( previousPipeline && previousPipeline.usedTimes === 0 ) this._releasePipeline( previousPipeline ); | ||||
|  | ||||
| 				pipeline = this._getRenderPipeline( renderObject, stageVertex, stageFragment, cacheKey, promises ); | ||||
|  | ||||
| 			} else { | ||||
|  | ||||
| 				renderObject.pipeline = pipeline; | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 			// keep track of all used times | ||||
|  | ||||
| 			pipeline.usedTimes ++; | ||||
| 			stageVertex.usedTimes ++; | ||||
| 			stageFragment.usedTimes ++; | ||||
|  | ||||
| 			// | ||||
|  | ||||
| 			data.pipeline = pipeline; | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		return data.pipeline; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	delete( object ) { | ||||
|  | ||||
| 		const pipeline = this.get( object ).pipeline; | ||||
|  | ||||
| 		if ( pipeline ) { | ||||
|  | ||||
| 			// pipeline | ||||
|  | ||||
| 			pipeline.usedTimes --; | ||||
|  | ||||
| 			if ( pipeline.usedTimes === 0 ) this._releasePipeline( pipeline ); | ||||
|  | ||||
| 			// programs | ||||
|  | ||||
| 			if ( pipeline.isComputePipeline ) { | ||||
|  | ||||
| 				pipeline.computeProgram.usedTimes --; | ||||
|  | ||||
| 				if ( pipeline.computeProgram.usedTimes === 0 ) this._releaseProgram( pipeline.computeProgram ); | ||||
|  | ||||
| 			} else { | ||||
|  | ||||
| 				pipeline.fragmentProgram.usedTimes --; | ||||
| 				pipeline.vertexProgram.usedTimes --; | ||||
|  | ||||
| 				if ( pipeline.vertexProgram.usedTimes === 0 ) this._releaseProgram( pipeline.vertexProgram ); | ||||
| 				if ( pipeline.fragmentProgram.usedTimes === 0 ) this._releaseProgram( pipeline.fragmentProgram ); | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		super.delete( object ); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	dispose() { | ||||
|  | ||||
| 		super.dispose(); | ||||
|  | ||||
| 		this.caches = new Map(); | ||||
| 		this.programs = { | ||||
| 			vertex: new Map(), | ||||
| 			fragment: new Map(), | ||||
| 			compute: new Map() | ||||
| 		}; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	updateForRender( renderObject ) { | ||||
|  | ||||
| 		this.getForRender( renderObject ); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	_getComputePipeline( computeNode, stageCompute, cacheKey, bindings ) { | ||||
|  | ||||
| 		// check for existing pipeline | ||||
|  | ||||
| 		cacheKey = cacheKey || this._getComputeCacheKey( computeNode, stageCompute ); | ||||
|  | ||||
| 		let pipeline = this.caches.get( cacheKey ); | ||||
|  | ||||
| 		if ( pipeline === undefined ) { | ||||
|  | ||||
| 			pipeline = new ComputePipeline( cacheKey, stageCompute ); | ||||
|  | ||||
| 			this.caches.set( cacheKey, pipeline ); | ||||
|  | ||||
| 			this.backend.createComputePipeline( pipeline, bindings ); | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		return pipeline; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	_getRenderPipeline( renderObject, stageVertex, stageFragment, cacheKey, promises ) { | ||||
|  | ||||
| 		// check for existing pipeline | ||||
|  | ||||
| 		cacheKey = cacheKey || this._getRenderCacheKey( renderObject, stageVertex, stageFragment ); | ||||
|  | ||||
| 		let pipeline = this.caches.get( cacheKey ); | ||||
|  | ||||
| 		if ( pipeline === undefined ) { | ||||
|  | ||||
| 			pipeline = new RenderPipeline( cacheKey, stageVertex, stageFragment ); | ||||
|  | ||||
| 			this.caches.set( cacheKey, pipeline ); | ||||
|  | ||||
| 			renderObject.pipeline = pipeline; | ||||
|  | ||||
| 			this.backend.createRenderPipeline( renderObject, promises ); | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		return pipeline; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	_getComputeCacheKey( computeNode, stageCompute ) { | ||||
|  | ||||
| 		return computeNode.id + ',' + stageCompute.id; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	_getRenderCacheKey( renderObject, stageVertex, stageFragment ) { | ||||
|  | ||||
| 		return stageVertex.id + ',' + stageFragment.id + ',' + this.backend.getRenderCacheKey( renderObject ); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	_releasePipeline( pipeline ) { | ||||
|  | ||||
| 		this.caches.delete( pipeline.cacheKey ); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	_releaseProgram( program ) { | ||||
|  | ||||
| 		const code = program.code; | ||||
| 		const stage = program.stage; | ||||
|  | ||||
| 		this.programs[ stage ].delete( code ); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	_needsComputeUpdate( computeNode ) { | ||||
|  | ||||
| 		const data = this.get( computeNode ); | ||||
|  | ||||
| 		return data.pipeline === undefined || data.version !== computeNode.version; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	_needsRenderUpdate( renderObject ) { | ||||
|  | ||||
| 		const data = this.get( renderObject ); | ||||
|  | ||||
| 		return data.pipeline === undefined || this.backend.needsRenderUpdate( renderObject ); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| export default Pipelines; | ||||
		Reference in New Issue
	
	Block a user