Bläddra i källkod

make DirectX source-to-binary shader cache common to all Drivers

Nicolas Cannasse 2 år sedan
förälder
incheckning
5d058556a2
3 ändrade filer med 124 tillägg och 69 borttagningar
  1. 5 69
      h3d/impl/DirectXDriver.hx
  2. 8 0
      h3d/impl/Driver.hx
  3. 111 0
      h3d/impl/ShaderCache.hx

+ 5 - 69
h3d/impl/DirectXDriver.hx

@@ -70,12 +70,6 @@ class DirectXDriver extends h3d.impl.Driver {
 	static inline var RECTS_ELTS = 4 * NTARGETS;
 	static inline var RECTS_ELTS = 4 * NTARGETS;
 	static inline var BLEND_FACTORS = NTARGETS;
 	static inline var BLEND_FACTORS = NTARGETS;
 
 
-	public static var CACHE_FILE : { input : String, output : String } = null;
-	var cacheFileData : Map<String,haxe.io.Bytes>;
-	#if debug_shader_cache
-	var cacheFileDebugData = new Map<String, String>();
-	#end
-
 	var driver : DriverInstance;
 	var driver : DriverInstance;
 	var shaders : Map<Int,CompiledShader>;
 	var shaders : Map<Int,CompiledShader>;
 
 
@@ -804,37 +798,8 @@ class DirectXDriver extends h3d.impl.Driver {
 			if( end >= 0 )
 			if( end >= 0 )
 				return haxe.crypto.Base64.decode(code.substr(bin + 6, end - bin - 6));
 				return haxe.crypto.Base64.decode(code.substr(bin + 6, end - bin - 6));
 		}
 		}
-		if( CACHE_FILE != null ) {
-			if( cacheFileData == null ) {
-				cacheFileData = new Map();
-				function loadCacheData( file : String ) {
-					var cache = new haxe.io.BytesInput(sys.io.File.getBytes(file));
-					while( cache.position < cache.length ) {
-						var len = cache.readInt32();
-						if( len < 0 || len > 4<<20 ) break;
-						var key = cache.readString(len);
-						if( key == "" ) break;
-						var len = cache.readInt32();
-						if( len < 0 || len > 4<<20 ) break;
-						var str = cache.readString(len);
-						cacheFileData.set(key,haxe.crypto.Base64.decode(str));
-						#if debug_shader_cache
-						var peek = @:privateAccess cache.b[cache.position];
-						if(peek != '\n'.code) {
-							cache.readByte(); // skip null marker
-							var len = cache.readInt32();
-							if( len < 0 || len > 4<<20 ) break;
-							var code = cache.readString(len);
-							cacheFileDebugData.set(key, code);
-						}
-						#end
-						cache.readByte(); // newline
-					}
-				}
-				try loadCacheData(CACHE_FILE.input) catch( e : Dynamic ) {};
-				if( CACHE_FILE.output != CACHE_FILE.input ) try loadCacheData(CACHE_FILE.output) catch( e : Dynamic ) {};
-			}
-			var bytes = cacheFileData.get(shaderVersion + haxe.crypto.Md5.encode(code));
+		if( shaderCache != null ) {
+			var bytes = shaderCache.resolveShaderBinary(code, shaderVersion);
 			if( bytes != null ) {
 			if( bytes != null ) {
 				var sh = vertex ? Driver.createVertexShader(bytes) : Driver.createPixelShader(bytes);
 				var sh = vertex ? Driver.createVertexShader(bytes) : Driver.createPixelShader(bytes);
 				// shader can't be compiled !
 				// shader can't be compiled !
@@ -869,7 +834,7 @@ class DirectXDriver extends h3d.impl.Driver {
 				});
 				});
 				throw "Shader compilation error " + err + "\n\nin\n\n" + shader.code;
 				throw "Shader compilation error " + err + "\n\nin\n\n" + shader.code;
 			}
 			}
-			if( cacheFileData == null )
+			if( shaderCache == null )
 				shader.code += addBinaryPayload(bytes);
 				shader.code += addBinaryPayload(bytes);
 		}
 		}
 		if( compileOnly )
 		if( compileOnly )
@@ -880,37 +845,8 @@ class DirectXDriver extends h3d.impl.Driver {
 			throw "Failed to create shader\n" + shader.code;
 			throw "Failed to create shader\n" + shader.code;
 		}
 		}
 
 
-		if( cacheFileData != null ) {
-			var key = shaderVersion + haxe.crypto.Md5.encode(shader.code);
-			if( cacheFileData.get(key) != bytes ) {
-				cacheFileData.set(key, bytes);
-				#if debug_shader_cache
-				cacheFileDebugData.set(key, shader.code.split('\n').join('\\n'));
-				#end
-				if( CACHE_FILE != null ) {
-					var out = new haxe.io.BytesOutput();
-					var keys = Lambda.array({ iterator : cacheFileData.keys });
-					keys.sort(Reflect.compare);
-					for( key in keys ) {
-						out.writeInt32(key.length);
-						out.writeString(key);
-						var b64 = haxe.crypto.Base64.encode(cacheFileData.get(key));
-						out.writeInt32(b64.length);
-						out.writeString(b64);
-						#if debug_shader_cache
-						var s = cacheFileDebugData.get(key);
-						if(s != null) {
-							out.writeByte(0);
-							out.writeInt32(s.length);
-							out.writeString(s);
-						}
-						#end
-						out.writeByte('\n'.code);
-					}
-					try sys.io.File.saveBytes(CACHE_FILE.output, out.getBytes()) catch( e : Dynamic ) {};
-				}
-			}
-		}
+		if( shaderCache != null )
+			shaderCache.saveCompiledShader(shader.code, bytes, shaderVersion);
 
 
 		var ctx = new ShaderContext(s);
 		var ctx = new ShaderContext(s);
 		ctx.globalsSize = shader.globalsSize;
 		ctx.globalsSize = shader.globalsSize;

