diff options
| author | Anthony <Helios747@users.noreply.github.com> | 2017-07-30 01:00:16 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-07-30 01:00:16 -0700 |
| commit | ba57605266b9ab178963bf56e146f355d1b93cd4 (patch) | |
| tree | 0ddc89cfca6db3d343d317c18b7c07c9ab83e9c4 /Source/Core/VideoBackends/D3D/PixelShaderCache.cpp | |
| parent | 5bad2ee4a4129e734ff4f4d861cedc4cd573df55 (diff) | |
| parent | b154edb4fbdb327920a33b44f35f34cdf2636d6f (diff) | |
Merge pull request #5702 from stenzek/ubershaders
Ubershaders 2.0
Diffstat (limited to 'Source/Core/VideoBackends/D3D/PixelShaderCache.cpp')
| -rw-r--r-- | Source/Core/VideoBackends/D3D/PixelShaderCache.cpp | 282 |
1 files changed, 239 insertions, 43 deletions
diff --git a/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp b/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp index 6bb02b890a..bb1aa04911 100644 --- a/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp @@ -8,12 +8,15 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/LinearDiskCache.h" +#include "Common/MsgHandler.h" #include "Common/StringUtil.h" #include "Core/ConfigManager.h" +#include "Core/Host.h" #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DShader.h" +#include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/PixelShaderCache.h" #include "VideoCommon/Debugger.h" @@ -25,10 +28,15 @@ namespace DX11 { PixelShaderCache::PSCache PixelShaderCache::PixelShaders; +PixelShaderCache::UberPSCache PixelShaderCache::UberPixelShaders; const PixelShaderCache::PSCacheEntry* PixelShaderCache::last_entry; +const PixelShaderCache::PSCacheEntry* PixelShaderCache::last_uber_entry; PixelShaderUid PixelShaderCache::last_uid; +UberShader::PixelShaderUid PixelShaderCache::last_uber_uid; LinearDiskCache<PixelShaderUid, u8> g_ps_disk_cache; +LinearDiskCache<UberShader::PixelShaderUid, u8> g_uber_ps_disk_cache; +extern std::unique_ptr<VideoCommon::AsyncShaderCompiler> g_async_compiler; ID3D11PixelShader* s_ColorMatrixProgram[2] = {nullptr}; ID3D11PixelShader* s_ColorCopyProgram[2] = {nullptr}; @@ -429,10 +437,8 @@ ID3D11PixelShader* PixelShaderCache::GetDepthResolveProgram() return s_DepthResolveProgram; } -ID3D11Buffer*& PixelShaderCache::GetConstantBuffer() +static void UpdateConstantBuffers() { - // TODO: divide the global variables of the generated shaders into about 5 constant buffers to - // speed this up if (PixelShaderManager::dirty) { D3D11_MAPPED_SUBRESOURCE map; @@ -443,14 +449,20 @@ ID3D11Buffer*& PixelShaderCache::GetConstantBuffer() ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(PixelShaderConstants)); } +} + +ID3D11Buffer* PixelShaderCache::GetConstantBuffer() +{ + UpdateConstantBuffers(); return pscbuf; } // this class will load the precompiled shaders into our cache -class PixelShaderCacheInserter : public LinearDiskCacheReader<PixelShaderUid, u8> +template <typename UidType> +class PixelShaderCacheInserter : public LinearDiskCacheReader<UidType, u8> { public: - void Read(const PixelShaderUid& key, const u8* value, u32 value_size) + void Read(const UidType& key, const u8* value, u32 value_size) { PixelShaderCache::InsertByteCode(key, value, value_size); } @@ -499,22 +511,34 @@ void PixelShaderCache::Init() if (g_ActiveConfig.bShaderCache) LoadShaderCache(); + + if (g_ActiveConfig.CanPrecompileUberShaders()) + QueueUberShaderCompiles(); } void PixelShaderCache::LoadShaderCache() { - PixelShaderCacheInserter inserter; + PixelShaderCacheInserter<PixelShaderUid> inserter; g_ps_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "PS", true, true), inserter); + + PixelShaderCacheInserter<UberShader::PixelShaderUid> uber_inserter; + g_uber_ps_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "UberPS", false, true), + uber_inserter); } void PixelShaderCache::Reload() { g_ps_disk_cache.Sync(); g_ps_disk_cache.Close(); + g_uber_ps_disk_cache.Sync(); + g_uber_ps_disk_cache.Close(); Clear(); if (g_ActiveConfig.bShaderCache) LoadShaderCache(); + + if (g_ActiveConfig.CanPrecompileUberShaders()) + QueueUberShaderCompiles(); } // ONLY to be used during shutdown. @@ -522,10 +546,15 @@ void PixelShaderCache::Clear() { for (auto& iter : PixelShaders) iter.second.Destroy(); + for (auto& iter : UberPixelShaders) + iter.second.Destroy(); PixelShaders.clear(); + UberPixelShaders.clear(); last_entry = nullptr; + last_uber_entry = nullptr; last_uid = {}; + last_uber_uid = {}; } // Used in Swap() when AA mode has changed @@ -558,82 +587,249 @@ void PixelShaderCache::Shutdown() Clear(); g_ps_disk_cache.Sync(); g_ps_disk_cache.Close(); + g_uber_ps_disk_cache.Sync(); + g_uber_ps_disk_cache.Close(); } bool PixelShaderCache::SetShader() { - PixelShaderUid uid = GetPixelShaderUid(); + if (g_ActiveConfig.bDisableSpecializedShaders || g_ActiveConfig.bForcePixelUberShaders) + return SetUberShader(); - // Check if the shader is already set - if (last_entry) + PixelShaderUid uid = GetPixelShaderUid(); + if (last_entry && uid == last_uid) { - if (uid == last_uid) - { - GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - return (last_entry->shader != nullptr); - } - } + if (last_entry->pending) + return SetUberShader(); - last_uid = uid; + if (!last_entry->shader) + return false; + + D3D::stateman->SetPixelShader(last_entry->shader); + return true; + } // Check if the shader is already in the cache - PSCache::iterator iter; - iter = PixelShaders.find(uid); + auto iter = PixelShaders.find(uid); if (iter != PixelShaders.end()) { const PSCacheEntry& entry = iter->second; + if (entry.pending) + return SetUberShader(); + + last_uid = uid; last_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - return (entry.shader != nullptr); + if (!last_entry->shader) + return false; + + D3D::stateman->SetPixelShader(last_entry->shader); + return true; + } + + // Background compiling? + if (g_ActiveConfig.CanBackgroundCompileShaders()) + { + // Create a pending entry + PSCacheEntry entry; + entry.pending = true; + PixelShaders[uid] = entry; + + // Queue normal shader compiling and use ubershader + g_async_compiler->QueueWorkItem( + g_async_compiler->CreateWorkItem<PixelShaderCompilerWorkItem>(uid)); + return SetUberShader(); } // Need to compile a new shader + D3DBlob* bytecode = nullptr; ShaderCode code = GeneratePixelShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData()); - - D3DBlob* pbytecode; - if (!D3D::CompilePixelShader(code.GetBuffer(), &pbytecode)) + D3D::CompilePixelShader(code.GetBuffer(), &bytecode); + if (!InsertByteCode(uid, bytecode->Data(), bytecode->Size())) { - GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); + SAFE_RELEASE(bytecode); return false; } - // Insert the bytecode into the caches - g_ps_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); + g_ps_disk_cache.Append(uid, bytecode->Data(), bytecode->Size()); + return SetShader(); +} + +bool PixelShaderCache::SetUberShader() +{ + UberShader::PixelShaderUid uid = UberShader::GetPixelShaderUid(); + + if (last_uber_entry && last_uber_uid == uid) + { + if (!last_uber_entry->shader) + return false; + + D3D::stateman->SetPixelShader(last_uber_entry->shader); + return true; + } + + auto iter = UberPixelShaders.find(uid); + if (iter != UberPixelShaders.end()) + { + const PSCacheEntry& entry = iter->second; + last_uber_uid = uid; + last_uber_entry = &entry; + + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + if (!last_uber_entry->shader) + return false; + + D3D::stateman->SetPixelShader(last_uber_entry->shader); + return true; + } - bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); - pbytecode->Release(); + D3DBlob* bytecode = nullptr; + ShaderCode code = + UberShader::GenPixelShader(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData()); + D3D::CompilePixelShader(code.GetBuffer(), &bytecode); + if (!InsertByteCode(uid, bytecode->Data(), bytecode->Size())) + { + SAFE_RELEASE(bytecode); + return false; + } - GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - return success; + // Lookup map again. + g_uber_ps_disk_cache.Append(uid, bytecode->Data(), bytecode->Size()); + bytecode->Release(); + return SetUberShader(); } -bool PixelShaderCache::InsertByteCode(const PixelShaderUid& uid, const void* bytecode, - unsigned int bytecodelen) +bool PixelShaderCache::InsertByteCode(const PixelShaderUid& uid, const u8* data, size_t len) { - ID3D11PixelShader* shader = D3D::CreatePixelShaderFromByteCode(bytecode, bytecodelen); - if (shader == nullptr) + ID3D11PixelShader* shader = data ? D3D::CreatePixelShaderFromByteCode(data, len) : nullptr; + if (!InsertShader(uid, shader)) + { + SAFE_RELEASE(shader); return false; + } - // TODO: Somehow make the debug name a bit more specific - D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of PixelShaderCache"); - - // Make an entry in the table - PSCacheEntry newentry; - newentry.shader = shader; - PixelShaders[uid] = newentry; - last_entry = &PixelShaders[uid]; + return true; +} - if (!shader) +bool PixelShaderCache::InsertByteCode(const UberShader::PixelShaderUid& uid, const u8* data, + size_t len) +{ + ID3D11PixelShader* shader = data ? D3D::CreatePixelShaderFromByteCode(data, len) : nullptr; + if (!InsertShader(uid, shader)) { - // INCSTAT(stats.numPixelShadersFailed); + SAFE_RELEASE(shader); return false; } + return true; +} + +bool PixelShaderCache::InsertShader(const PixelShaderUid& uid, ID3D11PixelShader* shader) +{ + auto iter = PixelShaders.find(uid); + if (iter != PixelShaders.end() && !iter->second.pending) + return false; + + PSCacheEntry& newentry = PixelShaders[uid]; + newentry.pending = false; + newentry.shader = shader; + INCSTAT(stats.numPixelShadersCreated); SETSTAT(stats.numPixelShadersAlive, PixelShaders.size()); + return (shader != nullptr); +} + +bool PixelShaderCache::InsertShader(const UberShader::PixelShaderUid& uid, + ID3D11PixelShader* shader) +{ + auto iter = UberPixelShaders.find(uid); + if (iter != UberPixelShaders.end() && !iter->second.pending) + return false; + + PSCacheEntry& newentry = UberPixelShaders[uid]; + newentry.pending = false; + newentry.shader = shader; + return (shader != nullptr); +} + +void PixelShaderCache::QueueUberShaderCompiles() +{ + UberShader::EnumeratePixelShaderUids([&](const UberShader::PixelShaderUid& uid) { + if (UberPixelShaders.find(uid) != UberPixelShaders.end()) + return; + + g_async_compiler->QueueWorkItem( + g_async_compiler->CreateWorkItem<UberPixelShaderCompilerWorkItem>(uid)); + }); + + g_async_compiler->WaitUntilCompletion([](size_t completed, size_t total) { + Host_UpdateProgressDialog(GetStringT("Compiling shaders...").c_str(), + static_cast<int>(completed), static_cast<int>(total)); + }); + g_async_compiler->RetrieveWorkItems(); + Host_UpdateProgressDialog("", -1, -1); +} + +PixelShaderCache::PixelShaderCompilerWorkItem::PixelShaderCompilerWorkItem( + const PixelShaderUid& uid) +{ + std::memcpy(&m_uid, &uid, sizeof(uid)); +} + +PixelShaderCache::PixelShaderCompilerWorkItem::~PixelShaderCompilerWorkItem() +{ + SAFE_RELEASE(m_bytecode); +} + +bool PixelShaderCache::PixelShaderCompilerWorkItem::Compile() +{ + ShaderCode code = + GeneratePixelShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), m_uid.GetUidData()); + + if (D3D::CompilePixelShader(code.GetBuffer(), &m_bytecode)) + m_shader = D3D::CreatePixelShaderFromByteCode(m_bytecode); + return true; } +void PixelShaderCache::PixelShaderCompilerWorkItem::Retrieve() +{ + if (InsertShader(m_uid, m_shader)) + g_ps_disk_cache.Append(m_uid, m_bytecode->Data(), m_bytecode->Size()); + else + SAFE_RELEASE(m_shader); +} + +PixelShaderCache::UberPixelShaderCompilerWorkItem::UberPixelShaderCompilerWorkItem( + const UberShader::PixelShaderUid& uid) +{ + std::memcpy(&m_uid, &uid, sizeof(uid)); +} + +PixelShaderCache::UberPixelShaderCompilerWorkItem::~UberPixelShaderCompilerWorkItem() +{ + SAFE_RELEASE(m_bytecode); +} + +bool PixelShaderCache::UberPixelShaderCompilerWorkItem::Compile() +{ + ShaderCode code = + UberShader::GenPixelShader(APIType::D3D, ShaderHostConfig::GetCurrent(), m_uid.GetUidData()); + + if (D3D::CompilePixelShader(code.GetBuffer(), &m_bytecode)) + m_shader = D3D::CreatePixelShaderFromByteCode(m_bytecode); + + return true; +} + +void PixelShaderCache::UberPixelShaderCompilerWorkItem::Retrieve() +{ + if (InsertShader(m_uid, m_shader)) + g_uber_ps_disk_cache.Append(m_uid, m_bytecode->Data(), m_bytecode->Size()); + else + SAFE_RELEASE(m_shader); +} + } // DX11 |
