Selaa lähdekoodia

hl vulkan driver wip

Nicolas Cannasse 4 vuotta sitten
vanhempi
commit
93b34e0597
2 muutettua tiedostoa jossa 215 lisäystä ja 18 poistoa
  1. 175 11
      h3d/impl/VulkanDriver.hx
  2. 40 7
      hxsl/GlslOut.hx

+ 175 - 11
h3d/impl/VulkanDriver.hx

@@ -1,16 +1,63 @@
 package h3d.impl;
 import h3d.impl.Driver;
+import sdl.Vulkan;
+
+class CompiledShader {
+	public var shader : hxsl.RuntimeShader;
+	public var vertex : VkShaderModule;
+	public var fragment : VkShaderModule;
+	public var stages : ArrayStruct<VkPipelineShaderStage>;
+	public var input : VkPipelineVertexInput;
+	public var inputID : InputNames;
+	public function new(shader) {
+		this.shader = shader;
+	}
+}
 
 #if (hlsdl && heaps_vulkan)
 
 class VulkanDriver extends Driver {
 
-	var ctx : sdl.Vulkan.VKContext;
-	var cur : hxsl.RuntimeShader;
+	var ctx : VKContext;
+	var currentShader : CompiledShader;
+	var programs : Map<Int,CompiledShader> = new Map();
+	var defaultInput : VkPipelineInputAssembly;
+	var defaultViewport : VkPipelineViewport;
+	var defaultMultisample : VkPipelineMultisample;
+	var defaultLayout : VkPipelineLayout;
 
 	public function new() {
-		ctx = @:privateAccess hxd.Window.getInstance().window.vkctx;
+		var win = hxd.Window.getInstance();
+		ctx = @:privateAccess win.window.vkctx;
+		ctx.setCurrent();
+		initViewport(win.width, win.height);
 		if( !ctx.beginFrame() ) throw "assert";
+		defaultInput = new VkPipelineInputAssembly();
+		defaultInput.topology = TRIANGLE_LIST;
+		defaultMultisample = new VkPipelineMultisample();
+		defaultMultisample.rasterizationSamples = 1;
+
+		var inf = new VkPipelineLayoutInfo();
+		defaultLayout = ctx.createPipelineLayout(inf);
+	}
+
+	function initViewport(width:Int,height:Int) {
+		var vp = new VkPipelineViewport();
+
+		var vdef = new VkViewport();
+		vdef.width = width;
+		vdef.height = height;
+		vdef.maxDepth = 1;
+		vp.viewportCount = 1;
+		vp.viewports = makeArray([vdef]);
+
+		var sdef = new VkRect2D();
+		sdef.extendX = width;
+		sdef.extendY = height;
+		vp.scissorCount = 1;
+		vp.scissors = makeArray([sdef]);
+
+		defaultViewport = vp;
 	}
 
 	override function hasFeature( f : Feature ) {
@@ -41,7 +88,9 @@ class VulkanDriver extends Driver {
 		ctx.endFrame();
 		if( !ctx.beginFrame() ) {
 			var win = hxd.Window.getInstance();
-			ctx.initSwapchain(win.width, win.height);
+			if( !ctx.initSwapchain(win.width, win.height) )
+				throw "assert";
+			initViewport(win.width, win.height);
 			if( !ctx.beginFrame() )
 				throw "assert";
 		}
@@ -52,21 +101,98 @@ class VulkanDriver extends Driver {
 	}
 
 	override function selectShader( shader : hxsl.RuntimeShader ) {
-		if( cur == shader ) return false;
-		cur = shader;
+		if( currentShader != null && currentShader.shader == shader )
+			return false;
+		var p = programs.get(shader.id);
+		if( p == null ) {
+			p = compileShader(shader);
+			programs.set(shader.id, p);
+		}
+		currentShader = p;
 		return true;
 	}
 
-	override function getShaderInputNames() : InputNames {
+	static var STAGE_NAME = @:privateAccess "main".toUtf8();
+
+	function compile( shader : hxsl.RuntimeShader.RuntimeShaderData ) {
+		var out = new hxsl.GlslOut();
+		out.version = 450;
+		out.isVulkan = true;
+		var source = out.run(shader.data);
+		var bytes = sdl.Vulkan.compileShader(source, "", "main", shader.vertex ? Vertex : Fragment);
+		var mod = ctx.createShaderModule(bytes, bytes.length);
+		if( mod == null ) throw "assert";
+		return mod;
+	}
+
+	/**
+		/!\ Warning : this function converts an array of struct pointers into a single
+		block aligned struct array. All references inside this block are not scanned so
+		it's important to keep any pointer that is referenced by this data
+	**/
+	@:generic static inline function makeArray<T>( a : Array<T> ) {
+		var n = new hl.NativeArray<T>(a.length);
+		for( i in 0...a.length )
+			n[i] = a[i];
+		return Vulkan.makeArray(n);
+	}
+
+	function compileShader( shader : hxsl.RuntimeShader ) {
+		var c = new CompiledShader(shader);
+		c.vertex = compile(shader.vertex);
+		c.fragment = compile(shader.fragment);
+		inline function makeStage(module,t) {
+			var stage = new VkPipelineShaderStage();
+			stage.module = module;
+			stage.name = STAGE_NAME;
+			stage.stage.set(t);
+			return stage;
+		}
+		c.stages = makeArray([makeStage(c.vertex,VERTEX_BIT), makeStage(c.fragment,FRAGMENT_BIT)]);
+
+		var attribs = [], position = 0;
 		var names = [];
-		for( v in cur.vertex.data.vars )
-			if( v.kind == Input )
+		for( v in shader.vertex.data.vars )
+			if( v.kind == Input ) {
 				names.push(v.name);
-		return InputNames.get(names);
+				var a = new VkVertexInputAttributeDescription();
+				a.binding = attribs.length;
+				a.offset = position;
+				a.format = switch( v.type ) {
+				case TFloat: position++; R32_SFLOAT;
+				case TVec(2, t): position += 2; R32G32_SFLOAT;
+				case TVec(3, t): position += 3; R32G32B32_SFLOAT;
+				case TVec(4, t): position += 4; R32G32B32A32_SFLOAT;
+				default: throw "assert";
+				}
+				attribs.push(a);
+			}
+
+		var vin = new VkPipelineVertexInput();
+		vin.vertexAttributeDescriptionCount = attribs.length;
+		vin.vertexAttributeDescriptions = makeArray(attribs);
+		var bindings = [for( i in 0...attribs.length ) {
+			var b = new VkVertexInputBindingDescription();
+			b.binding = i;
+			b.inputRate = VERTEX;
+			b.stride = position;
+			b;
+		}];
+		vin.vertexBindingDescriptionCount = bindings.length;
+		vin.vertexBindingDescriptions = makeArray(bindings);
+
+		c.input = vin;
+		c.inputID = InputNames.get(names);
+
+		return c;
+	}
+
+	override function getShaderInputNames() : InputNames {
+		return currentShader.inputID;
 	}
 
 	override function begin(frame:Int) {
-		sdl.Vulkan.clearColorImage(0, Math.random(), 0, 1);
+		sdl.Vulkan.clearColorImage(0, 0.5, 0, 1);
 	}
 
 	override function allocTexture( t : h3d.mat.Texture ) : Texture {
@@ -81,6 +207,44 @@ class VulkanDriver extends Driver {
 		return cast {};
 	}
 
+	override function selectMaterial( pass : h3d.mat.Pass ) {
+		var inf = new VkGraphicsPipelineInfo();
+
+		inf.stageCount = 2;
+		inf.stages = currentShader.stages;
+		inf.vertexInput = currentShader.input;
+		inf.inputAssembly = defaultInput;
+		inf.viewport = defaultViewport;
+
+		var raster = new VkPipelineRasterization();
+		raster.rasterizerDiscardEnable = true;
+		raster.polygonMode = pass.wireframe	? LINE : FILL;
+		raster.cullMode = CULLING[pass.culling.getIndex()];
+		raster.lineWidth = 1;
+		inf.rasterization = raster;
+
+		inf.multisample = defaultMultisample;
+
+		var stencil = new VkPipelineDepthStencil();
+		stencil.depthTestEnable = pass.depthTest != Always;
+		stencil.depthWriteEnable = pass.depthWrite;
+		stencil.depthCompareOp = COMPARE[pass.depthTest.getIndex()];
+		inf.depthStencil = stencil;
+
+		var blend = new VkPipelineColorBlend();
+		inf.colorBlend = blend;
+
+
+		inf.layout = defaultLayout;
+		//inf.renderPass = new VkRenderPass();
+
+		var pipe = ctx.createGraphicsPipeline(inf);
+		if( pipe == null ) throw "Failed to create pipeline";
+	}
+
+	static var CULLING : Array<VkCullModeFlags> = [NONE, BACK, FRONT, FRONT_AND_BACK];
+	static var COMPARE : Array<VkCompareOp> = [ALWAYS, NEVER, EQUAL, NOT_EQUAL, GREATER, GREATER_OR_EQUAL, LESS, LESS_OR_EQUAL];
+
 }
 
 #end

+ 40 - 7
hxsl/GlslOut.hx

@@ -54,9 +54,11 @@ class GlslOut {
 	var isES2(get,never) : Bool;
 	var uniformBuffer : Int = 0;
 	var outIndex : Int = 0;
+	var inputIndex : Int = 0;
 	public var varNames : Map<Int,String>;
 	public var glES : Null<Float>;
 	public var version : Null<Int>;
+	public var isVulkan : Bool;
 
 	/*
 		Intel HD driver fix:
@@ -598,10 +600,14 @@ class GlslOut {
 	function initVar( v : TVar ){
 		switch( v.kind ) {
 		case Param, Global:
-			if( v.type.match(TBuffer(_)) )
-				add("layout(std140) ");
-			add("uniform ");
+			if( !isVulkan ) {
+				if( v.type.match(TBuffer(_)) )
+					add("layout(std140) ");
+				add("uniform ");
+			}
 		case Input:
+			if( isVulkan )
+				add('layout(location=${inputIndex++}) ');
 			add( isES2 ? "attribute " : "in ");
 		case Var:
 			add( isES2 ? "varying " : (isVertex ? "out " : "in "));
@@ -611,7 +617,7 @@ class GlslOut {
 				return;
 			}
 			if( isVertex ) return;
-			if( isES )
+			if( isES || isVulkan )
 				add('layout(location=${outIndex++}) ');
 			add("out ");
 		case Function:
@@ -635,10 +641,37 @@ class GlslOut {
 
 	function initVars( s : ShaderData ){
 		outIndex = 0;
+		inputIndex = 0;
 		uniformBuffer = 0;
 		outIndexes = new Map();
-		for( v in s.vars )
-			initVar(v);
+		if( isVulkan ) {
+			var params = [], globals = [];
+			for( v in s.vars )
+				switch( v.kind ) {
+				case Param: params.push(v);
+				case Global: globals.push(v);
+				default: initVar(v);
+				}
+			if( params.length > 0 ) {
+				add("layout(binding=0) uniform _Parameters_ {\n");
+				for( v in params ) {
+					add("\t");
+					initVar(v);
+				}
+				add("};\n");
+			}
+			if( globals.length > 0 ) {
+				add("layout(binding=1) uniform _Globals_ {\n");
+				for( v in globals ) {
+					add("\t");
+					initVar(v);
+				}
+				add("};\n");
+			}
+		} else {
+			for( v in s.vars )
+				initVar(v);
+		}
 		add("\n");
 
 		if( outIndex < 2 )
@@ -702,7 +735,7 @@ class GlslOut {
 		if( isES )
 			decl("#version " + (version < 100 ? 100 : version) + (version > 150 ? " es" : ""));
 		else if( version != null )
-			decl("#version " + (version > 150 ? 150 : version));
+			decl("#version " + (version > 150 && !isVulkan ? 150 : version));
 		else
 			decl("#version 130"); // OpenGL 3.0