summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp
diff options
context:
space:
mode:
authorAnthony <Helios747@users.noreply.github.com>2017-07-30 01:00:16 -0700
committerGitHub <noreply@github.com>2017-07-30 01:00:16 -0700
commitba57605266b9ab178963bf56e146f355d1b93cd4 (patch)
tree0ddc89cfca6db3d343d317c18b7c07c9ab83e9c4 /Source/Core/VideoBackends/D3D/PixelShaderCache.cpp
parent5bad2ee4a4129e734ff4f4d861cedc4cd573df55 (diff)
parentb154edb4fbdb327920a33b44f35f34cdf2636d6f (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.cpp282
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