ShaderCache: Implement background shader compilation
This enables shaders to be compiled while the game is starting, instead of blocking startup. If a shader is needed before it is compiled, emulation will block.
This commit is contained in:
parent
9fa24700b6
commit
e31cc1f679
|
@ -76,6 +76,8 @@ const ConfigInfo<bool> GFX_BACKEND_MULTITHREADING{
|
||||||
const ConfigInfo<int> GFX_COMMAND_BUFFER_EXECUTE_INTERVAL{
|
const ConfigInfo<int> GFX_COMMAND_BUFFER_EXECUTE_INTERVAL{
|
||||||
{System::GFX, "Settings", "CommandBufferExecuteInterval"}, 100};
|
{System::GFX, "Settings", "CommandBufferExecuteInterval"}, 100};
|
||||||
const ConfigInfo<bool> GFX_SHADER_CACHE{{System::GFX, "Settings", "ShaderCache"}, true};
|
const ConfigInfo<bool> GFX_SHADER_CACHE{{System::GFX, "Settings", "ShaderCache"}, true};
|
||||||
|
const ConfigInfo<bool> GFX_WAIT_FOR_SHADERS_BEFORE_STARTING{
|
||||||
|
{System::GFX, "Settings", "WaitForShadersBeforeStarting"}, false};
|
||||||
const ConfigInfo<int> GFX_UBERSHADER_MODE{{System::GFX, "Settings", "UberShaderMode"},
|
const ConfigInfo<int> GFX_UBERSHADER_MODE{{System::GFX, "Settings", "UberShaderMode"},
|
||||||
static_cast<int>(UberShaderMode::Disabled)};
|
static_cast<int>(UberShaderMode::Disabled)};
|
||||||
const ConfigInfo<int> GFX_SHADER_COMPILER_THREADS{
|
const ConfigInfo<int> GFX_SHADER_COMPILER_THREADS{
|
||||||
|
|
|
@ -59,6 +59,7 @@ extern const ConfigInfo<bool> GFX_ENABLE_VALIDATION_LAYER;
|
||||||
extern const ConfigInfo<bool> GFX_BACKEND_MULTITHREADING;
|
extern const ConfigInfo<bool> GFX_BACKEND_MULTITHREADING;
|
||||||
extern const ConfigInfo<int> GFX_COMMAND_BUFFER_EXECUTE_INTERVAL;
|
extern const ConfigInfo<int> GFX_COMMAND_BUFFER_EXECUTE_INTERVAL;
|
||||||
extern const ConfigInfo<bool> GFX_SHADER_CACHE;
|
extern const ConfigInfo<bool> GFX_SHADER_CACHE;
|
||||||
|
extern const ConfigInfo<bool> GFX_WAIT_FOR_SHADERS_BEFORE_STARTING;
|
||||||
extern const ConfigInfo<int> GFX_UBERSHADER_MODE;
|
extern const ConfigInfo<int> GFX_UBERSHADER_MODE;
|
||||||
extern const ConfigInfo<int> GFX_SHADER_COMPILER_THREADS;
|
extern const ConfigInfo<int> GFX_SHADER_COMPILER_THREADS;
|
||||||
extern const ConfigInfo<int> GFX_SHADER_PRECOMPILER_THREADS;
|
extern const ConfigInfo<int> GFX_SHADER_PRECOMPILER_THREADS;
|
||||||
|
|
|
@ -46,8 +46,8 @@ bool IsSettingSaveable(const Config::ConfigLocation& config_location)
|
||||||
Config::GFX_DISABLE_FOG.location, Config::GFX_BORDERLESS_FULLSCREEN.location,
|
Config::GFX_DISABLE_FOG.location, Config::GFX_BORDERLESS_FULLSCREEN.location,
|
||||||
Config::GFX_ENABLE_VALIDATION_LAYER.location, Config::GFX_BACKEND_MULTITHREADING.location,
|
Config::GFX_ENABLE_VALIDATION_LAYER.location, Config::GFX_BACKEND_MULTITHREADING.location,
|
||||||
Config::GFX_COMMAND_BUFFER_EXECUTE_INTERVAL.location, Config::GFX_SHADER_CACHE.location,
|
Config::GFX_COMMAND_BUFFER_EXECUTE_INTERVAL.location, Config::GFX_SHADER_CACHE.location,
|
||||||
Config::GFX_UBERSHADER_MODE.location, Config::GFX_SHADER_COMPILER_THREADS.location,
|
Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING.location, Config::GFX_UBERSHADER_MODE.location,
|
||||||
Config::GFX_SHADER_PRECOMPILER_THREADS.location,
|
Config::GFX_SHADER_COMPILER_THREADS.location, Config::GFX_SHADER_PRECOMPILER_THREADS.location,
|
||||||
|
|
||||||
Config::GFX_SW_ZCOMPLOC.location, Config::GFX_SW_ZFREEZE.location,
|
Config::GFX_SW_ZCOMPLOC.location, Config::GFX_SW_ZFREEZE.location,
|
||||||
Config::GFX_SW_DUMP_OBJECTS.location, Config::GFX_SW_DUMP_TEV_STAGES.location,
|
Config::GFX_SW_DUMP_OBJECTS.location, Config::GFX_SW_DUMP_TEV_STAGES.location,
|
||||||
|
|
|
@ -87,6 +87,8 @@ void GeneralWidget::CreateWidgets()
|
||||||
m_keep_window_top = new QCheckBox(tr("Keep Window on Top"));
|
m_keep_window_top = new QCheckBox(tr("Keep Window on Top"));
|
||||||
m_hide_cursor = new QCheckBox(tr("Hide Mouse Cursor"));
|
m_hide_cursor = new QCheckBox(tr("Hide Mouse Cursor"));
|
||||||
m_render_main_window = new QCheckBox(tr("Render to Main Window"));
|
m_render_main_window = new QCheckBox(tr("Render to Main Window"));
|
||||||
|
m_wait_for_shaders = new GraphicsBool(tr("Immediately Compile Shaders"),
|
||||||
|
Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING);
|
||||||
|
|
||||||
m_options_box->setLayout(m_options_layout);
|
m_options_box->setLayout(m_options_layout);
|
||||||
|
|
||||||
|
@ -101,6 +103,7 @@ void GeneralWidget::CreateWidgets()
|
||||||
|
|
||||||
m_options_layout->addWidget(m_hide_cursor, 3, 0);
|
m_options_layout->addWidget(m_hide_cursor, 3, 0);
|
||||||
m_options_layout->addWidget(m_render_main_window, 3, 1);
|
m_options_layout->addWidget(m_render_main_window, 3, 1);
|
||||||
|
m_options_layout->addWidget(m_wait_for_shaders, 4, 0);
|
||||||
|
|
||||||
main_layout->addWidget(m_video_box);
|
main_layout->addWidget(m_video_box);
|
||||||
main_layout->addWidget(m_options_box);
|
main_layout->addWidget(m_options_box);
|
||||||
|
@ -265,6 +268,12 @@ void GeneralWidget::AddDescriptions()
|
||||||
static const char* TR_SHOW_NETPLAY_MESSAGES_DESCRIPTION =
|
static const char* TR_SHOW_NETPLAY_MESSAGES_DESCRIPTION =
|
||||||
QT_TR_NOOP("When playing on NetPlay, show chat messages, buffer changes and "
|
QT_TR_NOOP("When playing on NetPlay, show chat messages, buffer changes and "
|
||||||
"desync alerts.\n\nIf unsure, leave this unchecked.");
|
"desync alerts.\n\nIf unsure, leave this unchecked.");
|
||||||
|
static const char* TR_WAIT_FOR_SHADERS_DESCRIPTION = QT_TR_NOOP(
|
||||||
|
"Waits for all shaders to finish compiling before starting a game. Enabling this "
|
||||||
|
"option may reduce stuttering or hitching for a short time after the game is "
|
||||||
|
"started, at the cost of a longer delay before the game starts.\n\nFor systems "
|
||||||
|
"with two or fewer cores, it is recommended to enable this option, as a large "
|
||||||
|
"shader queue may reduce frame rates. Otherwise, if unsure, leave this unchecked.");
|
||||||
|
|
||||||
AddDescription(m_backend_combo, TR_BACKEND_DESCRIPTION);
|
AddDescription(m_backend_combo, TR_BACKEND_DESCRIPTION);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -282,6 +291,7 @@ void GeneralWidget::AddDescriptions()
|
||||||
AddDescription(m_show_messages, TR_SHOW_FPS_DESCRIPTION);
|
AddDescription(m_show_messages, TR_SHOW_FPS_DESCRIPTION);
|
||||||
AddDescription(m_keep_window_top, TR_KEEP_WINDOW_ON_TOP_DESCRIPTION);
|
AddDescription(m_keep_window_top, TR_KEEP_WINDOW_ON_TOP_DESCRIPTION);
|
||||||
AddDescription(m_show_messages, TR_SHOW_NETPLAY_MESSAGES_DESCRIPTION);
|
AddDescription(m_show_messages, TR_SHOW_NETPLAY_MESSAGES_DESCRIPTION);
|
||||||
|
AddDescription(m_wait_for_shaders, TR_WAIT_FOR_SHADERS_DESCRIPTION);
|
||||||
}
|
}
|
||||||
void GeneralWidget::OnBackendChanged(const QString& backend_name)
|
void GeneralWidget::OnBackendChanged(const QString& backend_name)
|
||||||
{
|
{
|
||||||
|
|
|
@ -52,6 +52,7 @@ private:
|
||||||
QCheckBox* m_keep_window_top;
|
QCheckBox* m_keep_window_top;
|
||||||
QCheckBox* m_hide_cursor;
|
QCheckBox* m_hide_cursor;
|
||||||
QCheckBox* m_render_main_window;
|
QCheckBox* m_render_main_window;
|
||||||
|
QCheckBox* m_wait_for_shaders;
|
||||||
|
|
||||||
X11Utils::XRRConfiguration* m_xrr_config;
|
X11Utils::XRRConfiguration* m_xrr_config;
|
||||||
};
|
};
|
||||||
|
|
|
@ -317,6 +317,12 @@ static wxString ubershader_desc =
|
||||||
"stuttering. Balances performance and smoothness.\n\n"
|
"stuttering. Balances performance and smoothness.\n\n"
|
||||||
"Exclusive: Ubershaders will always be used. Only recommended for high-end "
|
"Exclusive: Ubershaders will always be used. Only recommended for high-end "
|
||||||
"systems.");
|
"systems.");
|
||||||
|
static wxString wait_for_shaders_desc =
|
||||||
|
wxTRANSLATE("Waits for all shaders to finish compiling before starting a game. Enabling this "
|
||||||
|
"option may reduce stuttering or hitching for a short time after the game is "
|
||||||
|
"started, at the cost of a longer delay before the game starts.\n\nFor systems "
|
||||||
|
"with two or fewer cores, it is recommended to enable this option, as a large "
|
||||||
|
"shader queue may reduce frame rates. Otherwise, if unsure, leave this unchecked.");
|
||||||
|
|
||||||
VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
|
VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
|
||||||
: wxDialog(parent, wxID_ANY, wxString::Format(_("Dolphin %s Graphics Configuration"),
|
: wxDialog(parent, wxID_ANY, wxString::Format(_("Dolphin %s Graphics Configuration"),
|
||||||
|
@ -442,6 +448,10 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
|
||||||
wxGetTranslation(backend_multithreading_desc),
|
wxGetTranslation(backend_multithreading_desc),
|
||||||
Config::GFX_BACKEND_MULTITHREADING));
|
Config::GFX_BACKEND_MULTITHREADING));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
szr_other->Add(CreateCheckBox(page_general, _("Immediately Compile Shaders"),
|
||||||
|
wxGetTranslation(wait_for_shaders_desc),
|
||||||
|
Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING));
|
||||||
}
|
}
|
||||||
|
|
||||||
wxStaticBoxSizer* const group_basic =
|
wxStaticBoxSizer* const group_basic =
|
||||||
|
|
|
@ -18,7 +18,6 @@ AsyncShaderCompiler::~AsyncShaderCompiler()
|
||||||
// Pending work can be left at shutdown.
|
// Pending work can be left at shutdown.
|
||||||
// The work item classes are expected to clean up after themselves.
|
// The work item classes are expected to clean up after themselves.
|
||||||
_assert_(!HasWorkerThreads());
|
_assert_(!HasWorkerThreads());
|
||||||
_assert_(m_completed_work.empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncShaderCompiler::QueueWorkItem(WorkItemPtr item)
|
void AsyncShaderCompiler::QueueWorkItem(WorkItemPtr item)
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
// Copyright 2018 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "VideoCommon/GeometryShaderGen.h"
|
||||||
|
#include "VideoCommon/PixelShaderGen.h"
|
||||||
|
#include "VideoCommon/RenderState.h"
|
||||||
|
#include "VideoCommon/UberShaderPixel.h"
|
||||||
|
#include "VideoCommon/UberShaderVertex.h"
|
||||||
|
#include "VideoCommon/VertexShaderGen.h"
|
||||||
|
|
||||||
|
class NativeVertexFormat;
|
||||||
|
|
||||||
|
namespace VideoCommon
|
||||||
|
{
|
||||||
|
struct GXPipelineUid
|
||||||
|
{
|
||||||
|
const NativeVertexFormat* vertex_format;
|
||||||
|
VertexShaderUid vs_uid;
|
||||||
|
GeometryShaderUid gs_uid;
|
||||||
|
PixelShaderUid ps_uid;
|
||||||
|
RasterizationState rasterization_state;
|
||||||
|
DepthState depth_state;
|
||||||
|
BlendingState blending_state;
|
||||||
|
|
||||||
|
// We use memcmp() for comparing pipelines as std::tie generates a large number of instructions,
|
||||||
|
// and this map lookup can happen every draw call. However, as using memcmp() will also compare
|
||||||
|
// any padding bytes, we have to ensure these are zeroed out.
|
||||||
|
GXPipelineUid() { std::memset(this, 0, sizeof(*this)); }
|
||||||
|
GXPipelineUid(const GXPipelineUid& rhs) { std::memcpy(this, &rhs, sizeof(*this)); }
|
||||||
|
GXPipelineUid& operator=(const GXPipelineUid& rhs)
|
||||||
|
{
|
||||||
|
std::memcpy(this, &rhs, sizeof(*this));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
bool operator<(const GXPipelineUid& rhs) const
|
||||||
|
{
|
||||||
|
return std::memcmp(this, &rhs, sizeof(*this)) < 0;
|
||||||
|
}
|
||||||
|
bool operator==(const GXPipelineUid& rhs) const
|
||||||
|
{
|
||||||
|
return std::memcmp(this, &rhs, sizeof(*this)) == 0;
|
||||||
|
}
|
||||||
|
bool operator!=(const GXPipelineUid& rhs) const { return !operator==(rhs); }
|
||||||
|
};
|
||||||
|
struct GXUberPipelineUid
|
||||||
|
{
|
||||||
|
const NativeVertexFormat* vertex_format;
|
||||||
|
UberShader::VertexShaderUid vs_uid;
|
||||||
|
GeometryShaderUid gs_uid;
|
||||||
|
UberShader::PixelShaderUid ps_uid;
|
||||||
|
RasterizationState rasterization_state;
|
||||||
|
DepthState depth_state;
|
||||||
|
BlendingState blending_state;
|
||||||
|
|
||||||
|
GXUberPipelineUid() { std::memset(this, 0, sizeof(*this)); }
|
||||||
|
GXUberPipelineUid(const GXUberPipelineUid& rhs) { std::memcpy(this, &rhs, sizeof(*this)); }
|
||||||
|
GXUberPipelineUid& operator=(const GXUberPipelineUid& rhs)
|
||||||
|
{
|
||||||
|
std::memcpy(this, &rhs, sizeof(*this));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
bool operator<(const GXUberPipelineUid& rhs) const
|
||||||
|
{
|
||||||
|
return std::memcmp(this, &rhs, sizeof(*this)) < 0;
|
||||||
|
}
|
||||||
|
bool operator==(const GXUberPipelineUid& rhs) const
|
||||||
|
{
|
||||||
|
return std::memcmp(this, &rhs, sizeof(*this)) == 0;
|
||||||
|
}
|
||||||
|
bool operator!=(const GXUberPipelineUid& rhs) const { return !operator==(rhs); }
|
||||||
|
};
|
||||||
|
} // namespace VideoCommon
|
|
@ -43,6 +43,8 @@ bool ShaderCache::Initialize()
|
||||||
|
|
||||||
// Compile all known UIDs.
|
// Compile all known UIDs.
|
||||||
CompileMissingPipelines();
|
CompileMissingPipelines();
|
||||||
|
if (g_ActiveConfig.bWaitForShadersBeforeStarting)
|
||||||
|
WaitForAsyncCompiler();
|
||||||
|
|
||||||
// Switch to the runtime shader compiler thread configuration.
|
// Switch to the runtime shader compiler thread configuration.
|
||||||
m_async_shader_compiler->ResizeWorkerThreads(g_ActiveConfig.GetShaderCompilerThreads());
|
m_async_shader_compiler->ResizeWorkerThreads(g_ActiveConfig.GetShaderCompilerThreads());
|
||||||
|
@ -61,9 +63,7 @@ void ShaderCache::SetHostConfig(const ShaderHostConfig& host_config, u32 efb_mul
|
||||||
|
|
||||||
void ShaderCache::Reload()
|
void ShaderCache::Reload()
|
||||||
{
|
{
|
||||||
m_async_shader_compiler->WaitUntilCompletion();
|
WaitForAsyncCompiler();
|
||||||
m_async_shader_compiler->RetrieveWorkItems();
|
|
||||||
|
|
||||||
InvalidateCachedPipelines();
|
InvalidateCachedPipelines();
|
||||||
ClearShaderCaches();
|
ClearShaderCaches();
|
||||||
|
|
||||||
|
@ -77,6 +77,8 @@ void ShaderCache::Reload()
|
||||||
// UIDs are still be in the map. Therefore, when these are rebuilt, the shaders will also
|
// UIDs are still be in the map. Therefore, when these are rebuilt, the shaders will also
|
||||||
// be recompiled.
|
// be recompiled.
|
||||||
CompileMissingPipelines();
|
CompileMissingPipelines();
|
||||||
|
if (g_ActiveConfig.bWaitForShadersBeforeStarting)
|
||||||
|
WaitForAsyncCompiler();
|
||||||
m_async_shader_compiler->ResizeWorkerThreads(g_ActiveConfig.GetShaderCompilerThreads());
|
m_async_shader_compiler->ResizeWorkerThreads(g_ActiveConfig.GetShaderCompilerThreads());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,14 +89,14 @@ void ShaderCache::RetrieveAsyncShaders()
|
||||||
|
|
||||||
void ShaderCache::Shutdown()
|
void ShaderCache::Shutdown()
|
||||||
{
|
{
|
||||||
|
// This may leave shaders uncommitted to the cache, but it's better than blocking shutdown
|
||||||
|
// until everything has finished compiling.
|
||||||
m_async_shader_compiler->StopWorkerThreads();
|
m_async_shader_compiler->StopWorkerThreads();
|
||||||
m_async_shader_compiler->RetrieveWorkItems();
|
|
||||||
|
|
||||||
ClearShaderCaches();
|
ClearShaderCaches();
|
||||||
ClearPipelineCaches();
|
ClearPipelineCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
const AbstractPipeline* ShaderCache::GetPipelineForUid(const GXPipelineConfig& uid)
|
const AbstractPipeline* ShaderCache::GetPipelineForUid(const GXPipelineUid& uid)
|
||||||
{
|
{
|
||||||
auto it = m_gx_pipeline_cache.find(uid);
|
auto it = m_gx_pipeline_cache.find(uid);
|
||||||
if (it != m_gx_pipeline_cache.end() && !it->second.second)
|
if (it != m_gx_pipeline_cache.end() && !it->second.second)
|
||||||
|
@ -109,8 +111,7 @@ const AbstractPipeline* ShaderCache::GetPipelineForUid(const GXPipelineConfig& u
|
||||||
return InsertGXPipeline(uid, std::move(pipeline));
|
return InsertGXPipeline(uid, std::move(pipeline));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<const AbstractPipeline*>
|
std::optional<const AbstractPipeline*> ShaderCache::GetPipelineForUidAsync(const GXPipelineUid& uid)
|
||||||
ShaderCache::GetPipelineForUidAsync(const GXPipelineConfig& uid)
|
|
||||||
{
|
{
|
||||||
auto it = m_gx_pipeline_cache.find(uid);
|
auto it = m_gx_pipeline_cache.find(uid);
|
||||||
if (it != m_gx_pipeline_cache.end())
|
if (it != m_gx_pipeline_cache.end())
|
||||||
|
@ -159,7 +160,7 @@ ShaderCache::GetPipelineForUidAsync(const GXPipelineConfig& uid)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const AbstractPipeline* ShaderCache::GetUberPipelineForUid(const GXUberPipelineConfig& uid)
|
const AbstractPipeline* ShaderCache::GetUberPipelineForUid(const GXUberPipelineUid& uid)
|
||||||
{
|
{
|
||||||
auto it = m_gx_uber_pipeline_cache.find(uid);
|
auto it = m_gx_uber_pipeline_cache.find(uid);
|
||||||
if (it != m_gx_uber_pipeline_cache.end() && !it->second.second)
|
if (it != m_gx_uber_pipeline_cache.end() && !it->second.second)
|
||||||
|
@ -172,12 +173,16 @@ const AbstractPipeline* ShaderCache::GetUberPipelineForUid(const GXUberPipelineC
|
||||||
return InsertGXUberPipeline(uid, std::move(pipeline));
|
return InsertGXUberPipeline(uid, std::move(pipeline));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderCache::WaitForAsyncCompiler(const std::string& msg)
|
void ShaderCache::WaitForAsyncCompiler()
|
||||||
{
|
{
|
||||||
m_async_shader_compiler->WaitUntilCompletion([&msg](size_t completed, size_t total) {
|
while (m_async_shader_compiler->HasPendingWork())
|
||||||
Host_UpdateProgressDialog(msg.c_str(), static_cast<int>(completed), static_cast<int>(total));
|
{
|
||||||
});
|
m_async_shader_compiler->WaitUntilCompletion([](size_t completed, size_t total) {
|
||||||
m_async_shader_compiler->RetrieveWorkItems();
|
Host_UpdateProgressDialog(GetStringT("Compiling shaders...").c_str(),
|
||||||
|
static_cast<int>(completed), static_cast<int>(total));
|
||||||
|
});
|
||||||
|
m_async_shader_compiler->RetrieveWorkItems();
|
||||||
|
}
|
||||||
Host_UpdateProgressDialog("", -1, -1);
|
Host_UpdateProgressDialog("", -1, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +279,7 @@ void ShaderCache::LoadPipelineUIDCache()
|
||||||
CacheReader(ShaderCache* shader_cache_) : shader_cache(shader_cache_) {}
|
CacheReader(ShaderCache* shader_cache_) : shader_cache(shader_cache_) {}
|
||||||
void Read(const GXPipelineDiskCacheUid& key, const u8* data, u32 data_size)
|
void Read(const GXPipelineDiskCacheUid& key, const u8* data, u32 data_size)
|
||||||
{
|
{
|
||||||
GXPipelineConfig config = {};
|
GXPipelineUid config = {};
|
||||||
config.vertex_format = VertexLoaderManager::GetOrCreateMatchingFormat(key.vertex_decl);
|
config.vertex_format = VertexLoaderManager::GetOrCreateMatchingFormat(key.vertex_decl);
|
||||||
config.vs_uid = key.vs_uid;
|
config.vs_uid = key.vs_uid;
|
||||||
config.gs_uid = key.gs_uid;
|
config.gs_uid = key.gs_uid;
|
||||||
|
@ -315,8 +320,6 @@ void ShaderCache::CompileMissingPipelines()
|
||||||
if (!it.second.second)
|
if (!it.second.second)
|
||||||
QueueUberPipelineCompile(it.first);
|
QueueUberPipelineCompile(it.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitForAsyncCompiler(GetStringT("Compiling shaders..."));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderCache::InvalidateCachedPipelines()
|
void ShaderCache::InvalidateCachedPipelines()
|
||||||
|
@ -508,8 +511,7 @@ AbstractPipelineConfig ShaderCache::GetGXPipelineConfig(
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<AbstractPipelineConfig>
|
std::optional<AbstractPipelineConfig> ShaderCache::GetGXPipelineConfig(const GXPipelineUid& config)
|
||||||
ShaderCache::GetGXPipelineConfig(const GXPipelineConfig& config)
|
|
||||||
{
|
{
|
||||||
const AbstractShader* vs;
|
const AbstractShader* vs;
|
||||||
auto vs_iter = m_vs_cache.shader_map.find(config.vs_uid);
|
auto vs_iter = m_vs_cache.shader_map.find(config.vs_uid);
|
||||||
|
@ -545,7 +547,7 @@ ShaderCache::GetGXPipelineConfig(const GXPipelineConfig& config)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<AbstractPipelineConfig>
|
std::optional<AbstractPipelineConfig>
|
||||||
ShaderCache::GetGXUberPipelineConfig(const GXUberPipelineConfig& config)
|
ShaderCache::GetGXUberPipelineConfig(const GXUberPipelineUid& config)
|
||||||
{
|
{
|
||||||
const AbstractShader* vs;
|
const AbstractShader* vs;
|
||||||
auto vs_iter = m_uber_vs_cache.shader_map.find(config.vs_uid);
|
auto vs_iter = m_uber_vs_cache.shader_map.find(config.vs_uid);
|
||||||
|
@ -580,7 +582,7 @@ ShaderCache::GetGXUberPipelineConfig(const GXUberPipelineConfig& config)
|
||||||
config.depth_state, config.blending_state);
|
config.depth_state, config.blending_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
const AbstractPipeline* ShaderCache::InsertGXPipeline(const GXPipelineConfig& config,
|
const AbstractPipeline* ShaderCache::InsertGXPipeline(const GXPipelineUid& config,
|
||||||
std::unique_ptr<AbstractPipeline> pipeline)
|
std::unique_ptr<AbstractPipeline> pipeline)
|
||||||
{
|
{
|
||||||
auto& entry = m_gx_pipeline_cache[config];
|
auto& entry = m_gx_pipeline_cache[config];
|
||||||
|
@ -592,7 +594,7 @@ const AbstractPipeline* ShaderCache::InsertGXPipeline(const GXPipelineConfig& co
|
||||||
}
|
}
|
||||||
|
|
||||||
const AbstractPipeline*
|
const AbstractPipeline*
|
||||||
ShaderCache::InsertGXUberPipeline(const GXUberPipelineConfig& config,
|
ShaderCache::InsertGXUberPipeline(const GXUberPipelineUid& config,
|
||||||
std::unique_ptr<AbstractPipeline> pipeline)
|
std::unique_ptr<AbstractPipeline> pipeline)
|
||||||
{
|
{
|
||||||
auto& entry = m_gx_uber_pipeline_cache[config];
|
auto& entry = m_gx_uber_pipeline_cache[config];
|
||||||
|
@ -603,7 +605,7 @@ ShaderCache::InsertGXUberPipeline(const GXUberPipelineConfig& config,
|
||||||
return entry.first.get();
|
return entry.first.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderCache::AppendGXPipelineUID(const GXPipelineConfig& config)
|
void ShaderCache::AppendGXPipelineUID(const GXPipelineUid& config)
|
||||||
{
|
{
|
||||||
// Convert to disk format.
|
// Convert to disk format.
|
||||||
GXPipelineDiskCacheUid disk_uid = {};
|
GXPipelineDiskCacheUid disk_uid = {};
|
||||||
|
@ -633,7 +635,7 @@ void ShaderCache::QueueVertexShaderCompile(const VertexShaderUid& uid)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Retrieve() override { shader_cache->InsertVertexShader(uid, std::move(shader)); }
|
void Retrieve() override { shader_cache->InsertVertexShader(uid, std::move(shader)); }
|
||||||
private:
|
private:
|
||||||
ShaderCache* shader_cache;
|
ShaderCache* shader_cache;
|
||||||
std::unique_ptr<AbstractShader> shader;
|
std::unique_ptr<AbstractShader> shader;
|
||||||
|
@ -661,11 +663,7 @@ void ShaderCache::QueueVertexUberShaderCompile(const UberShader::VertexShaderUid
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Retrieve() override
|
void Retrieve() override { shader_cache->InsertVertexUberShader(uid, std::move(shader)); }
|
||||||
{
|
|
||||||
shader_cache->InsertVertexUberShader(uid, std::move(shader));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ShaderCache* shader_cache;
|
ShaderCache* shader_cache;
|
||||||
std::unique_ptr<AbstractShader> shader;
|
std::unique_ptr<AbstractShader> shader;
|
||||||
|
@ -693,7 +691,7 @@ void ShaderCache::QueuePixelShaderCompile(const PixelShaderUid& uid)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Retrieve() override { shader_cache->InsertPixelShader(uid, std::move(shader)); }
|
void Retrieve() override { shader_cache->InsertPixelShader(uid, std::move(shader)); }
|
||||||
private:
|
private:
|
||||||
ShaderCache* shader_cache;
|
ShaderCache* shader_cache;
|
||||||
std::unique_ptr<AbstractShader> shader;
|
std::unique_ptr<AbstractShader> shader;
|
||||||
|
@ -721,11 +719,7 @@ void ShaderCache::QueuePixelUberShaderCompile(const UberShader::PixelShaderUid&
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Retrieve() override
|
void Retrieve() override { shader_cache->InsertPixelUberShader(uid, std::move(shader)); }
|
||||||
{
|
|
||||||
shader_cache->InsertPixelUberShader(uid, std::move(shader));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ShaderCache* shader_cache;
|
ShaderCache* shader_cache;
|
||||||
std::unique_ptr<AbstractShader> shader;
|
std::unique_ptr<AbstractShader> shader;
|
||||||
|
@ -737,12 +731,12 @@ void ShaderCache::QueuePixelUberShaderCompile(const UberShader::PixelShaderUid&
|
||||||
m_async_shader_compiler->QueueWorkItem(std::move(wi));
|
m_async_shader_compiler->QueueWorkItem(std::move(wi));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderCache::QueuePipelineCompile(const GXPipelineConfig& uid)
|
void ShaderCache::QueuePipelineCompile(const GXPipelineUid& uid)
|
||||||
{
|
{
|
||||||
class PipelineWorkItem final : public AsyncShaderCompiler::WorkItem
|
class PipelineWorkItem final : public AsyncShaderCompiler::WorkItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PipelineWorkItem(ShaderCache* shader_cache_, const GXPipelineConfig& uid_,
|
PipelineWorkItem(ShaderCache* shader_cache_, const GXPipelineUid& uid_,
|
||||||
const AbstractPipelineConfig& config_)
|
const AbstractPipelineConfig& config_)
|
||||||
: shader_cache(shader_cache_), uid(uid_), config(config_)
|
: shader_cache(shader_cache_), uid(uid_), config(config_)
|
||||||
{
|
{
|
||||||
|
@ -754,11 +748,11 @@ void ShaderCache::QueuePipelineCompile(const GXPipelineConfig& uid)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Retrieve() override { shader_cache->InsertGXPipeline(uid, std::move(pipeline)); }
|
void Retrieve() override { shader_cache->InsertGXPipeline(uid, std::move(pipeline)); }
|
||||||
private:
|
private:
|
||||||
ShaderCache* shader_cache;
|
ShaderCache* shader_cache;
|
||||||
std::unique_ptr<AbstractPipeline> pipeline;
|
std::unique_ptr<AbstractPipeline> pipeline;
|
||||||
GXPipelineConfig uid;
|
GXPipelineUid uid;
|
||||||
AbstractPipelineConfig config;
|
AbstractPipelineConfig config;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -775,13 +769,15 @@ void ShaderCache::QueuePipelineCompile(const GXPipelineConfig& uid)
|
||||||
m_gx_pipeline_cache[uid].second = true;
|
m_gx_pipeline_cache[uid].second = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderCache::QueueUberPipelineCompile(const GXUberPipelineConfig& uid)
|
void ShaderCache::QueueUberPipelineCompile(const GXUberPipelineUid& uid)
|
||||||
{
|
{
|
||||||
class UberPipelineWorkItem final : public AsyncShaderCompiler::WorkItem
|
// Since the shaders may not be compiled at pipelines request time, we do this in two passes.
|
||||||
|
// This is necessary because we can't access the caches in the worker thread.
|
||||||
|
class UberPipelineCompilePass final : public AsyncShaderCompiler::WorkItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
UberPipelineWorkItem(ShaderCache* shader_cache_, const GXUberPipelineConfig& uid_,
|
UberPipelineCompilePass(ShaderCache* shader_cache_, const GXUberPipelineUid& uid_,
|
||||||
const AbstractPipelineConfig& config_)
|
const AbstractPipelineConfig& config_)
|
||||||
: shader_cache(shader_cache_), uid(uid_), config(config_)
|
: shader_cache(shader_cache_), uid(uid_), config(config_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -792,27 +788,43 @@ void ShaderCache::QueueUberPipelineCompile(const GXUberPipelineConfig& uid)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Retrieve() override
|
void Retrieve() override { shader_cache->InsertGXUberPipeline(uid, std::move(pipeline)); }
|
||||||
|
private:
|
||||||
|
ShaderCache* shader_cache;
|
||||||
|
std::unique_ptr<AbstractPipeline> pipeline;
|
||||||
|
GXUberPipelineUid uid;
|
||||||
|
AbstractPipelineConfig config;
|
||||||
|
};
|
||||||
|
class UberPipelinePreparePass final : public AsyncShaderCompiler::WorkItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UberPipelinePreparePass(ShaderCache* shader_cache_, const GXUberPipelineUid& uid_)
|
||||||
|
: shader_cache(shader_cache_), uid(uid_)
|
||||||
{
|
{
|
||||||
shader_cache->InsertGXUberPipeline(uid, std::move(pipeline));
|
}
|
||||||
|
|
||||||
|
bool Compile() override { return true; }
|
||||||
|
void Retrieve() override
|
||||||
|
{
|
||||||
|
auto config = shader_cache->GetGXUberPipelineConfig(uid);
|
||||||
|
if (!config)
|
||||||
|
{
|
||||||
|
// One or more stages failed to compile.
|
||||||
|
shader_cache->InsertGXUberPipeline(uid, nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto wi = shader_cache->m_async_shader_compiler->CreateWorkItem<UberPipelineCompilePass>(
|
||||||
|
shader_cache, uid, *config);
|
||||||
|
shader_cache->m_async_shader_compiler->QueueWorkItem(std::move(wi));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ShaderCache* shader_cache;
|
ShaderCache* shader_cache;
|
||||||
std::unique_ptr<AbstractPipeline> pipeline;
|
GXUberPipelineUid uid;
|
||||||
GXUberPipelineConfig uid;
|
|
||||||
AbstractPipelineConfig config;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
auto config = GetGXUberPipelineConfig(uid);
|
auto wi = m_async_shader_compiler->CreateWorkItem<UberPipelinePreparePass>(this, uid);
|
||||||
if (!config)
|
|
||||||
{
|
|
||||||
// One or more stages failed to compile.
|
|
||||||
InsertGXUberPipeline(uid, nullptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto wi = m_async_shader_compiler->CreateWorkItem<UberPipelineWorkItem>(this, uid, *config);
|
|
||||||
m_async_shader_compiler->QueueWorkItem(std::move(wi));
|
m_async_shader_compiler->QueueWorkItem(std::move(wi));
|
||||||
m_gx_uber_pipeline_cache[uid].second = true;
|
m_gx_uber_pipeline_cache[uid].second = true;
|
||||||
}
|
}
|
||||||
|
@ -841,9 +853,6 @@ void ShaderCache::PrecompileUberShaders()
|
||||||
QueuePixelUberShaderCompile(puid);
|
QueuePixelUberShaderCompile(puid);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wait for shaders to finish compiling.
|
|
||||||
WaitForAsyncCompiler(GetStringT("Compiling uber shaders..."));
|
|
||||||
|
|
||||||
// Create a dummy vertex format with no attributes.
|
// Create a dummy vertex format with no attributes.
|
||||||
// All attributes will be enabled in GetUberVertexFormat.
|
// All attributes will be enabled in GetUberVertexFormat.
|
||||||
PortableVertexDeclaration dummy_vertex_decl = {};
|
PortableVertexDeclaration dummy_vertex_decl = {};
|
||||||
|
@ -856,7 +865,7 @@ void ShaderCache::PrecompileUberShaders()
|
||||||
auto QueueDummyPipeline = [&](const UberShader::VertexShaderUid& vs_uid,
|
auto QueueDummyPipeline = [&](const UberShader::VertexShaderUid& vs_uid,
|
||||||
const GeometryShaderUid& gs_uid,
|
const GeometryShaderUid& gs_uid,
|
||||||
const UberShader::PixelShaderUid& ps_uid) {
|
const UberShader::PixelShaderUid& ps_uid) {
|
||||||
GXUberPipelineConfig config;
|
GXUberPipelineUid config;
|
||||||
config.vertex_format = dummy_vertex_format;
|
config.vertex_format = dummy_vertex_format;
|
||||||
config.vs_uid = vs_uid;
|
config.vs_uid = vs_uid;
|
||||||
config.gs_uid = gs_uid;
|
config.gs_uid = gs_uid;
|
||||||
|
|
|
@ -19,10 +19,10 @@
|
||||||
|
|
||||||
#include "VideoCommon/AbstractPipeline.h"
|
#include "VideoCommon/AbstractPipeline.h"
|
||||||
#include "VideoCommon/AbstractShader.h"
|
#include "VideoCommon/AbstractShader.h"
|
||||||
#include "VideoCommon/NativeVertexFormat.h"
|
|
||||||
|
|
||||||
#include "VideoCommon/AsyncShaderCompiler.h"
|
#include "VideoCommon/AsyncShaderCompiler.h"
|
||||||
|
#include "VideoCommon/GXPipelineTypes.h"
|
||||||
#include "VideoCommon/GeometryShaderGen.h"
|
#include "VideoCommon/GeometryShaderGen.h"
|
||||||
|
#include "VideoCommon/NativeVertexFormat.h"
|
||||||
#include "VideoCommon/PixelShaderGen.h"
|
#include "VideoCommon/PixelShaderGen.h"
|
||||||
#include "VideoCommon/RenderState.h"
|
#include "VideoCommon/RenderState.h"
|
||||||
#include "VideoCommon/UberShaderPixel.h"
|
#include "VideoCommon/UberShaderPixel.h"
|
||||||
|
@ -33,64 +33,6 @@ class NativeVertexFormat;
|
||||||
|
|
||||||
namespace VideoCommon
|
namespace VideoCommon
|
||||||
{
|
{
|
||||||
struct GXPipelineConfig
|
|
||||||
{
|
|
||||||
const NativeVertexFormat* vertex_format;
|
|
||||||
VertexShaderUid vs_uid;
|
|
||||||
GeometryShaderUid gs_uid;
|
|
||||||
PixelShaderUid ps_uid;
|
|
||||||
RasterizationState rasterization_state;
|
|
||||||
DepthState depth_state;
|
|
||||||
BlendingState blending_state;
|
|
||||||
|
|
||||||
// We use memcmp() for comparing pipelines as std::tie generates a large number of instructions,
|
|
||||||
// and this map lookup can happen every draw call. However, as using memcmp() will also compare
|
|
||||||
// any padding bytes, we have to ensure these are zeroed out.
|
|
||||||
GXPipelineConfig() { std::memset(this, 0, sizeof(*this)); }
|
|
||||||
GXPipelineConfig(const GXPipelineConfig& rhs) { std::memcpy(this, &rhs, sizeof(*this)); }
|
|
||||||
GXPipelineConfig& operator=(const GXPipelineConfig& rhs)
|
|
||||||
{
|
|
||||||
std::memcpy(this, &rhs, sizeof(*this));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
bool operator<(const GXPipelineConfig& rhs) const
|
|
||||||
{
|
|
||||||
return std::memcmp(this, &rhs, sizeof(*this)) < 0;
|
|
||||||
}
|
|
||||||
bool operator==(const GXPipelineConfig& rhs) const
|
|
||||||
{
|
|
||||||
return std::memcmp(this, &rhs, sizeof(*this)) == 0;
|
|
||||||
}
|
|
||||||
bool operator!=(const GXPipelineConfig& rhs) const { return !operator==(rhs); }
|
|
||||||
};
|
|
||||||
struct GXUberPipelineConfig
|
|
||||||
{
|
|
||||||
const NativeVertexFormat* vertex_format;
|
|
||||||
UberShader::VertexShaderUid vs_uid;
|
|
||||||
GeometryShaderUid gs_uid;
|
|
||||||
UberShader::PixelShaderUid ps_uid;
|
|
||||||
RasterizationState rasterization_state;
|
|
||||||
DepthState depth_state;
|
|
||||||
BlendingState blending_state;
|
|
||||||
|
|
||||||
GXUberPipelineConfig() { std::memset(this, 0, sizeof(*this)); }
|
|
||||||
GXUberPipelineConfig(const GXUberPipelineConfig& rhs) { std::memcpy(this, &rhs, sizeof(*this)); }
|
|
||||||
GXUberPipelineConfig& operator=(const GXUberPipelineConfig& rhs)
|
|
||||||
{
|
|
||||||
std::memcpy(this, &rhs, sizeof(*this));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
bool operator<(const GXUberPipelineConfig& rhs) const
|
|
||||||
{
|
|
||||||
return std::memcmp(this, &rhs, sizeof(*this)) < 0;
|
|
||||||
}
|
|
||||||
bool operator==(const GXUberPipelineConfig& rhs) const
|
|
||||||
{
|
|
||||||
return std::memcmp(this, &rhs, sizeof(*this)) == 0;
|
|
||||||
}
|
|
||||||
bool operator!=(const GXUberPipelineConfig& rhs) const { return !operator==(rhs); }
|
|
||||||
};
|
|
||||||
|
|
||||||
class ShaderCache final
|
class ShaderCache final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -114,15 +56,15 @@ public:
|
||||||
std::string GetUtilityShaderHeader() const;
|
std::string GetUtilityShaderHeader() const;
|
||||||
|
|
||||||
// Accesses ShaderGen shader caches
|
// Accesses ShaderGen shader caches
|
||||||
const AbstractPipeline* GetPipelineForUid(const GXPipelineConfig& uid);
|
const AbstractPipeline* GetPipelineForUid(const GXPipelineUid& uid);
|
||||||
const AbstractPipeline* GetUberPipelineForUid(const GXUberPipelineConfig& uid);
|
const AbstractPipeline* GetUberPipelineForUid(const GXUberPipelineUid& uid);
|
||||||
|
|
||||||
// Accesses ShaderGen shader caches asynchronously.
|
// Accesses ShaderGen shader caches asynchronously.
|
||||||
// The optional will be empty if this pipeline is now background compiling.
|
// The optional will be empty if this pipeline is now background compiling.
|
||||||
std::optional<const AbstractPipeline*> GetPipelineForUidAsync(const GXPipelineConfig& uid);
|
std::optional<const AbstractPipeline*> GetPipelineForUidAsync(const GXPipelineUid& uid);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void WaitForAsyncCompiler(const std::string& msg);
|
void WaitForAsyncCompiler();
|
||||||
void LoadShaderCaches();
|
void LoadShaderCaches();
|
||||||
void ClearShaderCaches();
|
void ClearShaderCaches();
|
||||||
void LoadPipelineUIDCache();
|
void LoadPipelineUIDCache();
|
||||||
|
@ -155,21 +97,21 @@ private:
|
||||||
const AbstractShader* geometry_shader, const AbstractShader* pixel_shader,
|
const AbstractShader* geometry_shader, const AbstractShader* pixel_shader,
|
||||||
const RasterizationState& rasterization_state, const DepthState& depth_state,
|
const RasterizationState& rasterization_state, const DepthState& depth_state,
|
||||||
const BlendingState& blending_state);
|
const BlendingState& blending_state);
|
||||||
std::optional<AbstractPipelineConfig> GetGXPipelineConfig(const GXPipelineConfig& uid);
|
std::optional<AbstractPipelineConfig> GetGXPipelineConfig(const GXPipelineUid& uid);
|
||||||
std::optional<AbstractPipelineConfig> GetGXUberPipelineConfig(const GXUberPipelineConfig& uid);
|
std::optional<AbstractPipelineConfig> GetGXUberPipelineConfig(const GXUberPipelineUid& uid);
|
||||||
const AbstractPipeline* InsertGXPipeline(const GXPipelineConfig& config,
|
const AbstractPipeline* InsertGXPipeline(const GXPipelineUid& config,
|
||||||
std::unique_ptr<AbstractPipeline> pipeline);
|
std::unique_ptr<AbstractPipeline> pipeline);
|
||||||
const AbstractPipeline* InsertGXUberPipeline(const GXUberPipelineConfig& config,
|
const AbstractPipeline* InsertGXUberPipeline(const GXUberPipelineUid& config,
|
||||||
std::unique_ptr<AbstractPipeline> pipeline);
|
std::unique_ptr<AbstractPipeline> pipeline);
|
||||||
void AppendGXPipelineUID(const GXPipelineConfig& config);
|
void AppendGXPipelineUID(const GXPipelineUid& config);
|
||||||
|
|
||||||
// ASync Compiler Methods
|
// ASync Compiler Methods
|
||||||
void QueueVertexShaderCompile(const VertexShaderUid& uid);
|
void QueueVertexShaderCompile(const VertexShaderUid& uid);
|
||||||
void QueueVertexUberShaderCompile(const UberShader::VertexShaderUid& uid);
|
void QueueVertexUberShaderCompile(const UberShader::VertexShaderUid& uid);
|
||||||
void QueuePixelShaderCompile(const PixelShaderUid& uid);
|
void QueuePixelShaderCompile(const PixelShaderUid& uid);
|
||||||
void QueuePixelUberShaderCompile(const UberShader::PixelShaderUid& uid);
|
void QueuePixelUberShaderCompile(const UberShader::PixelShaderUid& uid);
|
||||||
void QueuePipelineCompile(const GXPipelineConfig& uid);
|
void QueuePipelineCompile(const GXPipelineUid& uid);
|
||||||
void QueueUberPipelineCompile(const GXUberPipelineConfig& uid);
|
void QueueUberPipelineCompile(const GXUberPipelineUid& uid);
|
||||||
|
|
||||||
// Configuration bits.
|
// Configuration bits.
|
||||||
APIType m_api_type = APIType::Nothing;
|
APIType m_api_type = APIType::Nothing;
|
||||||
|
@ -196,10 +138,8 @@ private:
|
||||||
ShaderModuleCache<UberShader::PixelShaderUid> m_uber_ps_cache;
|
ShaderModuleCache<UberShader::PixelShaderUid> m_uber_ps_cache;
|
||||||
|
|
||||||
// GX Pipeline Caches - .first - pipeline, .second - pending
|
// GX Pipeline Caches - .first - pipeline, .second - pending
|
||||||
// TODO: Use unordered_map for speed.
|
std::map<GXPipelineUid, std::pair<std::unique_ptr<AbstractPipeline>, bool>> m_gx_pipeline_cache;
|
||||||
std::map<GXPipelineConfig, std::pair<std::unique_ptr<AbstractPipeline>, bool>>
|
std::map<GXUberPipelineUid, std::pair<std::unique_ptr<AbstractPipeline>, bool>>
|
||||||
m_gx_pipeline_cache;
|
|
||||||
std::map<GXUberPipelineConfig, std::pair<std::unique_ptr<AbstractPipeline>, bool>>
|
|
||||||
m_gx_uber_pipeline_cache;
|
m_gx_uber_pipeline_cache;
|
||||||
|
|
||||||
// Disk cache of pipeline UIDs
|
// Disk cache of pipeline UIDs
|
||||||
|
|
|
@ -83,8 +83,8 @@ protected:
|
||||||
Slope m_zslope = {};
|
Slope m_zslope = {};
|
||||||
void CalculateZSlope(NativeVertexFormat* format);
|
void CalculateZSlope(NativeVertexFormat* format);
|
||||||
|
|
||||||
VideoCommon::GXPipelineConfig m_current_pipeline_config;
|
VideoCommon::GXPipelineUid m_current_pipeline_config;
|
||||||
VideoCommon::GXUberPipelineConfig m_current_uber_pipeline_config;
|
VideoCommon::GXUberPipelineUid m_current_uber_pipeline_config;
|
||||||
const AbstractPipeline* m_current_pipeline_object = nullptr;
|
const AbstractPipeline* m_current_pipeline_object = nullptr;
|
||||||
PrimitiveType m_current_primitive_type = PrimitiveType::Points;
|
PrimitiveType m_current_primitive_type = PrimitiveType::Points;
|
||||||
bool m_pipeline_config_changed = true;
|
bool m_pipeline_config_changed = true;
|
||||||
|
|
|
@ -120,6 +120,7 @@
|
||||||
<ClInclude Include="Fifo.h" />
|
<ClInclude Include="Fifo.h" />
|
||||||
<ClInclude Include="FPSCounter.h" />
|
<ClInclude Include="FPSCounter.h" />
|
||||||
<ClInclude Include="FramebufferManagerBase.h" />
|
<ClInclude Include="FramebufferManagerBase.h" />
|
||||||
|
<ClInclude Include="GXPipelineTypes.h" />
|
||||||
<ClInclude Include="ShaderCache.h" />
|
<ClInclude Include="ShaderCache.h" />
|
||||||
<ClInclude Include="UberShaderCommon.h" />
|
<ClInclude Include="UberShaderCommon.h" />
|
||||||
<ClInclude Include="UberShaderPixel.h" />
|
<ClInclude Include="UberShaderPixel.h" />
|
||||||
|
|
|
@ -198,7 +198,7 @@
|
||||||
<Filter>Base</Filter>
|
<Filter>Base</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="ShaderCache.cpp">
|
<ClCompile Include="ShaderCache.cpp">
|
||||||
<Filter>Shader Managers</Filter>
|
<Filter>Shader Generators</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -381,8 +381,11 @@
|
||||||
<ClInclude Include="AbstractFramebuffer.h">
|
<ClInclude Include="AbstractFramebuffer.h">
|
||||||
<Filter>Base</Filter>
|
<Filter>Base</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="GXPipelineTypes.h">
|
||||||
|
<Filter>Shader Generators</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="ShaderCache.h">
|
<ClInclude Include="ShaderCache.h">
|
||||||
<Filter>Shader Managers</Filter>
|
<Filter>Shader Generators</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -102,6 +102,7 @@ void VideoConfig::Refresh()
|
||||||
bBackendMultithreading = Config::Get(Config::GFX_BACKEND_MULTITHREADING);
|
bBackendMultithreading = Config::Get(Config::GFX_BACKEND_MULTITHREADING);
|
||||||
iCommandBufferExecuteInterval = Config::Get(Config::GFX_COMMAND_BUFFER_EXECUTE_INTERVAL);
|
iCommandBufferExecuteInterval = Config::Get(Config::GFX_COMMAND_BUFFER_EXECUTE_INTERVAL);
|
||||||
bShaderCache = Config::Get(Config::GFX_SHADER_CACHE);
|
bShaderCache = Config::Get(Config::GFX_SHADER_CACHE);
|
||||||
|
bWaitForShadersBeforeStarting = Config::Get(Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING);
|
||||||
iUberShaderMode = static_cast<UberShaderMode>(Config::Get(Config::GFX_UBERSHADER_MODE));
|
iUberShaderMode = static_cast<UberShaderMode>(Config::Get(Config::GFX_UBERSHADER_MODE));
|
||||||
iShaderCompilerThreads = Config::Get(Config::GFX_SHADER_COMPILER_THREADS);
|
iShaderCompilerThreads = Config::Get(Config::GFX_SHADER_COMPILER_THREADS);
|
||||||
iShaderPrecompilerThreads = Config::Get(Config::GFX_SHADER_PRECOMPILER_THREADS);
|
iShaderPrecompilerThreads = Config::Get(Config::GFX_SHADER_PRECOMPILER_THREADS);
|
||||||
|
@ -196,6 +197,10 @@ u32 VideoConfig::GetShaderCompilerThreads() const
|
||||||
|
|
||||||
u32 VideoConfig::GetShaderPrecompilerThreads() const
|
u32 VideoConfig::GetShaderPrecompilerThreads() const
|
||||||
{
|
{
|
||||||
|
// When using background compilation, always keep the same thread count.
|
||||||
|
if (bWaitForShadersBeforeStarting)
|
||||||
|
return GetShaderCompilerThreads();
|
||||||
|
|
||||||
if (!backend_info.bSupportsBackgroundCompiling)
|
if (!backend_info.bSupportsBackgroundCompiling)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -169,6 +169,7 @@ struct VideoConfig final
|
||||||
int iCommandBufferExecuteInterval;
|
int iCommandBufferExecuteInterval;
|
||||||
|
|
||||||
// Shader compilation settings.
|
// Shader compilation settings.
|
||||||
|
bool bWaitForShadersBeforeStarting;
|
||||||
UberShaderMode iUberShaderMode;
|
UberShaderMode iUberShaderMode;
|
||||||
|
|
||||||
// Number of shader compiler threads.
|
// Number of shader compiler threads.
|
||||||
|
|
Loading…
Reference in New Issue