From d5ebdf7a9755217ed599d0e02d8a6ae2343410c3 Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Wed, 3 Dec 2014 22:17:56 +0100 Subject: [PATCH] D3D: Add GeometryShaderCache. --- Source/Core/VideoBackends/D3D/D3D.vcxproj | 2 + .../VideoBackends/D3D/D3D.vcxproj.filters | 6 + .../VideoBackends/D3D/GeometryShaderCache.cpp | 160 ++++++++++++++++++ .../VideoBackends/D3D/GeometryShaderCache.h | 46 +++++ .../Core/VideoBackends/D3D/VertexManager.cpp | 1 + Source/Core/VideoBackends/D3D/main.cpp | 3 + Source/Core/VideoCommon/GeometryShaderGen.cpp | 2 +- 7 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp create mode 100644 Source/Core/VideoBackends/D3D/GeometryShaderCache.h diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj b/Source/Core/VideoBackends/D3D/D3D.vcxproj index 7ea9e09d07..f70efea502 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj @@ -43,6 +43,7 @@ + @@ -66,6 +67,7 @@ + diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters index c0158038b2..a83db06c6a 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters @@ -30,6 +30,9 @@ Render + + Render + Render @@ -93,6 +96,9 @@ Render + + Render + Render diff --git a/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp new file mode 100644 index 0000000000..a7bc1a470e --- /dev/null +++ b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp @@ -0,0 +1,160 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include + +#include "Common/FileUtil.h" +#include "Common/LinearDiskCache.h" +#include "Common/StringUtil.h" + +#include "Core/ConfigManager.h" + +#include "VideoBackends/D3D/D3DBase.h" +#include "VideoBackends/D3D/D3DShader.h" +#include "VideoBackends/D3D/GeometryShaderCache.h" +#include "VideoBackends/D3D/Globals.h" + +#include "VideoCommon/Debugger.h" +#include "VideoCommon/GeometryShaderGen.h" +#include "VideoCommon/VideoConfig.h" + +namespace DX11 +{ + +GeometryShaderCache::GSCache GeometryShaderCache::GeometryShaders; +const GeometryShaderCache::GSCacheEntry* GeometryShaderCache::last_entry; +GeometryShaderUid GeometryShaderCache::last_uid; +UidChecker GeometryShaderCache::geometry_uid_checker; + +LinearDiskCache g_gs_disk_cache; + +ID3D11Buffer* gscbuf = nullptr; + +// this class will load the precompiled shaders into our cache +class GeometryShaderCacheInserter : public LinearDiskCacheReader +{ +public: + void Read(const GeometryShaderUid &key, const u8 *value, u32 value_size) + { + GeometryShaderCache::InsertByteCode(key, value, value_size); + } +}; + +void GeometryShaderCache::Init() +{ + Clear(); + + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + + std::string cache_filename = StringFromFormat("%sdx11-%s-gs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str()); + GeometryShaderCacheInserter inserter; + g_gs_disk_cache.OpenAndRead(cache_filename, inserter); + + if (g_Config.bEnableShaderDebugging) + Clear(); + + last_entry = nullptr; +} + +// ONLY to be used during shutdown. +void GeometryShaderCache::Clear() +{ + for (auto& iter : GeometryShaders) + iter.second.Destroy(); + GeometryShaders.clear(); + geometry_uid_checker.Invalidate(); + + last_entry = nullptr; +} + +void GeometryShaderCache::Shutdown() +{ + Clear(); + g_gs_disk_cache.Sync(); + g_gs_disk_cache.Close(); +} + +bool GeometryShaderCache::SetShader(u32 components) +{ + GeometryShaderUid uid; + GetGeometryShaderUid(uid, components, API_D3D); + if (g_ActiveConfig.bEnableShaderDebugging) + { + ShaderCode code; + GenerateGeometryShaderCode(code, components, API_D3D); + geometry_uid_checker.AddToIndexAndCheck(code, uid, "Geometry", "g"); + } + + // Check if the shader is already set + if (last_entry) + { + if (uid == last_uid) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); + return (last_entry->shader != nullptr); + } + } + + last_uid = uid; + + // Check if the shader is already in the cache + GSCache::iterator iter; + iter = GeometryShaders.find(uid); + if (iter != GeometryShaders.end()) + { + const GSCacheEntry &entry = iter->second; + last_entry = &entry; + + return (entry.shader != nullptr); + } + + // Need to compile a new shader + ShaderCode code; + GenerateGeometryShaderCode(code, components, API_D3D); + + D3DBlob* pbytecode; + if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode)) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); + return false; + } + + // Insert the bytecode into the caches + g_gs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); + + bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); + pbytecode->Release(); + + if (g_ActiveConfig.bEnableShaderDebugging && success) + { + GeometryShaders[uid].code = code.GetBuffer(); + } + + return success; +} + +bool GeometryShaderCache::InsertByteCode(const GeometryShaderUid &uid, const void* bytecode, unsigned int bytecodelen) +{ + ID3D11GeometryShader* shader = D3D::CreateGeometryShaderFromByteCode(bytecode, bytecodelen); + if (shader == nullptr) + return false; + + // TODO: Somehow make the debug name a bit more specific + D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of GeometryShaderCache"); + + // Make an entry in the table + GSCacheEntry newentry; + newentry.shader = shader; + GeometryShaders[uid] = newentry; + last_entry = &GeometryShaders[uid]; + + if (!shader) + return false; + + return true; +} + +} // DX11 diff --git a/Source/Core/VideoBackends/D3D/GeometryShaderCache.h b/Source/Core/VideoBackends/D3D/GeometryShaderCache.h new file mode 100644 index 0000000000..b200323be8 --- /dev/null +++ b/Source/Core/VideoBackends/D3D/GeometryShaderCache.h @@ -0,0 +1,46 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "VideoCommon/GeometryShaderGen.h" + +namespace DX11 +{ + +class GeometryShaderCache +{ +public: + static void Init(); + static void Clear(); + static void Shutdown(); + static bool SetShader(u32 components); // TODO: Should be renamed to LoadShader + static bool InsertByteCode(const GeometryShaderUid &uid, const void* bytecode, unsigned int bytecodelen); + + static ID3D11GeometryShader* GetActiveShader() { return last_entry->shader; } + +private: + struct GSCacheEntry + { + ID3D11GeometryShader* shader; + + std::string code; + + GSCacheEntry() : shader(nullptr) {} + void Destroy() { SAFE_RELEASE(shader); } + }; + + typedef std::map GSCache; + + static GSCache GeometryShaders; + static const GSCacheEntry* last_entry; + static GeometryShaderUid last_uid; + + static UidChecker geometry_uid_checker; +}; + +} // namespace DX11 \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D/VertexManager.cpp b/Source/Core/VideoBackends/D3D/VertexManager.cpp index 7ab4f950bc..c782586a65 100644 --- a/Source/Core/VideoBackends/D3D/VertexManager.cpp +++ b/Source/Core/VideoBackends/D3D/VertexManager.cpp @@ -5,6 +5,7 @@ #include "VideoBackends/D3D/BoundingBox.h" #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DState.h" +#include "VideoBackends/D3D/GeometryShaderCache.h" #include "VideoBackends/D3D/PixelShaderCache.h" #include "VideoBackends/D3D/Render.h" #include "VideoBackends/D3D/VertexManager.h" diff --git a/Source/Core/VideoBackends/D3D/main.cpp b/Source/Core/VideoBackends/D3D/main.cpp index 34a11d493f..c840c2a9bc 100644 --- a/Source/Core/VideoBackends/D3D/main.cpp +++ b/Source/Core/VideoBackends/D3D/main.cpp @@ -16,6 +16,7 @@ #include "VideoBackends/D3D/BoundingBox.h" #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DUtil.h" +#include "VideoBackends/D3D/GeometryShaderCache.h" #include "VideoBackends/D3D/Globals.h" #include "VideoBackends/D3D/PerfQuery.h" #include "VideoBackends/D3D/PixelShaderCache.h" @@ -168,6 +169,7 @@ void VideoBackend::Video_Prepare() g_perf_query = new PerfQuery; VertexShaderCache::Init(); PixelShaderCache::Init(); + GeometryShaderCache::Init(); D3D::InitUtils(); // VideoCommon @@ -205,6 +207,7 @@ void VideoBackend::Shutdown() D3D::ShutdownUtils(); PixelShaderCache::Shutdown(); VertexShaderCache::Shutdown(); + GeometryShaderCache::Shutdown(); BBox::Shutdown(); delete g_perf_query; diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp index f9a8704269..424768e2ec 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.cpp +++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp @@ -69,7 +69,7 @@ static inline void GenerateGeometryShader(T& out, u32 components, API_TYPE ApiTy out.Write("\tfor (int l = 0; l < %d; ++l) {\n", g_ActiveConfig.iStereoMode > 0 ? 2 : 1); out.Write("\tfor (int i = 0; i < 3; ++i) {\n"); - out.Write("\t\tlayer = l;\n"); + out.Write("\t\tgs.layer = l;\n"); out.Write("\t\tgl_Layer = l;\n"); out.Write("\t\tf = o[i];\n"); out.Write("\t\tfloat4 pos = o[i].pos;\n");