mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-11-15 20:30:48 +01:00
Remove LSFG HDR + other optimizations on extra frame
This commit is contained in:
parent
52ffc8a7ce
commit
42b8ca5f9d
14 changed files with 38 additions and 47 deletions
|
|
@ -38,7 +38,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
||||||
RENDERER_VERTEX_INPUT_DYNAMIC_STATE("vertex_input_dynamic_state"),
|
RENDERER_VERTEX_INPUT_DYNAMIC_STATE("vertex_input_dynamic_state"),
|
||||||
RENDERER_SAMPLE_SHADING("sample_shading"),
|
RENDERER_SAMPLE_SHADING("sample_shading"),
|
||||||
RENDERER_FRAME_GEN("frame_gen"),
|
RENDERER_FRAME_GEN("frame_gen"),
|
||||||
RENDERER_FRAME_GEN_HDR("frame_gen_hdr"),
|
|
||||||
RENDERER_FRAME_GEN_FP16("frame_gen_fp16"),
|
RENDERER_FRAME_GEN_FP16("frame_gen_fp16"),
|
||||||
RENDERER_FRAME_GEN_DUMP_FLOW("frame_gen_dump_flow"),
|
RENDERER_FRAME_GEN_DUMP_FLOW("frame_gen_dump_flow"),
|
||||||
GPU_UNSWIZZLE_ENABLED("gpu_unswizzle_enabled"),
|
GPU_UNSWIZZLE_ENABLED("gpu_unswizzle_enabled"),
|
||||||
|
|
|
||||||
|
|
@ -633,13 +633,6 @@ abstract class SettingsItem(
|
||||||
units = "%"
|
units = "%"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
put(
|
|
||||||
SwitchSetting(
|
|
||||||
BooleanSetting.RENDERER_FRAME_GEN_HDR,
|
|
||||||
titleId = R.string.frame_gen_hdr,
|
|
||||||
descriptionId = R.string.frame_gen_hdr_description
|
|
||||||
)
|
|
||||||
)
|
|
||||||
put(
|
put(
|
||||||
SwitchSetting(
|
SwitchSetting(
|
||||||
BooleanSetting.RENDERER_FRAME_GEN_FP16,
|
BooleanSetting.RENDERER_FRAME_GEN_FP16,
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,6 @@ class SettingsFragmentPresenter(
|
||||||
add(IntSetting.RENDERER_FRAME_GEN_MULTIPLIER.key)
|
add(IntSetting.RENDERER_FRAME_GEN_MULTIPLIER.key)
|
||||||
add(IntSetting.RENDERER_FRAME_GEN_FLOW_SCALE.key)
|
add(IntSetting.RENDERER_FRAME_GEN_FLOW_SCALE.key)
|
||||||
add(BooleanSetting.RENDERER_FRAME_GEN_FP16.key)
|
add(BooleanSetting.RENDERER_FRAME_GEN_FP16.key)
|
||||||
add(BooleanSetting.RENDERER_FRAME_GEN_HDR.key)
|
|
||||||
add(BooleanSetting.RENDERER_FRAME_GEN_DUMP_FLOW.key)
|
add(BooleanSetting.RENDERER_FRAME_GEN_DUMP_FLOW.key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -309,8 +309,6 @@
|
||||||
<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_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>
|
<string name="frame_gen_fp16">Half precision shaders</string>
|
||||||
<string name="frame_gen_fp16_description">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.</string>
|
<string name="frame_gen_fp16_description">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.</string>
|
||||||
<string name="frame_gen_hdr">HDR interpolation</string>
|
|
||||||
<string name="frame_gen_hdr_description">Treat frames as HDR when interpolating. Only useful on an HDR output.</string>
|
|
||||||
<string name="frame_gen_dump_flow">Dump generated frame</string>
|
<string name="frame_gen_dump_flow">Dump generated frame</string>
|
||||||
<string name="frame_gen_dump_flow_description">Write the optical flow mip levels and the interpolated frame to the lossless/debug folder once, for troubleshooting</string>
|
<string name="frame_gen_dump_flow_description">Write the optical flow mip levels and the interpolated frame to the lossless/debug folder once, for troubleshooting</string>
|
||||||
<string name="frame_gen_unsupported">Frame generation unavailable</string>
|
<string name="frame_gen_unsupported">Frame generation unavailable</string>
|
||||||
|
|
|
||||||
|
|
@ -414,9 +414,6 @@ struct Values {
|
||||||
true,
|
true,
|
||||||
&frame_gen};
|
&frame_gen};
|
||||||
|
|
||||||
SwitchableSetting<bool> frame_gen_hdr{linkage, false, "frame_gen_hdr", Category::Renderer,
|
|
||||||
Specialization::Default, true, true, &frame_gen};
|
|
||||||
|
|
||||||
SwitchableSetting<bool> frame_gen_fp16{linkage, true, "frame_gen_fp16", Category::Renderer,
|
SwitchableSetting<bool> frame_gen_fp16{linkage, true, "frame_gen_fp16", Category::Renderer,
|
||||||
Specialization::Default, true, true, &frame_gen};
|
Specialization::Default, true, true, &frame_gen};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,9 @@ FrameGen::FrameGen(MemoryAllocator& memory_allocator_, Scheduler& scheduler_)
|
||||||
|
|
||||||
FrameGen::~FrameGen() = default;
|
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()) {
|
if (unavailable || !Settings::values.frame_gen.GetValue()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -198,20 +200,23 @@ void FrameGen::Process(const Device& device, Frame* frame, VkFormat format) {
|
||||||
const VkExtent2D extent{.width = frame->width, .height = frame->height};
|
const VkExtent2D extent{.width = frame->width, .height = frame->height};
|
||||||
if (!chain || built_extent.width != extent.width || built_extent.height != extent.height ||
|
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 != ConfiguredFlowScale() ||
|
||||||
built_hdr != Settings::values.frame_gen_hdr.GetValue() ||
|
|
||||||
built_generations != ConfiguredGenerations()) {
|
built_generations != ConfiguredGenerations()) {
|
||||||
Rebuild(device, extent, format);
|
Rebuild(device, extent, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
const u64 count = frame_count++;
|
const u64 count = frame_count++;
|
||||||
|
generated = generate && count + 1 >= LSFG_REQUIRED_FRAMES;
|
||||||
|
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
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);
|
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) {
|
if (!dump_requested) {
|
||||||
dumped = false;
|
dumped = false;
|
||||||
} else if (!dumped) {
|
} else if (!dumped) {
|
||||||
|
|
@ -220,12 +225,15 @@ void FrameGen::Process(const Device& device, Frame* frame, VkFormat format) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t FrameGen::GeneratedFrameCount() const {
|
size_t FrameGen::WantedGenerations() const {
|
||||||
if (!chain || frame_count < LSFG_REQUIRED_FRAMES ||
|
if (unavailable || !Settings::values.frame_gen.GetValue()) {
|
||||||
!Settings::values.frame_gen.GetValue()) {
|
|
||||||
return 0;
|
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) {
|
void FrameGen::CopyToFrame(Frame* destination, size_t generation) {
|
||||||
|
|
@ -273,14 +281,14 @@ void FrameGen::Rebuild(const Device& device, VkExtent2D extent, VkFormat format)
|
||||||
chain.reset();
|
chain.reset();
|
||||||
|
|
||||||
built_flow_scale = ConfiguredFlowScale();
|
built_flow_scale = ConfiguredFlowScale();
|
||||||
built_hdr = Settings::values.frame_gen_hdr.GetValue();
|
|
||||||
built_generations = ConfiguredGenerations();
|
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_generations);
|
||||||
built_extent = extent;
|
built_extent = extent;
|
||||||
built_format = format;
|
built_format = format;
|
||||||
frame_count = 0;
|
frame_count = 0;
|
||||||
|
generated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameGen::DumpDebugImages(u64 count) {
|
void FrameGen::DumpDebugImages(u64 count) {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,9 @@ public:
|
||||||
explicit FrameGen(MemoryAllocator& memory_allocator, Scheduler& scheduler);
|
explicit FrameGen(MemoryAllocator& memory_allocator, Scheduler& scheduler);
|
||||||
~FrameGen();
|
~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;
|
[[nodiscard]] size_t GeneratedFrameCount() const;
|
||||||
|
|
||||||
|
|
@ -39,9 +41,9 @@ private:
|
||||||
VkExtent2D built_extent{};
|
VkExtent2D built_extent{};
|
||||||
VkFormat built_format{VK_FORMAT_UNDEFINED};
|
VkFormat built_format{VK_FORMAT_UNDEFINED};
|
||||||
f32 built_flow_scale{};
|
f32 built_flow_scale{};
|
||||||
bool built_hdr{};
|
|
||||||
size_t built_generations{};
|
size_t built_generations{};
|
||||||
u64 frame_count{};
|
u64 frame_count{};
|
||||||
|
bool generated{};
|
||||||
bool unavailable{};
|
bool unavailable{};
|
||||||
bool dumped{};
|
bool dumped{};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ constexpr size_t FIRST_DELTA_LEVEL = 4;
|
||||||
|
|
||||||
LsfgChain::LsfgChain(const Device& device, MemoryAllocator& memory_allocator,
|
LsfgChain::LsfgChain(const Device& device, MemoryAllocator& memory_allocator,
|
||||||
const LsfgShaders& shaders, VkExtent2D extent, VkFormat format,
|
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_},
|
: generation_count{generation_count_},
|
||||||
resources{device, memory_allocator, flow_scale, is_hdr},
|
resources{device, memory_allocator, flow_scale},
|
||||||
descriptor_pool{CreateLsfgDescriptorPool(
|
descriptor_pool{CreateLsfgDescriptorPool(
|
||||||
device, FIXED_DESCRIPTOR_SETS +
|
device, FIXED_DESCRIPTOR_SETS +
|
||||||
DESCRIPTOR_SETS_PER_GENERATION * static_cast<u32>(generation_count))} {
|
DESCRIPTOR_SETS_PER_GENERATION * static_cast<u32>(generation_count))} {
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,7 @@ constexpr size_t LSFG_DELTA_INSTANCES = 3;
|
||||||
class LsfgChain {
|
class LsfgChain {
|
||||||
public:
|
public:
|
||||||
LsfgChain(const Device& device, MemoryAllocator& memory_allocator, const LsfgShaders& shaders,
|
LsfgChain(const Device& device, MemoryAllocator& memory_allocator, const LsfgShaders& shaders,
|
||||||
VkExtent2D extent, VkFormat format, f32 flow_scale, bool is_hdr,
|
VkExtent2D extent, VkFormat format, f32 flow_scale, size_t generation_count_);
|
||||||
size_t generation_count_);
|
|
||||||
|
|
||||||
LsfgChain(const LsfgChain&) = delete;
|
LsfgChain(const LsfgChain&) = delete;
|
||||||
LsfgChain& operator=(const LsfgChain&) = delete;
|
LsfgChain& operator=(const LsfgChain&) = delete;
|
||||||
|
|
|
||||||
|
|
@ -154,8 +154,8 @@ VkBuffer LsfgResources::GetBuffer(f32 timestamp, bool first_iter, bool first_ite
|
||||||
.input_offset = {0, 0},
|
.input_offset = {0, 0},
|
||||||
.first_iter = first_iter ? 1u : 0u,
|
.first_iter = first_iter ? 1u : 0u,
|
||||||
.first_iter_s = first_iter_s ? 1u : 0u,
|
.first_iter_s = first_iter_s ? 1u : 0u,
|
||||||
.advanced_color_kind = is_hdr ? 2u : 0u,
|
.advanced_color_kind = 0,
|
||||||
.hdr_support = is_hdr ? 1u : 0u,
|
.hdr_support = 0,
|
||||||
.resolution_inv_scale = 1.0f / flow_scale,
|
.resolution_inv_scale = 1.0f / flow_scale,
|
||||||
.timestamp = timestamp,
|
.timestamp = timestamp,
|
||||||
.ui_threshold = 0.5f,
|
.ui_threshold = 0.5f,
|
||||||
|
|
|
||||||
|
|
@ -76,10 +76,8 @@ using LsfgImageHistory = std::array<LsfgImagePair, LSFG_HISTORY_SLOTS>;
|
||||||
class LsfgResources {
|
class LsfgResources {
|
||||||
public:
|
public:
|
||||||
LsfgResources() = default;
|
LsfgResources() = default;
|
||||||
LsfgResources(const Device& device_, MemoryAllocator& memory_allocator_, f32 flow_scale_,
|
LsfgResources(const Device& device_, MemoryAllocator& memory_allocator_, f32 flow_scale_)
|
||||||
bool is_hdr_)
|
: device{&device_}, memory_allocator{&memory_allocator_}, flow_scale{flow_scale_} {}
|
||||||
: device{&device_}, memory_allocator{&memory_allocator_}, flow_scale{flow_scale_},
|
|
||||||
is_hdr{is_hdr_} {}
|
|
||||||
|
|
||||||
[[nodiscard]] VkSampler GetSampler(
|
[[nodiscard]] VkSampler GetSampler(
|
||||||
VkSamplerAddressMode address_mode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
|
VkSamplerAddressMode address_mode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
|
||||||
|
|
@ -94,7 +92,6 @@ private:
|
||||||
const Device* device{};
|
const Device* device{};
|
||||||
MemoryAllocator* memory_allocator{};
|
MemoryAllocator* memory_allocator{};
|
||||||
f32 flow_scale{1.0f};
|
f32 flow_scale{1.0f};
|
||||||
bool is_hdr{};
|
|
||||||
|
|
||||||
std::map<u64, vk::Sampler> samplers;
|
std::map<u64, vk::Sampler> samplers;
|
||||||
std::map<u64, vk::Buffer> buffers;
|
std::map<u64, vk::Buffer> buffers;
|
||||||
|
|
|
||||||
|
|
@ -193,14 +193,13 @@ void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebu
|
||||||
render_window.GetFramebufferLayout(), swapchain.GetImageCount(),
|
render_window.GetFramebufferLayout(), swapchain.GetImageCount(),
|
||||||
swapchain.GetImageViewFormat());
|
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();
|
const size_t generated_frames = frame_gen.GeneratedFrameCount();
|
||||||
for (size_t generation = 0; generation < generated_frames; ++generation) {
|
for (size_t generation = 0; generation < generated_frames; ++generation) {
|
||||||
if (!present_manager.CanQueueExtraFrame()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Frame* generated = present_manager.GetRenderFrame();
|
Frame* generated = present_manager.GetRenderFrame();
|
||||||
blit_swapchain.PrepareFrame(device, generated, render_window.GetFramebufferLayout());
|
blit_swapchain.PrepareFrame(device, generated, render_window.GetFramebufferLayout());
|
||||||
frame_gen.CopyToFrame(generated, generation);
|
frame_gen.CopyToFrame(generated, generation);
|
||||||
|
|
|
||||||
|
|
@ -181,9 +181,9 @@ void PresentManager::Present(Frame* frame) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PresentManager::CanQueueExtraFrame() {
|
size_t PresentManager::AvailableExtraFrames() {
|
||||||
std::scoped_lock lock{free_mutex};
|
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,
|
void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat image_view_format,
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,8 @@ public:
|
||||||
/// Waits for the present thread to finish presenting all queued frames.
|
/// Waits for the present thread to finish presenting all queued frames.
|
||||||
void WaitPresent();
|
void WaitPresent();
|
||||||
|
|
||||||
/// Whether an additional frame can be queued without stalling the render thread
|
/// How many additional frames can be queued without stalling the render thread
|
||||||
bool CanQueueExtraFrame();
|
size_t AvailableExtraFrames();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void PresentThread(std::stop_token token);
|
void PresentThread(std::stop_token token);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue