Pārlūkot izejas kodu

finalise gl compute textures implementation

Nicolas Cannasse 1 gadu atpakaļ
vecāks
revīzija
b188ada1a8
5 mainītis faili ar 193 papildinājumiem un 100 dzēšanām
  1. 26 2
      h3d/impl/GlDriver.hx
  2. 36 16
      hxsl/Ast.hx
  3. 91 46
      hxsl/Checker.hx
  4. 9 1
      hxsl/Dce.hx
  5. 31 35
      hxsl/GlslOut.hx

+ 26 - 2
h3d/impl/GlDriver.hx

@@ -627,9 +627,33 @@ class GlDriver extends Driver {
 
 				if( pt.u == null ) continue;
 
-				if( pt.t.match(TRWTexture(_)) ) {
-					gl.bindImageTexture(i, cast t.t.t, 0, false, 0, GL.READ_WRITE, GL.RGBA8);
+				switch( pt.t ) {
+				case TRWTexture(dim,arr,chans):
+					var tdim : hxsl.Ast.TexDimension = t.flags.has(Cube) ? TCube : T2D;
+					var fmt;
+					if( (arr != t.flags.has(IsArray)) || dim != tdim )
+						fmt = 0;
+					else {
+						// we suppose it's possible to map from one pixel format to shader declared 32f
+						fmt = switch( [chans,t.format] ) {
+						case [1, R8]: GL.R8;
+						case [2, RG8]: GL.RG8;
+						case [4, RGBA]: GL.RGBA8;
+						case [1, R16F]: GL.R16F;
+						case [2, RG16F]: GL.RG16F;
+						case [4, RGBA16F]: GL.RGBA16F;
+						case [1, R32F]: GL.R32F;
+						case [2, RG32F]: GL.RG32F;
+						case [4, RGBA32F]: GL.RGBA32F;
+						default: 0;
+						}
+					}
+					if( fmt == 0 )
+						throw "Texture format does not match: "+t+"["+t.format+"] should be "+hxsl.Ast.Tools.toString(pt.t);
+					gl.bindImageTexture(i, cast t.t.t, 0, false, 0, GL.READ_WRITE, fmt);
+					boundTextures[i] = null;
 					continue;
+				default:
 				}
 
 				var idx = s.kind == Fragment ? curShader.vertex.textures.length + i : i;

+ 36 - 16
hxsl/Ast.hx

@@ -202,15 +202,6 @@ enum FunctionKind {
 	Main;
 }
 
-enum ComputeVar {
-	GlobalInvocation;
-	LocalInvocation;
-	NumWorkGroups;
-	WorkGroup;
-	WorkGroupSize;
-	LocalInvocationIndex;
-}
-
 enum TGlobal {
 	Radians;
 	Degrees;
@@ -304,7 +295,13 @@ enum TGlobal {
 	RoundEven;
 	// compute
 	SetLayout;
-	ComputeVar;
+	ImageStore;
+	ComputeVar_GlobalInvocation;
+	ComputeVar_LocalInvocation;
+	ComputeVar_NumWorkGroups;
+	ComputeVar_WorkGroup;
+	ComputeVar_WorkGroupSize;
+	ComputeVar_LocalInvocationIndex;
 }
 
 enum Component {
@@ -339,6 +336,26 @@ class Tools {
 		#end
 	}
 
+	public static function getTexUVSize( dim : TexDimension, arr = false ) {
+		var size = switch( dim ) {
+		case T1D: 1;
+		case T2D: 2;
+		case T3D, TCube: 3;
+		}
+		if( arr ) size++;
+		return size;
+	}
+
+	public static function getDimSize( dim : TexDimension, arr = false ) {
+		var size = switch( dim ){
+		case T1D: 1;
+		case T2D, TCube: 2;
+		case T3D: 3;
+		}
+		if( arr ) size++;
+		return size;
+	}
+
 	public static function getName( v : TVar ) {
 		if( v.qualifiers == null )
 			return v.name;
@@ -437,16 +454,16 @@ class Tools {
 		case TVec(size, t):
 			var prefix = switch( t ) {
 			case VFloat: "";
-			case VInt: "I";
-			case VBool: "B";
+			case VInt: "i";
+			case VBool: "b";
 			}
-			prefix + "Vec" + size;
+			prefix + "vec" + size;
 		case TStruct(vl):"{" + [for( v in vl ) v.name + " : " + toString(v.type)].join(",") + "}";
 		case TArray(t, s): toString(t) + "[" + (switch( s ) { case SConst(i): "" + i; case SVar(v): v.name; } ) + "]";
 		case TBuffer(t, s, k):
 			var prefix = switch( k ) {
-			case Uniform: "buffer";
-			case RW: "rwbuffer";
+			case Uniform: "Buffer";
+			case RW: "RWBuffer";
 			};
 			prefix+" "+toString(t) + "[" + (switch( s ) { case SConst(i): "" + i; case SVar(v): v.name; } ) + "]";
 		case TBytes(n): "Bytes" + n;
@@ -494,8 +511,11 @@ class Tools {
 		case TCall({ e : TGlobal(SetLayout) },_):
 			return true;
 		case TCall(e, pl):
-			if( !e.e.match(TGlobal(_)) )
+			switch( e.e ) {
+			case TGlobal(g) if( g != ImageStore ):
+			default:
 				return true;
+			}
 			for( p in pl )
 				if( hasSideEffect(p) )
 					return true;

+ 91 - 46
hxsl/Checker.hx

@@ -25,7 +25,6 @@ class Checker {
 	static var ivec2 = TVec(2, VInt);
 	static var ivec3 = TVec(3, VInt);
 	static var ivec4 = TVec(4, VInt);
-	static var anyRWT = TRWTexture(T1D,false,-1);
 
 	var vars : Map<String,TVar>;
 	var globals : Map<String,{ g : TGlobal, t : Type }>;
@@ -56,9 +55,9 @@ class Checker {
 			{ dim : TCube, arr : false, uv : vec3, iuv : ivec3 },
 			{ dim : T1D, arr : true, uv : vec2, iuv : ivec2 },
 			{ dim : T2D, arr : true, uv : vec3, iuv : ivec3 },
-			{ dim : T3D, arr : false, uv : vec4, iuv : ivec4 },
-			{ dim : TCube, arr : false, uv : vec4, iuv : ivec4 },
+			{ dim : TCube, arr : true, uv : vec4, iuv : ivec4 },
 		];
+		var gvars = new Map();
 		for( g in Ast.TGlobal.createAll() ) {
 			var def = switch( g ) {
 			case Vec2, Vec3, Vec4, Mat2, Mat3, Mat3x4, Mat4, IVec2, IVec3, IVec4, BVec2, BVec3, BVec4: [];
@@ -84,10 +83,7 @@ class Checker {
 			case Texel:
 				[for( t in texDefs ) { args : [{ name : "tex", type : TSampler(t.dim,t.arr) }, { name : "pos", type : t.iuv }], ret : vec4 }];
 			case TextureSize:
-				var arr = [for( t in texDefs ) { args : [{ name : "tex", type : TSampler(t.dim,t.arr) }], ret : vec2 }].concat(
-				[for( t in texDefs ) { args : [{ name : "tex", type : TSampler(t.dim,t.arr) },{ name : "lod", type : TInt }], ret : vec2 }]);
-				arr.push({ args : [{name : "tex", type : TRWTexture(T2D,false,-1)}], ret : vec2 });
-				arr;
+				[];
 			case ToInt:
 				[for( t in baseType ) { args : [ { name : "value", type : t } ], ret : TInt } ];
 			case ToFloat:
@@ -184,10 +180,34 @@ class Checker {
 				[for( i => t in genType ) { args : [ { name: "x", type: genIType[i] } ], ret: t }];
 			case SetLayout:
 				[{ args : [{ name : "x", type : TInt },{ name : "y", type : TInt },{ name : "z", type : TInt }], ret : TVoid }];
-			case ComputeVar:
+			case ImageStore:
 				[];
 			case VertexID, InstanceID, FragCoord, FrontFacing:
 				null;
+			case _ if( g.getName().indexOf("_") > 0 ):
+				var name = g.getName();
+				var idx = name.indexOf("_");
+				var vname = name.substr(0, idx);
+				vname = vname.charAt(0).toLowerCase() + vname.substr(1);
+				var vl = gvars.get(vname);
+				if( vl == null ) {
+					vl = [];
+					gvars.set(vname, vl);
+				}
+				var vt = switch( g ) {
+				case ComputeVar_GlobalInvocation, ComputeVar_LocalInvocation, ComputeVar_NumWorkGroups, ComputeVar_WorkGroup, ComputeVar_WorkGroupSize:
+					ivec3;
+				case ComputeVar_LocalInvocationIndex:
+					TInt;
+				default:
+					throw "Unknown type for global var "+g;
+				}
+				var fname = name.substr(idx+1);
+				fname = fname.charAt(0).toLowerCase() + fname.substr(1);
+				vl.push({ name : fname, type : vt });
+				null;
+			default:
+				throw "Unsupported global "+g;
 			}
 			if( def != null )
 				globals.set(g.toString(), { t : TFun(def), g : g } );
@@ -196,6 +216,16 @@ class Checker {
 		globals.set("instanceID", { t : TInt, g : InstanceID });
 		globals.set("fragCoord", { t : vec4, g : FragCoord });
 		globals.set("frontFacing", { t : TBool, g : FrontFacing });
+		for( gname => vl in gvars )
+			globals.set(gname, { t : TStruct([
+				for( v in vl )
+					{
+						name: v.name,
+						kind : Global,
+						type : v.type,
+						id : 0
+					}
+			]), g : null });
 		globals.set("int", globals.get("toInt"));
 		globals.set("float", globals.get("toFloat"));
 		globals.set("reflect", globals.get("lReflect"));
@@ -339,7 +369,7 @@ class Checker {
 		case [TSampler(dim1, arr1), TSampler(dim2, arr2)]:
 			return dim1 == dim2 && arr1 == arr2;
 		case [TRWTexture(dim1, arr1, chans1), TRWTexture(dim2, arr2, chans2)]:
-			return dim1 == dim2 && arr1 == arr2 && (chans1 == chans2 || chans2 == -1);
+			return dim1 == dim2 && arr1 == arr2 && chans1 == chans2;
 		default:
 		}
 		return false;
@@ -474,7 +504,7 @@ class Checker {
 				TVar(v);
 			} else {
 				var g = globals.get(name);
-				if( g != null ) {
+				if( g != null && g.g != null ) {
 					type = g.t;
 					TGlobal(g.g);
 				} else {
@@ -487,6 +517,18 @@ class Checker {
 					}
 				}
 			}
+		case EField({ expr : EIdent(name) }, f) if( vars.get(name) == null && globals.get(name) != null && globals.get(name).g == null ):
+			switch( globals.get(name).t ) {
+			case TStruct(vl):
+				for( v in vl )
+					if( v.name == f ) {
+						var g = name.charAt(0).toUpperCase()+name.substr(1)+"_"+f.charAt(0).toUpperCase()+f.substr(1);
+						return { e : TGlobal(Ast.TGlobal.createByName(g)), t : v.type, p : e.pos };
+					}
+				error(name+" field should be "+[for( v in vl ) v.name].join("|"), e.pos);
+			default:
+				throw "assert";
+			}
 		case EField(e1, f):
 			var e1 = typeExpr(e1, Value);
 			var ef = fieldAccess(e1, f, with, e.pos);
@@ -501,21 +543,6 @@ class Checker {
 			}
 		case ECall(e1, args):
 			function makeCall(e1) {
-				switch( e1.e ) {
-				case TGlobal(ComputeVar) if( args.length <= 1 ):
-					switch( args[0] ) {
-					case { expr : EIdent(name) }:
-						var v = try ComputeVar.createByName(name,[]) catch( e : Dynamic ) null;
-						if( v != null ) {
-							type = v == LocalInvocationIndex ? TInt : ivec3;
-							return TCall(e1,[{ e : TConst(CInt(v.getIndex())), t : TInt, p : e.pos }]);
-						}
-					case null:
-					default:
-					}
-					error("computeVar() argument should be "+ComputeVar.createAll().join("|"), e.pos);
-				default:
-				}
 				return switch( e1.t ) {
 				case TFun(variants):
 					var e = unifyCallParams(e1, args, variants, e.pos);
@@ -673,17 +700,8 @@ class Checker {
 			TBreak;
 		case EArray(e1, e2):
 			var e1 = typeExpr(e1, Value);
-			var indexType = switch( e1.t ) {
-			case TRWTexture(dim, arr, _):
-				var count = dim.getIndex() + 1;
-				if( count >= 3 ) count = 3;
-				if( arr ) count++;
-				count == 1 ? TInt : TVec(count,VInt);
-			default:
-				TInt;
-			}
-			var e2 = typeExpr(e2, With(indexType));
-			unify(e2.t, indexType, e2.p);
+			var e2 = typeExpr(e2, With(TInt));
+			unify(e2.t, TInt, e2.p);
 			switch( e1.t ) {
 			case TArray(t, size), TBuffer(t,size,_):
 				switch( [size, e2.e] ) {
@@ -700,14 +718,6 @@ class Checker {
 				type = vec3;
 			case TMat4, TMat3x4:
 				type = vec4;
-			case TRWTexture(_, _, chans):
-				type = switch(chans) {
-				case 2: vec2;
-				case 3: vec3;
-				case 4: vec4;
-				default:
-					TFloat;
-				}
 			default:
 				error("Cannot index " + e1.t.toString() + " : should be an array", e.pos);
 			}
@@ -778,6 +788,12 @@ class Checker {
 				var v = makeVar(v, e.pos);
 				if( isImport && v.kind == Param )
 					continue;
+
+				switch( v.type ) {
+				case TSampler(T3D, true), TRWTexture(T3D, true, _), TRWTexture(_,_,3):
+					error("Unsupported texture type", e.pos);
+				default:
+				}
 				if( einit != null )
 					inits.push({ v : v, e : einit });
 				else if( v.qualifiers != null && v.qualifiers.indexOf(Final) >= 0 )
@@ -999,6 +1015,7 @@ class Checker {
 			case ["fetch"|"fetchLod", TChannel(_)]: ChannelFetch;
 			case ["size", TSampler(_) | TRWTexture(_)]: TextureSize;
 			case ["size", TChannel(_)]: ChannelTextureSize;
+			case ["store", TRWTexture(_)]: ImageStore;
 			default: null;
 			}
 			if( gl != null ) {
@@ -1016,8 +1033,6 @@ class Checker {
 					args.shift();
 					sel.push({ args : args, ret : v.ret });
 				}
-				if( f == "get" )
-					trace(variants, sel);
 				if( sel.length > 0 || variants.length == 0 )
 					return FGlobal(g.g, e, sel);
 			default:
@@ -1058,6 +1073,16 @@ class Checker {
 		return null;
 	}
 
+	function getSizeType(size,vtype) {
+		return switch( size ) {
+		case 1: vtype == VInt ? TInt : TFloat;
+		case 2: vtype == VInt ? ivec2 : vec2;
+		case 3: vtype == VInt ? ivec3 : vec3;
+		case 4: vtype == VInt ? ivec4 : vec4;
+		default: throw "assert";
+		}
+	}
+
 	function specialGlobal( g : TGlobal, e : TExpr, args : Array<TExpr>, pos : Position ) : TExpr {
 		var type = null;
 		inline function checkLength(n,t) {
@@ -1150,6 +1175,26 @@ class Checker {
 			}
 		case Trace:
 			type = TVoid;
+		case ImageStore:
+			switch( ([for( a in args ) a.t]) ) {
+			case [TRWTexture(dim,arr,chans), uv, color]:
+				var szt = getSizeType(Tools.getDimSize(dim,arr),VInt);
+				unify(uv, szt, args[1].p);
+				unify(color, chans == 1 ? TFloat : TVec(chans,VFloat), args[2].p);
+				type = TVoid;
+			default:
+				error("Cannot apply " + g.toString() + " to these parameters", pos);
+			}
+		case TextureSize:
+			if( args.length != 1 )
+				error("TextureSize() requires one single argument", pos);
+			switch( args[0].t ) {
+			case TSampler(dim,arr), TRWTexture(dim,arr,_):
+				type = getSizeType(Tools.getDimSize(dim,arr),VFloat);
+			default:
+				unify(args[0].t, TSampler(T2D,false), args[0].p);
+				type = vec2;
+			}
 		default:
 		}
 		if( type == null )

+ 9 - 1
hxsl/Dce.hx

@@ -149,7 +149,7 @@ class Dce {
 			check(i, writeTo, isAffected);
 			check(e, writeTo, isAffected);
 			writeTo.pop();
-			if ( isAffected.indexOf(v) < 0 )
+			if( isAffected.indexOf(v) < 0 )
 				isAffected.push(v);
 		case TBlock(el):
 			var noWrite = [];
@@ -197,6 +197,14 @@ class Dce {
 			} else {
 				link(channelVars[cid], writeTo);
 			}
+		case TCall({ e : TGlobal(ImageStore)}, [{ e : TVar(v) }, uv, val]):
+			var v = get(v);
+			writeTo.push(v);
+			check(uv, writeTo, isAffected);
+			check(val, writeTo, isAffected);
+			writeTo.pop();
+			if( isAffected.indexOf(v) < 0 )
+				isAffected.push(v);
 		default:
 			e.iter(check.bind(_, writeTo, isAffected));
 		}

+ 31 - 35
hxsl/GlslOut.hx

@@ -71,6 +71,14 @@ class GlslOut {
 		set(FrontFacing, "gl_FrontFacing");
 		set(FloatBitsToUint, "_floatBitsToUint");
 		set(UintBitsToFloat, "_uintBitsToFloat");
+
+		set(ComputeVar_LocalInvocation, "ivec3(gl_LocalInvocationID)");
+		set(ComputeVar_GlobalInvocation, "ivec3(gl_GlobalInvocationID)");
+		set(ComputeVar_LocalInvocationIndex, "int(gl_LocalInvocationIndex)");
+		set(ComputeVar_NumWorkGroups, "ivec3(gl_NumWorkGroups)");
+		set(ComputeVar_WorkGroup, "ivec3(gl_WorkGroup)");
+		set(ComputeVar_WorkGroupSize, "ivec3(gl_WorkGroupSize)");
+
 		for( g in gl )
 			KWDS.set(g, true);
 		gl;
@@ -323,14 +331,15 @@ class GlslOut {
 				return "texelFetch";
 		case TextureSize:
 			switch( args[0].t ) {
-			case TSampler(_,false), TChannel(_):
+			case TChannel(_):
 				decl("vec2 _textureSize(sampler2D sampler, int lod) { return vec2(textureSize(sampler, lod)); }");
-			case TSampler(dim,true):
-				var t = getSamplerType(dim, true);
-				decl("vec3 _textureSize("+t+" sampler, int lod) { return vec3(textureSize(sampler, lod)); }");
-			case TRWTexture(_,arr,_):
-				var size = arr ? "vec3" : "vec2";
-				return size+"(imageSize";
+			case TSampler(dim,arr):
+				var size = Tools.getDimSize(dim,arr);
+				var t = "sampler"+dim.getName().substr(1)+(arr?"Array":"");
+				decl('vec$size _textureSize($t sampler, int lod) { return vec$size(textureSize(sampler, lod)); }');
+			case TRWTexture(dim,arr,_):
+				var size = Tools.getDimSize(dim,arr);
+				return "vec"+size+"(imageSize";
 			default:
 			}
 			return "_textureSize";
@@ -442,19 +451,6 @@ class GlslOut {
 				add(",");
 				addValue(e2, tabs);
 				add("))");
-			case [OpAssign, _, _] if( e1.e.match(TArray({ t : TRWTexture(_) },_)) ):
-				add("imageStore(");
-				switch( e1.e ) {
-				case TArray(tex,uv):
-					addValue(tex, tabs);
-					add(",");
-					addValue(uv, tabs);
-					add(",");
-					addValue(e2, tabs);
-					add(")");
-				default:
-					throw "assert";
-				}
 			default:
 				addValue(e1, tabs);
 				add(" ");
@@ -481,21 +477,6 @@ class GlslOut {
 			} else {
 				add("/*var*/");
 			}
-		case TCall( { e : TGlobal(ComputeVar) }, [{ e : TConst(CInt(i)) }]):
-			switch( ComputeVar.createByIndex(i,[]) ) {
-			case LocalInvocation:
-				add("ivec3(gl_LocalInvocationID)");
-			case LocalInvocationIndex:
-				add("int(gl_LocalInvocationIndex)");
-			case GlobalInvocation:
-				add("ivec3(gl_GlobalInvocationID)");
-			case NumWorkGroups:
-				add("ivec3(gl_NumWorkGroups)");
-			case WorkGroup:
-				add("ivec3(gl_WorkGroup)");
-			case WorkGroupSize:
-				add("ivec3(gl_WorkGroupSize)");
-			}
 		case TCall( { e : TGlobal(SetLayout) }, _):
 			// nothing
 		case TCall( { e : TGlobal(Saturate) }, [e]):
@@ -530,6 +511,21 @@ class GlslOut {
 			} else {
 				add(", 0)");
 			}
+		case TCall({ e : TGlobal(ImageStore) }, [tex, uv, color]):
+			var chans = switch( tex.t ) {
+			case TRWTexture(_, _, chans): chans;
+			default: throw "assert";
+			}
+			// we can use function decl because of some GLSL compiler bug
+			add("imageStore(");
+			addValue(tex, tabs);
+			add(",");
+			addValue(uv, tabs);
+			add(",");
+			if( chans != 4 ) add("(");
+			addValue(color, tabs);
+			if( chans != 4 ) add(")"+(chans == 1 ? ".xx" : ".xyyy"));
+			add(")");
 		case TCall(v, args):
 			switch( v.e ) {
 			case TGlobal(g):