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);