+ 8 - 0
h3d/impl/Driver.hx

@@ -119,8 +119,16 @@ enum RenderFlag {
 
 
 class Driver {
 class Driver {
 
 
+	static var SHADER_CACHE : h3d.impl.ShaderCache;
+	var shaderCache = SHADER_CACHE;
+
+	public static function setShaderCache( cache : h3d.impl.ShaderCache ) {
+		SHADER_CACHE = cache;
+	}
+
 	public var logEnable : Bool;
 	public var logEnable : Bool;
 
 
+
 	public function hasFeature( f : Feature ) {
 	public function hasFeature( f : Feature ) {
 		return false;
 		return false;
 	}
 	}

+ 111 - 0
h3d/impl/ShaderCache.hx

@@ -0,0 +1,111 @@
+package h3d.impl;
+
+class ShaderCache {
+
+	var file : String;
+	var outputFile : String;
+	var data : Map<String, haxe.io.Bytes>;
+	var sources : Map<String, String>;
+	var sourceFile : String;
+	public var keepSource : Bool;
+
+	public function new( file : String, ?outputFile : String ) {
+		this.file = file;
+		this.outputFile = outputFile ?? file;
+		sourceFile = file + ".source";
+	}
+
+	function load() {
+		data = new Map();
+		try loadFile(file) catch( e : Dynamic ) {};
+		if( outputFile != file ) try loadFile(outputFile) catch( e : Dynamic ) {};
+		if( keepSource ) try loadSources() catch( e : Dynamic ) {};
+	}
+
+	function loadFile( file : String ) {
+		if( !sys.FileSystem.exists(file) )
+			return;
+		var cache = new haxe.io.BytesInput(sys.io.File.getBytes(file));
+		while( cache.position < cache.length ) {
+			var len = cache.readInt32();
+			if( len < 0 || len > 4<<20 ) break;
+			var key = cache.readString(len);
+			if( key == "" ) break;
+			var len = cache.readInt32();
+			if( len < 0 || len > 4<<20 ) break;
+			var str = cache.readString(len);
+			data.set(key,haxe.crypto.Base64.decode(str));
+			cache.readByte(); // newline
+		}
+	}
+
+	function loadSources() {
+		sources = new Map();
+		if( !sys.FileSystem.exists(sourceFile) )
+			return;
+		var cache = new haxe.io.BytesInput(sys.io.File.getBytes(sourceFile));
+		while( cache.position < cache.length ) {
+			var len = cache.readInt32();
+			if( len < 0 || len > 4<<20 ) break;
+			var key = cache.readString(len);
+			if( key == "" ) break;
+			var len = cache.readInt32();
+			if( len < 0 || len > 4<<20 ) break;
+			var str = cache.readString(len);
+			sources.set(key, str);
+			cache.readByte(); // newline
+			cache.readByte(); // newline
+		}
+	}
+
+	public function resolveShaderBinary( source : String, ?configurationKey = "" ) {
+		if( data == null ) load();
+		return data.get(configurationKey + haxe.crypto.Md5.encode(source));
+	}
+
+	public function saveCompiledShader( source : String, bytes : haxe.io.Bytes, ?configurationKey = "" ) {
+		if( outputFile == null )
+			return;
+		if( data == null ) load();
+		var key = configurationKey + haxe.crypto.Md5.encode(source);
+		if( data.get(key) == bytes && (!keepSource || sources.get(key) == source) )
+			return;
+		data.set(key, bytes);
+		save();
+		if( keepSource ) {
+			sources.set(key, source);
+			saveSources();
+		}
+	}
+
+	function save() {
+		var out = new haxe.io.BytesOutput();
+		var keys = Lambda.array({ iterator : data.keys });
+		keys.sort(Reflect.compare);
+		for( key in keys ) {
+			out.writeInt32(key.length);
+			out.writeString(key);
+			var b64 = haxe.crypto.Base64.encode(data.get(key));
+			out.writeInt32(b64.length);
+			out.writeString(b64);
+			out.writeByte('\n'.code);
+		}
+		try sys.io.File.saveBytes(outputFile, out.getBytes()) catch( e : Dynamic ) {};
+	}
+
+	function saveSources() {
+		var out = new haxe.io.BytesOutput();
+		var keys = Lambda.array({ iterator : sources.keys });
+		keys.sort(Reflect.compare);
+		for( key in keys ) {
+			out.writeInt32(key.length);
+			out.writeString(key);
+			var src = sources.get(key);
+			out.writeInt32(src.length);
+			out.writeString(src);
+			out.writeByte('\n'.code);
+			out.writeByte('\n'.code);
+		}
+		try sys.io.File.saveBytes(sourceFile, out.getBytes()) catch( e : Dynamic ) {};
+	}
+}