Przeglądaj źródła

added tools/hxsl to showcase and debug different hxsl steps and final output

Nicolas Cannasse 7 lat temu
rodzic
commit
7426ab5eb3
5 zmienionych plików z 408 dodań i 12 usunięć
  1. 17 12
      hxsl/Cache.hx
  2. 236 0
      tools/hxsl/Main.hx
  3. 5 0
      tools/hxsl/hxsl.hxml
  4. 54 0
      tools/hxsl/hxsl.hxproj
  5. 96 0
      tools/hxsl/index.html

+ 17 - 12
hxsl/Cache.hx

@@ -253,18 +253,7 @@ class Cache {
 		}
 		#end
 
-		var r = new RuntimeShader();
-		r.vertex = flattenShader(s.vertex, Vertex, paramVars);
-		r.vertex.vertex = true;
-		r.fragment = flattenShader(s.fragment, Fragment, paramVars);
-		r.globals = new Map();
-		initGlobals(r, r.vertex);
-		initGlobals(r, r.fragment);
-
-		#if debug
-		Printer.check(r.vertex.data,[s.vertex]);
-		Printer.check(r.fragment.data,[s.fragment]);
-		#end
+		var r = buildRuntimeShader(s.vertex, s.fragment, paramVars);
 
 		#if shader_debug_dump
 		if( dbg != null ) {
@@ -287,6 +276,22 @@ class Cache {
 		return r;
 	}
 
+	function buildRuntimeShader( vertex : ShaderData, fragment : ShaderData, paramVars ) {
+		var r = new RuntimeShader();
+		r.vertex = flattenShader(vertex, Vertex, paramVars);
+		r.vertex.vertex = true;
+		r.fragment = flattenShader(fragment, Fragment, paramVars);
+		r.globals = new Map();
+		initGlobals(r, r.vertex);
+		initGlobals(r, r.fragment);
+
+		#if debug
+		Printer.check(r.vertex.data,[vertex]);
+		Printer.check(r.fragment.data,[fragment]);
+		#end
+		return r;
+	}
+
 	function initGlobals( r : RuntimeShader, s : RuntimeShaderData ) {
 		var p = s.globals;
 		while( p != null ) {

+ 236 - 0
tools/hxsl/Main.hx

@@ -0,0 +1,236 @@
+import js.html.webgl.GL;
+
+enum Output {
+	Input;
+	Link;
+	Split;
+	Dce;
+	HXSL;
+	GLSL;
+	HLSL;
+}
+
+class Main {
+
+	var text : js.html.TextAreaElement;
+	var vars : js.html.TextAreaElement;
+	var out : js.html.InputElement;
+	var display : js.html.Element;
+	var error : js.html.Element;
+	var canvas : js.html.CanvasElement;
+	var currentOutput = GLSL;
+	var codes : Map<Output,String>;
+	var showVars : Bool = false;
+	var gl : js.html.webgl.RenderingContext;
+
+	function new() {
+		var doc = js.Browser.document;
+
+		text = cast doc.getElementById("hxsl");
+		out = cast doc.getElementById("outputs");
+		error = doc.getElementById("errorLog");
+		vars = cast doc.getElementById("vars");
+		display = doc.getElementById("display");
+		canvas = cast doc.getElementById("canvas");
+
+		var varids : js.html.InputElement = cast doc.getElementById("varids");
+		varids.onchange = function(_) {
+			showVars = varids.checked;
+			rebuild();
+		};
+
+		Reflect.setField(doc, "show", function(e:js.html.Element) {
+			currentOutput = Output.createByName(e.textContent);
+			syncOutput();
+			display.textContent = ""+codes.get(currentOutput);
+
+			var store = js.Browser.getLocalStorage();
+			store.setItem("select", currentOutput.getName());
+		});
+
+		gl = canvas.getContextWebGL();
+
+		text.onkeyup = rebuild;
+		vars.onkeyup = rebuild;
+
+		var store = js.Browser.getLocalStorage();
+		var str = store.getItem("hxsl");
+		if( str != null && str != "" ) text.value = str;
+		str = store.getItem("output");
+		if( str != null && str != "" ) out.value = str;
+		str = store.getItem("vars");
+		if( str != null && str != "" ) vars.value = str;
+		str = store.getItem("select");
+		if( str != null && str != "" ) currentOutput = Output.createByName(str);
+		syncOutput();
+
+		rebuild();
+
+		for( t in doc.getElementsByTagName('textarea') ) {
+			var t : js.html.TextAreaElement = cast t;
+			t.onkeydown = function(e) {
+				if( e.keyCode == 9 ) {
+					e.preventDefault();
+					var s = t.selectionStart;
+					t.value = t.value.substring(0,t.selectionStart) + "\t" + t.value.substring(t.selectionEnd);
+					t.selectionEnd = s+1;
+				}
+			};
+		}
+	}
+
+	function formatHxsl( e : hxsl.Ast.ShaderData ) {
+		return hxsl.Printer.shaderToString(e, showVars);
+	}
+
+	function syncOutput() {
+		for( e in js.Browser.document.getElementsByTagName("a") ) {
+			e.className = e.className.split(" active").join("");
+			if( e.textContent == currentOutput.getName() )
+				e.className += " active";
+		}
+	}
+
+	function rebuild() {
+		var code = text.value;
+		var output = out.value;
+		var vars = vars.value;
+
+		var store = js.Browser.getLocalStorage();
+		store.setItem("hxsl", code);
+		store.setItem("output", output);
+		store.setItem("vars", vars);
+
+		var outputs = [for( o in output.split(",") ) hxsl.Output.Value(StringTools.trim(o))];
+		codes = new Map();
+		try {
+
+			var parser = new hscript.Parser();
+			parser.allowMetadata = true;
+			parser.allowTypes = true;
+			parser.allowJSON = true;
+
+			var vars : Dynamic = new hscript.Interp().execute(parser.parseString(vars));
+
+			var expr = parser.parseString(code);
+			var e = new hscript.Macro({ file : "hxsl", min : 0, max : code.length }).convert(expr);
+			var ast = new hxsl.MacroParser().parseExpr(e);
+
+			var checked = new hxsl.Checker().check("HxslShader", ast);
+			codes.set(Input, formatHxsl(checked));
+
+			var cache = @:privateAccess new hxsl.Cache();
+			var outLink = cache.getLinkShader(outputs);
+
+			var shared = new hxsl.SharedShader("");
+			shared.data = checked;
+			@:privateAccess shared.initialize();
+			var shader = new hxsl.DynamicShader(shared);
+			for( v in Reflect.fields(vars) )
+				shader.hscriptSet(v, Reflect.field(vars, v));
+
+			var globals = new hxsl.Globals();
+			var shaders = [shader, outLink];
+			shader.updateConstants(globals);
+
+			var shaderIndex = 0;
+			var shaders = [for( s in shaders ) {
+				index : shaderIndex++,
+				inst : @:privateAccess s.instance,
+			}];
+
+			var linker = new hxsl.Linker();
+			var linked = linker.link([for( s in shaders ) s.inst.shader]);
+
+			var paramVars = new Map();
+			for( v in linker.allVars )
+				if( v.v.kind == Param ) {
+					switch( v.v.type ) {
+					case TStruct(_): continue;
+					default:
+					}
+					var inf = shaders[v.instanceIndex];
+					paramVars.set(v.id, { instance : inf.index, index : inf.inst.params.get(v.merged[0].id) } );
+				}
+
+			codes.set(Link, formatHxsl(linked));
+
+			var split = new hxsl.Splitter().split(linked);
+
+			codes.set(Split, formatHxsl(split.vertex)+"\n\n"+formatHxsl(split.fragment));
+
+			var dce = new hxsl.Dce().dce(split.vertex, split.fragment);
+
+			codes.set(Dce, formatHxsl(dce.vertex) + "\n\n" + formatHxsl(dce.fragment));
+
+			var r = @:privateAccess cache.buildRuntimeShader(dce.vertex, dce.fragment, paramVars);
+
+			codes.set(HXSL, formatHxsl(r.vertex.data) + "\n\n" + formatHxsl(r.fragment.data)); // todo : add mapping of constants to buffers
+
+
+			var glsl = new hxsl.GlslOut();
+			glsl.glES = true;
+			var vertexSource = glsl.run(r.vertex.data);
+			var fragmentSource = glsl.run(r.fragment.data);
+			codes.set(GLSL, vertexSource+"\n\n" + fragmentSource);
+
+			function compile(source,type) {
+				var s = gl.createShader(type);
+				gl.shaderSource(s, source);
+				gl.compileShader(s);
+				var log = gl.getShaderInfoLog(s);
+				if( gl.getShaderParameter(s, GL.COMPILE_STATUS) != cast 1 ) {
+					var log = gl.getShaderInfoLog(s);
+					var lid = Std.parseInt(log.substr(9));
+					var line = lid == null ? null : code.split("\n")[lid - 1];
+					if( line == null ) line = "" else line = "(" + StringTools.trim(line) + ")";
+					var codeLines = code.split("\n");
+					for( i in 0...codeLines.length )
+						codeLines[i] = (i+1) + "\t" + codeLines[i];
+					throw "An error occurred compiling the shaders: " + log + line+"\n\n"+codeLines.join("\n");
+				}
+				return s;
+			}
+
+			var vgl = compile(vertexSource, GL.VERTEX_SHADER);
+			var fgl = compile(fragmentSource, GL.FRAGMENT_SHADER);
+			var p = gl.createProgram();
+			gl.attachShader(p, vgl);
+			gl.attachShader(p, fgl);
+			gl.linkProgram(p);
+			if( gl.getProgramParameter(p, GL.LINK_STATUS) != cast 1 )
+				throw gl.getProgramInfoLog(p);
+			gl.deleteShader(vgl);
+			gl.deleteShader(fgl);
+			gl.deleteProgram(p);
+
+			var hlsl = new hxsl.HlslOut();
+			codes.set(HLSL, hlsl.run(r.vertex.data) + "\n\n" + hlsl.run(r.fragment.data));
+
+			setError("OK");
+
+
+
+		} catch( e : hscript.Expr.Error ) {
+
+			var str = hscript.Printer.errorToString(e);
+			setError(str);
+		} catch( e : hxsl.Ast.Error ) {
+			setError("Line "+code.substr(0,e.pos.min).split("\n").length+": "+e.msg);
+		} catch( e : Dynamic ) {
+			setError("" + e);
+		}
+
+		if( codes.exists(currentOutput) )
+			display.textContent = codes.get(currentOutput);
+	}
+
+	function setError( msg : String ) {
+		error.textContent = msg;
+	}
+
+	static function main() {
+		new Main();
+	}
+
+}

+ 5 - 0
tools/hxsl/hxsl.hxml

@@ -0,0 +1,5 @@
+-lib heaps
+-lib hscript
+-js hxsl.js
+-main Main
+-D hscriptPos

+ 54 - 0
tools/hxsl/hxsl.hxproj

@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<project version="2">
+  <!-- Output SWF options -->
+  <output>
+    <movie outputType="Application" />
+    <movie input="" />
+    <movie path="hxsl.js" />
+    <movie fps="60" />
+    <movie width="815" />
+    <movie height="600" />
+    <movie version="0" />
+    <movie minorVersion="0" />
+    <movie platform="JavaScript" />
+    <movie background="#FFFFFF" />
+  </output>
+  <!-- Other classes to be compiled into your SWF -->
+  <classpaths>
+    <!-- example: <class path="..." /> -->
+  </classpaths>
+  <!-- Build options -->
+  <build>
+    <option directives="" />
+    <option flashStrict="False" />
+    <option noInlineOnDebug="False" />
+    <option mainClass="Main" />
+    <option enabledebug="False" />
+    <option additional="-D hscriptPos" />
+  </build>
+  <!-- haxelib libraries -->
+  <haxelib>
+    <library name="heaps" />
+    <library name="hscript" />
+  </haxelib>
+  <!-- Class files to compile (other referenced classes will automatically be included) -->
+  <compileTargets>
+    <!-- example: <compile path="..." /> -->
+  </compileTargets>
+  <!-- Paths to exclude from the Project Explorer tree -->
+  <hiddenPaths>
+    <hidden path="obj" />
+  </hiddenPaths>
+  <!-- Executed before build -->
+  <preBuildCommand />
+  <!-- Executed after build -->
+  <postBuildCommand alwaysRun="False" />
+  <!-- Other project options -->
+  <options>
+    <option showHiddenPaths="False" />
+    <option testMovie="OpenDocument" />
+    <option testMovieCommand="index.html" />
+  </options>
+  <!-- Plugin storage -->
+  <storage />
+</project>

+ 96 - 0
tools/hxsl/index.html

@@ -0,0 +1,96 @@
+<html>
+
+<body>
+
+<style>
+th, td, p {
+	font-family : "Verdana";
+}
+th {
+	font-weight: normal;
+}
+td, tr {
+	vertical-align : top;
+}
+a {
+	color : #008;
+	text-decoration:none;
+}
+a:hover {
+	text-decoration:underline;
+}
+a.active {
+	font-weight : bold;
+}
+.error {
+	color : #800;
+	font-weight : bold;
+}
+</style>
+
+<table style="width:100%;table-layout:fixed;">
+<tr>
+	<th>
+		<b>HxSL code</b>
+		Outputs: <input type="text" id="outputs" value="output.color"/>
+
+	</th>
+	<th>
+		<a href="#" onclick="show(this)">Input</a>
+		&gt; <a href="#" onclick="show(this)">Link</a>
+		&gt; <a href="#" onclick="show(this)">Split</a>
+		&gt; <a href="#" onclick="show(this)">Dce</a>
+		&gt; <a href="#" onclick="show(this)">HXSL</a>
+		&gt; <a href="#" onclick="show(this)">GLSL</a>
+		| <a href="#" onclick="show(this)">HLSL</a>
+	</th>
+</tr>
+<tr>
+<td style="width:50%; min-width:50%">
+
+<textarea id="hxsl" style="width:100%;height:400px">
+@input var input : {
+	var position : Vec3;
+};
+
+@const var white : Bool;
+@param var modelView : Mat4;
+
+var output : {
+	var color : Vec4;
+	var position : Vec4;
+};
+
+function vertex() {
+	output.position = vec4(input.position,1.) * modelView;
+}
+
+function fragment() {
+	output.color = vec4(white ? 1. : 0.);
+}
+</textarea>
+
+<textarea id="vars" style="width:100%; height: 40px">
+{ white : true }
+</textarea>
+
+<div class="error" id="errorLog">
+</div>
+
+</td>
+
+<td style="width:50%; max-width:50%">
+<div style="border:1px solid #888; display:inline-block; width:100%; margin-left : 5px; height : 400px; overflow:scroll">
+<pre id="display" style="width:100%">
+</pre>
+</div>
+<input type="checkbox" id="varids"/> var-ids
+</td>
+</table>
+
+<canvas id="canvas"></canvas>
+<script src="hxsl.js"></script>
+
+
+</body>
+</html>