summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/ShaderCache.cpp
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2022-09-20 17:14:07 -0400
committerGitHub <noreply@github.com>2022-09-20 17:14:07 -0400
commit22197c09a3cf2753c007d8ef8d75daa5fc2c44b9 (patch)
tree14d5aa4ae61d100f3bc7a394021963258fbf3dc1 /Source/Core/VideoCommon/ShaderCache.cpp
parent4ea694a7e403c673b457643e52435b355c96fd87 (diff)
parentee692abbe1032e9eb888defedb1bb00f569f68a3 (diff)
Merge pull request #10781 from tellowkrinkle/UberVertexLoader
VideoCommon: Add dynamic vertex loader for ubershaders to reduce pipeline count
Diffstat (limited to 'Source/Core/VideoCommon/ShaderCache.cpp')
-rw-r--r--Source/Core/VideoCommon/ShaderCache.cpp99
1 files changed, 70 insertions, 29 deletions
diff --git a/Source/Core/VideoCommon/ShaderCache.cpp b/Source/Core/VideoCommon/ShaderCache.cpp
index 6049fd29a7..f281024f22 100644
--- a/Source/Core/VideoCommon/ShaderCache.cpp
+++ b/Source/Core/VideoCommon/ShaderCache.cpp
@@ -588,10 +588,10 @@ AbstractPipelineConfig ShaderCache::GetGXPipelineConfig(
const NativeVertexFormat* vertex_format, const AbstractShader* vertex_shader,
const AbstractShader* geometry_shader, const AbstractShader* pixel_shader,
const RasterizationState& rasterization_state, const DepthState& depth_state,
- const BlendingState& blending_state)
+ const BlendingState& blending_state, AbstractPipelineUsage usage)
{
AbstractPipelineConfig config = {};
- config.usage = AbstractPipelineUsage::GX;
+ config.usage = usage;
config.vertex_format = vertex_format;
config.vertex_shader = vertex_shader;
config.geometry_shader = geometry_shader;
@@ -735,7 +735,7 @@ ShaderCache::GetGXPipelineConfig(const GXPipelineUid& config_in)
}
return GetGXPipelineConfig(config.vertex_format, vs, gs, ps, config.rasterization_state,
- config.depth_state, config.blending_state);
+ config.depth_state, config.blending_state, AbstractPipelineUsage::GX);
}
/// Edits the UID based on driver bugs and other special configurations
@@ -743,6 +743,8 @@ static GXUberPipelineUid ApplyDriverBugs(const GXUberPipelineUid& in)
{
GXUberPipelineUid out;
memcpy(&out, &in, sizeof(out)); // Copy padding
+ if (g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader)
+ out.vertex_format = nullptr;
if (g_ActiveConfig.backend_info.bSupportsFramebufferFetch)
{
// Always blend in shader
@@ -798,7 +800,8 @@ ShaderCache::GetGXPipelineConfig(const GXUberPipelineUid& config_in)
}
return GetGXPipelineConfig(config.vertex_format, vs, gs, ps, config.rasterization_state,
- config.depth_state, config.blending_state);
+ config.depth_state, config.blending_state,
+ AbstractPipelineUsage::GXUber);
}
const AbstractPipeline* ShaderCache::InsertGXPipeline(const GXPipelineUid& config,
@@ -1233,32 +1236,32 @@ void ShaderCache::QueueUberShaderPipelines()
dummy_vertex_decl.stride = sizeof(float) * 4;
NativeVertexFormat* dummy_vertex_format =
VertexLoaderManager::GetUberVertexFormat(dummy_vertex_decl);
- auto QueueDummyPipeline = [&](const UberShader::VertexShaderUid& vs_uid,
- const GeometryShaderUid& gs_uid,
- const UberShader::PixelShaderUid& ps_uid) {
- GXUberPipelineUid config;
- config.vertex_format = dummy_vertex_format;
- config.vs_uid = vs_uid;
- config.gs_uid = gs_uid;
- config.ps_uid = ps_uid;
- config.rasterization_state = RenderState::GetCullBackFaceRasterizationState(
- static_cast<PrimitiveType>(gs_uid.GetUidData()->primitive_type));
- config.depth_state = RenderState::GetNoDepthTestingDepthState();
- config.blending_state = RenderState::GetNoBlendingBlendState();
- if (ps_uid.GetUidData()->uint_output)
- {
- // uint_output is only ever enabled when logic ops are enabled.
- config.blending_state.logicopenable = true;
- config.blending_state.logicmode = LogicOp::And;
- }
+ auto QueueDummyPipeline =
+ [&](const UberShader::VertexShaderUid& vs_uid, const GeometryShaderUid& gs_uid,
+ const UberShader::PixelShaderUid& ps_uid, const BlendingState& blend) {
+ GXUberPipelineUid config;
+ config.vertex_format = dummy_vertex_format;
+ config.vs_uid = vs_uid;
+ config.gs_uid = gs_uid;
+ config.ps_uid = ps_uid;
+ config.rasterization_state = RenderState::GetCullBackFaceRasterizationState(
+ static_cast<PrimitiveType>(gs_uid.GetUidData()->primitive_type));
+ config.depth_state = RenderState::GetNoDepthTestingDepthState();
+ config.blending_state = blend;
+ if (ps_uid.GetUidData()->uint_output)
+ {
+ // uint_output is only ever enabled when logic ops are enabled.
+ config.blending_state.logicopenable = true;
+ config.blending_state.logicmode = LogicOp::And;
+ }
- auto iter = m_gx_uber_pipeline_cache.find(config);
- if (iter != m_gx_uber_pipeline_cache.end())
- return;
+ auto iter = m_gx_uber_pipeline_cache.find(config);
+ if (iter != m_gx_uber_pipeline_cache.end())
+ return;
- auto& entry = m_gx_uber_pipeline_cache[config];
- entry.second = false;
- };
+ auto& entry = m_gx_uber_pipeline_cache[config];
+ entry.second = false;
+ };
// Populate the pipeline configs with empty entries, these will be compiled afterwards.
UberShader::EnumerateVertexShaderUids([&](const UberShader::VertexShaderUid& vuid) {
@@ -1275,7 +1278,45 @@ void ShaderCache::QueueUberShaderPipelines()
{
return;
}
- QueueDummyPipeline(vuid, guid, cleared_puid);
+ BlendingState blend = RenderState::GetNoBlendingBlendState();
+ QueueDummyPipeline(vuid, guid, cleared_puid, blend);
+ if (g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader)
+ {
+ // Not all GPUs need all the pipeline state compiled into shaders, so they tend to key
+ // compiled shaders based on some subset of the pipeline state.
+ // Some test results:
+ // (GPUs tested: AMD Radeon Pro 5600M, Nvidia GT 750M, Intel UHD 630,
+ // Intel Iris Pro 5200, Apple M1)
+ // MacOS Metal:
+ // - AMD, Nvidia, Intel GPUs: Shaders are keyed on vertex layout and whether or not
+ // dual source blend is enabled. That's it.
+ // - Apple GPUs: Shaders are keyed on vertex layout and all blending settings. We use
+ // framebuffer fetch here, so the only blending settings used by ubershaders are the
+ // alphaupdate and colorupdate ones. Also keyed on primitive type, but Metal supports
+ // setting it to "unknown" and we do for ubershaders (but MoltenVK won't).
+ // Windows Vulkan:
+ // - AMD, Nvidia: Definitely keyed on dual source blend, but the others seem more random
+ // Changing a setting on one shader will require a recompile, but changing the same
+ // setting on another won't. Compiling a copy with alphaupdate off, colorupdate off,
+ // and one with DSB on seems to get pretty good coverage though.
+ // Windows D3D12:
+ // - AMD: Keyed on dual source blend and vertex layout
+ // - Nvidia Kepler: No recompiles for changes to vertex layout or blend
+ blend.alphaupdate = false;
+ QueueDummyPipeline(vuid, guid, cleared_puid, blend);
+ blend.alphaupdate = true;
+ blend.colorupdate = false;
+ QueueDummyPipeline(vuid, guid, cleared_puid, blend);
+ blend.colorupdate = true;
+ if (!cleared_puid.GetUidData()->no_dual_src && !cleared_puid.GetUidData()->uint_output)
+ {
+ blend.blendenable = true;
+ blend.usedualsrc = true;
+ blend.srcfactor = SrcBlendFactor::SrcAlpha;
+ blend.dstfactor = DstBlendFactor::InvSrcAlpha;
+ QueueDummyPipeline(vuid, guid, cleared_puid, blend);
+ }
+ }
});
});
});