mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-21 05:09:34 -06:00
Move shader caches to VideoCommon
This commit is contained in:
@ -7,7 +7,6 @@
|
||||
#include "Common/Align.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/LinearDiskCache.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
@ -28,22 +27,11 @@
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
VertexShaderCache::VSCache VertexShaderCache::vshaders;
|
||||
VertexShaderCache::UberVSCache VertexShaderCache::ubervshaders;
|
||||
const VertexShaderCache::VSCacheEntry* VertexShaderCache::last_entry;
|
||||
const VertexShaderCache::VSCacheEntry* VertexShaderCache::last_uber_entry;
|
||||
VertexShaderUid VertexShaderCache::last_uid;
|
||||
UberShader::VertexShaderUid VertexShaderCache::last_uber_uid;
|
||||
|
||||
static ID3D11VertexShader* SimpleVertexShader = nullptr;
|
||||
static ID3D11VertexShader* ClearVertexShader = nullptr;
|
||||
static ID3D11InputLayout* SimpleLayout = nullptr;
|
||||
static ID3D11InputLayout* ClearLayout = nullptr;
|
||||
|
||||
LinearDiskCache<VertexShaderUid, u8> g_vs_disk_cache;
|
||||
LinearDiskCache<UberShader::VertexShaderUid, u8> g_uber_vs_disk_cache;
|
||||
std::unique_ptr<VideoCommon::AsyncShaderCompiler> g_async_compiler;
|
||||
|
||||
ID3D11VertexShader* VertexShaderCache::GetSimpleVertexShader()
|
||||
{
|
||||
return SimpleVertexShader;
|
||||
@ -164,73 +152,12 @@ void VertexShaderCache::Init()
|
||||
D3D::SetDebugObjectName(ClearVertexShader, "clear vertex shader");
|
||||
D3D::SetDebugObjectName(ClearLayout, "clear input layout");
|
||||
|
||||
Clear();
|
||||
|
||||
SETSTAT(stats.numVertexShadersCreated, 0);
|
||||
SETSTAT(stats.numVertexShadersAlive, 0);
|
||||
|
||||
if (g_ActiveConfig.bShaderCache)
|
||||
LoadShaderCache();
|
||||
|
||||
g_async_compiler = std::make_unique<VideoCommon::AsyncShaderCompiler>();
|
||||
g_async_compiler->ResizeWorkerThreads(g_ActiveConfig.CanPrecompileUberShaders() ?
|
||||
g_ActiveConfig.GetShaderPrecompilerThreads() :
|
||||
g_ActiveConfig.GetShaderCompilerThreads());
|
||||
|
||||
if (g_ActiveConfig.CanPrecompileUberShaders())
|
||||
QueueUberShaderCompiles();
|
||||
}
|
||||
|
||||
void VertexShaderCache::LoadShaderCache()
|
||||
{
|
||||
VertexShaderCacheInserter<VertexShaderUid> inserter;
|
||||
g_vs_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "VS", true, true), inserter);
|
||||
|
||||
VertexShaderCacheInserter<UberShader::VertexShaderUid> uber_inserter;
|
||||
g_uber_vs_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "UberVS", false, true),
|
||||
uber_inserter);
|
||||
}
|
||||
|
||||
void VertexShaderCache::Reload()
|
||||
{
|
||||
g_async_compiler->WaitUntilCompletion();
|
||||
g_async_compiler->RetrieveWorkItems();
|
||||
|
||||
g_vs_disk_cache.Sync();
|
||||
g_vs_disk_cache.Close();
|
||||
g_uber_vs_disk_cache.Sync();
|
||||
g_uber_vs_disk_cache.Close();
|
||||
Clear();
|
||||
|
||||
if (g_ActiveConfig.bShaderCache)
|
||||
LoadShaderCache();
|
||||
|
||||
if (g_ActiveConfig.CanPrecompileUberShaders())
|
||||
QueueUberShaderCompiles();
|
||||
}
|
||||
|
||||
void VertexShaderCache::Clear()
|
||||
{
|
||||
for (auto& iter : vshaders)
|
||||
iter.second.Destroy();
|
||||
for (auto& iter : ubervshaders)
|
||||
iter.second.Destroy();
|
||||
vshaders.clear();
|
||||
ubervshaders.clear();
|
||||
|
||||
last_uid = {};
|
||||
last_uber_uid = {};
|
||||
last_entry = nullptr;
|
||||
last_uber_entry = nullptr;
|
||||
last_uid = {};
|
||||
last_uber_uid = {};
|
||||
}
|
||||
|
||||
void VertexShaderCache::Shutdown()
|
||||
{
|
||||
g_async_compiler->StopWorkerThreads();
|
||||
g_async_compiler->RetrieveWorkItems();
|
||||
|
||||
SAFE_RELEASE(vscbuf);
|
||||
|
||||
SAFE_RELEASE(SimpleVertexShader);
|
||||
@ -238,271 +165,5 @@ void VertexShaderCache::Shutdown()
|
||||
|
||||
SAFE_RELEASE(SimpleLayout);
|
||||
SAFE_RELEASE(ClearLayout);
|
||||
|
||||
Clear();
|
||||
g_vs_disk_cache.Sync();
|
||||
g_vs_disk_cache.Close();
|
||||
g_uber_vs_disk_cache.Sync();
|
||||
g_uber_vs_disk_cache.Close();
|
||||
}
|
||||
|
||||
bool VertexShaderCache::SetShader(D3DVertexFormat* vertex_format)
|
||||
{
|
||||
if (g_ActiveConfig.bDisableSpecializedShaders)
|
||||
return SetUberShader(vertex_format);
|
||||
|
||||
VertexShaderUid uid = GetVertexShaderUid();
|
||||
if (last_entry && uid == last_uid)
|
||||
{
|
||||
if (last_entry->pending)
|
||||
return SetUberShader(vertex_format);
|
||||
|
||||
if (!last_entry->shader)
|
||||
return false;
|
||||
|
||||
D3D::stateman->SetInputLayout(vertex_format->GetInputLayout(last_entry->bytecode));
|
||||
D3D::stateman->SetVertexShader(last_entry->shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto iter = vshaders.find(uid);
|
||||
if (iter != vshaders.end())
|
||||
{
|
||||
const VSCacheEntry& entry = iter->second;
|
||||
if (entry.pending)
|
||||
return SetUberShader(vertex_format);
|
||||
|
||||
last_uid = uid;
|
||||
last_entry = &entry;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
if (!last_entry->shader)
|
||||
return false;
|
||||
|
||||
D3D::stateman->SetInputLayout(vertex_format->GetInputLayout(last_entry->bytecode));
|
||||
D3D::stateman->SetVertexShader(last_entry->shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Background compiling?
|
||||
if (g_ActiveConfig.CanBackgroundCompileShaders())
|
||||
{
|
||||
// Create a pending entry
|
||||
VSCacheEntry entry;
|
||||
entry.pending = true;
|
||||
vshaders[uid] = entry;
|
||||
|
||||
// Queue normal shader compiling and use ubershader
|
||||
g_async_compiler->QueueWorkItem(
|
||||
g_async_compiler->CreateWorkItem<VertexShaderCompilerWorkItem>(uid));
|
||||
return SetUberShader(vertex_format);
|
||||
}
|
||||
|
||||
// Need to compile a new shader
|
||||
D3DBlob* bytecode = nullptr;
|
||||
ShaderCode code =
|
||||
GenerateVertexShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData());
|
||||
D3D::CompileVertexShader(code.GetBuffer(), &bytecode);
|
||||
if (!InsertByteCode(uid, bytecode))
|
||||
{
|
||||
SAFE_RELEASE(bytecode);
|
||||
return false;
|
||||
}
|
||||
|
||||
g_vs_disk_cache.Append(uid, bytecode->Data(), bytecode->Size());
|
||||
bytecode->Release();
|
||||
return SetShader(vertex_format);
|
||||
}
|
||||
|
||||
bool VertexShaderCache::SetUberShader(D3DVertexFormat* vertex_format)
|
||||
{
|
||||
D3DVertexFormat* uber_vertex_format = static_cast<D3DVertexFormat*>(
|
||||
VertexLoaderManager::GetUberVertexFormat(vertex_format->GetVertexDeclaration()));
|
||||
UberShader::VertexShaderUid uid = UberShader::GetVertexShaderUid();
|
||||
if (last_uber_entry && last_uber_uid == uid)
|
||||
{
|
||||
if (!last_uber_entry->shader)
|
||||
return false;
|
||||
|
||||
D3D::stateman->SetInputLayout(uber_vertex_format->GetInputLayout(last_uber_entry->bytecode));
|
||||
D3D::stateman->SetVertexShader(last_uber_entry->shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto iter = ubervshaders.find(uid);
|
||||
if (iter != ubervshaders.end())
|
||||
{
|
||||
const VSCacheEntry& entry = iter->second;
|
||||
last_uber_uid = uid;
|
||||
last_uber_entry = &entry;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
if (!last_uber_entry->shader)
|
||||
return false;
|
||||
|
||||
D3D::stateman->SetInputLayout(uber_vertex_format->GetInputLayout(last_uber_entry->bytecode));
|
||||
D3D::stateman->SetVertexShader(last_uber_entry->shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Need to compile a new shader
|
||||
D3DBlob* bytecode = nullptr;
|
||||
ShaderCode code =
|
||||
UberShader::GenVertexShader(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData());
|
||||
D3D::CompileVertexShader(code.GetBuffer(), &bytecode);
|
||||
if (!InsertByteCode(uid, bytecode))
|
||||
{
|
||||
SAFE_RELEASE(bytecode);
|
||||
return false;
|
||||
}
|
||||
|
||||
g_uber_vs_disk_cache.Append(uid, bytecode->Data(), bytecode->Size());
|
||||
bytecode->Release();
|
||||
return SetUberShader(vertex_format);
|
||||
}
|
||||
|
||||
bool VertexShaderCache::InsertByteCode(const VertexShaderUid& uid, D3DBlob* blob)
|
||||
{
|
||||
ID3D11VertexShader* shader =
|
||||
blob ? D3D::CreateVertexShaderFromByteCode(blob->Data(), blob->Size()) : nullptr;
|
||||
bool result = InsertShader(uid, shader, blob);
|
||||
SAFE_RELEASE(shader);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool VertexShaderCache::InsertByteCode(const UberShader::VertexShaderUid& uid, D3DBlob* blob)
|
||||
{
|
||||
ID3D11VertexShader* shader =
|
||||
blob ? D3D::CreateVertexShaderFromByteCode(blob->Data(), blob->Size()) : nullptr;
|
||||
bool result = InsertShader(uid, shader, blob);
|
||||
SAFE_RELEASE(shader);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool VertexShaderCache::InsertShader(const VertexShaderUid& uid, ID3D11VertexShader* shader,
|
||||
D3DBlob* blob)
|
||||
{
|
||||
auto iter = vshaders.find(uid);
|
||||
if (iter != vshaders.end() && !iter->second.pending)
|
||||
return false;
|
||||
|
||||
VSCacheEntry& newentry = vshaders[uid];
|
||||
newentry.pending = false;
|
||||
if (!shader || !blob)
|
||||
return false;
|
||||
|
||||
shader->AddRef();
|
||||
newentry.SetByteCode(blob);
|
||||
newentry.shader = shader;
|
||||
|
||||
INCSTAT(stats.numPixelShadersCreated);
|
||||
SETSTAT(stats.numPixelShadersAlive, static_cast<int>(vshaders.size()));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VertexShaderCache::InsertShader(const UberShader::VertexShaderUid& uid,
|
||||
ID3D11VertexShader* shader, D3DBlob* blob)
|
||||
{
|
||||
auto iter = ubervshaders.find(uid);
|
||||
if (iter != ubervshaders.end() && !iter->second.pending)
|
||||
return false;
|
||||
|
||||
VSCacheEntry& newentry = ubervshaders[uid];
|
||||
newentry.pending = false;
|
||||
if (!shader || !blob)
|
||||
return false;
|
||||
|
||||
shader->AddRef();
|
||||
newentry.SetByteCode(blob);
|
||||
newentry.shader = shader;
|
||||
return true;
|
||||
}
|
||||
|
||||
void VertexShaderCache::RetreiveAsyncShaders()
|
||||
{
|
||||
g_async_compiler->RetrieveWorkItems();
|
||||
}
|
||||
|
||||
void VertexShaderCache::QueueUberShaderCompiles()
|
||||
{
|
||||
UberShader::EnumerateVertexShaderUids([&](const UberShader::VertexShaderUid& uid) {
|
||||
if (ubervshaders.find(uid) != ubervshaders.end())
|
||||
return;
|
||||
|
||||
g_async_compiler->QueueWorkItem(
|
||||
g_async_compiler->CreateWorkItem<UberVertexShaderCompilerWorkItem>(uid));
|
||||
});
|
||||
}
|
||||
|
||||
void VertexShaderCache::WaitForBackgroundCompilesToComplete()
|
||||
{
|
||||
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);
|
||||
|
||||
// Switch from precompile -> runtime compiler threads.
|
||||
g_async_compiler->ResizeWorkerThreads(g_ActiveConfig.GetShaderCompilerThreads());
|
||||
}
|
||||
|
||||
VertexShaderCache::VertexShaderCompilerWorkItem::VertexShaderCompilerWorkItem(
|
||||
const VertexShaderUid& uid)
|
||||
{
|
||||
std::memcpy(&m_uid, &uid, sizeof(uid));
|
||||
}
|
||||
|
||||
VertexShaderCache::VertexShaderCompilerWorkItem::~VertexShaderCompilerWorkItem()
|
||||
{
|
||||
SAFE_RELEASE(m_bytecode);
|
||||
SAFE_RELEASE(m_vs);
|
||||
}
|
||||
|
||||
bool VertexShaderCache::VertexShaderCompilerWorkItem::Compile()
|
||||
{
|
||||
ShaderCode code =
|
||||
GenerateVertexShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), m_uid.GetUidData());
|
||||
|
||||
if (D3D::CompileVertexShader(code.GetBuffer(), &m_bytecode))
|
||||
m_vs = D3D::CreateVertexShaderFromByteCode(m_bytecode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VertexShaderCache::VertexShaderCompilerWorkItem::Retrieve()
|
||||
{
|
||||
if (InsertShader(m_uid, m_vs, m_bytecode))
|
||||
g_vs_disk_cache.Append(m_uid, m_bytecode->Data(), m_bytecode->Size());
|
||||
}
|
||||
|
||||
VertexShaderCache::UberVertexShaderCompilerWorkItem::UberVertexShaderCompilerWorkItem(
|
||||
const UberShader::VertexShaderUid& uid)
|
||||
{
|
||||
std::memcpy(&m_uid, &uid, sizeof(uid));
|
||||
}
|
||||
|
||||
VertexShaderCache::UberVertexShaderCompilerWorkItem::~UberVertexShaderCompilerWorkItem()
|
||||
{
|
||||
SAFE_RELEASE(m_bytecode);
|
||||
SAFE_RELEASE(m_vs);
|
||||
}
|
||||
|
||||
bool VertexShaderCache::UberVertexShaderCompilerWorkItem::Compile()
|
||||
{
|
||||
ShaderCode code =
|
||||
UberShader::GenVertexShader(APIType::D3D, ShaderHostConfig::GetCurrent(), m_uid.GetUidData());
|
||||
|
||||
if (D3D::CompileVertexShader(code.GetBuffer(), &m_bytecode))
|
||||
m_vs = D3D::CreateVertexShaderFromByteCode(m_bytecode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VertexShaderCache::UberVertexShaderCompilerWorkItem::Retrieve()
|
||||
{
|
||||
if (InsertShader(m_uid, m_vs, m_bytecode))
|
||||
g_uber_vs_disk_cache.Append(m_uid, m_bytecode->Data(), m_bytecode->Size());
|
||||
}
|
||||
|
||||
} // namespace DX11
|
||||
|
Reference in New Issue
Block a user