Parcourir la source

compute textures support (glsl)

Nicolas Cannasse il y a 1 an
Parent
commit
28ec43cbec
14 fichiers modifiés avec 323 ajouts et 126 suppressions
  1. 37 10
      h3d/impl/GlDriver.hx
  2. 4 0
      h3d/mat/Data.hx
  3. 27 7
      hxsl/Ast.hx
  4. 2 2
      hxsl/Cache.hx
  5. 1 1
      hxsl/ChannelTexture.hx
  6. 73 37
      hxsl/Checker.hx
  7. 1 1
      hxsl/Dce.hx
  8. 5 5
      hxsl/Eval.hx
  9. 39 20
      hxsl/Flatten.hx
  10. 61 19
      hxsl/GlslOut.hx
  11. 35 3
      hxsl/MacroParser.hx
  12. 6 8
      hxsl/Macros.hx
  13. 29 8
      hxsl/Serializer.hx
  14. 3 5
      hxsl/Types.hx

+ 37 - 10
h3d/impl/GlDriver.hx

@@ -267,7 +267,7 @@ class GlDriver extends Driver {
 			return makeCompiler().run(sh);
 			return makeCompiler().run(sh);
 		}
 		}
 		if( shader.mode == Compute )
 		if( shader.mode == Compute )
-			return "// compute:\n" + compile(shader.compute.data);
+			return compile(shader.compute.data);
 		return "// vertex:\n" + compile(shader.vertex.data) + "// fragment:\n" + compile(shader.fragment.data);
 		return "// vertex:\n" + compile(shader.vertex.data) + "// fragment:\n" + compile(shader.fragment.data);
 	}
 	}
 
 
