From e7a3ffdb54f12a18599c6b4414cdd8e910d380af Mon Sep 17 00:00:00 2001 From: Richard Stanway Date: Tue, 9 May 2023 03:43:19 +0200 Subject: [PATCH] libobs-d3d11: Implement shader cache Co-Authored-By: derrod --- UI/obs-app.cpp | 6 ++++ libobs-d3d11/d3d11-shader.cpp | 62 +++++++++++++++++++++++++++----- libobs-d3d11/d3d11-subsystem.cpp | 4 ++- libobs-d3d11/d3d11-subsystem.hpp | 4 +++ 4 files changed, 66 insertions(+), 10 deletions(-) diff --git a/UI/obs-app.cpp b/UI/obs-app.cpp index 77aabe005..6b2b9c9a3 100644 --- a/UI/obs-app.cpp +++ b/UI/obs-app.cpp @@ -567,6 +567,12 @@ static bool MakeUserDirs() return false; if (!do_mkdir(path)) return false; + + if (GetProgramDataPath(path, sizeof(path), "obs-studio/shader-cache") <= + 0) + return false; + if (!do_mkdir(path)) + return false; #endif #ifdef WHATSNEW_ENABLED diff --git a/libobs-d3d11/d3d11-shader.cpp b/libobs-d3d11/d3d11-shader.cpp index 2525aed22..f26b59106 100644 --- a/libobs-d3d11/d3d11-shader.cpp +++ b/libobs-d3d11/d3d11-shader.cpp @@ -21,6 +21,11 @@ #include #include #include +#include +#include + +#include +#include void gs_vertex_shader::GetBuffersExpected( const vector &inputs) @@ -200,24 +205,63 @@ void gs_shader::BuildConstantBuffer() gs_shader_set_default(¶ms[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, const char *target, ID3D10Blob **shader) { ComPtr errorsBlob; HRESULT hr; + char hashstr[20]; + if (!shaderString) 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 diff --git a/libobs-d3d11/d3d11-subsystem.cpp b/libobs-d3d11/d3d11-subsystem.cpp index 1c7d398e7..e2f9bd49a 100644 --- a/libobs-d3d11/d3d11-subsystem.cpp +++ b/libobs-d3d11/d3d11-subsystem.cpp @@ -294,12 +294,14 @@ void gs_device::InitCompiler() if (module) { d3dCompile = (pD3DCompile)GetProcAddress(module, "D3DCompile"); + d3dCreateBlob = (pD3DCreateBlob)GetProcAddress( + module, "D3DCreateBlob"); #ifdef DISASSEMBLE_SHADERS d3dDisassemble = (pD3DDisassemble)GetProcAddress( module, "D3DDisassemble"); #endif - if (d3dCompile) { + if (d3dCompile && d3dCreateBlob) { return; } diff --git a/libobs-d3d11/d3d11-subsystem.hpp b/libobs-d3d11/d3d11-subsystem.hpp index 3bd407bdb..ff99cdf49 100644 --- a/libobs-d3d11/d3d11-subsystem.hpp +++ b/libobs-d3d11/d3d11-subsystem.hpp @@ -38,6 +38,9 @@ // #define DISASSEMBLE_SHADERS +typedef HRESULT(WINAPI *pD3DCreateBlob)(_In_ SIZE_T Size, + _Out_ ID3DBlob **ppBlob); + struct shader_var; struct shader_sampler; struct gs_vertex_shader; @@ -1052,6 +1055,7 @@ struct gs_device { D3D11_PRIMITIVE_TOPOLOGY curToplogy; pD3DCompile d3dCompile = nullptr; + pD3DCreateBlob d3dCreateBlob = nullptr; #ifdef DISASSEMBLE_SHADERS pD3DDisassemble d3dDisassemble = nullptr; #endif