Ver Fonte

added uniform buffer support to hxsl

Nicolas Cannasse há 7 anos atrás
pai
commit
d686c8504d

+ 1 - 0
h2d/RenderContext.hx

@@ -271,6 +271,7 @@ class RenderContext extends h3d.impl.RenderContext {
 		engine.selectMaterial(pass);
 		engine.uploadShaderBuffers(buffers, Params);
 		engine.uploadShaderBuffers(buffers, Textures);
+		engine.uploadShaderBuffers(buffers, Buffers);
 	}
 
 	@:access(h2d.Drawable)

+ 4 - 0
h3d/Buffer.hx

@@ -25,6 +25,10 @@ enum BufferFlag {
 		Used internaly
 	**/
 	NoAlloc;
+	/**
+		Used for shader input buffer
+	**/
+	UniformBuffer;
 }
 
 class Buffer {

+ 21 - 0
h3d/impl/DirectXDriver.hx

@@ -22,6 +22,7 @@ private class ShaderContext {
 	public var paramsSize : Int;
 	public var texturesCount : Int;
 	public var textures2DCount : Int;
+	public var bufferCount : Int;
 	public var paramsContent : hl.Bytes;
 	public var globals : dx.Resource;
 	public var params : dx.Resource;
@@ -643,6 +644,7 @@ class DirectXDriver extends h3d.impl.Driver {
 		ctx.paramsContent.fill(0, shader.paramsSize * 16, 0xDD);
 		ctx.texturesCount = shader.textures2DCount + shader.texturesCubeCount;
 		ctx.textures2DCount = shader.textures2DCount;
+		ctx.bufferCount = shader.bufferCount;
 		ctx.globals = dx.Driver.createBuffer(shader.globalsSize * 16, Dynamic, ConstantBuffer, CpuWrite, None, 0, null);
 		ctx.params = dx.Driver.createBuffer(shader.paramsSize * 16, Dynamic, ConstantBuffer, CpuWrite, None, 0, null);
 		#if debug
@@ -935,6 +937,25 @@ class DirectXDriver extends h3d.impl.Driver {
 					}
 				}
 			}
+		case Buffers:
+			var first = -1;
+			var max = -1;
+			for( i in 0...shader.bufferCount ) {
+				var buf = @:privateAccess buffers.buffers[i].buffer.vbuf.res;
+				var tid = i + 2;
+				if( buf != state.buffers[tid] ) {
+					state.buffers[tid] = buf;
+					if( first < 0 ) first = tid;
+					max = tid;
+				}
+			}
+			if( max >= 0 )
+				switch( state.kind ) {
+				case Vertex:
+					Driver.vsSetConstantBuffers(first,max-first+1,state.buffers.getRef().offset(first));
+				case Pixel:
+					Driver.psSetConstantBuffers(first,max-first+1,state.buffers.getRef().offset(first));
+				}
 		case Textures:
 			var start = -1, max = -1;
 			var sstart = -1, smax = -1;

+ 15 - 0
h3d/impl/GlDriver.hx

@@ -14,6 +14,9 @@ private typedef GL = js.html.webgl.GL;
 private extern class GL2 extends js.html.webgl.GL {
 	// webgl2
 	function drawBuffers( buffers : Array<Int> ) : Void;
+	function getUniformBlockIndex( p : Program, name : String ) : Int;
+	function bindBufferBase( target : Int, index : Int, buffer : js.html.webgl.Buffer ) : Void;
+	function uniformBlockBinding( p : Program, blockIndex : Int, blockBinding : Int ) : Void;
 	static inline var RGBA16F = 0x881A;
 	static inline var RGBA32F = 0x8814;
 	static inline var ALPHA16F = 0x881C;
@@ -26,6 +29,7 @@ private extern class GL2 extends js.html.webgl.GL {
 	static inline var SRGB_ALPHA = 0x8C42;
 	static inline var SRGB8_ALPHA = 0x8C43;
 	static inline var DEPTH_COMPONENT24 = 0x81A6;
+	static inline var UNIFORM_BUFFER = 0x8A11;
 }
 private typedef Uniform = js.html.webgl.UniformLocation;
 private typedef Program = js.html.webgl.Program;
@@ -85,6 +89,7 @@ private class CompiledShader {
 	public var params : Uniform;
 	public var textures : Array<Uniform>;
 	public var cubeTextures : Array<Uniform>;
+	public var buffers : Array<Int>;
 	public var shader : hxsl.RuntimeShader.RuntimeShaderData;
 	public function new(s,vertex,shader) {
 		this.s = s;
@@ -285,6 +290,11 @@ class GlDriver extends Driver {
 		s.params = gl.getUniformLocation(p.p, prefix + "Params");
 		s.textures = [for( i in 0...shader.textures2DCount ) gl.getUniformLocation(p.p, prefix + "Textures[" + i + "]")];
 		s.cubeTextures = [for( i in 0...shader.texturesCubeCount ) gl.getUniformLocation(p.p, prefix + "TexturesCube[" + i + "]")];
+		if( shader.bufferCount > 0 ) {
+			s.buffers = [for( i in 0...shader.bufferCount ) gl.getUniformBlockIndex(p.p,"uniform_buffer"+i)];
+			for( i in 0...shader.bufferCount )
+				gl.uniformBlockBinding(p.p,s.buffers[i],i);
+		}
 	}
 
 	override function selectShader( shader : hxsl.RuntimeShader ) {
@@ -410,6 +420,11 @@ class GlDriver extends Driver {
 				gl.uniform4fv(s.params, a);
 				#end
 			}
+		case Buffers:
+			if( s.buffers != null ) {
+				for( i in 0...s.buffers.length )
+					gl.bindBufferBase(GL2.UNIFORM_BUFFER, i, @:privateAccess buf.buffers[i].buffer.vbuf.b);
+			}
 		case Textures:
 			var tcount = s.textures.length;
 			for( i in 0...s.textures.length + s.cubeTextures.length ) {

+ 4 - 1
h3d/impl/MemoryManager.hx

@@ -153,7 +153,10 @@ class MemoryManager {
 		}
 
 		if( !b.flags.has(Managed) ) {
-			var m = new ManagedBuffer(stride, b.vertices, b.flags.has(Dynamic) ? [Dynamic] : null);
+			var flags : Array<h3d.Buffer.BufferFlag> = null;
+			if( b.flags.has(Dynamic) ) { if( flags == null ) flags = []; flags.push(Dynamic); }
+			if( b.flags.has(UniformBuffer) ) { if( flags == null ) flags = []; flags.push(UniformBuffer); }
+ 			var m = new ManagedBuffer(stride, b.vertices, flags);
 			#if debug
 			m.next = buffers[0];
 			buffers[0] = m;

+ 3 - 0
h3d/impl/Stage3dDriver.hx

@@ -664,6 +664,9 @@ class Stage3dDriver extends Driver {
 					curSamplerBits[i] = -1;
 				}
 			}
+		case Buffers:
+			if( curShader.s.fragment.bufferCount + curShader.s.vertex.bufferCount > 0 )
+				throw "Uniform Buffers are not supported";
 		case Params:
 			if( curShader.s.vertex.paramsSize > 0 ) ctx.setProgramConstantsFromVector(flash.display3D.Context3DProgramType.VERTEX, curShader.s.vertex.globalsSize, buffers.vertex.params.toData(), curShader.s.vertex.paramsSize);
 			if( curShader.s.fragment.paramsSize > 0 ) ctx.setProgramConstantsFromVector(flash.display3D.Context3DProgramType.FRAGMENT, curShader.s.fragment.globalsSize, buffers.fragment.params.toData(), curShader.s.fragment.paramsSize);

+ 1 - 0
h3d/pass/Default.hx

@@ -158,6 +158,7 @@ class Default extends Base {
 				manager.fillParams(buf, p.shader, p.shaders);
 				ctx.engine.uploadShaderBuffers(buf, Params);
 				ctx.engine.uploadShaderBuffers(buf, Textures);
+				ctx.engine.uploadShaderBuffers(buf, Buffers);
 			}
 			drawObject(p);
 			p = p.next;

+ 7 - 0
h3d/pass/ShaderManager.hx

@@ -231,6 +231,13 @@ class ShaderManager {
 				buf.tex[tid++] = t;
 				p = p.next;
 			}
+			var p = s.buffers;
+			var bid = 0;
+			while( p != null ) {
+				var b : h3d.Buffer = getParamValue(p, shaders, !STRICT);
+				buf.buffers[bid++] = b;
+				p = p.next;
+			}
 		}
 		fill(buf.vertex, s.vertex);
 		fill(buf.fragment, s.fragment);

+ 5 - 0
h3d/shader/Buffers.hx

@@ -4,6 +4,7 @@ package h3d.shader;
 	public var Globals = 0;
 	public var Params = 1;
 	public var Textures = 2;
+	public var Buffers = 3;
 }
 
 typedef ShaderBufferData = #if js js.html.Float32Array #else haxe.ds.Vector<hxd.impl.Float32> #end;
@@ -13,20 +14,24 @@ class ShaderBuffers {
 	public var globals : ShaderBufferData;
 	public var params : ShaderBufferData;
 	public var tex : haxe.ds.Vector<h3d.mat.Texture>;
+	public var buffers : haxe.ds.Vector<h3d.Buffer>;
 
 	public function new( s : hxsl.RuntimeShader.RuntimeShaderData ) {
 		globals = new ShaderBufferData(s.globalsSize<<2);
 		params = new ShaderBufferData(s.paramsSize<<2);
 		tex = new haxe.ds.Vector(s.textures2DCount + s.texturesCubeCount);
+		buffers = s.bufferCount > 0 ? new haxe.ds.Vector(s.bufferCount) : null;
 	}
 
 	public function grow( s : hxsl.RuntimeShader.RuntimeShaderData ) {
 		var ng = s.globalsSize << 2;
 		var np = s.paramsSize << 2;
 		var nt = s.textures2DCount + s.texturesCubeCount;
+		var nb = s.bufferCount;
 		if( globals.length < ng ) globals = new ShaderBufferData(ng);
 		if( params.length < np ) params = new ShaderBufferData(np);
 		if( tex.length < nt ) tex = new haxe.ds.Vector(nt);
+		if( nb > 0 && (buffers == null || buffers.length < nb) ) buffers = new haxe.ds.Vector(nb);
 	}
 
 }

+ 2 - 2
hxsl/AgalOut.hx

@@ -800,9 +800,9 @@ class AgalOut {
 		case TInt, TFloat, TVec(_), TBytes(_), TBool: 1;
 		case TMat3, TMat3x4: 3;
 		case TMat4: 4;
-		case TArray(t, SConst(size)): (Tools.size(t) * size + 3) >> 2;
+		case TArray(t, SConst(size)), TBuffer(t, SConst(size)): (Tools.size(t) * size + 3) >> 2;
 		case TStruct(vl): throw "TODO";
-		case TVoid, TString, TSampler2D, TSamplerCube, TFun(_), TArray(_), TChannel(_): throw "assert "+t;
+		case TVoid, TString, TSampler2D, TSamplerCube, TFun(_), TArray(_), TBuffer(_), TChannel(_): throw "assert "+t;
 		}
 	}
 

+ 4 - 2
hxsl/Ast.hx

@@ -16,6 +16,7 @@ enum Type {
 	TStruct( vl : Array<TVar> );
 	TFun( variants : Array<FunType> );
 	TArray( t : Type, size : SizeDecl );
+	TBuffer( t : Type, size : SizeDecl );
 	TChannel( size : Int );
 }
 
@@ -373,6 +374,7 @@ class Tools {
 			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): "buffer "+toString(t) + "[" + (switch( s ) { case SConst(i): "" + i; case SVar(v): v.name; } ) + "]";
 		case TBytes(n): "Bytes" + n;
 		default: t.getName().substr(1);
 		}
@@ -491,8 +493,8 @@ class Tools {
 		case TMat3x4: 12;
 		case TBytes(s): s;
 		case TBool, TString, TSampler2D, TSamplerCube, TFun(_): 0;
-		case TArray(t, SConst(v)): size(t) * v;
-		case TArray(_, SVar(_)): 0;
+		case TArray(t, SConst(v)), TBuffer(t, SConst(v)): size(t) * v;
+		case TArray(_, SVar(_)), TBuffer(_): 0;
 		}
 	}
 

+ 5 - 0
hxsl/Cache.hx

@@ -367,6 +367,9 @@ class Cache {
 				case TArray(TVec(4, VFloat), SConst(size)):
 					c.params = out[0];
 					c.paramsSize = size;
+				case TArray(TBuffer(_), _):
+					c.buffers = out[0];
+					c.bufferCount = out.length;
 				default: throw "assert";
 				}
 			case Global:
@@ -391,6 +394,8 @@ class Cache {
 			c.textures2DCount = 0;
 		if( c.texturesCube == null )
 			c.texturesCubeCount = 0;
+		if( c.buffers == null )
+			c.bufferCount = 0;
 		c.data = data;
 		return c;
 	}

+ 1 - 1
hxsl/Checker.hx

@@ -532,7 +532,7 @@ class Checker {
 			default: unify(e2.t, TInt, e2.p);
 			}
 			switch( e1.t ) {
-			case TArray(t, size):
+			case TArray(t, size), TBuffer(t,size):
 				switch( [size, e2.e] ) {
 				case [SConst(v), TConst(CInt(i))] if( i >= v ):
 					error("Indexing outside array bounds", e.pos);

+ 21 - 1
hxsl/Flatten.hx

@@ -80,6 +80,7 @@ class Flatten {
 		pack(prefix + "Params", Param, params, VFloat);
 		var allVars = globals.concat(params);
 		var textures = packTextures(prefix + "Textures", allVars, TSampler2D).concat(packTextures(prefix+"TexturesCube", allVars, TSamplerCube));
+		packBuffers(allVars);
 		var funs = [for( f in s.funs ) mapFun(f, mapExpr)];
 		for( t in textures )
 			t.pos >>= 2;
@@ -359,6 +360,25 @@ class Flatten {
 		return alloc;
 	}
 
+	function packBuffers( vars : Array<TVar> ) {
+		var alloc = new Array<Alloc>();
+		var g : TVar = {
+			id : Tools.allocVarId(),
+			name : "buffers",
+			type : TVoid,
+			kind : Param,
+		};
+		for( v in vars )
+			if( v.type.match(TBuffer(_)) ) {
+				var a = new Alloc(g, null, alloc.length, 1);
+				a.v = v;
+				alloc.push(a);
+				outVars.push(v);
+			}
+		g.type = TArray(TBuffer(TVoid,SConst(0)),SConst(alloc.length));
+		allocData.set(g, alloc);
+	}
+
 	function pack( name : String, kind : VarKind, vars : Array<TVar>, t : VecType ) {
 		var alloc = new Array<Alloc>(), apos = 0;
 		var g : TVar = {
@@ -369,7 +389,7 @@ class Flatten {
 		};
 		for( v in vars ) {
 			switch( v.type ) {
-			case TSampler2D, TSamplerCube, TChannel(_):
+			case TSampler2D, TSamplerCube, TChannel(_), TBuffer(_):
 				continue;
 			default:
 			}

+ 13 - 0
hxsl/GlslOut.hx

@@ -44,6 +44,7 @@ class GlslOut {
 	var intelDriverFix : Bool;
 	var isES(get,never) : Bool;
 	var isES2(get,never) : Bool;
+	var uniformBuffer : Int = 0;
 	public var varNames : Map<Int,String>;
 	public var flipY : Bool;
 	public var glES : Null<Float>;
@@ -130,6 +131,8 @@ class GlslOut {
 				add(v);
 			}
 			add("]");
+		case TBuffer(_):
+			throw "assert";
 		case TChannel(n):
 			add("channel" + n);
 		}
@@ -149,6 +152,13 @@ class GlslOut {
 			case SConst(n): add(n);
 			}
 			add("]");
+		case TBuffer(t, size):
+			add("uniform_buffer"+(uniformBuffer++));
+			add(" { ");
+			v.type = TArray(t,size);
+			addVar(v);
+			v.type = TBuffer(t,size);
+			add("; }");
 		default:
 			addType(v.type);
 			add(" ");
@@ -541,10 +551,13 @@ class GlslOut {
 		isVertex = f.kind == Vertex;
 
 		var outIndex = 0;
+		uniformBuffer = 0;
 		outIndexes = new Map();
 		for( v in s.vars ) {
 			switch( v.kind ) {
 			case Param, Global:
+				if( v.type.match(TBuffer(_)) )
+					add("layout(std140) ");
 				add("uniform ");
 			case Input:
 				add( isES2 ? "attribute " : "in ");

+ 15 - 2
hxsl/HlslOut.hx

@@ -104,7 +104,7 @@ class HlslOut {
 			add(" }");
 		case TFun(_):
 			add("function");
-		case TArray(t, size):
+		case TArray(t, size), TBuffer(t,size):
 			addType(t);
 			add("[");
 			switch( size ) {
@@ -130,7 +130,7 @@ class HlslOut {
 
 	function addVar( v : TVar ) {
 		switch( v.type ) {
-		case TArray(t, size):
+		case TArray(t, size), TBuffer(t,size):
 			var old = v.type;
 			v.type = t;
 			addVar(v);
@@ -548,6 +548,7 @@ class HlslOut {
 
 	function initParams( s : ShaderData ) {
 		var textures = [];
+		var buffers = [];
 		add("cbuffer _params : register(b1) {\n");
 		for( v in s.vars )
 			if( v.kind == Param ) {
@@ -555,6 +556,9 @@ class HlslOut {
 				case TArray(t, _) if( t.isSampler() ):
 					textures.push(v);
 					continue;
+				case TBuffer(_):
+					buffers.push(v);
+					continue;
 				default:
 				}
 				add("\t");
@@ -563,6 +567,15 @@ class HlslOut {
 			}
 		add("};\n\n");
 
+		var bufCount = 0;
+		for( b in buffers ) {
+			add('cbuffer _buffer$bufCount : register(b${bufCount+2}) { ');
+			addVar(b);
+			add("; };\n");
+			bufCount++;
+		}
+		if( bufCount > 0 ) add("\n");
+
 		for( v in textures ) {
 			switch( v.type ) {
 			case TArray(t, size):

+ 2 - 2
hxsl/MacroParser.hx

@@ -88,7 +88,7 @@ class MacroParser {
 			case "Channel3": return TChannel(3);
 			case "Channel4": return TChannel(4);
 			}
-		case TPath( { pack : [], name : "Array", sub : null, params : [t, size] } ):
+		case TPath( { pack : [], name : name = ("Array"|"Buffer"), sub : null, params : [t, size] } ):
 			var t = switch( t ) {
 			case TPType(t): parseType(t, pos);
 			default: null;
@@ -102,7 +102,7 @@ class MacroParser {
 			default: null;
 			}
 			if( t != null && size != null )
-				return TArray(t, size);
+				return name == "Array" ? TArray(t, size) : TBuffer(t,size);
 		case TAnonymous(fl):
 			return TStruct([for( f in fl ) {
 				switch( f.kind ) {

+ 2 - 0
hxsl/Macros.hx

@@ -47,6 +47,8 @@ class Macros {
 			macro : hxsl.Types.ChannelTexture;
 		case TFun(_):
 			throw "assert";
+		case TBuffer(_):
+			macro : hxsl.Types.Buffer;
 		}
 	}
 

+ 2 - 0
hxsl/RuntimeShader.hx

@@ -55,6 +55,8 @@ class RuntimeShaderData {
 	public var textures2DCount : Int;
 	public var texturesCube : AllocParam;
 	public var texturesCubeCount : Int;
+	public var buffers : AllocParam;
+	public var bufferCount : Int;
 	public var consts : Array<Float>;
 	public function new() {
 	}

+ 1 - 0
hxsl/Types.hx

@@ -8,6 +8,7 @@ typedef Texture = h3d.mat.Texture;
 typedef Sampler2D = h3d.mat.Texture;
 typedef SamplerCube = h3d.mat.Texture;
 typedef ChannelTexture = h3d.mat.Texture;
+typedef Buffer = h3d.Buffer;
 
 class ChannelTools {
 	public static inline function isPackedFormat( c : ChannelTexture ) {

+ 11 - 0
samples/UniformBuffer.hx

@@ -0,0 +1,11 @@
+class UniformBuffer extends hxd.App {
+
+	override function init() {
+	}
+
+
+	static function main() {
+		new UniformBuffer();
+	}
+
+}