@@ -335,16 +335,37 @@ class GlDriver extends Driver {
 			var tt = t.type;
 			var tt = t.type;
 			var count = 1;
 			var count = 1;
 			switch( tt ) {
 			switch( tt ) {
-			case TChannel(_): tt = TSampler2D;
+			case TChannel(_): tt = TSampler(T2D,false);
 			case TArray(t,SConst(n)): tt = t; count = n;
 			case TArray(t,SConst(n)): tt = t; count = n;
 			default:
 			default:
 			}
 			}
 			if( tt != curT ) {
 			if( tt != curT ) {
 				curT = tt;
 				curT = tt;
 				name = switch( tt ) {
 				name = switch( tt ) {
-				case TSampler2D: mode = GL.TEXTURE_2D; "Textures";
-				case TSamplerCube: mode = GL.TEXTURE_CUBE_MAP; "TexturesCube";
-				case TSampler2DArray: mode = GL.TEXTURE_2D_ARRAY; "TexturesArray";
+				case TSampler(dim,arr):
+					mode = switch( [dim, arr] ) {
+					case [T1D, false]: GL.TEXTURE_1D;
+					case [T2D, false]: GL.TEXTURE_2D;
+					case [T3D, false]: GL.TEXTURE_3D;
+					case [TCube, false]: GL.TEXTURE_CUBE_MAP;
+					case [T1D, true]: GL.TEXTURE_1D_ARRAY;
+					case [T2D, true]: GL.TEXTURE_2D_ARRAY;
+					case [TCube, true]: GL.TEXTURE_CUBE_MAP_ARRAY;
+					default: throw "Texture not supported "+tt;
+					}
+					"Textures" + (dim == T2D ? "" : dim.getName().substr(1))+(arr ? "Array" : "");
+				case TRWTexture(dim, arr, chans):
+					mode = switch( [dim, arr] ) {
+					case [T1D, false]: GL.IMAGE_1D;
+					case [T2D, false]: GL.IMAGE_2D;
+					case [T3D, false]: GL.IMAGE_3D;
+					case [TCube, false]: GL.IMAGE_CUBE;
+					case [T1D, true]: GL.IMAGE_1D_ARRAY;
+					case [T2D, true]: GL.IMAGE_2D_ARRAY;
+					case [TCube, true]: GL.IMAGE_CUBE_MAP_ARRAY;
+					default: throw "Texture not supported "+tt;
+					};
+					"TexturesRW" + (dim == T2D ? "" : dim.getName().substr(1))+chans+(arr ? "Array" : "");
 				default: throw "Unsupported texture type "+tt;
 				default: throw "Unsupported texture type "+tt;
 				}
 				}
 				index = 0;
 				index = 0;
@@ -579,11 +600,11 @@ class GlDriver extends Driver {
 				var pt = s.textures[i];
 				var pt = s.textures[i];
 				if( t == null || t.isDisposed() ) {
 				if( t == null || t.isDisposed() ) {
 					switch( pt.t ) {
 					switch( pt.t ) {
-					case TSampler2D:
+					case TSampler(TCube, false):
+						t = h3d.mat.Texture.defaultCubeTexture();
+					case TSampler(_, false):
 						var color = h3d.mat.Defaults.loadingTextureColor;
 						var color = h3d.mat.Defaults.loadingTextureColor;
 						t = h3d.mat.Texture.fromColor(color, (color >>> 24) / 255);
 						t = h3d.mat.Texture.fromColor(color, (color >>> 24) / 255);
-					case TSamplerCube:
-						t = h3d.mat.Texture.defaultCubeTexture();
 					default:
 					default:
 						throw "Missing texture";
 						throw "Missing texture";
 					}
 					}
@@ -606,6 +627,11 @@ class GlDriver extends Driver {
 
 
 				if( pt.u == null ) continue;
 				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);
+					continue;
+				}
+
 				var idx = s.kind == Fragment ? curShader.vertex.textures.length + i : i;
 				var idx = s.kind == Fragment ? curShader.vertex.textures.length + i : i;
 				if( boundTextures[idx] != t.t ) {
 				if( boundTextures[idx] != t.t ) {
 					boundTextures[idx] = t.t;
 					boundTextures[idx] = t.t;
@@ -910,9 +936,10 @@ class GlDriver extends Driver {
 	}
 	}
 
 
 	function getBindType( t : h3d.mat.Texture ) {
 	function getBindType( t : h3d.mat.Texture ) {
-		var isCube = t.flags.has(Cube);
 		var isArray = t.flags.has(IsArray);
 		var isArray = t.flags.has(IsArray);
-		return isCube ? GL.TEXTURE_CUBE_MAP : isArray ? GL.TEXTURE_2D_ARRAY : GL.TEXTURE_2D;
+		if( t.flags.has(Cube) )
+			return isArray ? GL.TEXTURE_CUBE_MAP_ARRAY : GL.TEXTURE_CUBE_MAP;
+		return isArray ? GL.TEXTURE_2D_ARRAY : GL.TEXTURE_2D;
 	}
 	}
 
 
 	override function allocTexture( t : h3d.mat.Texture ) : Texture {
 	override function allocTexture( t : h3d.mat.Texture ) : Texture {

+ 4 - 0
h3d/mat/Data.hx

@@ -130,6 +130,10 @@ enum TextureFlags {
 		By default, the texture are loaded from images when created. If this flag is enabled, the texture will be loaded from disk when first used.
 		By default, the texture are loaded from images when created. If this flag is enabled, the texture will be loaded from disk when first used.
 	**/
 	**/
 	LazyLoading;
 	LazyLoading;
+	/**
+		Texture can be written in shaders using RWTexture
+	**/
+	Writable;
 }
 }
 
 
 typedef TextureFormat = hxd.PixelFormat;
 typedef TextureFormat = hxd.PixelFormat;

+ 27 - 7
hxsl/Ast.hx

@@ -5,6 +5,13 @@ enum BufferKind {
 	RW;
 	RW;
 }
 }
 
 
+enum TexDimension {
+	T1D;
+	T2D;
+	T3D;
+	TCube;
+}
+
 enum Type {
 enum Type {
 	TVoid;
 	TVoid;
 	TInt;
 	TInt;
@@ -16,15 +23,14 @@ enum Type {
 	TMat4;
 	TMat4;
 	TMat3x4;
 	TMat3x4;
 	TBytes( size : Int );
 	TBytes( size : Int );
-	TSampler2D;
-	TSampler2DArray;
-	TSamplerCube;
+	TSampler( dim : TexDimension, isArray : Bool );
+	TRWTexture( dim : TexDimension, isArray : Bool, channels : Int );
+	TMat2;
 	TStruct( vl : Array<TVar> );
 	TStruct( vl : Array<TVar> );
 	TFun( variants : Array<FunType> );
 	TFun( variants : Array<FunType> );
 	TArray( t : Type, size : SizeDecl );
 	TArray( t : Type, size : SizeDecl );
 	TBuffer( t : Type, size : SizeDecl, kind : BufferKind );
 	TBuffer( t : Type, size : SizeDecl, kind : BufferKind );
 	TChannel( size : Int );
 	TChannel( size : Int );
-	TMat2;
 }
 }
 
 
 enum VecType {
 enum VecType {
@@ -196,6 +202,15 @@ enum FunctionKind {
 	Main;
 	Main;
 }
 }
 
 
+enum ComputeVar {
+	GlobalInvocation;
+	LocalInvocation;
+	NumWorkGroups;
+	WorkGroup;
+	WorkGroupSize;
+	LocalInvocationIndex;
+}
+
 enum TGlobal {
 enum TGlobal {
 	Radians;
 	Radians;
 	Degrees;
 	Degrees;
@@ -289,6 +304,7 @@ enum TGlobal {
 	RoundEven;
 	RoundEven;
 	// compute
 	// compute
 	SetLayout;
 	SetLayout;
+	ComputeVar;
 }
 }
 
 
 enum Component {
 enum Component {
@@ -407,9 +423,9 @@ class Tools {
 		return false;
 		return false;
 	}
 	}
 
 
-	public static function isSampler( t : Type ) {
+	public static function isTexture( t : Type ) {
 		return switch( t ) {
 		return switch( t ) {
-		case TSampler2D, TSamplerCube, TSampler2DArray, TChannel(_):
+		case TSampler(_), TChannel(_), TRWTexture(_):
 			true;
 			true;
 		default:
 		default:
 			false;
 			false;
@@ -434,6 +450,10 @@ class Tools {
 			};
 			};
 			prefix+" "+toString(t) + "[" + (switch( s ) { case SConst(i): "" + i; case SVar(v): v.name; } ) + "]";
 			prefix+" "+toString(t) + "[" + (switch( s ) { case SConst(i): "" + i; case SVar(v): v.name; } ) + "]";
 		case TBytes(n): "Bytes" + n;
 		case TBytes(n): "Bytes" + n;
+		case TSampler(dim, arr):
+			"Sampler"+dim.getName().substr(1)+(arr ? "Array":"");
+		case TRWTexture(dim, arr,dims):
+			"RWTexture"+dim.getName().substr(1)+(arr ? "Array":"")+"<"+(dims == 1 ? "Float" : "Vec"+dims)+">";
 		default: t.getName().substr(1);
 		default: t.getName().substr(1);
 		}
 		}
 	}
 	}
@@ -560,7 +580,7 @@ class Tools {
 		case TMat4: 16;
 		case TMat4: 16;
 		case TMat3x4: 12;
 		case TMat3x4: 12;
 		case TBytes(s): s;
 		case TBytes(s): s;
-		case TBool, TString, TSampler2D, TSampler2DArray, TSamplerCube, TFun(_): 0;
+		case TBool, TString, TSampler(_), TRWTexture(_), TFun(_): 0;
 		case TArray(t, SConst(v)), TBuffer(t, SConst(v),_): size(t) * v;
 		case TArray(t, SConst(v)), TBuffer(t, SConst(v),_): size(t) * v;
 		case TArray(_, SVar(_)), TBuffer(_): 0;
 		case TArray(_, SVar(_)), TBuffer(_): 0;
 		}
 		}

+ 2 - 2
hxsl/Cache.hx

@@ -461,7 +461,7 @@ class Cache {
 					}
 					}
 					var ap = new AllocParam(a.v.name, a.pos, p.instance, p.index, a.v.type);
 					var ap = new AllocParam(a.v.name, a.pos, p.instance, p.index, a.v.type);
 					switch( a.v.type ) {
 					switch( a.v.type ) {
-					case TArray(t,_) if( t.isSampler() ):
+					case TArray(t,_) if( t.isTexture() ):
 						// hack to mark array of texture, see ShaderManager.fillParams
 						// hack to mark array of texture, see ShaderManager.fillParams
 						ap.pos = -a.size;
 						ap.pos = -a.size;
 						count += a.size;
 						count += a.size;
@@ -473,7 +473,7 @@ class Cache {
 				for( i in 0...out.length - 1 )
 				for( i in 0...out.length - 1 )
 					out[i].next = out[i + 1];
 					out[i].next = out[i + 1];
 				switch( g.type ) {
 				switch( g.type ) {
-				case TArray(t, _) if( t.isSampler() ):
+				case TArray(t, _) if( t.isTexture() ):
 					textures.push({ t : t, all : out });
 					textures.push({ t : t, all : out });
 					c.texturesCount += count;
 					c.texturesCount += count;
 				case TArray(TVec(4, VFloat), SConst(size)):
 				case TArray(TVec(4, VFloat), SConst(size)):

+ 1 - 1
hxsl/ChannelTexture.hx

@@ -1,3 +1,3 @@
 package hxsl;
 package hxsl;
 
 
-typedef ChannelTexture = { texture : hxsl.Types.ChannelTextureType, channel : hxsl.Channel };
+typedef ChannelTexture = { texture : hxsl.Types.TextureChannel, channel : hxsl.Channel };

+ 73 - 37
hxsl/Checker.hx

@@ -25,6 +25,7 @@ class Checker {
 	static var ivec2 = TVec(2, VInt);
 	static var ivec2 = TVec(2, VInt);
 	static var ivec3 = TVec(3, VInt);
 	static var ivec3 = TVec(3, VInt);
 	static var ivec4 = TVec(4, VInt);
 	static var ivec4 = TVec(4, VInt);
+	static var anyRWT = TRWTexture(T1D,false,-1);
 
 
 	var vars : Map<String,TVar>;
 	var vars : Map<String,TVar>;
 	var globals : Map<String,{ g : TGlobal, t : Type }>;
 	var globals : Map<String,{ g : TGlobal, t : Type }>;
@@ -48,6 +49,16 @@ class Checker {
 		var genFloat = [for( t in genType ) { args : [ { name : "value", type : t } ], ret : t } ];
 		var genFloat = [for( t in genType ) { args : [ { name : "value", type : t } ], ret : t } ];
 		var genFloat2 = [for( t in genType ) { args : [ { name : "a", type : t }, { name : "b", type : t } ], ret : t } ];
 		var genFloat2 = [for( t in genType ) { args : [ { name : "a", type : t }, { name : "b", type : t } ], ret : t } ];
 		var genWithFloat = [for( t in genType ) { args : [ { name : "a", type : t }, { name : "b", type : TFloat } ], ret : t } ];
 		var genWithFloat = [for( t in genType ) { args : [ { name : "a", type : t }, { name : "b", type : TFloat } ], ret : t } ];
+		var texDefs = [
+			{ dim : T1D, arr : false, uv : TFloat, iuv : TInt },
+			{ dim : T2D, arr : false, uv : vec2, iuv : ivec2 },
+			{ dim : T3D, arr : false, uv : vec3, iuv : ivec3 },
+			{ 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 },
+		];
 		for( g in Ast.TGlobal.createAll() ) {
 		for( g in Ast.TGlobal.createAll() ) {
 			var def = switch( g ) {
 			var def = switch( g ) {
 			case Vec2, Vec3, Vec4, Mat2, Mat3, Mat3x4, Mat4, IVec2, IVec3, IVec4, BVec2, BVec3, BVec4: [];
 			case Vec2, Vec3, Vec4, Mat2, Mat3, Mat3x4, Mat4, IVec2, IVec3, IVec4, BVec2, BVec3, BVec4: [];
@@ -67,33 +78,16 @@ class Checker {
 			case Cross:
 			case Cross:
 				[ { args : [ { name : "a", type : vec3 }, { name : "b", type : vec3 } ], ret : vec3 } ];
 				[ { args : [ { name : "a", type : vec3 }, { name : "b", type : vec3 } ], ret : vec3 } ];
 			case Texture:
 			case Texture:
-				[
-					{ args : [ { name : "tex", type : TSampler2D }, { name : "uv", type : vec2 } ], ret : vec4 },
-					{ args : [ { name : "tex", type : TSamplerCube }, { name : "normal", type : vec3 } ], ret : vec4 },
-					{ args : [ { name : "tex", type : TSampler2DArray }, { name : "uv", type : vec3 } ], ret : vec4 },
-				];
+				[for( t in texDefs ) { args : [{ name : "tex", type : TSampler(t.dim,t.arr) }, { name : "uv", type : t.uv }], ret : vec4 }];
 			case TextureLod:
 			case TextureLod:
-				[
-					{ args : [ { name : "tex", type : TSampler2D }, { name : "uv", type : vec2 }, { name : "lod", type : TFloat } ], ret : vec4 },
-					{ args : [ { name : "tex", type : TSamplerCube }, { name : "normal", type : vec3 }, { name : "lod", type : TFloat } ], ret : vec4 },
-					{ args : [ { name : "tex", type : TSampler2DArray }, { name : "uv", type : vec3 }, { name : "lod", type : TFloat } ], ret : vec4 },
-				];
+				[for( t in texDefs ) { args : [{ name : "tex", type : TSampler(t.dim,t.arr) }, { name : "uv", type : t.uv }, { name : "lod", type : TFloat }], ret : vec4 }];
 			case Texel:
 			case Texel:
-				[
-					{ args : [ { name: "tex", type: TSampler2D }, { name: "pos", type: ivec2 } ], ret: vec4 },
-					{ args : [ { name: "tex", type: TSampler2DArray }, { name: "pos", type: ivec3 } ], ret: vec4 },
-					{ args : [ { name: "tex", type: TSampler2D }, { name: "pos", type: ivec2 }, { name: "lod", type: TInt } ], ret: vec4 },
-					{ args : [ { name: "tex", type: TSampler2DArray }, { name: "pos", type: ivec3 }, { name: "lod", type: TInt } ], ret: vec4 },
-				];
+				[for( t in texDefs ) { args : [{ name : "tex", type : TSampler(t.dim,t.arr) }, { name : "pos", type : t.iuv }], ret : vec4 }];
 			case TextureSize:
 			case TextureSize:
-				[
-					{ args : [ { name: "tex", type: TSampler2D } ], ret: vec2 },
-					{ args : [ { name: "tex", type: TSampler2DArray } ], ret: vec3 },
-					{ args : [ { name: "tex", type: TSamplerCube } ], ret: vec2 },
-					{ args : [ { name: "tex", type: TSampler2D }, { name: "lod", type: TInt } ], ret: vec2 },
-					{ args : [ { name: "tex", type: TSampler2DArray }, { name: "lod", type: TInt } ], ret: vec3 },
-					{ args : [ { name: "tex", type: TSamplerCube }, { name: "lod", type: TInt } ], ret: vec2 },
-				];
+				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:
 			case ToInt:
 				[for( t in baseType ) { args : [ { name : "value", type : t } ], ret : TInt } ];
 				[for( t in baseType ) { args : [ { name : "value", type : t } ], ret : TInt } ];
 			case ToFloat:
 			case ToFloat:
@@ -190,6 +184,8 @@ class Checker {
 				[for( i => t in genType ) { args : [ { name: "x", type: genIType[i] } ], ret: t }];
 				[for( i => t in genType ) { args : [ { name: "x", type: genIType[i] } ], ret: t }];
 			case SetLayout:
 			case SetLayout:
 				[{ args : [{ name : "x", type : TInt },{ name : "y", type : TInt },{ name : "z", type : TInt }], ret : TVoid }];
 				[{ args : [{ name : "x", type : TInt },{ name : "y", type : TInt },{ name : "z", type : TInt }], ret : TVoid }];
+			case ComputeVar:
+				[];
 			case VertexID, InstanceID, FragCoord, FrontFacing:
 			case VertexID, InstanceID, FragCoord, FrontFacing:
 				null;
 				null;
 			}
 			}
@@ -340,6 +336,10 @@ class Checker {
 			return tryUnify(t1,t2);
 			return tryUnify(t1,t2);
 		case [TChannel(n1), TChannel(n2)] if( n1 == n2 ):
 		case [TChannel(n1), TChannel(n2)] if( n1 == n2 ):
 			return true;
 			return true;
+		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);
 		default:
 		default:
 		}
 		}
 		return false;
 		return false;
@@ -368,7 +368,7 @@ class Checker {
 				return;
 				return;
 			case Local if( v.qualifiers == null || v.qualifiers.indexOf(Final) < 0 ):
 			case Local if( v.qualifiers == null || v.qualifiers.indexOf(Final) < 0 ):
 				return;
 				return;
-			case Param if( v.type.match(TBuffer(_,_,RW)) ):
+			case Param, Local if( v.type.match(TBuffer(_,_,RW) | TRWTexture(_)) ):
 				return;
 				return;
 			default:
 			default:
 			}
 			}
@@ -501,6 +501,21 @@ class Checker {
 			}
 			}
 		case ECall(e1, args):
 		case ECall(e1, args):
 			function makeCall(e1) {
 			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 ) {
 				return switch( e1.t ) {
 				case TFun(variants):
 				case TFun(variants):
 					var e = unifyCallParams(e1, args, variants, e.pos);
 					var e = unifyCallParams(e1, args, variants, e.pos);
@@ -658,11 +673,17 @@ class Checker {
 			TBreak;
 			TBreak;
 		case EArray(e1, e2):
 		case EArray(e1, e2):
 			var e1 = typeExpr(e1, Value);
 			var e1 = typeExpr(e1, Value);
-			var e2 = typeExpr(e2, With(TInt));
-			switch( e2.t ) {
-			case TInt:
-			default: unify(e2.t, TInt, e2.p);
+			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);
 			switch( e1.t ) {
 			switch( e1.t ) {
 			case TArray(t, size), TBuffer(t,size,_):
 			case TArray(t, size), TBuffer(t,size,_):
 				switch( [size, e2.e] ) {
 				switch( [size, e2.e] ) {
@@ -679,6 +700,14 @@ class Checker {
 				type = vec3;
 				type = vec3;
 			case TMat4, TMat3x4:
 			case TMat4, TMat3x4:
 				type = vec4;
 				type = vec4;
+			case TRWTexture(_, _, chans):
+				type = switch(chans) {
+				case 2: vec2;
+				case 3: vec3;
+				case 4: vec4;
+				default:
+					TFloat;
+				}
 			default:
 			default:
 				error("Cannot index " + e1.t.toString() + " : should be an array", e.pos);
 				error("Cannot index " + e1.t.toString() + " : should be an array", e.pos);
 			}
 			}
@@ -864,8 +893,7 @@ class Checker {
 					if ( v.kind != Local ) error("Borrow should not have a type qualifier", pos);
 					if ( v.kind != Local ) error("Borrow should not have a type qualifier", pos);
 				case Sampler(_):
 				case Sampler(_):
 					switch( v.type ) {
 					switch( v.type ) {
-					case TArray(t, _) if( t.isSampler() ):
-					case t if( t.isSampler() ):
+					case TSampler(_), TArray(TSampler(_), _):
 					default: error("Sampler should be on sampler type or sampler array", pos);
 					default: error("Sampler should be on sampler type or sampler array", pos);
 					}
 					}
 				case Ignore, Doc(_):
 				case Ignore, Doc(_):
@@ -963,13 +991,13 @@ class Checker {
 		var g = globals.get(f);
 		var g = globals.get(f);
 		if( g == null ) {
 		if( g == null ) {
 			var gl : TGlobal = switch( [f, e.t] ) {
 			var gl : TGlobal = switch( [f, e.t] ) {
-			case ["get", TSampler2D|TSampler2DArray|TSamplerCube]: Texture;
+			case ["get", TSampler(_)]: Texture;
 			case ["get", TChannel(_)]: ChannelRead;
 			case ["get", TChannel(_)]: ChannelRead;
-			case ["getLod", TSampler2D|TSampler2DArray|TSamplerCube]: TextureLod;
+			case ["getLod", TSampler(_)]: TextureLod;
 			case ["getLod", TChannel(_)]: ChannelReadLod;
 			case ["getLod", TChannel(_)]: ChannelReadLod;
-			case ["fetch"|"fetchLod", TSampler2D|TSampler2DArray]: Texel;
+			case ["fetch"|"fetchLod", TSampler(_)]: Texel;
 			case ["fetch"|"fetchLod", TChannel(_)]: ChannelFetch;
 			case ["fetch"|"fetchLod", TChannel(_)]: ChannelFetch;
-			case ["size", TSampler2D|TSampler2DArray|TSamplerCube]: TextureSize;
+			case ["size", TSampler(_) | TRWTexture(_)]: TextureSize;
 			case ["size", TChannel(_)]: ChannelTextureSize;
 			case ["size", TChannel(_)]: ChannelTextureSize;
 			default: null;
 			default: null;
 			}
 			}
@@ -988,6 +1016,8 @@ class Checker {
 					args.shift();
 					args.shift();
 					sel.push({ args : args, ret : v.ret });
 					sel.push({ args : args, ret : v.ret });
 				}
 				}
+				if( f == "get" )
+					trace(variants, sel);
 				if( sel.length > 0 || variants.length == 0 )
 				if( sel.length > 0 || variants.length == 0 )
 					return FGlobal(g.g, e, sel);
 					return FGlobal(g.g, e, sel);
 			default:
 			default:
@@ -1031,6 +1061,14 @@ class Checker {
 	function specialGlobal( g : TGlobal, e : TExpr, args : Array<TExpr>, pos : Position ) : TExpr {
 	function specialGlobal( g : TGlobal, e : TExpr, args : Array<TExpr>, pos : Position ) : TExpr {
 		var type = null;
 		var type = null;
 		inline function checkLength(n,t) {
 		inline function checkLength(n,t) {
+			var skip = false;
+			if( args.length == 1 && (t == TInt || t == TFloat) ) {
+				switch( args[0].t ) {
+				case TVec(n2,t2) if( (t2 == VInt || t2 == VFloat) && n2 == n ): skip = true;
+				default: false;
+				}
+			}
+			if( skip ) return;
 			var tsize = 0;
 			var tsize = 0;
 			for( a in args )
 			for( a in args )
 				switch( a.t ) {
 				switch( a.t ) {
@@ -1065,8 +1103,6 @@ class Checker {
 			if( args.length == 1 ) {
 			if( args.length == 1 ) {
 				switch( args[0].t ) {
 				switch( args[0].t ) {
 				case TInt, TFloat:
 				case TInt, TFloat:
-				case TVec(n,VFloat):
-					if( n != 3 ) error("Invalid input vector length: "+n+" should be "+k, pos);
 				default:
 				default:
 					checkLength(k,TInt);
 					checkLength(k,TInt);
 				}
 				}

+ 1 - 1
hxsl/Dce.hx

@@ -45,7 +45,7 @@ class Dce {
 				var i = get(v);
 				var i = get(v);
 				if( v.kind == Input )
 				if( v.kind == Input )
 					inputs.push(i);
 					inputs.push(i);
-				if( v.kind == Output || v.type.match(TBuffer(_,_,RW)) )
+				if( v.kind == Output || v.type.match(TBuffer(_,_,RW) | TRWTexture(_)) )
 					i.keep = true;
 					i.keep = true;
 			}
 			}
 		}
 		}

+ 5 - 5
hxsl/Eval.hx

@@ -78,17 +78,17 @@ class Eval {
 		return v2;
 		return v2;
 	}
 	}
 
 
-	function checkSamplerRec(t:Type) {
-		if( t.isSampler() )
+	function checkTextureRec(t:Type) {
+		if( t.isTexture() )
 			return true;
 			return true;
 		switch( t ) {
 		switch( t ) {
 		case TStruct(vl):
 		case TStruct(vl):
 			for( v in vl )
 			for( v in vl )
-				if( checkSamplerRec(v.type) )
+				if( checkTextureRec(v.type) )
 					return true;
 					return true;
 			return false;
 			return false;
 		case TArray(t, _):
 		case TArray(t, _):
-			return checkSamplerRec(t);
+			return checkTextureRec(t);
 		case TBuffer(_):
 		case TBuffer(_):
 			return true;
 			return true;
 		default:
 		default:
@@ -98,7 +98,7 @@ class Eval {
 
 
 	function needsInline(f:TFunction) {
 	function needsInline(f:TFunction) {
 		for( a in f.args )
 		for( a in f.args )
-			if( checkSamplerRec(a.type) )
+			if( checkTextureRec(a.type) )
 				return true;
 				return true;
 		return false;
 		return false;
 	}
 	}

+ 39 - 20
hxsl/Flatten.hx

@@ -26,6 +26,7 @@ class Flatten {
 	var params : Array<TVar>;
 	var params : Array<TVar>;
 	var outVars : Array<TVar>;
 	var outVars : Array<TVar>;
 	var varMap : Map<TVar,Alloc>;
 	var varMap : Map<TVar,Alloc>;
+	var textureFormats : Array<{ dim : TexDimension, arr : Bool, rw : Int }>;
 	public var allocData : Map< TVar, Array<Alloc> >;
 	public var allocData : Map< TVar, Array<Alloc> >;
 
 
 	public function new() {
 	public function new() {
@@ -35,6 +36,7 @@ class Flatten {
 		globals = [];
 		globals = [];
 		params = [];
 		params = [];
 		outVars = [];
 		outVars = [];
+		textureFormats = [];
 		varMap = new Map();
 		varMap = new Map();
 		allocData = new Map();
 		allocData = new Map();
 		for( v in s.vars )
 		for( v in s.vars )
@@ -48,9 +50,12 @@ class Flatten {
 		pack(prefix + "Globals", Global, globals, VFloat);
 		pack(prefix + "Globals", Global, globals, VFloat);
 		pack(prefix + "Params", Param, params, VFloat);
 		pack(prefix + "Params", Param, params, VFloat);
 		var allVars = globals.concat(params);
 		var allVars = globals.concat(params);
-		var textures = packTextures(prefix + "Textures", allVars, TSampler2D)
-			.concat(packTextures(prefix+"TexturesCube", allVars, TSamplerCube))
-			.concat(packTextures(prefix+"TexturesArray", allVars, TSampler2DArray));
+		for( t in textureFormats ) {
+			var name = t.dim == T2D ? "" : t.dim.getName().substr(1);
+			if( t.rw > 0 ) name = "RW"+name+t.rw;
+			if( t.arr ) name += "Array";
+			packTextures(prefix + "Textures" + name, allVars, t.rw == 0 ? TSampler(t.dim, t.arr) : TRWTexture(t.dim, t.arr, t.rw));
+		}
 		packBuffers("buffers", allVars, Uniform);
 		packBuffers("buffers", allVars, Uniform);
 		packBuffers("rwbuffers", allVars, RW);
 		packBuffers("rwbuffers", allVars, RW);
 		var funs = [for( f in s.funs ) mapFun(f, mapExpr)];
 		var funs = [for( f in s.funs ) mapFun(f, mapExpr)];
@@ -79,13 +84,13 @@ class Flatten {
 				e
 				e
 			else
 			else
 				access(a, v.type, e.p, AIndex(a));
 				access(a, v.type, e.p, AIndex(a));
-		case TArray( { e : TVar(v), p : vp }, eindex) if( !eindex.e.match(TConst(CInt(_))) ):
+		case TArray( { e : TVar(v), p : vp }, eindex) if( !eindex.e.match(TConst(CInt(_))) && !v.type.match(TRWTexture(_)) ):
 			var a = varMap.get(v);
 			var a = varMap.get(v);
 			if( a == null )
 			if( a == null )
 				e
 				e
 			else {
 			else {
 				switch( v.type ) {
 				switch( v.type ) {
-				case TArray(t, _) if( t.isSampler() ):
+				case TArray(t, _) if( t.isTexture() ):
 					eindex = toInt(mapExpr(eindex));
 					eindex = toInt(mapExpr(eindex));
 					access(a, t, vp, AOffset(a,1,eindex));
 					access(a, t, vp, AOffset(a,1,eindex));
 				case TArray(t, _):
 				case TArray(t, _):
@@ -147,7 +152,7 @@ class Flatten {
 			var earr = [for( i in 0...len ) { var a = new Alloc(a.g, a.t, a.pos + stride * i, stride); access(a, t, pos, AIndex(a)); }];
 			var earr = [for( i in 0...len ) { var a = new Alloc(a.g, a.t, a.pos + stride * i, stride); access(a, t, pos, AIndex(a)); }];
 			return { e : TArrayDecl(earr), t : t, p : pos };
 			return { e : TArrayDecl(earr), t : t, p : pos };
 		default:
 		default:
-			if( t.isSampler() ) {
+			if( t.isTexture() ) {
 				var e = read(0, pos);
 				var e = read(0, pos);
 				e.t = t;
 				e.t = t;
 				return e;
 				return e;
@@ -222,9 +227,9 @@ class Flatten {
 		var samplers = [];
 		var samplers = [];
 		for( v in vars ) {
 		for( v in vars ) {
 			var count = 1;
 			var count = 1;
-			if( v.type != t ) {
+			if( !v.type.equals(t) ) {
 				switch( v.type ) {
 				switch( v.type ) {
-				case TChannel(_) if( t == TSampler2D ):
+				case TChannel(_) if( t.match(TSampler(T2D,false)) ):
 				case TArray(t2,SConst(n)) if( t2 == t ):
 				case TArray(t2,SConst(n)) if( t2 == t ):
 					count = n;
 					count = n;
 				default:
 				default:
@@ -291,10 +296,10 @@ class Flatten {
 			kind : kind,
 			kind : kind,
 		};
 		};
 		for( v in vars ) {
 		for( v in vars ) {
-			if( v.type.isSampler() || v.type.match(TBuffer(_)) )
+			if( v.type.isTexture() || v.type.match(TBuffer(_)) )
 				continue;
 				continue;
 			switch( v.type ) {
 			switch( v.type ) {
-			case TArray(t,_) if( t.isSampler() ): continue;
+			case TArray(t,_) if( t.isTexture() ): continue;
 			default:
 			default:
 			}
 			}
 			var size = varSize(v.type, t);
 			var size = varSize(v.type, t);
@@ -358,18 +363,32 @@ class Flatten {
 		case TStruct(vl):
 		case TStruct(vl):
 			for( v in vl )
 			for( v in vl )
 				gatherVar(v);
 				gatherVar(v);
+			return;
+		case TSampler(dim, arr), TRWTexture(dim, arr, _):
+			var rw = switch( v.type ) {
+			case TRWTexture(_,_,chans): chans;
+			default: 0;
+			}
+			var found = false;
+			for( f in textureFormats )
+				if( f.dim == dim && f.arr == arr && f.rw == rw ) {
+					found = true;
+					break;
+				}
+			if( !found )
+				textureFormats.push({ dim : dim, arr : arr, rw : rw });
 		default:
 		default:
-			switch( v.kind ) {
-			case Global:
-				if( v.hasQualifier(PerObject) )
-					params.push(v);
-				else
-					globals.push(v);
-			case Param:
+		}
+		switch( v.kind ) {
+		case Global:
+			if( v.hasQualifier(PerObject) )
 				params.push(v);
 				params.push(v);
-			default:
-				outVars.push(v);
-			}
+			else
+				globals.push(v);
+		case Param:
+			params.push(v);
+		default:
+			outVars.push(v);
 		}
 		}
 	}
 	}
 
 

+ 61 - 19
hxsl/GlslOut.hx

@@ -130,6 +130,12 @@ class GlslOut {
 			decls.push(s);
 			decls.push(s);
 	}
 	}
 
 
+	function getSamplerType(dim:TexDimension,arr) {
+		var name = "sampler" + dim.getName().substr(1);
+		if( arr ) name += "Array";
+		return name;
+	}
+
 	function addType( t : Type ) {
 	function addType( t : Type ) {
 		switch( t ) {
 		switch( t ) {
 		case TVoid:
 		case TVoid:
@@ -162,14 +168,13 @@ class GlslOut {
 		case TMat3x4:
 		case TMat3x4:
 			decl(MAT34);
 			decl(MAT34);
 			add("_mat3x4");
 			add("_mat3x4");
-		case TSampler2D:
-			add("sampler2D");
-		case TSampler2DArray:
-			add("sampler2DArray");
-			if( isES )
-				decl("precision lowp sampler2DArray;");
-		case TSamplerCube:
-			add("samplerCube");
+		case TSampler(dim,arr):
+			var name = getSamplerType(dim,arr);
+			add(name);
+			if( isES && arr )
+				decl("precision lowp "+name+";");
+		case TRWTexture(dim, arr, chans):
+			add("image"+dim.getName().substr(1)+(arr?"Array":""));
 		case TStruct(vl):
 		case TStruct(vl):
 			add("struct { ");
 			add("struct { ");
 			for( v in vl ) {
 			for( v in vl ) {
@@ -294,18 +299,18 @@ class GlslOut {
 			decl("vec3 unpackNormal( vec4 v ) { return normalize((v.xyz - vec3(0.5)) * vec3(2.)); }");
 			decl("vec3 unpackNormal( vec4 v ) { return normalize((v.xyz - vec3(0.5)) * vec3(2.)); }");
 		case Texture:
 		case Texture:
 			switch( args[0].t ) {
 			switch( args[0].t ) {
-			case TSampler2D, TSampler2DArray, TChannel(_) if( isES2 ):
+			case TSampler(T2D,_), TChannel(_) if( isES2 ):
 				return "texture2D";
 				return "texture2D";
-			case TSamplerCube if( isES2 ):
+			case TSampler(TCube,_) if( isES2 ):
 				return "textureCube";
 				return "textureCube";
 			default:
 			default:
 			}
 			}
 		case TextureLod:
 		case TextureLod:
 			switch( args[0].t ) {
 			switch( args[0].t ) {
-			case TSampler2D, TSampler2DArray, TChannel(_) if( isES2 ):
+			case TSampler(T2D,_), TChannel(_) if( isES2 ):
 				decl("#extension GL_EXT_shader_texture_lod : enable");
 				decl("#extension GL_EXT_shader_texture_lod : enable");
 				return "texture2DLodEXT";
 				return "texture2DLodEXT";
-			case TSamplerCube if( isES2 ):
+			case TSampler(TCube,_) if( isES2 ):
 				decl("#extension GL_EXT_shader_texture_lod : enable");
 				decl("#extension GL_EXT_shader_texture_lod : enable");
 				return "textureCubeLodEXT";
 				return "textureCubeLodEXT";
 			default:
 			default:
@@ -318,12 +323,14 @@ class GlslOut {
 				return "texelFetch";
 				return "texelFetch";
 		case TextureSize:
 		case TextureSize:
 			switch( args[0].t ) {
 			switch( args[0].t ) {
-			case TSampler2D, TChannel(_):
+			case TSampler(_,false), TChannel(_):
 				decl("vec2 _textureSize(sampler2D sampler, int lod) { return vec2(textureSize(sampler, lod)); }");
 				decl("vec2 _textureSize(sampler2D sampler, int lod) { return vec2(textureSize(sampler, lod)); }");
-			case TSamplerCube:
-				decl("vec2 _textureSize(samplerCube sampler, int lod) { return vec2(textureSize(sampler, lod)); }");
-			case TSampler2DArray:
-				decl("vec3 _textureSize(sampler2DArray sampler, int lod) { return vec3(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";
 			default:
 			default:
 			}
 			}
 			return "_textureSize";
 			return "_textureSize";
@@ -435,6 +442,19 @@ class GlslOut {
 				add(",");
 				add(",");
 				addValue(e2, tabs);
 				addValue(e2, tabs);
 				add("))");
 				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:
 			default:
 				addValue(e1, tabs);
 				addValue(e1, tabs);
 				add(" ");
 				add(" ");
@@ -461,6 +481,21 @@ class GlslOut {
 			} else {
 			} else {
 				add("/*var*/");
 				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) }, _):
 		case TCall( { e : TGlobal(SetLayout) }, _):
 			// nothing
 			// nothing
 		case TCall( { e : TGlobal(Saturate) }, [e]):
 		case TCall( { e : TGlobal(Saturate) }, [e]):
@@ -485,11 +520,13 @@ class GlslOut {
 			add(getFunName(g,args,e.t));
 			add(getFunName(g,args,e.t));
 			add("(");
 			add("(");
 			addValue(args[0], tabs);
 			addValue(args[0], tabs);
-			if ( args.length != 1 ) {
+			if( args.length != 1 ) {
 				// with LOD argument
 				// with LOD argument
 				add(", ");
 				add(", ");
 				addValue(args[1], tabs);
 				addValue(args[1], tabs);
 				add(")");
 				add(")");
+			} else if( args[0].t.match(TRWTexture(_)) ) {
+				add("))");
 			} else {
 			} else {
 				add(", 0)");
 				add(", 0)");
 			}
 			}
@@ -679,6 +716,9 @@ class GlslOut {
 				case RW:
 				case RW:
 					add("buffer ");
 					add("buffer ");
 				}
 				}
+			case TArray(TRWTexture(_, _, chans), _):
+				var format = "rgba".substr(0, chans);
+				add('layout(${format}32f) uniform ');
 			default:
 			default:
 				add("uniform ");
 				add("uniform ");
 			}
 			}
@@ -754,7 +794,9 @@ class GlslOut {
 		isVertex = f.kind == Vertex;
 		isVertex = f.kind == Vertex;
 		isCompute = f.kind == Main;
 		isCompute = f.kind == Main;
 
 
-		if (isVertex || isCompute)
+		if( isCompute ) {
+			// no prec
+		} else if( isVertex )
 			decl("precision highp float;");
 			decl("precision highp float;");
 		else
 		else
 			decl("precision mediump float;");
 			decl("precision mediump float;");

+ 35 - 3
hxsl/MacroParser.hx

@@ -83,6 +83,21 @@ class MacroParser {
 		}
 		}
 	}
 	}
 
 
+	function getTexDim( n : String, f : Ast.TexDimension -> Bool -> Ast.Type ) {
+		var arr = false;
+		if( StringTools.endsWith(n,"Array") ) {
+			arr = true;
+			n = n.substr(0,-5);
+		}
+		return switch( n ) {
+		case "1D": f(T1D,arr);
+		case "2D": f(T2D,arr);
+		case "3D": f(T3D,arr);
+		case "Cube": f(TCube,arr);
+		default: null;
+		}
+	}
+
 	public function parseType( t : ComplexType, pos : Position ) : Ast.Type {
 	public function parseType( t : ComplexType, pos : Position ) : Ast.Type {
 		switch( t ) {
 		switch( t ) {
 		case TPath( { pack : [], name : name, sub : null, params : [] } ):
 		case TPath( { pack : [], name : name, sub : null, params : [] } ):
@@ -104,9 +119,6 @@ class MacroParser {
 			case "Mat3x4": return TMat3x4;
 			case "Mat3x4": return TMat3x4;
 			case "Mat2": return TMat2;
 			case "Mat2": return TMat2;
 			case "String": return TString;
 			case "String": return TString;
-			case "Sampler2D": return TSampler2D;
-			case "Sampler2DArray": return TSampler2DArray;
-			case "SamplerCube": return TSamplerCube;
 			case "Bytes2": return TBytes(2);
 			case "Bytes2": return TBytes(2);
 			case "Bytes3": return TBytes(3);
 			case "Bytes3": return TBytes(3);
 			case "Bytes4": return TBytes(4);
 			case "Bytes4": return TBytes(4);
@@ -114,7 +126,27 @@ class MacroParser {
 			case "Channel2": return TChannel(2);
 			case "Channel2": return TChannel(2);
 			case "Channel3": return TChannel(3);
 			case "Channel3": return TChannel(3);
 			case "Channel4": return TChannel(4);
 			case "Channel4": return TChannel(4);
+			case _ if( StringTools.startsWith(name,"Sampler") ):
+				var t = getTexDim(name.substr(7), (d,arr) -> TSampler(d,arr));
+				if( t != null ) return t;
+			}
+		case TPath( { pack : [], name : name, sub : null, params : pl } ) if( StringTools.startsWith(name,"RWTexture") ):
+			var chans = switch( pl[0] ) {
+			case TPType(TPath({ pack : [], name : n, sub : null, params : [] })):
+				switch( n ) {
+				case "Float": 1;
+				case "Vec2": 2;
+				case "Vec3": 3;
+				case "Vec4": 4;
+				default: 0;
+				}
+			case null, _: 0;
 			}
 			}
+			if( chans == 0 )
+				error("Unsupported RWTexture parameter, should be Float|Vec2|Vec3|Vec4", pos);
+			var t = getTexDim(name.substr(9), (dim,arr) -> TRWTexture(dim,arr,chans));
+			if( t != null )
+				return t;
 		case TPath( { pack : [], name : name = ("Array"|"Buffer"|"RWBuffer"), sub : null, params : [t, size] } ):
 		case TPath( { pack : [], name : name = ("Array"|"Buffer"|"RWBuffer"), sub : null, params : [t, size] } ):
 			var t = switch( t ) {
 			var t = switch( t ) {
 			case TPType(t): parseType(t, pos);
 			case TPType(t): parseType(t, pos);

+ 6 - 8
hxsl/Macros.hx

@@ -23,15 +23,13 @@ class Macros {
 			for( v in vl ) {
 			for( v in vl ) {
 				fields.push({ pos : pos, name : v.name, kind : FVar(makeType(v.type)) });
 				fields.push({ pos : pos, name : v.name, kind : FVar(makeType(v.type)) });
 				if( v.type.match(TChannel(_)) )
 				if( v.type.match(TChannel(_)) )
-				fields.push({ pos : pos, name : v.name+"Channel", kind : FVar(macro : hxsl.Channel) });
+					fields.push({ pos : pos, name : v.name+"Channel", kind : FVar(macro : hxsl.Channel) });
 			}
 			}
 			TAnonymous(fields);
 			TAnonymous(fields);
-		case TSampler2D:
-			macro : hxsl.Types.Sampler2D;
-		case TSampler2DArray:
-			macro : hxsl.Types.Sampler2DArray;
-		case TSamplerCube:
-			macro : hxsl.Types.SamplerCube;
+		case TSampler(_, false), TRWTexture(_,false,_):
+			macro : hxsl.Types.Texture;
+		case TSampler(_, true), TRWTexture(_,true,_):
+			macro : hxsl.Types.TextureArray;
 		case TMat2, TMat3, TMat3x4, TMat4:
 		case TMat2, TMat3, TMat3x4, TMat4:
 			macro : hxsl.Types.Matrix;
 			macro : hxsl.Types.Matrix;
 		case TString:
 		case TString:
@@ -46,7 +44,7 @@ class Macros {
 			var t = makeType(t);
 			var t = makeType(t);
 			macro : Array<$t>;
 			macro : Array<$t>;
 		case TChannel(_):
 		case TChannel(_):
-			macro : hxsl.Types.ChannelTextureType;
+			macro : hxsl.Types.TextureChannel;
 		case TFun(_):
 		case TFun(_):
 			throw "assert";
 			throw "assert";
 		case TBuffer(_):
 		case TBuffer(_):

+ 29 - 8
hxsl/Serializer.hx

@@ -11,6 +11,7 @@ class Serializer {
 	var types : Array<Type>;
 	var types : Array<Type>;
 	var uid = 1;
 	var uid = 1;
 	var tid = 1;
 	var tid = 1;
+	var version : Int;
 
 
 	public function new() {
 	public function new() {
 	}
 	}
@@ -76,7 +77,7 @@ class Serializer {
 
 
 	function writeType( t : Type ) {
 	function writeType( t : Type ) {
 		out.addByte(t.getIndex());
 		out.addByte(t.getIndex());
-		switch (t) {
+		switch( t ) {
 		case TVec(size, t):
 		case TVec(size, t):
 			out.addByte(size | (t.getIndex() << 3));
 			out.addByte(size | (t.getIndex() << 3));
 		case TBytes(size):
 		case TBytes(size):
@@ -101,11 +102,18 @@ class Serializer {
 			}
 			}
 		case TChannel(size):
 		case TChannel(size):
 			out.addByte(size);
 			out.addByte(size);
-		case TVoid, TInt, TBool, TFloat, TString, TMat2, TMat3, TMat4, TMat3x4, TSampler2D, TSampler2DArray, TSamplerCube:
+		case TSampler(dim, arr):
+			out.addByte((dim.getIndex() << 1) | (arr ? 1 : 0));
+		case TRWTexture(dim, arr, chans):
+			out.addByte((dim.getIndex() << 3) | (arr ? 1 : 0) | ((chans - 1) << 1));
+		case TVoid, TInt, TBool, TFloat, TString, TMat2, TMat3, TMat4, TMat3x4:
+		case __TUnused:
+			throw "assert";
 		}
 		}
 	}
 	}
 
 
 	static var TVECS = new Map();
 	static var TVECS = new Map();
+	static var TDIMS = hxsl.Ast.TexDimension.createAll();
 
 
 	function readType() : Type {
 	function readType() : Type {
 		return switch( input.readByte() ) {
 		return switch( input.readByte() ) {
@@ -126,9 +134,20 @@ class Serializer {
 		case 7: TMat4;
 		case 7: TMat4;
 		case 8: TMat3x4;
 		case 8: TMat3x4;
 		case 9: TBytes(input.readInt32());
 		case 9: TBytes(input.readInt32());
-		case 10: TSampler2D;
-		case 11: TSampler2DArray;
-		case 12: TSamplerCube;
+		case 10 if( version == 0 ): TSampler(T2D, false);
+		case 11 if( version == 0 ): TSampler(T2D, true);
+		case 12 if( version == 0 ): TSampler(TCube, false);
+		case 18 if( version == 0 ): TMat2;
+		case 10:
+			var b = input.readByte();
+			var dim = TDIMS[b>>1];
+			TSampler(dim, b & 1 != 0);
+		case 11:
+			var b = input.readByte();
+			var dim = TDIMS[b>>3];
+			TRWTexture(dim, b & 1 != 0, ((b>>1)&3) + 1);
+		case 12:
+			TMat2;
 		case 13:
 		case 13:
 			var id = readVarInt();
 			var id = readVarInt();
 			var t = types[id];
 			var t = types[id];
@@ -154,7 +173,6 @@ class Serializer {
 			TBuffer(t, v == null ? SConst(readVarInt()) : SVar(v), kind);
 			TBuffer(t, v == null ? SConst(readVarInt()) : SVar(v), kind);
 		case 17:
 		case 17:
 			TChannel(input.readByte());
 			TChannel(input.readByte());
-		case 18: TMat2;
 		default:
 		default:
 			throw "assert";
 			throw "assert";
 		}
 		}
@@ -437,11 +455,14 @@ class Serializer {
 		};
 		};
 	}
 	}
 
 
-	static var SIGN = 0x8B741D; // will be encoded to HXSL
+	static var SIGN = 0x8C741D; // will be encoded to HXSL
 
 
 	public function unserialize( data : String ) : ShaderData {
 	public function unserialize( data : String ) : ShaderData {
 		input = new haxe.io.BytesInput(haxe.crypto.Base64.decode(data,false));
 		input = new haxe.io.BytesInput(haxe.crypto.Base64.decode(data,false));
-		if( input.readByte() != (SIGN & 0xFF) || input.readByte() != (SIGN >> 8) & 0xFF || input.readByte() != (SIGN >> 16) & 0xFF )
+		if( input.readByte() != (SIGN & 0xFF) || input.readByte() != (SIGN >> 8) & 0xFF )
+			throw "Invalid HXSL data";
+		version = input.readByte() - 0x8B;
+		if( version < 0 || version > 1 )
 			throw "Invalid HXSL data";
 			throw "Invalid HXSL data";
 		varMap = new Map();
 		varMap = new Map();
 		types = [];
 		types = [];

+ 3 - 5
hxsl/Types.hx

@@ -6,14 +6,12 @@ typedef IVec = Array<Int>;
 typedef BVec = Array<Bool>;
 typedef BVec = Array<Bool>;
 typedef Matrix = h3d.Matrix;
 typedef Matrix = h3d.Matrix;
 typedef Texture = h3d.mat.Texture;
 typedef Texture = h3d.mat.Texture;
-typedef Sampler2D = h3d.mat.Texture;
-typedef Sampler2DArray = h3d.mat.TextureArray;
-typedef SamplerCube = h3d.mat.Texture;
-typedef ChannelTextureType = h3d.mat.Texture;
+typedef TextureArray = h3d.mat.TextureArray;
+typedef TextureChannel = h3d.mat.Texture;
 typedef Buffer = h3d.Buffer;
 typedef Buffer = h3d.Buffer;
 
 
 class ChannelTools {
 class ChannelTools {
-	public static inline function isPackedFormat( c : ChannelTextureType ) {
+	public static inline function isPackedFormat( c : TextureChannel ) {
 		return c.format == h3d.mat.Texture.nativeFormat;
 		return c.format == h3d.mat.Texture.nativeFormat;
 	}
 	}
 }
 }