Ver Fonte

more webgpu support

Nicolas Cannasse há 11 meses atrás
pai
commit
9da28119f1
4 ficheiros alterados com 129 adições e 44 exclusões
  1. 1 1
      h3d/impl/Driver.hx
  2. 4 0
      h3d/impl/PipelineCache.hx
  3. 88 28
      h3d/impl/WebGpuDriver.hx
  4. 36 15
      hxsl/WgslOut.hx

+ 1 - 1
h3d/impl/Driver.hx

@@ -8,7 +8,7 @@ typedef Query = {};
 #elseif (js && webgpu)
 typedef IndexBuffer = { buf : WebGpuApi.GPU_Buffer, stride : Int };
 typedef GPUBuffer = WebGpuApi.GPU_Buffer;
-typedef Texture = { tex : WebGpuApi.GPUTexture, view : WebGpuApi.GPUTextureView };
+typedef Texture = { tex : WebGpuApi.GPUTexture, view : WebGpuApi.GPUTextureView, ?views : Array<WebGpuApi.GPUTextureView> };
 typedef DepthBuffer = {};
 typedef Query = {};
 #elseif js

+ 4 - 0
h3d/impl/PipelineCache.hx

@@ -115,6 +115,10 @@ class PipelineBuilder {
 		needFlush = true;
 	}
 
