浏览代码

started AGAL output for hxsl3

Nicolas Cannasse 11 年之前
父节点
当前提交
a3bb6ac484
共有 2 个文件被更改,包括 272 次插入11 次删除
  1. 36 11
      h3d/impl/Stage3dDriver.hx
  2. 236 0
      hxsl/AgalOut.hx

+ 36 - 11
h3d/impl/Stage3dDriver.hx

@@ -32,6 +32,12 @@ class VertexWrapper {
 
 }
 
+private class CompiledProgram {
+	public var p : flash.display3D.Program3D;
+	public function new() {
+	}
+}
+
 class Stage3dDriver extends Driver {
 
 	public static var PROFILE = flash.display3D.Context3DProfile.BASELINE;
@@ -54,6 +60,7 @@ class Stage3dDriver extends Driver {
 	var enableDraw : Bool;
 	var capture : { bmp : hxd.BitmapData, callb : Void -> Void };
 	var frame : Int;
+	var programs : Map<Int, CompiledProgram>;
 
 	@:allow(h3d.impl.VertexWrapper)
 	var empty : flash.utils.ByteArray;
@@ -61,6 +68,7 @@ class Stage3dDriver extends Driver {
 	public function new() {
 		empty = new flash.utils.ByteArray();
 		s3d = flash.Lib.current.stage.stage3Ds[0];
+		programs = new Map();
 		curTextures = [];
 		curMultiBuffer = [];
 	}
@@ -97,6 +105,9 @@ class Stage3dDriver extends Driver {
 
 	function onCreate(_) {
 		var old = ctx;
+		for( p in programs )
+			p.p.dispose();
+		programs = new Map();
 		if( old != null ) {
 			if( old.driverInfo != "Disposed" ) throw "Duplicate onCreate()";
 			old.dispose();
@@ -306,21 +317,36 @@ class Stage3dDriver extends Driver {
 		curMatBits = bits;
 	}
 
+	function compileShader( s : hxsl.RuntimeShader.RuntimeShaderData ) : haxe.io.Bytes {
+		var agal = hxsl.AgalOut.toAgal(s, 1);
+		//trace(format.agal.Tools.toString(agal));
+		var o = new haxe.io.BytesOutput();
+		new format.agal.Writer(o).write(agal);
+		return o.getBytes();
+	}
+	
 	override function selectShader( shader : hxsl.RuntimeShader ) {
-		throw "TODO";
-		return true;
-		/*
 		var shaderChanged = false;
-		var s = shader.getInstance();
-		if( s.program == null ) {
-			s.program = ctx.createProgram();
-			var vdata = s.vertexBytes.getData();
-			var fdata = s.fragmentBytes.getData();
+		var p = programs.get(shader.id);
+		if( p == null ) {
+			p = new CompiledProgram();
+			p.p = ctx.createProgram();
+			var vdata = compileShader(shader.vertex).getData();
+			var fdata = compileShader(shader.fragment).getData();
 			vdata.endian = flash.utils.Endian.LITTLE_ENDIAN;
 			fdata.endian = flash.utils.Endian.LITTLE_ENDIAN;
-			s.program.upload(vdata, fdata);
-			curShader = null; // in case we had the same shader and it was disposed
+			p.p.upload(vdata, fdata);
+			programs.set(shader.id, p);
+			curShader = null;
+		}
+		if( shader != curShader ) {
+			ctx.setProgram(p.p);
+			shaderChanged = true;
+			curShader = shader;
 		}
+		throw "TODO";
+		return true;
+		/*
 		if( s != curShader ) {
 			ctx.setProgram(s.program);
 			shaderChanged = true;
@@ -366,7 +392,6 @@ class Stage3dDriver extends Driver {
 				}
 			}
 		}
-		return shaderChanged;
 		*/
 	}
 

+ 236 - 0
hxsl/AgalOut.hx

@@ -0,0 +1,236 @@
+package hxsl;
+
+import hxsl.Ast;
+import hxsl.RuntimeShader;
+import format.agal.Data;
+
+class AgalOut {
+	
+	static var COMPS = [X, Y, Z, W];
+
+	var code : Array<Opcode>;
+	var vertex : Bool;
+	var version : Int;
+	var opcodes : Array<Opcode>;
+	var varMap : Map<Int, Reg>;
+	var tmpCount : Int;
+	var nullReg : Reg;
+
+	public function new() {
+	}
+
+	public dynamic function error( msg : String, p : Position ) {
+		throw msg;
+	}
+	
+	public function compile( s : RuntimeShaderData, version ) : Data {
+		vertex = s.vertex;
+		nullReg = { t : RTemp, index : -1, swiz : null, access : null };
+		this.version = version;
+		opcodes = [];
+		tmpCount = 0;
+		varMap = new Map();
+		
+		var varying = [];
+		var paramCount = 0, varCount = 0, inputCount = 0, outCount = 0, texCount = 0;
+		for( v in s.data.vars ) {
+			var r : Reg;
+			switch( v.kind ) {
+			case Param, Global:
+				switch( v.type ) {
+				case TArray(TSampler2D | TSamplerCube, SConst(n)):
+					r = { t : RTexture, index : texCount, swiz : null, access : null };
+					texCount += n;
+				default:
+					r = { t : RConst, index : paramCount, swiz : defSwiz(v.type), access : null };
+					paramCount += regSize(v.type);
+				}
+			case Var:
+				r = { t : RVar, index : varCount, swiz : defSwiz(v.type), access : null };
+				varying.push(r);
+				varCount += regSize(v.type);
+			case Output:
+				r = { t : ROut, index : outCount, swiz : defSwiz(v.type), access : null };
+				outCount += regSize(v.type);
+			case Input:
+				r = { t : RAttr, index : inputCount, swiz : defSwiz(v.type), access : null };
+				inputCount += regSize(v.type);
+			case Local, Function:
+				continue;
+			}
+			varMap.set(v.id, r);
+		}
+		if( paramCount != s.globalsSize + s.paramsSize )
+			throw "assert";
+		
+		if( s.data.funs.length != 1 ) throw "assert";
+		expr(s.data.funs[0].expr);
+		
+		// force write of all varying components
+		for( v in varying ) {
+			if( v.swiz == null ) continue;
+			for( i in 0...opcodes.length )
+				switch( opcodes[i] ) {
+				case OMov(dst, val) if( dst == v ):
+					var dst = Reflect.copy(dst);
+					var val = Reflect.copy(val);
+					val.swiz = null;
+					dst.swiz = null;
+					opcodes[i] = OMov(dst, val);
+					break;
+				default:
+				}
+		}
+		return {
+			fragmentShader : !vertex,
+			version : version,
+			code : opcodes,
+		};
+	}
+	
+	inline function mov(dst, src) {
+		op(OMov(dst, src));
+	}
+	
+	inline function op(o) {
+		opcodes.push(o);
+	}
+	
+	inline function swiz( r : Reg, sw : Array<C> ) : Reg {
+		if( r.access != null || r.swiz != null ) throw "assert";
+		return {
+			t : r.t,
+			index : r.index,
+			swiz : sw,
+			access : null
+		};
+	}
+	
+	function expr( e : TExpr ) : Reg {
+		switch( e.e ) {
+		case TVarDecl(v, init):
+			if( init != null )
+				mov(reg(v), expr(init));
+			return nullReg;
+		case TBlock(el):
+			var r = nullReg;
+			for( e in el )
+				r = expr(e);
+			return r;
+		case TVar(v):
+			return reg(v);
+		case TBinop(bop, e1, e2):
+			switch( bop ) {
+			case OpAssign:
+				var r = expr(e1);
+				mov(r, expr(e2));
+				return r;
+			case OpAssignOp(op):
+				var r1 = expr(e1);
+				mov(r1, expr( { e : TBinop(op, e1, e2), t : e.t, p : e.p } ));
+				return r1;
+			case OpMult:
+				var r = allocReg(e.t);
+				op(OMul(r, expr(e1), expr(e2)));
+				return r;
+			default:
+				throw "TODO " + bop;
+			}
+		case TCall(e, args):
+			switch( e.e ) {
+			case TGlobal(g):
+				switch( [g, args] ) {
+				case [Vec4, _]:
+					var r = allocReg();
+					var pos = 0;
+					for( a in args ) {
+						var e = expr(a);
+						switch( a.t ) {
+						case TFloat:
+							mov(swiz(r, [COMPS[pos++]]), e);
+						case TVec(2, VFloat):
+							mov(swiz(r, [COMPS[pos++], COMPS[pos++]]), e);
+						case TVec(3, VFloat):
+							mov(swiz(r, [COMPS[pos++], COMPS[pos++], COMPS[pos++]]), e);
+						case TVec(4, VFloat):
+							mov(r, e);
+						default:
+							throw "assert " + e.t;
+						}
+					}
+					return r;
+				case [Texture2D, [t,uv]]:
+					var t = expr(t);
+					var uv = expr(uv);
+					var r = allocReg();
+					if( t.t != RTexture ) throw "assert";
+					op(OTex(r, uv, { index : t.index, flags : [TIgnoreSampler] }));
+					return r;
+				default:
+					throw "TODO " + g + ":" + args.length;
+				}
+			default:
+				throw "TODO CALL " + e.e;
+			}
+		case TArray(e, index):
+			switch( index.e ) {
+			case TConst(CInt(v)):
+				var r = expr(e);
+				var stride = switch( e.t ) {
+				case TArray(TSampler2D | TSamplerCube, _): 1;
+				case TArray(t, _): regSize(t);
+				default: throw "assert " + e.t;
+				};
+				return { t : r.t, index : r.index + v * stride, swiz : null, access : null };
+			default:
+				throw "TODO " + index.e;
+			}
+		case TSwiz(e, regs):
+			var r = expr(e);
+			return swiz(r, [for( r in regs ) COMPS[r.getIndex()]]);
+		default:
+			throw "TODO " + e.e;
+		}
+	}
+	
+	function regSize( t : Type ) {
+		return switch( t ) {
+		case TInt, TFloat, TVec(_), TBytes(_): 1;
+		case TMat3, TMat3x4: 3;
+		case TMat4: 4;
+		case TArray(t, SConst(size)): regSize(t) * size;
+		case TStruct(vl): throw "TODO";
+		case TVoid, TString, TBool, TSampler2D, TSamplerCube, TFun(_), TArray(_): throw "assert "+t;
+		}
+	}
+	
+	function defSwiz( t : Type ) {
+		return switch( t ) {
+		case TInt, TFloat: [X];
+		case TVec(2, _), TBytes(2): [X, Y];
+		case TVec(3, _), TBytes(3): [X, Y, Z];
+		default: null;
+		}
+	}
+	
+	function reg( v : TVar ) : Reg {
+		var r = varMap.get(v.id);
+		if( r != null ) return r;
+		if( v.kind != Local ) throw "assert " + v;
+		r = allocReg(v.type);
+		varMap.set(v.id, r);
+		return r;
+	}
+	
+	function allocReg( ?t : Type ) : Reg {
+		var r = { t : RTemp, index : tmpCount, swiz : t == null ? null : defSwiz(t), access : null };
+		tmpCount += t == null ? 1 : regSize(t);
+		return r;
+	}
+	
+	public static function toAgal( shader, version ) {
+		var a = new AgalOut();
+		return a.compile(shader, version);
+	}
+
+}