From 42b8ca5f9d7c8832e59f691e953728ad6cc08fcf Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Thu, 13 Aug 2026 03:48:54 -0400 Subject: [PATCH] Remove LSFG HDR + other optimizations on extra frame --- .../features/settings/model/BooleanSetting.kt | 1 - .../settings/model/view/SettingsItem.kt | 7 ----- .../settings/ui/SettingsFragmentPresenter.kt | 1 - .../app/src/main/res/values/strings.xml | 2 -- src/common/settings.h | 3 -- .../renderer_vulkan/present/frame_gen.cpp | 30 ++++++++++++------- .../renderer_vulkan/present/frame_gen.h | 6 ++-- .../renderer_vulkan/present/lsfg_chain.cpp | 4 +-- .../renderer_vulkan/present/lsfg_chain.h | 3 +- .../renderer_vulkan/present/lsfg_common.cpp | 4 +-- .../renderer_vulkan/present/lsfg_common.h | 7 ++--- .../renderer_vulkan/renderer_vulkan.cpp | 9 +++--- .../renderer_vulkan/vk_present_manager.cpp | 4 +-- .../renderer_vulkan/vk_present_manager.h | 4 +-- 14 files changed, 38 insertions(+), 47 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index db562848fd..ddeebd6ce0 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -38,7 +38,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { RENDERER_VERTEX_INPUT_DYNAMIC_STATE("vertex_input_dynamic_state"), RENDERER_SAMPLE_SHADING("sample_shading"), RENDERER_FRAME_GEN("frame_gen"), - RENDERER_FRAME_GEN_HDR("frame_gen_hdr"), RENDERER_FRAME_GEN_FP16("frame_gen_fp16"), RENDERER_FRAME_GEN_DUMP_FLOW("frame_gen_dump_flow"), GPU_UNSWIZZLE_ENABLED("gpu_unswizzle_enabled"), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 1811045d63..4838291ae4 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -633,13 +633,6 @@ abstract class SettingsItem( units = "%" ) ) - put( - SwitchSetting( - BooleanSetting.RENDERER_FRAME_GEN_HDR, - titleId = R.string.frame_gen_hdr, - descriptionId = R.string.frame_gen_hdr_description - ) - ) put( SwitchSetting( BooleanSetting.RENDERER_FRAME_GEN_FP16, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 2f8fd9474d..ffb99e4c63 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -119,7 +119,6 @@ class SettingsFragmentPresenter( add(IntSetting.RENDERER_FRAME_GEN_MULTIPLIER.key) add(IntSetting.RENDERER_FRAME_GEN_FLOW_SCALE.key) add(BooleanSetting.RENDERER_FRAME_GEN_FP16.key) - add(BooleanSetting.RENDERER_FRAME_GEN_HDR.key) add(BooleanSetting.RENDERER_FRAME_GEN_DUMP_FLOW.key) } } diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 225912ec87..6648aaedd4 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -309,8 +309,6 @@ Resolution of the optical flow pass, as a fraction of the output. Lowering it is the cheapest way to reclaim performance. Half precision shaders Use the 16-bit shader variant shipped in Lossless.dll. Much faster on Adreno. Falls back automatically if the driver or the file lacks it. - HDR interpolation - Treat frames as HDR when interpolating. Only useful on an HDR output. Dump generated frame Write the optical flow mip levels and the interpolated frame to the lossless/debug folder once, for troubleshooting Frame generation unavailable diff --git a/src/common/settings.h b/src/common/settings.h index 3c7172e855..9ed33556c1 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -414,9 +414,6 @@ struct Values { true, &frame_gen}; - SwitchableSetting frame_gen_hdr{linkage, false, "frame_gen_hdr", Category::Renderer, - Specialization::Default, true, true, &frame_gen}; - SwitchableSetting frame_gen_fp16{linkage, true, "frame_gen_fp16", Category::Renderer, Specialization::Default, true, true, &frame_gen}; diff --git a/src/video_core/renderer_vulkan/present/frame_gen.cpp b/src/video_core/renderer_vulkan/present/frame_gen.cpp index 7ec2364083..d87a3562d4 100644 --- a/src/video_core/renderer_vulkan/present/frame_gen.cpp +++ b/src/video_core/renderer_vulkan/present/frame_gen.cpp @@ -182,7 +182,9 @@ FrameGen::FrameGen(MemoryAllocator& memory_allocator_, Scheduler& scheduler_) FrameGen::~FrameGen() = default; -void FrameGen::Process(const Device& device, Frame* frame, VkFormat format) { +void FrameGen::Process(const Device& device, Frame* frame, VkFormat format, bool generate) { + generated = false; + if (unavailable || !Settings::values.frame_gen.GetValue()) { return; } @@ -198,20 +200,23 @@ void FrameGen::Process(const Device& device, Frame* frame, VkFormat format) { const VkExtent2D extent{.width = frame->width, .height = frame->height}; if (!chain || built_extent.width != extent.width || built_extent.height != extent.height || built_format != format || built_flow_scale != ConfiguredFlowScale() || - built_hdr != Settings::values.frame_gen_hdr.GetValue() || built_generations != ConfiguredGenerations()) { Rebuild(device, extent, format); } const u64 count = frame_count++; + generated = generate && count + 1 >= LSFG_REQUIRED_FRAMES; scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([this, source = *frame->image, extent, count](vk::CommandBuffer cmdbuf) { + scheduler.Record([this, source = *frame->image, extent, count, + dispatch = generated](vk::CommandBuffer cmdbuf) { CopyPresentedFrame(cmdbuf, source, chain->Input(count), extent); - chain->Dispatch(cmdbuf, count); + if (dispatch) { + chain->Dispatch(cmdbuf, count); + } }); - const bool dump_requested = Settings::values.frame_gen_dump_flow.GetValue(); + const bool dump_requested = generated && Settings::values.frame_gen_dump_flow.GetValue(); if (!dump_requested) { dumped = false; } else if (!dumped) { @@ -220,12 +225,15 @@ void FrameGen::Process(const Device& device, Frame* frame, VkFormat format) { } } -size_t FrameGen::GeneratedFrameCount() const { - if (!chain || frame_count < LSFG_REQUIRED_FRAMES || - !Settings::values.frame_gen.GetValue()) { +size_t FrameGen::WantedGenerations() const { + if (unavailable || !Settings::values.frame_gen.GetValue()) { return 0; } - return chain->GenerationCount(); + return ConfiguredGenerations(); +} + +size_t FrameGen::GeneratedFrameCount() const { + return generated && chain ? chain->GenerationCount() : 0; } void FrameGen::CopyToFrame(Frame* destination, size_t generation) { @@ -273,14 +281,14 @@ void FrameGen::Rebuild(const Device& device, VkExtent2D extent, VkFormat format) chain.reset(); built_flow_scale = ConfiguredFlowScale(); - built_hdr = Settings::values.frame_gen_hdr.GetValue(); built_generations = ConfiguredGenerations(); - chain.emplace(device, memory_allocator, *shaders, extent, format, built_flow_scale, built_hdr, + chain.emplace(device, memory_allocator, *shaders, extent, format, built_flow_scale, built_generations); built_extent = extent; built_format = format; frame_count = 0; + generated = false; } void FrameGen::DumpDebugImages(u64 count) { diff --git a/src/video_core/renderer_vulkan/present/frame_gen.h b/src/video_core/renderer_vulkan/present/frame_gen.h index 42991fbf23..93f8cc83ac 100644 --- a/src/video_core/renderer_vulkan/present/frame_gen.h +++ b/src/video_core/renderer_vulkan/present/frame_gen.h @@ -21,7 +21,9 @@ public: explicit FrameGen(MemoryAllocator& memory_allocator, Scheduler& scheduler); ~FrameGen(); - void Process(const Device& device, Frame* frame, VkFormat format); + void Process(const Device& device, Frame* frame, VkFormat format, bool generate); + + [[nodiscard]] size_t WantedGenerations() const; [[nodiscard]] size_t GeneratedFrameCount() const; @@ -39,9 +41,9 @@ private: VkExtent2D built_extent{}; VkFormat built_format{VK_FORMAT_UNDEFINED}; f32 built_flow_scale{}; - bool built_hdr{}; size_t built_generations{}; u64 frame_count{}; + bool generated{}; bool unavailable{}; bool dumped{}; }; diff --git a/src/video_core/renderer_vulkan/present/lsfg_chain.cpp b/src/video_core/renderer_vulkan/present/lsfg_chain.cpp index 886f9eb16c..102c9b69fa 100644 --- a/src/video_core/renderer_vulkan/present/lsfg_chain.cpp +++ b/src/video_core/renderer_vulkan/present/lsfg_chain.cpp @@ -19,9 +19,9 @@ constexpr size_t FIRST_DELTA_LEVEL = 4; LsfgChain::LsfgChain(const Device& device, MemoryAllocator& memory_allocator, const LsfgShaders& shaders, VkExtent2D extent, VkFormat format, - f32 flow_scale, bool is_hdr, size_t generation_count_) + f32 flow_scale, size_t generation_count_) : generation_count{generation_count_}, - resources{device, memory_allocator, flow_scale, is_hdr}, + resources{device, memory_allocator, flow_scale}, descriptor_pool{CreateLsfgDescriptorPool( device, FIXED_DESCRIPTOR_SETS + DESCRIPTOR_SETS_PER_GENERATION * static_cast(generation_count))} { diff --git a/src/video_core/renderer_vulkan/present/lsfg_chain.h b/src/video_core/renderer_vulkan/present/lsfg_chain.h index 36dc9fff32..0a988f2af0 100644 --- a/src/video_core/renderer_vulkan/present/lsfg_chain.h +++ b/src/video_core/renderer_vulkan/present/lsfg_chain.h @@ -24,8 +24,7 @@ constexpr size_t LSFG_DELTA_INSTANCES = 3; class LsfgChain { public: LsfgChain(const Device& device, MemoryAllocator& memory_allocator, const LsfgShaders& shaders, - VkExtent2D extent, VkFormat format, f32 flow_scale, bool is_hdr, - size_t generation_count_); + VkExtent2D extent, VkFormat format, f32 flow_scale, size_t generation_count_); LsfgChain(const LsfgChain&) = delete; LsfgChain& operator=(const LsfgChain&) = delete; diff --git a/src/video_core/renderer_vulkan/present/lsfg_common.cpp b/src/video_core/renderer_vulkan/present/lsfg_common.cpp index b882a10263..c84bf544c5 100644 --- a/src/video_core/renderer_vulkan/present/lsfg_common.cpp +++ b/src/video_core/renderer_vulkan/present/lsfg_common.cpp @@ -154,8 +154,8 @@ VkBuffer LsfgResources::GetBuffer(f32 timestamp, bool first_iter, bool first_ite .input_offset = {0, 0}, .first_iter = first_iter ? 1u : 0u, .first_iter_s = first_iter_s ? 1u : 0u, - .advanced_color_kind = is_hdr ? 2u : 0u, - .hdr_support = is_hdr ? 1u : 0u, + .advanced_color_kind = 0, + .hdr_support = 0, .resolution_inv_scale = 1.0f / flow_scale, .timestamp = timestamp, .ui_threshold = 0.5f, diff --git a/src/video_core/renderer_vulkan/present/lsfg_common.h b/src/video_core/renderer_vulkan/present/lsfg_common.h index 9a2cd3b608..f9fd7d98ae 100644 --- a/src/video_core/renderer_vulkan/present/lsfg_common.h +++ b/src/video_core/renderer_vulkan/present/lsfg_common.h @@ -76,10 +76,8 @@ using LsfgImageHistory = std::array; class LsfgResources { public: LsfgResources() = default; - LsfgResources(const Device& device_, MemoryAllocator& memory_allocator_, f32 flow_scale_, - bool is_hdr_) - : device{&device_}, memory_allocator{&memory_allocator_}, flow_scale{flow_scale_}, - is_hdr{is_hdr_} {} + LsfgResources(const Device& device_, MemoryAllocator& memory_allocator_, f32 flow_scale_) + : device{&device_}, memory_allocator{&memory_allocator_}, flow_scale{flow_scale_} {} [[nodiscard]] VkSampler GetSampler( VkSamplerAddressMode address_mode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, @@ -94,7 +92,6 @@ private: const Device* device{}; MemoryAllocator* memory_allocator{}; f32 flow_scale{1.0f}; - bool is_hdr{}; std::map samplers; std::map buffers; diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 7dc0043640..463573709c 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -193,14 +193,13 @@ void RendererVulkan::Composite(std::span framebu render_window.GetFramebufferLayout(), swapchain.GetImageCount(), swapchain.GetImageViewFormat()); - frame_gen.Process(device, frame, swapchain.GetImageFormat()); + const size_t wanted = frame_gen.WantedGenerations(); + const bool can_present_all = wanted > 0 && present_manager.AvailableExtraFrames() >= wanted; + + frame_gen.Process(device, frame, swapchain.GetImageFormat(), can_present_all); const size_t generated_frames = frame_gen.GeneratedFrameCount(); for (size_t generation = 0; generation < generated_frames; ++generation) { - if (!present_manager.CanQueueExtraFrame()) { - break; - } - Frame* generated = present_manager.GetRenderFrame(); blit_swapchain.PrepareFrame(device, generated, render_window.GetFramebufferLayout()); frame_gen.CopyToFrame(generated, generation); diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index bbef7b6e9e..04790afb9f 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp @@ -181,9 +181,9 @@ void PresentManager::Present(Frame* frame) { } } -bool PresentManager::CanQueueExtraFrame() { +size_t PresentManager::AvailableExtraFrames() { std::scoped_lock lock{free_mutex}; - return !free_queue.empty(); + return free_queue.size(); } void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat image_view_format, diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h index 3518f99a9b..1470c6c688 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.h +++ b/src/video_core/renderer_vulkan/vk_present_manager.h @@ -60,8 +60,8 @@ public: /// Waits for the present thread to finish presenting all queued frames. void WaitPresent(); - /// Whether an additional frame can be queued without stalling the render thread - bool CanQueueExtraFrame(); + /// How many additional frames can be queued without stalling the render thread + size_t AvailableExtraFrames(); private: void PresentThread(std::stop_token token);