aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 14:28:34 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 20:49:48 -0400
commit01fce03d24380ae647c07f02dd063981baae041a (patch)
tree62423c07f89d7048c797985a526e69da44da9498 /src
parent15e953cafd5cb348833cb373d7ddd996b81307f7 (diff)
vulkan: leave the alpha test reference out of pipelines that don't test alpha
FixedPipelineState stored alpha_test_ref whatever the alpha test function. Title 1 animates the register with the test off (text fading in and out), so every value made a new pipeline whose shaders were lowered and translated on the GPU thread: bursts of 600-1,900 pipelines in 10 s (up to 5 s of GPU thread) whenever text was on screen. The reference is now kept only while the test compares with it (not Always or Never). Driving title 1's menus: 400+ pipelines for already-known shaders before, 0 after; one shader lowered 79 times before, 2 after. EDEN_NX2_PIPELINE_DIFF=1 logs which fixed-state fields differ when a new pipeline reuses known shaders.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.cpp9
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp56
2 files changed, 64 insertions, 1 deletions
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
index 0ced890929..9dac98c830 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
@@ -179,7 +179,14 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
for (size_t i = 0; i < regs.rt.size(); ++i) {
color_formats[i] = static_cast<u8>(regs.rt[i].format);
}
- alpha_test_ref = std::bit_cast<u32>(regs.alpha_test_ref);
+ // The reference is part of the pipeline only while the test compares with it: title 1
+ // animates the register with the test off (text fading in and out), which made a new
+ // pipeline, translated on the GPU thread, for every value (~84% of its runtime pipelines).
+ const u32 packed_alpha_test = alpha_test_func.Value();
+ alpha_test_ref = packed_alpha_test != PackComparisonOp(Maxwell::ComparisonOp::Never_GL) &&
+ packed_alpha_test != PackComparisonOp(Maxwell::ComparisonOp::Always_GL)
+ ? std::bit_cast<u32>(regs.alpha_test_ref)
+ : 0;
point_size = std::bit_cast<u32>(regs.point_size);
if (maxwell3d.dirty.flags[Dirty::VertexInput]) {
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 60bb040984..17f57983e3 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -768,10 +768,66 @@ void PipelineCache::QueueVulkanPipelineCacheFlush() {
});
}
+namespace {
+// EDEN_NX2_PIPELINE_DIFF=1: for a new graphics pipeline whose shaders an earlier one uses too,
+// log which parts of the fixed state differ from that one (finds state that splits the same
+// draws into many pipelines, each translated on the GPU thread).
+void ReportNewPipelineKey(const GraphicsPipelineCacheKey& key) {
+ static const bool enabled = std::getenv("EDEN_NX2_PIPELINE_DIFF") != nullptr;
+ if (!enabled) {
+ return;
+ }
+ static std::unordered_map<u64, GraphicsPipelineCacheKey> last_by_shaders;
+ static u32 logged{};
+ const u64 shaders = Common::CityHash64(reinterpret_cast<const char*>(key.unique_hashes.data()),
+ sizeof(key.unique_hashes));
+ const auto [it, first] = last_by_shaders.try_emplace(shaders, key);
+ if (first) {
+ return;
+ }
+ const FixedPipelineState& now = key.state;
+ const FixedPipelineState& before = it->second.state;
+ std::string diffs;
+ if (now.raw1 != before.raw1) diffs += fmt::format(" raw1^{:#x}", now.raw1 ^ before.raw1);
+ if (now.raw2 != before.raw2) diffs += fmt::format(" raw2^{:#x}", now.raw2 ^ before.raw2);
+ if (now.color_formats != before.color_formats) {
+ diffs += fmt::format(" color_formats {:02x} -> {:02x}", fmt::join(before.color_formats, ""),
+ fmt::join(now.color_formats, ""));
+ }
+ if (now.alpha_test_ref != before.alpha_test_ref) {
+ diffs += fmt::format(" alpha_test_ref {:#x} -> {:#x} (func {})", before.alpha_test_ref,
+ now.alpha_test_ref, now.alpha_test_func.Value());
+ }
+ if (now.point_size != before.point_size) {
+ diffs += fmt::format(" point_size {:#x} -> {:#x}", before.point_size, now.point_size);
+ }
+ if (now.viewport_swizzles != before.viewport_swizzles) diffs += " viewport_swizzles";
+ if (now.attribute_types != before.attribute_types) {
+ diffs += fmt::format(" attribute_types^{:#x}", now.attribute_types ^ before.attribute_types);
+ }
+ if (std::memcmp(&now.dynamic_state, &before.dynamic_state, sizeof(now.dynamic_state)) != 0) {
+ diffs += " dynamic_state";
+ }
+ if (now.driver_id != before.driver_id || now.driver_version != before.driver_version) {
+ diffs += " driver";
+ }
+ const size_t size = now.Size();
+ if (diffs.empty() && size > offsetof(FixedPipelineState, attachments)) {
+ diffs = fmt::format(" past attachments (key size {})", size);
+ }
+ it->second = key;
+ if (logged++ < 400) {
+ LOG_INFO(Render_Vulkan, "New pipeline for known shaders {:016x} differs in:{}", shaders,
+ diffs.empty() ? std::string{" nothing in the key prefix"} : diffs);
+ }
+}
+} // Anonymous namespace
+
GraphicsPipeline* PipelineCache::CurrentGraphicsPipelineSlowPath() {
const auto [pair, is_new]{graphics_cache.try_emplace(graphics_key)};
auto& pipeline{pair->second};
if (is_new) {
+ ReportNewPipelineKey(graphics_key);
pipeline = CreateGraphicsPipeline();
}
if (!pipeline) {