From 986b5a2afe7d83a5354b0212c17ae69ddb0343b7 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sun, 9 Jan 2022 18:23:36 +1000 Subject: [PATCH] GS/DX11: Use shader cache --- pcsx2/GS/Renderers/DX11/GSDevice11.cpp | 233 ++++++++-------------- pcsx2/GS/Renderers/DX11/GSDevice11.h | 23 +-- pcsx2/GS/Renderers/DX11/GSTextureFX11.cpp | 16 +- 3 files changed, 92 insertions(+), 180 deletions(-) diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp index 7e5c95844a..63e79307b9 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp @@ -22,6 +22,7 @@ #include "GS/GSUtil.h" #include "Host.h" #include "HostDisplay.h" +#include "common/StringUtil.h" #include #include #include @@ -45,41 +46,6 @@ GSDevice11::GSDevice11() m_features.prefer_new_textures = false; } -bool GSDevice11::SetFeatureLevel(D3D_FEATURE_LEVEL level, bool compat_mode) -{ - m_shader.level = level; - - switch (level) - { - case D3D_FEATURE_LEVEL_10_0: - m_shader.model = "0x400"; - m_shader.vs = "vs_4_0"; - m_shader.gs = "gs_4_0"; - m_shader.ps = "ps_4_0"; - m_shader.cs = "cs_4_0"; - break; - case D3D_FEATURE_LEVEL_10_1: - m_shader.model = "0x401"; - m_shader.vs = "vs_4_1"; - m_shader.gs = "gs_4_1"; - m_shader.ps = "ps_4_1"; - m_shader.cs = "cs_4_1"; - break; - case D3D_FEATURE_LEVEL_11_0: - m_shader.model = "0x500"; - m_shader.vs = "vs_5_0"; - m_shader.gs = "gs_5_0"; - m_shader.ps = "ps_5_0"; - m_shader.cs = "cs_5_0"; - break; - default: - ASSERT(0); - return false; - } - - return true; -} - bool GSDevice11::Create(HostDisplay* display) { if (!__super::Create(display)) @@ -118,8 +84,19 @@ bool GSDevice11::Create(HostDisplay* display) } } - if (!SetFeatureLevel(m_dev->GetFeatureLevel(), true)) - return false; + if (!GSConfig.DisableShaderCache) + { + if (!m_shader_cache.Open(StringUtil::wxStringToUTF8String(EmuFolders::Cache.ToString()), + m_dev->GetFeatureLevel(), SHADER_VERSION, GSConfig.UseDebugDevice)) + { + Console.Warning("Shader cache failed to open."); + } + } + else + { + m_shader_cache.Open({}, m_dev->GetFeatureLevel(), SHADER_VERSION, GSConfig.UseDebugDevice); + Console.WriteLn("Not using shader cache."); + } // Set maximum texture size limit based on supported feature level. if (level >= D3D_FEATURE_LEVEL_11_0) @@ -152,21 +129,27 @@ bool GSDevice11::Create(HostDisplay* display) {"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0}, }; - ShaderMacro sm_model(m_shader.model); + ShaderMacro sm_model(m_shader_cache.GetFeatureLevel()); shader = Host::ReadResourceFileToString("shaders/dx11/convert.fx"); if (!shader.has_value()) return false; - CreateShader(*shader, "convert.fx", nullptr, "vs_main", sm_model.GetPtr(), &m_convert.vs, il_convert, std::size(il_convert), m_convert.il.put()); + if (!m_shader_cache.GetVertexShaderAndInputLayout(m_dev.get(), m_convert.vs.put(), m_convert.il.put(), + il_convert, std::size(il_convert), *shader, sm_model.GetPtr(), "vs_main")) + { + return false; + } - ShaderMacro sm_convert(m_shader.model); + ShaderMacro sm_convert(m_shader_cache.GetFeatureLevel()); sm_convert.AddMacro("PS_SCALE_FACTOR", std::max(1, m_upscale_multiplier)); D3D_SHADER_MACRO* sm_convert_ptr = sm_convert.GetPtr(); for (size_t i = 0; i < std::size(m_convert.ps); i++) { - CreateShader(*shader, "convert.fx", nullptr, shaderName(static_cast(i)), sm_convert_ptr, m_convert.ps[i].put()); + m_convert.ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *shader, sm_convert_ptr, shaderName(static_cast(i))); + if (!m_convert.ps[i]) + return false; } memset(&dsd, 0, sizeof(dsd)); @@ -201,7 +184,10 @@ bool GSDevice11::Create(HostDisplay* display) for (size_t i = 0; i < std::size(m_merge.ps); i++) { - CreateShader(*shader, "merge.fx", nullptr, format("ps_main%d", i).c_str(), sm_model.GetPtr(), m_merge.ps[i].put()); + const std::string entry_point(StringUtil::StdStringFromFormat("ps_main%d", i)); + m_merge.ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *shader, sm_model.GetPtr(), entry_point.c_str()); + if (!m_merge.ps[i]) + return false; } memset(&bsd, 0, sizeof(bsd)); @@ -232,12 +218,15 @@ bool GSDevice11::Create(HostDisplay* display) return false; for (size_t i = 0; i < std::size(m_interlace.ps); i++) { - CreateShader(*shader, "interlace.fx", nullptr, format("ps_main%d", i).c_str(), sm_model.GetPtr(), m_interlace.ps[i].put()); + const std::string entry_point(StringUtil::StdStringFromFormat("ps_main%d", i)); + m_interlace.ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *shader, sm_model.GetPtr(), entry_point.c_str()); + if (!m_interlace.ps[i]) + return false; } // Shade Boost - ShaderMacro sm_sboost(m_shader.model); + ShaderMacro sm_sboost(m_shader_cache.GetFeatureLevel()); sm_sboost.AddMacro("SB_CONTRAST", std::clamp(theApp.GetConfigI("ShadeBoost_Contrast"), 0, 100)); sm_sboost.AddMacro("SB_BRIGHTNESS", std::clamp(theApp.GetConfigI("ShadeBoost_Brightness"), 0, 100)); @@ -254,7 +243,9 @@ bool GSDevice11::Create(HostDisplay* display) shader = Host::ReadResourceFileToString("shaders/dx11/shadeboost.fx"); if (!shader.has_value()) return false; - CreateShader(*shader, "shadeboost.fx", nullptr, "ps_main", sm_sboost.GetPtr(), m_shadeboost.ps.put()); + m_shadeboost.ps = m_shader_cache.GetPixelShader(m_dev.get(), *shader, sm_sboost.GetPtr(), "ps_main"); + if (!m_shadeboost.ps) + return false; // External fx shader @@ -802,34 +793,31 @@ void GSDevice11::DoExternalFX(GSTexture* sTex, GSTexture* dTex) ExternalFXConstantBuffer cb; - if (m_shaderfx.ps == nullptr) + if (!m_shaderfx.ps) { - try + std::string config_name(theApp.GetConfigS("shaderfx_conf")); + std::ifstream fconfig(config_name); + std::stringstream shader; + if (fconfig.good()) + shader << fconfig.rdbuf() << "\n"; + else + fprintf(stderr, "GS: External shader config '%s' not loaded.\n", config_name.c_str()); + + std::string shader_name(theApp.GetConfigS("shaderfx_glsl")); + std::ifstream fshader(shader_name); + if (!fshader.good()) { - std::string config_name(theApp.GetConfigS("shaderfx_conf")); - std::ifstream fconfig(config_name); - std::stringstream shader; - if (fconfig.good()) - shader << fconfig.rdbuf() << "\n"; - else - fprintf(stderr, "GS: External shader config '%s' not loaded.\n", config_name.c_str()); - - std::string shader_name(theApp.GetConfigS("shaderfx_glsl")); - std::ifstream fshader(shader_name); - if (!fshader.good()) - { - fprintf(stderr, "GS: External shader '%s' not loaded and will be disabled!\n", shader_name.c_str()); - return; - } - - shader << fshader.rdbuf(); - const std::string& s = shader.str(); - ShaderMacro sm(m_shader.model); - CreateShader(s, shader_name.c_str(), D3D_COMPILE_STANDARD_FILE_INCLUDE, "ps_main", sm.GetPtr(), m_shaderfx.ps.put()); + fprintf(stderr, "GS: External shader '%s' not loaded and will be disabled!\n", shader_name.c_str()); + return; } - catch (GSRecoverableError) + + shader << fshader.rdbuf(); + ShaderMacro sm(m_shader_cache.GetFeatureLevel()); + m_shaderfx.ps = m_shader_cache.GetPixelShader(m_dev.get(), shader.str(), sm.GetPtr(), "ps_main"); + if (!m_shaderfx.ps) { printf("GS: Failed to compile external post-processing shader.\n"); + return; } } @@ -851,19 +839,17 @@ void GSDevice11::DoFXAA(GSTexture* sTex, GSTexture* dTex) if (!m_fxaa_ps) { - try + std::optional shader = Host::ReadResourceFileToString("shaders/common/fxaa.fx"); + if (!shader.has_value()) { - std::optional shader = Host::ReadResourceFileToString("shaders/common/fxaa.fx"); - if (shader.has_value()) - { - ShaderMacro sm(m_shader.model); - CreateShader(*shader, "fxaa.fx", nullptr, "ps_main", sm.GetPtr(), m_fxaa_ps.put()); - } - } - catch (GSRecoverableError) - { - printf("GS: Failed to compile fxaa shader.\n"); + Console.Error("FXAA shader is missing"); + return; } + + ShaderMacro sm(m_shader_cache.GetFeatureLevel()); + m_fxaa_ps = m_shader_cache.GetPixelShader(m_dev.get(), *shader, sm.GetPtr(), "ps_main"); + if (!m_fxaa_ps) + return; } StretchRect(sTex, sRect, dTex, dRect, m_fxaa_ps.get(), nullptr, true); @@ -1271,9 +1257,21 @@ void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector } } -GSDevice11::ShaderMacro::ShaderMacro(std::string& smodel) +GSDevice11::ShaderMacro::ShaderMacro(D3D_FEATURE_LEVEL fl) { - mlist.emplace_back("SHADER_MODEL", smodel); + switch (fl) + { + case D3D_FEATURE_LEVEL_10_0: + mlist.emplace_back("SHADER_MODEL", "0x400"); + break; + case D3D_FEATURE_LEVEL_10_1: + mlist.emplace_back("SHADER_MODEL", "0x401"); + break; + case D3D_FEATURE_LEVEL_11_0: + default: + mlist.emplace_back("SHADER_MODEL", "0x500"); + break; + } } void GSDevice11::ShaderMacro::AddMacro(const char* n, int d) @@ -1292,79 +1290,6 @@ D3D_SHADER_MACRO* GSDevice11::ShaderMacro::GetPtr(void) return (D3D_SHADER_MACRO*)mout.data(); } -void GSDevice11::CreateShader(const std::string& source, const char* fn, ID3DInclude* include, const char* entry, D3D_SHADER_MACRO* macro, ID3D11VertexShader** vs, D3D11_INPUT_ELEMENT_DESC* layout, int count, ID3D11InputLayout** il) -{ - HRESULT hr; - - wil::com_ptr_nothrow shader; - - CompileShader(source, fn, include, entry, macro, shader.put(), m_shader.vs); - - hr = m_dev->CreateVertexShader(shader->GetBufferPointer(), shader->GetBufferSize(), nullptr, vs); - - if (FAILED(hr)) - { - throw GSRecoverableError(); - } - - hr = m_dev->CreateInputLayout(layout, count, shader->GetBufferPointer(), shader->GetBufferSize(), il); - - if (FAILED(hr)) - { - throw GSRecoverableError(); - } -} - -void GSDevice11::CreateShader(const std::string& source, const char* fn, ID3DInclude* include, const char* entry, D3D_SHADER_MACRO* macro, ID3D11GeometryShader** gs) -{ - wil::com_ptr_nothrow shader; - - CompileShader(source, fn, include, entry, macro, shader.put(), m_shader.gs); - - HRESULT hr = m_dev->CreateGeometryShader(shader->GetBufferPointer(), shader->GetBufferSize(), nullptr, gs); - - if (FAILED(hr)) - { - throw GSRecoverableError(); - } -} - -void GSDevice11::CreateShader(const std::string& source, const char* fn, ID3DInclude* include, const char* entry, D3D_SHADER_MACRO* macro, ID3D11PixelShader** ps) -{ - wil::com_ptr_nothrow shader; - - CompileShader(source, fn, include, entry, macro, shader.put(), m_shader.ps); - - HRESULT hr = m_dev->CreatePixelShader(shader->GetBufferPointer(), shader->GetBufferSize(), nullptr, ps); - - if (FAILED(hr)) - { - throw GSRecoverableError(); - } -} - -void GSDevice11::CompileShader(const std::string& source, const char* fn, ID3DInclude* include, const char* entry, D3D_SHADER_MACRO* macro, ID3DBlob** shader, const std::string& shader_model) -{ - wil::com_ptr_nothrow error; - - UINT flags = 0; - -#ifdef _DEBUG - flags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION | D3DCOMPILE_AVOID_FLOW_CONTROL; -#endif - - const HRESULT hr = D3DCompile( - source.c_str(), source.size(), fn, macro, - include, entry, shader_model.c_str(), - flags, 0, shader, error.put()); - - if (error) - fprintf(stderr, "%s\n", (const char*)error->GetBufferPointer()); - - if (FAILED(hr)) - throw GSRecoverableError(); -} - static GSDevice11::OMBlendSelector convertSel(GSHWDrawConfig::ColorMaskSelector cm, GSHWDrawConfig::BlendState blend) { GSDevice11::OMBlendSelector out; diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.h b/pcsx2/GS/Renderers/DX11/GSDevice11.h index da213eee55..f8c4253563 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.h +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.h @@ -18,6 +18,7 @@ #include "GSTexture11.h" #include "GS/GSVector.h" #include "GS/Renderers/Common/GSDevice.h" +#include "common/D3D11/ShaderCache.h" #include #include #include @@ -101,12 +102,15 @@ public: std::vector mout; public: - ShaderMacro(std::string& smodel); + ShaderMacro(D3D_FEATURE_LEVEL fl); void AddMacro(const char* n, int d); D3D_SHADER_MACRO* GetPtr(void); }; private: + // Increment this constant whenever shaders change, to invalidate user's shader cache. + static constexpr u32 SHADER_VERSION = 1; + float m_hack_topleft_offset; int m_upscale_multiplier; int m_d3d_texsize; @@ -222,15 +226,9 @@ private: std::unique_ptr m_download_tex; + D3D11::ShaderCache m_shader_cache; std::string m_tfx_source; -protected: - struct - { - D3D_FEATURE_LEVEL level; - std::string model, vs, gs, ps, cs; - } m_shader; - public: GSDevice11(); virtual ~GSDevice11() {} @@ -239,9 +237,6 @@ public: __fi ID3D11Device* GetD3DDevice() const { return m_dev.get(); } __fi ID3D11DeviceContext* GetD3DContext() const { return m_ctx.get(); } - bool SetFeatureLevel(D3D_FEATURE_LEVEL level, bool compat_mode); - void GetFeatureLevel(D3D_FEATURE_LEVEL& level) const { level = m_shader.level; } - bool Create(HostDisplay* display); void ResetAPIState() override; @@ -306,10 +301,4 @@ public: ID3D11Device* operator->() { return m_dev.get(); } operator ID3D11Device*() { return m_dev.get(); } operator ID3D11DeviceContext*() { return m_ctx.get(); } - - void CreateShader(const std::string& source, const char* fn, ID3DInclude* include, const char* entry, D3D_SHADER_MACRO* macro, ID3D11VertexShader** vs, D3D11_INPUT_ELEMENT_DESC* layout, int count, ID3D11InputLayout** il); - void CreateShader(const std::string& source, const char* fn, ID3DInclude* include, const char* entry, D3D_SHADER_MACRO* macro, ID3D11GeometryShader** gs); - void CreateShader(const std::string& source, const char* fn, ID3DInclude* include, const char* entry, D3D_SHADER_MACRO* macro, ID3D11PixelShader** ps); - - void CompileShader(const std::string& source, const char* fn, ID3DInclude* include, const char* entry, D3D_SHADER_MACRO* macro, ID3DBlob** shader, const std::string& shader_model); }; diff --git a/pcsx2/GS/Renderers/DX11/GSTextureFX11.cpp b/pcsx2/GS/Renderers/DX11/GSTextureFX11.cpp index 3c45ad9675..56ce0630f6 100644 --- a/pcsx2/GS/Renderers/DX11/GSTextureFX11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSTextureFX11.cpp @@ -84,7 +84,7 @@ void GSDevice11::SetupVS(VSSelector sel, const GSHWDrawConfig::VSConstantBuffer* if (i == m_vs.end()) { - ShaderMacro sm(m_shader.model); + ShaderMacro sm(m_shader_cache.GetFeatureLevel()); sm.AddMacro("VS_TME", sel.tme); sm.AddMacro("VS_FST", sel.fst); @@ -102,8 +102,8 @@ void GSDevice11::SetupVS(VSSelector sel, const GSHWDrawConfig::VSConstantBuffer* }; GSVertexShader11 vs; - CreateShader(m_tfx_source, "tfx.fx", nullptr, "vs_main", sm.GetPtr(), &vs.vs, layout, std::size(layout), vs.il.put()); - + m_shader_cache.GetVertexShaderAndInputLayout(m_dev.get(), + vs.vs.put(), vs.il.put(), layout, std::size(layout), m_tfx_source, sm.GetPtr(), "vs_main"); i = m_vs.try_emplace(sel.key, std::move(vs)).first; } @@ -132,13 +132,13 @@ void GSDevice11::SetupGS(GSSelector sel) } else { - ShaderMacro sm(m_shader.model); + ShaderMacro sm(m_shader_cache.GetFeatureLevel()); sm.AddMacro("GS_IIP", sel.iip); sm.AddMacro("GS_PRIM", static_cast(sel.topology)); sm.AddMacro("GS_EXPAND", sel.expand); - CreateShader(m_tfx_source, "tfx.fx", nullptr, "gs_main", sm.GetPtr(), gs.put()); + gs = m_shader_cache.GetGeometryShader(m_dev.get(), m_tfx_source, sm.GetPtr(), "gs_main"); m_gs[sel.key] = gs; } @@ -153,7 +153,7 @@ void GSDevice11::SetupPS(PSSelector sel, const GSHWDrawConfig::PSConstantBuffer* if (i == m_ps.end()) { - ShaderMacro sm(m_shader.model); + ShaderMacro sm(m_shader_cache.GetFeatureLevel()); sm.AddMacro("PS_SCALE_FACTOR", std::max(1, m_upscale_multiplier)); sm.AddMacro("PS_FST", sel.fst); @@ -195,9 +195,7 @@ void GSDevice11::SetupPS(PSSelector sel, const GSHWDrawConfig::PSConstantBuffer* sm.AddMacro("PS_AUTOMATIC_LOD", sel.automatic_lod); sm.AddMacro("PS_MANUAL_LOD", sel.manual_lod); - wil::com_ptr_nothrow ps; - CreateShader(m_tfx_source, "tfx.fx", nullptr, "ps_main", sm.GetPtr(), ps.put()); - + wil::com_ptr_nothrow ps = m_shader_cache.GetPixelShader(m_dev.get(), m_tfx_source, sm.GetPtr(), "ps_main"); i = m_ps.try_emplace(sel.key, std::move(ps)).first; }