Quellcode durchsuchen

pipeline builder

Nicolas Cannasse vor 1 Jahr
Ursprung
Commit
0da2784894
1 geänderte Dateien mit 83 neuen und 31 gelöschten Zeilen
  1. 83 31
      h3d/impl/WebGpuDriver.hx

+ 83 - 31
h3d/impl/WebGpuDriver.hx

@@ -18,7 +18,8 @@ class WebGpuShader {
 	public var vertex : WebGpuSubShader;
 	public var vertex : WebGpuSubShader;
 	public var fragment : WebGpuSubShader;
 	public var fragment : WebGpuSubShader;
 	public var layout : GPUPipelineLayout;
 	public var layout : GPUPipelineLayout;
-	public var pipeline : GPURenderPipeline;
+	public var inputCount : Int;
+	public var pipelines : PipelineCache<GPURenderPipeline> = new PipelineCache();
 	public function new() {
 	public function new() {
 	}
 	}
 }
 }
@@ -49,6 +50,8 @@ class WebGpuDriver extends h3d.impl.Driver {
 	var frames : Array<WebGpuFrame> = [];
 	var frames : Array<WebGpuFrame> = [];
 	var frame : WebGpuFrame;
 	var frame : WebGpuFrame;
 	var frameCount : Int = 0;
 	var frameCount : Int = 0;
+	var pipelineBuilder = new PipelineCache.PipelineBuilder();
+	var curStencilRef : Int;
 
 
 	public function new() {
 	public function new() {
 		inst = this;
 		inst = this;
@@ -115,6 +118,7 @@ class WebGpuDriver extends h3d.impl.Driver {
 
 
 	override function setRenderTarget(tex:Null<h3d.mat.Texture>, layer:Int = 0, mipLevel:Int = 0, depthBinding : h3d.Engine.DepthBinding = ReadWrite ) {
 	override function setRenderTarget(tex:Null<h3d.mat.Texture>, layer:Int = 0, mipLevel:Int = 0, depthBinding : h3d.Engine.DepthBinding = ReadWrite ) {
 		flushPass();
 		flushPass();
+		pipelineBuilder.setRenderTarget(tex, depthBinding != NotBound);
 		if( tex == null ) {
 		if( tex == null ) {
 			renderPassDesc = {
 			renderPassDesc = {
 				colorAttachments : [{
 				colorAttachments : [{
@@ -135,6 +139,10 @@ class WebGpuDriver extends h3d.impl.Driver {
 		throw "TODO";
 		throw "TODO";
 	}
 	}
 
 
+	override function setRenderTargets(textures:Array<h3d.mat.Texture>, depthBinding:h3d.Engine.DepthBinding = ReadWrite) {
+		pipelineBuilder.setRenderTargets(textures, depthBinding != NotBound);
+	}
+
 	function beginFrame() {
 	function beginFrame() {
 		if( device == null ) return;
 		if( device == null ) return;
 		frame = frames[(frameCount++)%frames.length];
 		frame = frames[(frameCount++)%frames.length];
@@ -159,6 +167,7 @@ class WebGpuDriver extends h3d.impl.Driver {
 			depth.depthClearValue = js.Lib.undefined;
 			depth.depthClearValue = js.Lib.undefined;
 			depth.stencilClearValue = js.Lib.undefined;
 			depth.stencilClearValue = js.Lib.undefined;
 		}
 		}
+		curStencilRef = -1;
 		needClear = false;
 		needClear = false;
 	}
 	}
 
 
@@ -331,35 +340,19 @@ class WebGpuDriver extends h3d.impl.Driver {
 		sh.vertex = compile(shader.vertex,VERTEX);
 		sh.vertex = compile(shader.vertex,VERTEX);
 		sh.fragment = compile(shader.fragment,FRAGMENT);
 		sh.fragment = compile(shader.fragment,FRAGMENT);
 		sh.layout = device.createPipelineLayout({ bindGroupLayouts: sh.vertex.groups.concat(sh.fragment.groups) });
 		sh.layout = device.createPipelineLayout({ bindGroupLayouts: sh.vertex.groups.concat(sh.fragment.groups) });
-
-		var pipeline = device.createRenderPipeline({
-			layout : sh.layout,
-			vertex : { module : sh.vertex.module, entryPoint : "main", buffers : [
-				{
-					attributes: [{ shaderLocation : 0, offset : 0, format : Float32x3 }],
-					arrayStride: 4 * 6,
-					stepMode: GPUVertexStepMode.Vertex
-				},
-				{
-					attributes: [{ shaderLocation : 1, offset : 3*4, format : Float32x3 }],
-					arrayStride: 4 * 6, // sizeof(float) * 3
-					stepMode: GPUVertexStepMode.Vertex
-				}
-			]},
-			fragment : { module : sh.fragment.module, entryPoint : "main", targets : [{ format : Bgra8unorm }] },
-			primitive : { frontFace : CW, cullMode : None, topology : Triangle_list },
-			depthStencil : {
-				depthWriteEnabled: true,
-				depthCompare: Less,
-				format: Depth24plus_stencil8
-			}
-		});
-
-		sh.pipeline = pipeline;
-
+		sh.inputCount = format.length;
 		return sh;
 		return sh;
 	}
 	}
 
 
+	override function selectMaterial( pass : h3d.mat.Pass ) {
+		pipelineBuilder.selectMaterial(pass);
+		var st = pass.stencil;
+		if( st != null && curStencilRef != st.reference ) {
+			curStencilRef = st.reference;
+			renderPass.setStencilReference(st.reference);
+		}
+	}
+
 	override function selectShader( shader : hxsl.RuntimeShader ) {
 	override function selectShader( shader : hxsl.RuntimeShader ) {
 		var sh = shadersCache.get(shader.id);
 		var sh = shadersCache.get(shader.id);
 		if( sh == null ) {
 		if( sh == null ) {
@@ -370,13 +363,16 @@ class WebGpuDriver extends h3d.impl.Driver {
 			return false;
 			return false;
 		currentShader = sh;
 		currentShader = sh;
 		beginPass();
 		beginPass();
-		renderPass.setPipeline(sh.pipeline);
+		pipelineBuilder.setShader(shader);
 		return true;
 		return true;
 	}
 	}
 
 
-	override function selectBuffer(b:Buffer) {
-		for( i in 0...@:privateAccess currentShader.format.inputs.length )
-			renderPass.setVertexBuffer(i, b.vbuf);
+	override function selectBuffer(buffer:Buffer) {
+		var map = buffer.format.resolveMapping(currentShader.format);
+		for( i in 0...currentShader.inputCount ) {
+			renderPass.setVertexBuffer(i, buffer.vbuf);
+			pipelineBuilder.setBuffer(i, map[i], buffer.format.strideBytes);
+		}
 	}
 	}
 
 
 	override function uploadShaderBuffers(buffers:h3d.shader.Buffers, which:h3d.shader.Buffers.BufferKind) {
 	override function uploadShaderBuffers(buffers:h3d.shader.Buffers, which:h3d.shader.Buffers.BufferKind) {
@@ -423,11 +419,67 @@ class WebGpuDriver extends h3d.impl.Driver {
 		}
 		}
 	}
 	}
 
 
+	function flushPipeline() {
+		if( !pipelineBuilder.needFlush ) return;
+		var cache = pipelineBuilder.lookup(currentShader.pipelines, currentShader.inputCount);
+		if( cache.pipeline == null )
+			cache.pipeline = makePipeline(currentShader);
+		renderPass.setPipeline(cache.pipeline);
+	}
+
+	function makePipeline( sh : WebGpuShader ) {
+		var buffers : Array<GPUVertexBufferLayout> = [];
+		var targets = [{ format : Bgra8unorm }];
+		var pass = pipelineBuilder.getCurrentPass();
+		for( i in 0...sh.inputCount ) {
+			var inf = pipelineBuilder.getBufferInput(i);
+			var type = @:privateAccess currentShader.format.inputs[i].type;
+			if( inf.precision != F32 ) throw "TODO";
+			buffers.push({
+				attributes: [{ shaderLocation : i, offset : inf.offset, format :
+					switch( type ) {
+					case DFloat: Float32;
+					case DVec2: Float32x2;
+					case DVec3: Float32x3;
+					case DVec4: Float32x4;
+					case DBytes4: Uint8x4;
+					}
+				}],
+				arrayStride : pipelineBuilder.getBufferStride(i),
+				stepMode: GPUVertexStepMode.Vertex,
+			});
+		}
+		var pipeline = device.createRenderPipeline({
+			layout : sh.layout,
+			vertex : { module : sh.vertex.module, entryPoint : "main", buffers : buffers },
+			fragment : { module : sh.fragment.module, entryPoint : "main", targets : targets },
+			primitive : { frontFace : CW, cullMode : switch( pass.culling ) { case None, Both: None; case Back: Back; case Front: Front; }, topology : Triangle_list },
+			depthStencil : {
+				depthWriteEnabled: pass.depthWrite,
+				depthCompare: COMPARE[pass.depthTest.getIndex()],
+				format: Depth24plus_stencil8
+			}
+		});
+		return pipeline;
+	}
+
 	override function draw(ibuf:IndexBuffer, startIndex:Int, ntriangles:Int) {
 	override function draw(ibuf:IndexBuffer, startIndex:Int, ntriangles:Int) {
+		flushPipeline();
 		renderPass.setIndexBuffer(ibuf.buf, ibuf.stride==2?Uint16:Uint32, startIndex*ibuf.stride);
 		renderPass.setIndexBuffer(ibuf.buf, ibuf.stride==2?Uint16:Uint32, startIndex*ibuf.stride);
 		renderPass.drawIndexed(ntriangles*3);
 		renderPass.drawIndexed(ntriangles*3);
 	}
 	}
 
 
+	static var COMPARE : Array<GPUCompareFunction> = [
+		Always,
+		Never,
+		Equal,
+		Not_equal,
+		Greater,
+		Greater_equal,
+		Less,
+		Less_equal,
+	];
+
 	static var inst : WebGpuDriver;
 	static var inst : WebGpuDriver;
 	static function checkReady() {
 	static function checkReady() {
 		return true;
 		return true;