First intent on motion resolution flow auto

This commit is contained in:
CamilleLaVey
2026-08-13 21:17:09 -04:00
parent 59384de777
commit 9a8a30ba43
8 changed files with 76 additions and 10 deletions
@@ -39,6 +39,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
RENDERER_SAMPLE_SHADING("sample_shading"),
RENDERER_FRAME_GEN("frame_gen"),
RENDERER_FRAME_GEN_FP16("frame_gen_fp16"),
RENDERER_FRAME_GEN_FLOW_SCALE_AUTO("frame_gen_flow_scale_auto"),
RENDERER_FRAME_GEN_DUMP_FLOW("frame_gen_dump_flow"),
GPU_UNSWIZZLE_ENABLED("gpu_unswizzle_enabled"),
PICTURE_IN_PICTURE("picture_in_picture"),
@@ -100,6 +100,7 @@ abstract class SettingsItem(
BooleanSetting.RENDERER_FRAME_GEN.key,
IntSetting.RENDERER_FRAME_GEN_MULTIPLIER.key,
IntSetting.RENDERER_FRAME_GEN_QUEUE_TARGET.key,
BooleanSetting.RENDERER_FRAME_GEN_FLOW_SCALE_AUTO.key,
IntSetting.RENDERER_FRAME_GEN_FLOW_SCALE.key,
BooleanSetting.RENDERER_FRAME_GEN_FP16.key,
BooleanSetting.RENDERER_FRAME_GEN_DUMP_FLOW.key
@@ -648,6 +649,13 @@ abstract class SettingsItem(
valuesId = R.array.frameGenQueueTargetValues
)
)
put(
SwitchSetting(
BooleanSetting.RENDERER_FRAME_GEN_FLOW_SCALE_AUTO,
titleId = R.string.frame_gen_flow_scale_auto,
descriptionId = R.string.frame_gen_flow_scale_auto_description
)
)
put(
SliderSetting(
IntSetting.RENDERER_FRAME_GEN_FLOW_SCALE,
@@ -127,7 +127,13 @@ class SettingsFragmentPresenter(
add(BooleanSetting.RENDERER_FRAME_GEN.key)
add(IntSetting.RENDERER_FRAME_GEN_MULTIPLIER.key)
add(IntSetting.RENDERER_FRAME_GEN_QUEUE_TARGET.key)
add(IntSetting.RENDERER_FRAME_GEN_FLOW_SCALE.key)
add(BooleanSetting.RENDERER_FRAME_GEN_FLOW_SCALE_AUTO.key)
if (!BooleanSetting.RENDERER_FRAME_GEN_FLOW_SCALE_AUTO.getBoolean(
getNeedsGlobalForKey(BooleanSetting.RENDERER_FRAME_GEN_FLOW_SCALE_AUTO.key)
)
) {
add(IntSetting.RENDERER_FRAME_GEN_FLOW_SCALE.key)
}
add(BooleanSetting.RENDERER_FRAME_GEN_FP16.key)
}
}
@@ -311,6 +311,8 @@
<string name="frame_gen_queue_target_0">Unbuffered (lowest latency)</string>
<string name="frame_gen_queue_target_1">One frame (balanced)</string>
<string name="frame_gen_queue_target_2">Two frames (smoothest)</string>
<string name="frame_gen_flow_scale_auto">Match motion estimation to the game</string>
<string name="frame_gen_flow_scale_auto_description">Estimate motion at the resolution the game actually renders instead of the upscaled output. Costs nothing in accuracy, since upscaling adds no motion detail.</string>
<string name="frame_gen_flow_scale">Motion estimation resolution</string>
<string name="frame_gen_flow_scale_description">Resolution of the optical flow pass, as a fraction of the output. Lowering it is the cheapest way to reclaim performance.</string>
<string name="frame_gen_fp16">Half precision shaders</string>
+9
View File
@@ -402,6 +402,15 @@ struct Values {
false,
&frame_gen};
SwitchableSetting<bool> frame_gen_flow_scale_auto{linkage,
true,
"frame_gen_flow_scale_auto",
Category::Renderer,
Specialization::Default,
true,
false,
&frame_gen};
SwitchableSetting<u32, true> frame_gen_flow_scale{linkage,
75,
25,
@@ -22,10 +22,27 @@ namespace {
constexpr size_t COLOR_CHANNELS = 4;
constexpr u64 LSFG_REQUIRED_FRAMES = 2;
[[nodiscard]] f32 ConfiguredFlowScale() {
[[nodiscard]] f32 ManualFlowScale() {
return static_cast<f32>(Settings::values.frame_gen_flow_scale.GetValue()) / 100.0f;
}
[[nodiscard]] f32 ConfiguredFlowScale(VkExtent2D guest_extent, VkExtent2D presented_extent) {
if (!Settings::values.frame_gen_flow_scale_auto.GetValue()) {
return ManualFlowScale();
}
if (guest_extent.width == 0 || presented_extent.width == 0) {
return 1.0f;
}
const f32 rendered_width = static_cast<f32>(guest_extent.width) *
Settings::values.resolution_info.up_factor;
const f32 ratio = rendered_width / static_cast<f32>(presented_extent.width);
constexpr f32 FLOW_SCALE_STEPS = 20.0f;
const f32 stepped = std::ceil(ratio * FLOW_SCALE_STEPS) / FLOW_SCALE_STEPS;
return std::clamp(stepped, 0.25f, 1.0f);
}
[[nodiscard]] size_t ConfiguredGenerations() {
return Settings::FrameGenGenerations();
}
@@ -180,7 +197,8 @@ FrameGen::FrameGen(MemoryAllocator& memory_allocator_, Scheduler& scheduler_)
FrameGen::~FrameGen() = default;
void FrameGen::Process(const Device& device, Frame* frame, VkFormat format, bool generate) {
void FrameGen::Process(const Device& device, Frame* frame, VkFormat format, VkExtent2D guest_extent,
bool generate) {
generated = false;
if (unavailable || ConfiguredGenerations() == 0) {
@@ -204,11 +222,15 @@ void FrameGen::Process(const Device& device, Frame* frame, VkFormat format, bool
}
}
peak_guest_extent.width = std::max(peak_guest_extent.width, guest_extent.width);
peak_guest_extent.height = std::max(peak_guest_extent.height, guest_extent.height);
const VkExtent2D extent{.width = frame->width, .height = frame->height};
const f32 flow_scale = ConfiguredFlowScale(peak_guest_extent, extent);
if (!chain || built_extent.width != extent.width || built_extent.height != extent.height ||
built_format != format || built_flow_scale != ConfiguredFlowScale() ||
built_format != format || built_flow_scale != flow_scale ||
built_generations != ConfiguredGenerations()) {
Rebuild(device, extent, format);
Rebuild(device, extent, format, flow_scale);
}
const u64 count = frame_count++;
@@ -256,11 +278,11 @@ void FrameGen::GenerateInto(const Device& device, Frame* destination, size_t gen
});
}
void FrameGen::Rebuild(const Device& device, VkExtent2D extent, VkFormat format) {
void FrameGen::Rebuild(const Device& device, VkExtent2D extent, VkFormat format, f32 flow_scale) {
scheduler.Finish();
chain.reset();
built_flow_scale = ConfiguredFlowScale();
built_flow_scale = flow_scale;
built_generations = ConfiguredGenerations();
chain.emplace(device, memory_allocator, *shaders, extent, format, built_flow_scale,
@@ -21,7 +21,8 @@ public:
explicit FrameGen(MemoryAllocator& memory_allocator, Scheduler& scheduler);
~FrameGen();
void Process(const Device& device, Frame* frame, VkFormat format, bool generate);
void Process(const Device& device, Frame* frame, VkFormat format, VkExtent2D guest_extent,
bool generate);
[[nodiscard]] size_t WantedGenerations() const;
@@ -30,7 +31,7 @@ public:
void GenerateInto(const Device& device, Frame* destination, size_t generation);
private:
void Rebuild(const Device& device, VkExtent2D extent, VkFormat format);
void Rebuild(const Device& device, VkExtent2D extent, VkFormat format, f32 flow_scale);
void DumpDebugImages(u64 count);
MemoryAllocator& memory_allocator;
@@ -38,6 +39,7 @@ private:
std::optional<LsfgShaders> shaders;
std::optional<LsfgChain> chain;
VkExtent2D peak_guest_extent{};
VkExtent2D built_extent{};
VkFormat built_format{VK_FORMAT_UNDEFINED};
f32 built_flow_scale{};
@@ -49,6 +49,21 @@ constexpr VkExtent2D CaptureImageSize{
.height = VideoCore::Capture::LinearHeight,
};
[[nodiscard]] VkExtent2D GuestExtent(std::span<const Tegra::FramebufferConfig> framebuffers) {
if (framebuffers.empty()) {
return VkExtent2D{};
}
const auto& framebuffer = framebuffers.front();
if (framebuffer.crop_rect.IsEmpty()) {
return VkExtent2D{.width = framebuffer.width, .height = framebuffer.height};
}
return VkExtent2D{
.width = static_cast<u32>(framebuffer.crop_rect.GetWidth()),
.height = static_cast<u32>(framebuffer.crop_rect.GetHeight()),
};
}
constexpr VkExtent3D CaptureImageExtent{
.width = VideoCore::Capture::LinearWidth,
.height = VideoCore::Capture::LinearHeight,
@@ -196,7 +211,8 @@ void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebu
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);
frame_gen.Process(device, frame, swapchain.GetImageFormat(), GuestExtent(framebuffers),
can_present_all);
const size_t generated_frames = frame_gen.GeneratedFrameCount();
for (size_t generation = 0; generation < generated_frames; ++generation) {