1
0
Эх сурвалжийг харах

libobs-d3d11: Implement shader cache

Co-Authored-By: derrod <[email protected]>
Richard Stanway 2 жил өмнө
parent
commit
e7a3ffdb54

+ 6 - 0
UI/obs-app.cpp

@@ -567,6 +567,12 @@ static bool MakeUserDirs()
 		return false;
 		return false;
 	if (!do_mkdir(path))
 	if (!do_mkdir(path))
 		return false;
 		return false;
+
+	if (GetProgramDataPath(path, sizeof(path), "obs-studio/shader-cache") <=
+	    0)
+		return false;
+	if (!do_mkdir(path))
+		return false;
 #endif
 #endif
 
 
 #ifdef WHATSNEW_ENABLED
 #ifdef WHATSNEW_ENABLED

+ 53 - 9
libobs-d3d11/d3d11-shader.cpp

@@ -21,6 +21,11 @@
 #include <graphics/vec3.h>
 #include <graphics/vec3.h>
 #include <graphics/matrix3.h>
 #include <graphics/matrix3.h>
 #include <graphics/matrix4.h>
 #include <graphics/matrix4.h>
+#include <util/platform.h>
+#include <util/util.hpp>
+
+#include <filesystem>
+#include <fstream>
 
 
 void gs_vertex_shader::GetBuffersExpected(
 void gs_vertex_shader::GetBuffersExpected(
 	const vector<D3D11_INPUT_ELEMENT_DESC> &inputs)
 	const vector<D3D11_INPUT_ELEMENT_DESC> &inputs)
@@ -200,24 +205,63 @@ void gs_shader::BuildConstantBuffer()
 		gs_shader_set_default(&params[i]);
 		gs_shader_set_default(&params[i]);
 }
 }
 
 
+static uint64_t fnv1a_hash(const char *str)
+{
+	const uint64_t FNV_OFFSET = 14695981039346656037ULL;
+	const uint64_t FNV_PRIME = 1099511628211ULL;
+	uint64_t hash = FNV_OFFSET;
+	while (*str) {
+		hash ^= (uint64_t)*str++;
+		hash *= FNV_PRIME;
+	}
+	return hash;
+}
+
 void gs_shader::Compile(const char *shaderString, const char *file,
 void gs_shader::Compile(const char *shaderString, const char *file,
 			const char *target, ID3D10Blob **shader)
 			const char *target, ID3D10Blob **shader)
 {
 {
 	ComPtr<ID3D10Blob> errorsBlob;
 	ComPtr<ID3D10Blob> errorsBlob;
 	HRESULT hr;
 	HRESULT hr;
 
 
+	char hashstr[20];
+
 	if (!shaderString)
 	if (!shaderString)
 		throw "No shader string specified";
 		throw "No shader string specified";
 
 
-	hr = device->d3dCompile(shaderString, strlen(shaderString), file, NULL,
-				NULL, "main", target,
-				D3D10_SHADER_OPTIMIZATION_LEVEL1, 0, shader,
-				errorsBlob.Assign());
-	if (FAILED(hr)) {
-		if (errorsBlob != NULL && errorsBlob->GetBufferSize())
-			throw ShaderError(errorsBlob, hr);
-		else
-			throw HRError("Failed to compile shader", hr);
+	uint64_t hash = fnv1a_hash(shaderString);
+	snprintf(hashstr, sizeof(hashstr), "%02llx", hash);
+
+	BPtr program_data =
+		os_get_program_data_path_ptr("obs-studio/shader-cache");
+	auto cachePath = filesystem::u8path(program_data.Get()) / hashstr;
+
+	std::fstream cacheFile;
+	if (filesystem::exists(cachePath) && !filesystem::is_empty(cachePath))
+		cacheFile.open(cachePath, ios::in | ios::binary | ios::ate);
+
+	if (cacheFile.is_open()) {
+		streampos len = cacheFile.tellg();
+		cacheFile.seekg(0, ios::beg);
+
+		device->d3dCreateBlob(len, shader);
+		cacheFile.read((char *)(*shader)->GetBufferPointer(), len);
+	} else {
+		hr = device->d3dCompile(shaderString, strlen(shaderString),
+					file, NULL, NULL, "main", target,
+					D3D10_SHADER_OPTIMIZATION_LEVEL3, 0,
+					shader, errorsBlob.Assign());
+		if (FAILED(hr)) {
+			if (errorsBlob != NULL && errorsBlob->GetBufferSize())
+				throw ShaderError(errorsBlob, hr);
+			else
+				throw HRError("Failed to compile shader", hr);
+		}
+
+		cacheFile.open(cachePath, ios::out | ios::binary);
+		if (cacheFile.is_open()) {
+			cacheFile.write((char *)(*shader)->GetBufferPointer(),
+					(*shader)->GetBufferSize());
+		}
 	}
 	}
 
 
 #ifdef DISASSEMBLE_SHADERS
 #ifdef DISASSEMBLE_SHADERS

+ 3 - 1
libobs-d3d11/d3d11-subsystem.cpp

@@ -294,12 +294,14 @@ void gs_device::InitCompiler()
 		if (module) {
 		if (module) {
 			d3dCompile = (pD3DCompile)GetProcAddress(module,
 			d3dCompile = (pD3DCompile)GetProcAddress(module,
 								 "D3DCompile");
 								 "D3DCompile");
+			d3dCreateBlob = (pD3DCreateBlob)GetProcAddress(
+				module, "D3DCreateBlob");
 
 
 #ifdef DISASSEMBLE_SHADERS
 #ifdef DISASSEMBLE_SHADERS
 			d3dDisassemble = (pD3DDisassemble)GetProcAddress(
 			d3dDisassemble = (pD3DDisassemble)GetProcAddress(
 				module, "D3DDisassemble");
 				module, "D3DDisassemble");
 #endif
 #endif
-			if (d3dCompile) {
+			if (d3dCompile && d3dCreateBlob) {
 				return;
 				return;
 			}
 			}
 
 

+ 4 - 0
libobs-d3d11/d3d11-subsystem.hpp

@@ -38,6 +38,9 @@
 
 
 // #define DISASSEMBLE_SHADERS
 // #define DISASSEMBLE_SHADERS
 
 
+typedef HRESULT(WINAPI *pD3DCreateBlob)(_In_ SIZE_T Size,
+					_Out_ ID3DBlob **ppBlob);
+
 struct shader_var;
 struct shader_var;
 struct shader_sampler;
 struct shader_sampler;
 struct gs_vertex_shader;
 struct gs_vertex_shader;
@@ -1052,6 +1055,7 @@ struct gs_device {
 	D3D11_PRIMITIVE_TOPOLOGY curToplogy;
 	D3D11_PRIMITIVE_TOPOLOGY curToplogy;
 
 
 	pD3DCompile d3dCompile = nullptr;
 	pD3DCompile d3dCompile = nullptr;
+	pD3DCreateBlob d3dCreateBlob = nullptr;
 #ifdef DISASSEMBLE_SHADERS
 #ifdef DISASSEMBLE_SHADERS
 	pD3DDisassemble d3dDisassemble = nullptr;
 	pD3DDisassemble d3dDisassemble = nullptr;
 #endif
 #endif