+	public function getDepthEnabled() {
+		return signature.getI32(PSIGN_RENDER_TARGETS) & 0x80000000 != 0;
+	}
+
 	public function setDepth( depth : h3d.mat.Texture ) {
 		signature.setI32(PSIGN_RENDER_TARGETS, 0x80000000);
 		needFlush = true;

+ 88 - 28
h3d/impl/WebGpuDriver.hx

@@ -58,6 +58,7 @@ class WebGpuDriver extends h3d.impl.Driver {
 	var frameCount : Int = 0;
 	var pipelineBuilder = new PipelineCache.PipelineBuilder();
 	var curStencilRef : Int;
+	var currentRenderTargets : Array<h3d.mat.Texture>;
 
 	public function new() {
 		inst = this;
@@ -122,10 +123,20 @@ class WebGpuDriver extends h3d.impl.Driver {
 		beginFrame();
 	}
 
+	function createTexView( t : h3d.mat.Texture, layer, mip ) {
+		var index = layer + mip * t.layerCount;
+		if( t.t.views == null ) t.t.views = [];
+		if( t.t.views[index] == null ) t.t.views[index] = t.t.tex.createView({ baseMipLevel : mip, mipLevelCount : 1, baseArrayLayer : layer, arrayLayerCount : 1 });
+		return t.t.views[index];
+	}
+
 	override function setRenderTarget(tex:Null<h3d.mat.Texture>, layer:Int = 0, mipLevel:Int = 0, depthBinding : h3d.Engine.DepthBinding = ReadWrite ) {
 		flushPass();
+		if( tex != null && tex.depthBuffer == null )
+			depthBinding = NotBound;
 		pipelineBuilder.setRenderTarget(tex, depthBinding != NotBound);
 		if( tex == null ) {
+			currentRenderTargets = null;
 			renderPassDesc = {
 				colorAttachments : [{
 					view : frame.colorView,
@@ -142,11 +153,46 @@ class WebGpuDriver extends h3d.impl.Driver {
 			};
 			return;
 		}
-		throw "TODO";
+		currentRenderTargets = [tex];
+		renderPassDesc = {
+			colorAttachments : [{
+				view : layer == 0 && mipLevel == 0 ? tex.t.view : createTexView(tex,layer,mipLevel),
+				loadOp : Load,
+				storeOp: Store
+			}],
+		};
+		if( tex.depthBuffer != null && depthBinding != NotBound )
+			renderPassDesc.depthStencilAttachment = {
+				view : tex.depthBuffer.t.view,
+				depthLoadOp: Load,
+				depthStoreOp: Store,
+				stencilLoadOp: Load,
+				stencilStoreOp: Store,
+			};
 	}
 
 	override function setRenderTargets(textures:Array<h3d.mat.Texture>, depthBinding:h3d.Engine.DepthBinding = ReadWrite) {
+		flushPass();
+		var tex = textures[0];
+		if( tex != null && tex.depthBuffer == null )
+			depthBinding = NotBound;
 		pipelineBuilder.setRenderTargets(textures, depthBinding != NotBound);
+		currentRenderTargets = textures.copy();
+		renderPassDesc = {
+			colorAttachments : [for( t in textures ) {
+				view : t.t.view,
+				loadOp : Load,
+				storeOp: Store
+			}],
+		};
+		if( tex.depthBuffer != null && depthBinding != NotBound )
+			renderPassDesc.depthStencilAttachment = {
+				view : tex.depthBuffer.t.view,
+				depthLoadOp: Load,
+				depthStoreOp: Store,
+				stencilLoadOp: Load,
+				stencilStoreOp: Store,
+			};
 	}
 
 	function beginFrame() {
@@ -178,6 +224,7 @@ class WebGpuDriver extends h3d.impl.Driver {
 	}
 
 	function flushPass() {
+		var isClear = needClear;
 		if( needClear ) {
 			if( renderPass != null ) throw "assert";
 			beginPass();
@@ -240,17 +287,25 @@ class WebGpuDriver extends h3d.impl.Driver {
 		return _allocBuffer(VERTEX,b.vertices,b.format.strideBytes);
 	}
 
+	function getTexFormat( t : h3d.mat.Texture ) : GPUTextureFormat {
+		return switch( t.format ) {
+		case RGBA: Rgba8unorm;
+		default: throw "Unsupported texture format "+t.format;
+		}
+	}
+
 	override function allocTexture(t:h3d.mat.Texture):Texture {
+		var flags : GPUTextureUsageFlags = TEXTURE_BINDING | COPY_DST;
+		if( t.flags.has(Target) )
+			flags |= RENDER_ATTACHMENT;
 		var tex = device.createTexture({
-			size : { width : t.width, height : t.height },
+			size : { width : t.width, height : t.height, depthOrArrayLayers : t.layerCount },
 			mipLevelCount : t.mipLevels,
-			format : switch( t.format ) {
-			case RGBA: Rgba8unorm;
-			default: throw "Unsupported texture format "+t.format;
-			},
-			usage : TEXTURE_BINDING | COPY_DST,
+			format : getTexFormat(t),
+			dimension : D2,
+			usage : flags,
 		});
-		return { tex : tex, view : tex.createView() };
+		return { tex : tex, view : tex.createView({ dimension: t.flags.has(Cube) ? Cube : (t.layerCount > 1 ? D2_array : D2) }) };
 	}
 
 	override function allocIndexes(count:Int, is32:Bool):IndexBuffer {
@@ -289,22 +344,6 @@ class WebGpuDriver extends h3d.impl.Driver {
 	}
 
 	function uploadBuffer(buf:GPU_Buffer,stride:Int,start:Int,count:Int,data:Dynamic,bufPos:Int) {
-		/*
-		var size = ((count * stride) + 3) & ~3;
-		var tmpBuf = device.createBuffer({
-			size : size,
-			usage : (MAP_WRITE:GPUBufferUsageFlags) | COPY_SRC,
-			mappedAtCreation : true,
-		});
-		new js.lib.Uint8Array(tmpBuf.getMappedRange()).set(data, bufPos);
-		tmpBuf.unmap();
-		// copy
-		if( commandUpload == null )
-			commandUpload = device.createCommandEncoder();
-		commandUpload.copyBufferToBuffer(tmpBuf,0,buf,start*stride,size);
-		// delete later
-		frame.toDelete.push(tmpBuf);
-		*/
 		var map = buf.getMappedRange();
 		if( data is js.lib.Uint16Array )
 			new js.lib.Uint16Array(map).set(data,bufPos);
@@ -385,7 +424,12 @@ class WebGpuDriver extends h3d.impl.Driver {
 					visibility : kind,
 					texture: {
 						sampleType : Float,
-						viewDimension : D2,
+						viewDimension : switch( t ) {
+						case TSampler2D: D2;
+						case TSamplerCube: Cube;
+						case TSampler2DArray: D2_array;
+						default: throw "Unsupported texture type "+t;
+						},
 					}
 				}
 			]);
@@ -441,6 +485,7 @@ class WebGpuDriver extends h3d.impl.Driver {
 			curStencilRef = st.reference;
 			renderPass.setStencilReference(st.reference);
 		}
+		beginPass();
 	}
 
 	override function selectShader( shader : hxsl.RuntimeShader ) {
@@ -562,7 +607,7 @@ class WebGpuDriver extends h3d.impl.Driver {
 	function makePipeline( sh : WebGpuShader ) {
 		var buffers : Array<GPUVertexBufferLayout> = [];
 		var pass = pipelineBuilder.getCurrentPass();
-		var targets = [{
+		var targets = currentRenderTargets == null ? [{
 			format : Bgra8unorm,
 			writeMask : pass.colorMask,
 			blend : {
@@ -577,6 +622,21 @@ class WebGpuDriver extends h3d.impl.Driver {
 					dstFactor : BLEND[pass.blendAlphaDst.getIndex()],
 				},
 			},
+		}] : [for( t in currentRenderTargets ) {
+			format : getTexFormat(t),
+			writeMask : pass.colorMask,
+			blend : {
+				color : {
+					operation : OP[pass.blendOp.getIndex()],
+					srcFactor : BLEND[pass.blendSrc.getIndex()],
+					dstFactor : BLEND[pass.blendDst.getIndex()],
+				},
+				alpha : {
+					operation : OP[pass.blendAlphaOp.getIndex()],
+					srcFactor : BLEND[pass.blendAlphaSrc.getIndex()],
+					dstFactor : BLEND[pass.blendAlphaDst.getIndex()],
+				},
+			},
 		}];
 		for( i in 0...sh.inputCount ) {
 			var inf = pipelineBuilder.getBufferInput(i);
@@ -601,11 +661,11 @@ class WebGpuDriver extends h3d.impl.Driver {
 			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 : {
+			depthStencil : currentRenderTargets == null || pipelineBuilder.getDepthEnabled() ? {
 				depthWriteEnabled: pass.depthWrite,
 				depthCompare: COMPARE[pass.depthTest.getIndex()],
 				format: Depth24plus_stencil8
-			}
+			} : js.Lib.undefined,
 		});
 		return pipeline;
 	}

+ 36 - 15
hxsl/WgslOut.hx

@@ -8,8 +8,14 @@ class WgslOut {
 	static var GLOBALS = {
 		var m = new Map();
 		for( g in hxsl.Ast.TGlobal.createAll() ) {
-			var n = "" + g;
-			n = n.charAt(0).toLowerCase() + n.substr(1);
+			var n = switch( g ) {
+			case Mat4: "mat4x4";
+			case Mat3: "mat3x3";
+			case Mat2: "mat2x2";
+			default:
+				var n = "" + g;
+				n = n.charAt(0).toLowerCase() + n.substr(1);
+			}
 			m.set(g, n);
 		}
 		for( g in m )
@@ -136,10 +142,10 @@ class WgslOut {
 			var name = "val" + (exprIds++);
 			var tmp = buf;
 			buf = new StringBuf();
-			addType(e.t);
-			add(" ");
+			add("fn ");
 			add(name);
-			add("(void)");
+			add("() -> ");
+			addType(e.t);
 			var el2 = el.copy();
 			var last = el2[el2.length - 1];
 			el2[el2.length - 1] = { e : TReturn(last), t : e.t, p : last.p };
@@ -246,8 +252,13 @@ class WgslOut {
 				addValue(e,tabs);
 			}
 			add("}");
+		case TBinop(OpMult,e1 = { t : TVec(3,_) },e2 = { t : TMat3x4 }):
+			add("vec4(");
+			addValue(e1,tabs);
+			add(",1) * ");
+			addValue(e2,tabs);
 		case TBinop(op = OpAssign|OpAssignOp(_), { e : TSwiz(e,regs) }, e2) if( regs.length > 1 ):
-			// WSGL does not support swizzle writing outside of a single component (wth) 
+			// WSGL does not support swizzle writing outside of a single component (wth)
 			addValue(e, tabs);
 			add(" = ");
 			var size = switch(e.t) {
@@ -310,9 +321,15 @@ class WgslOut {
 				add("/*var*/");
 			}
 		case TCall({ e : TGlobal(g) },args):
+			var name = GLOBALS.get(g);
 			switch( [g,args] ) {
 			case [Texture,[t,uv]]:
-				add("textureSample(");
+				if( t.t == TSampler2DArray ) {
+					decl("fn textureSampleArr( t : texture_2d_array<f32>, s : sampler, uv : vec3<f32> ) -> vec4<f32> { return textureSample(t,s,uv.xy,i32(round(uv.z))); } ");
+					add("textureSampleArr");
+				} else
+					add("textureSample");
+				add("(");
 				addExpr(t, tabs);
 				add(",");
 				addExpr(t, tabs);
@@ -320,16 +337,20 @@ class WgslOut {
 				add(",");
 				addExpr(uv, tabs);
 				add(")");
+				return;
+			case [Mat3, [m = { t : TMat4 }]]:
+				decl("fn mat4to3( m : mat4x4<f32> ) -> mat3x3<f32> { return mat3x3(m[0].xyz,m[1].xyz,m[2].xyz); }");
+				name = "mat4to3";
 			default:
-				add(GLOBALS.get(g));
-				add("(");
-				var first = true;
-				for( e in args ) {
-					if( first ) first = false else add(", ");
-					addValue(e, tabs);
-				}
-				add(")");
 			}
+			add(name);
+			add("(");
+			var first = true;
+			for( e in args ) {
+				if( first ) first = false else add(", ");
+				addValue(e, tabs);
+			}
+			add(")");
 		case TCall(e, args):
 			addValue(e, tabs);
 			add("(");