libobs-d3d11: Implement shader cache

Co-Authored-By: derrod <dennis@obsproject.com>
This commit is contained in:
Richard Stanway
2023-05-09 03:43:19 +02:00
committed by Lain
parent 2f9df1372d
commit e7a3ffdb54
4 changed files with 66 additions and 10 deletions
+6
View File
@@ -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
+53 -9
View File
@@ -21,6 +21,11 @@
#include <graphics/vec3.h>
#include <graphics/matrix3.h>
#include <graphics/matrix4.h>
#include <util/platform.h>
#include <util/util.hpp>
#include <filesystem>
#include <fstream>
void gs_vertex_shader::GetBuffersExpected(
const vector<D3D11_INPUT_ELEMENT_DESC> &inputs)
@@ -200,24 +205,63 @@ void gs_shader::BuildConstantBuffer()
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,
const char *target, ID3D10Blob **shader)
{
ComPtr<ID3D10Blob> 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
+3 -1
View File
@@ -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;
}
+4
View File
@@ -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