mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-31 02:35:39 +00:00
Expose new settings
This commit is contained in:
+1
@@ -38,6 +38,7 @@ 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_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"),
|
||||||
PICTURE_IN_PICTURE("picture_in_picture"),
|
PICTURE_IN_PICTURE("picture_in_picture"),
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
|||||||
RENDERER_ASTC_DECODE_METHOD("accelerate_astc"),
|
RENDERER_ASTC_DECODE_METHOD("accelerate_astc"),
|
||||||
RENDERER_ACCURACY("gpu_accuracy"),
|
RENDERER_ACCURACY("gpu_accuracy"),
|
||||||
RENDERER_RESOLUTION("resolution_setup"),
|
RENDERER_RESOLUTION("resolution_setup"),
|
||||||
|
RENDERER_FRAME_GEN_MULTIPLIER("frame_gen_multiplier"),
|
||||||
|
RENDERER_FRAME_GEN_FLOW_SCALE("frame_gen_flow_scale"),
|
||||||
RENDERER_VSYNC("use_vsync"),
|
RENDERER_VSYNC("use_vsync"),
|
||||||
RENDERER_SCALING_FILTER("scaling_filter"),
|
RENDERER_SCALING_FILTER("scaling_filter"),
|
||||||
RENDERER_ANTI_ALIASING("anti_aliasing"),
|
RENDERER_ANTI_ALIASING("anti_aliasing"),
|
||||||
|
|||||||
+26
@@ -614,6 +614,32 @@ abstract class SettingsItem(
|
|||||||
descriptionId = R.string.frame_gen_description
|
descriptionId = R.string.frame_gen_description
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
put(
|
||||||
|
SingleChoiceSetting(
|
||||||
|
IntSetting.RENDERER_FRAME_GEN_MULTIPLIER,
|
||||||
|
titleId = R.string.frame_gen_multiplier,
|
||||||
|
descriptionId = R.string.frame_gen_multiplier_description,
|
||||||
|
choicesId = R.array.frameGenMultiplierNames,
|
||||||
|
valuesId = R.array.frameGenMultiplierValues
|
||||||
|
)
|
||||||
|
)
|
||||||
|
put(
|
||||||
|
SliderSetting(
|
||||||
|
IntSetting.RENDERER_FRAME_GEN_FLOW_SCALE,
|
||||||
|
titleId = R.string.frame_gen_flow_scale,
|
||||||
|
descriptionId = R.string.frame_gen_flow_scale_description,
|
||||||
|
min = 25,
|
||||||
|
max = 100,
|
||||||
|
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_DUMP_FLOW,
|
BooleanSetting.RENDERER_FRAME_GEN_DUMP_FLOW,
|
||||||
|
|||||||
+3
@@ -116,6 +116,9 @@ class SettingsFragmentPresenter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
add(BooleanSetting.RENDERER_FRAME_GEN.key)
|
add(BooleanSetting.RENDERER_FRAME_GEN.key)
|
||||||
|
add(IntSetting.RENDERER_FRAME_GEN_MULTIPLIER.key)
|
||||||
|
add(IntSetting.RENDERER_FRAME_GEN_FLOW_SCALE.key)
|
||||||
|
add(BooleanSetting.RENDERER_FRAME_GEN_HDR.key)
|
||||||
add(BooleanSetting.RENDERER_FRAME_GEN_DUMP_FLOW.key)
|
add(BooleanSetting.RENDERER_FRAME_GEN_DUMP_FLOW.key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,6 +162,18 @@
|
|||||||
<item>@string/resolution_four</item>
|
<item>@string/resolution_four</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="frameGenMultiplierNames">
|
||||||
|
<item>@string/frame_gen_multiplier_2x</item>
|
||||||
|
<item>@string/frame_gen_multiplier_3x</item>
|
||||||
|
<item>@string/frame_gen_multiplier_4x</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<integer-array name="frameGenMultiplierValues">
|
||||||
|
<item>2</item>
|
||||||
|
<item>3</item>
|
||||||
|
<item>4</item>
|
||||||
|
</integer-array>
|
||||||
|
|
||||||
<string-array name="rendererVSyncNames">
|
<string-array name="rendererVSyncNames">
|
||||||
<item>@string/renderer_vsync_immediate</item>
|
<item>@string/renderer_vsync_immediate</item>
|
||||||
<item>@string/renderer_vsync_mailbox</item>
|
<item>@string/renderer_vsync_mailbox</item>
|
||||||
|
|||||||
@@ -300,6 +300,15 @@
|
|||||||
<string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string>
|
<string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string>
|
||||||
<string name="frame_gen">Frame generation</string>
|
<string name="frame_gen">Frame generation</string>
|
||||||
<string name="frame_gen_description">Run the Lossless Scaling interpolation shaders on every frame. Incomplete: the interpolated frame is computed but not yet displayed, so this only costs performance for now.</string>
|
<string name="frame_gen_description">Run the Lossless Scaling interpolation shaders on every frame. Incomplete: the interpolated frame is computed but not yet displayed, so this only costs performance for now.</string>
|
||||||
|
<string name="frame_gen_multiplier">Frame multiplier</string>
|
||||||
|
<string name="frame_gen_multiplier_description">How many frames to display for each rendered frame. Higher values cost proportionally more GPU time.</string>
|
||||||
|
<string name="frame_gen_multiplier_2x">2x (one generated frame)</string>
|
||||||
|
<string name="frame_gen_multiplier_3x">3x (two generated frames)</string>
|
||||||
|
<string name="frame_gen_multiplier_4x">4x (three generated frames)</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_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>
|
||||||
|
|||||||
@@ -390,6 +390,33 @@ struct Values {
|
|||||||
|
|
||||||
SwitchableSetting<bool> frame_gen{linkage, false, "frame_gen", Category::Renderer,
|
SwitchableSetting<bool> frame_gen{linkage, false, "frame_gen", Category::Renderer,
|
||||||
Specialization::Default, true, true};
|
Specialization::Default, true, true};
|
||||||
|
|
||||||
|
SwitchableSetting<u32, true> frame_gen_multiplier{linkage,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
"frame_gen_multiplier",
|
||||||
|
Category::Renderer,
|
||||||
|
Specialization::Countable,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
&frame_gen};
|
||||||
|
|
||||||
|
SwitchableSetting<u32, true> frame_gen_flow_scale{linkage,
|
||||||
|
100,
|
||||||
|
25,
|
||||||
|
100,
|
||||||
|
"frame_gen_flow_scale",
|
||||||
|
Category::Renderer,
|
||||||
|
Specialization::Countable |
|
||||||
|
Specialization::Percentage,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
&frame_gen};
|
||||||
|
|
||||||
|
SwitchableSetting<bool> frame_gen_hdr{linkage, false, "frame_gen_hdr", Category::Renderer,
|
||||||
|
Specialization::Default, true, true, &frame_gen};
|
||||||
|
|
||||||
SwitchableSetting<bool> frame_gen_dump_flow{linkage, false, "frame_gen_dump_flow",
|
SwitchableSetting<bool> frame_gen_dump_flow{linkage, false, "frame_gen_dump_flow",
|
||||||
Category::Renderer};
|
Category::Renderer};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -18,10 +19,19 @@ namespace Vulkan {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr f32 LSFG_FLOW_SCALE = 1.0f;
|
|
||||||
constexpr size_t COLOR_CHANNELS = 4;
|
constexpr size_t COLOR_CHANNELS = 4;
|
||||||
constexpr u64 LSFG_REQUIRED_FRAMES = 2;
|
constexpr u64 LSFG_REQUIRED_FRAMES = 2;
|
||||||
|
|
||||||
|
[[nodiscard]] f32 ConfiguredFlowScale() {
|
||||||
|
return static_cast<f32>(Settings::values.frame_gen_flow_scale.GetValue()) / 100.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] size_t ConfiguredGenerations() {
|
||||||
|
const u32 multiplier = std::clamp<u32>(Settings::values.frame_gen_multiplier.GetValue(),
|
||||||
|
LSFG_MIN_MULTIPLIER, LSFG_MAX_MULTIPLIER);
|
||||||
|
return multiplier - 1;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsBlueFirst(VkFormat format) {
|
bool IsBlueFirst(VkFormat format) {
|
||||||
return format == VK_FORMAT_B8G8R8A8_UNORM || format == VK_FORMAT_B8G8R8A8_SRGB;
|
return format == VK_FORMAT_B8G8R8A8_UNORM || format == VK_FORMAT_B8G8R8A8_SRGB;
|
||||||
}
|
}
|
||||||
@@ -187,7 +197,9 @@ 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_format != format || built_flow_scale != ConfiguredFlowScale() ||
|
||||||
|
built_hdr != Settings::values.frame_gen_hdr.GetValue() ||
|
||||||
|
built_generations != ConfiguredGenerations()) {
|
||||||
Rebuild(device, extent, format);
|
Rebuild(device, extent, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,15 +220,19 @@ void FrameGen::Process(const Device& device, Frame* frame, VkFormat format) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameGen::HasGeneratedFrame() const {
|
size_t FrameGen::GeneratedFrameCount() const {
|
||||||
return chain.has_value() && frame_count >= LSFG_REQUIRED_FRAMES &&
|
if (!chain || frame_count < LSFG_REQUIRED_FRAMES ||
|
||||||
Settings::values.frame_gen.GetValue();
|
!Settings::values.frame_gen.GetValue()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return chain->GenerationCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameGen::CopyToFrame(Frame* destination) {
|
void FrameGen::CopyToFrame(Frame* destination, size_t generation) {
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
scheduler.Record([this, target = *destination->image](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([this, target = *destination->image,
|
||||||
LsfgImage& source = chain->Output();
|
generation](vk::CommandBuffer cmdbuf) {
|
||||||
|
LsfgImage& source = chain->Output(generation);
|
||||||
const VkExtent2D extent = source.Extent();
|
const VkExtent2D extent = source.Extent();
|
||||||
|
|
||||||
const std::array before{
|
const std::array before{
|
||||||
@@ -255,7 +271,13 @@ void FrameGen::CopyToFrame(Frame* destination) {
|
|||||||
void FrameGen::Rebuild(const Device& device, VkExtent2D extent, VkFormat format) {
|
void FrameGen::Rebuild(const Device& device, VkExtent2D extent, VkFormat format) {
|
||||||
scheduler.Finish();
|
scheduler.Finish();
|
||||||
chain.reset();
|
chain.reset();
|
||||||
chain.emplace(device, memory_allocator, *shaders, extent, format, LSFG_FLOW_SCALE);
|
|
||||||
|
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,
|
||||||
|
built_generations);
|
||||||
built_extent = extent;
|
built_extent = extent;
|
||||||
built_format = format;
|
built_format = format;
|
||||||
frame_count = 0;
|
frame_count = 0;
|
||||||
@@ -319,7 +341,9 @@ void FrameGen::DumpDebugImages(u64 count) {
|
|||||||
dump("gamma6", chain->GammaOutput(LSFG_MIP_LEVELS - 1));
|
dump("gamma6", chain->GammaOutput(LSFG_MIP_LEVELS - 1));
|
||||||
dump("delta2_out1", chain->DeltaOutput1(LSFG_DELTA_INSTANCES - 1));
|
dump("delta2_out1", chain->DeltaOutput1(LSFG_DELTA_INSTANCES - 1));
|
||||||
dump("delta2_out2", chain->DeltaOutput2(LSFG_DELTA_INSTANCES - 1));
|
dump("delta2_out2", chain->DeltaOutput2(LSFG_DELTA_INSTANCES - 1));
|
||||||
dump("generated", chain->Output());
|
for (size_t generation = 0; generation < chain->GenerationCount(); ++generation) {
|
||||||
|
dump("generated" + std::to_string(generation), chain->Output(generation));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ public:
|
|||||||
|
|
||||||
void Process(const Device& device, Frame* frame, VkFormat format);
|
void Process(const Device& device, Frame* frame, VkFormat format);
|
||||||
|
|
||||||
[[nodiscard]] bool HasGeneratedFrame() const;
|
[[nodiscard]] size_t GeneratedFrameCount() const;
|
||||||
|
|
||||||
void CopyToFrame(Frame* destination);
|
void CopyToFrame(Frame* destination, size_t generation);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Rebuild(const Device& device, VkExtent2D extent, VkFormat format);
|
void Rebuild(const Device& device, VkExtent2D extent, VkFormat format);
|
||||||
@@ -38,6 +38,9 @@ private:
|
|||||||
std::optional<LsfgChain> chain;
|
std::optional<LsfgChain> chain;
|
||||||
VkExtent2D built_extent{};
|
VkExtent2D built_extent{};
|
||||||
VkFormat built_format{VK_FORMAT_UNDEFINED};
|
VkFormat built_format{VK_FORMAT_UNDEFINED};
|
||||||
|
f32 built_flow_scale{};
|
||||||
|
bool built_hdr{};
|
||||||
|
size_t built_generations{};
|
||||||
u64 frame_count{};
|
u64 frame_count{};
|
||||||
bool unavailable{};
|
bool unavailable{};
|
||||||
bool dumped{};
|
bool dumped{};
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ LsfgBeta::LsfgBeta(const Device& device, MemoryAllocator& memory_allocator,
|
|||||||
.AddStorageImages(temp2)
|
.AddStorageImages(temp2)
|
||||||
.Build(device);
|
.Build(device);
|
||||||
LsfgDescriptorWriter(descriptor_sets[3])
|
LsfgDescriptorWriter(descriptor_sets[3])
|
||||||
.AddUniformBuffer(resources.GetBuffer(LSFG_TIMESTAMP), LsfgResources::BufferSize())
|
.AddUniformBuffer(resources.GetBuffer(0.5f), LsfgResources::BufferSize())
|
||||||
.AddSampler(sampler)
|
.AddSampler(sampler)
|
||||||
.AddSampledImages(temp2)
|
.AddSampledImages(temp2)
|
||||||
.AddStorageImages(out_images)
|
.AddStorageImages(out_images)
|
||||||
|
|||||||
@@ -11,16 +11,20 @@ namespace Vulkan {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr u32 DESCRIPTOR_SET_COUNT = 256;
|
constexpr u32 FIXED_DESCRIPTOR_SETS = 64;
|
||||||
|
constexpr u32 DESCRIPTOR_SETS_PER_GENERATION = 96;
|
||||||
constexpr size_t FIRST_DELTA_LEVEL = 4;
|
constexpr size_t FIRST_DELTA_LEVEL = 4;
|
||||||
|
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
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)
|
f32 flow_scale, bool is_hdr, size_t generation_count_)
|
||||||
: resources{device, memory_allocator, flow_scale},
|
: generation_count{generation_count_},
|
||||||
descriptor_pool{CreateLsfgDescriptorPool(device, DESCRIPTOR_SET_COUNT)} {
|
resources{device, memory_allocator, flow_scale, is_hdr},
|
||||||
|
descriptor_pool{CreateLsfgDescriptorPool(
|
||||||
|
device, FIXED_DESCRIPTOR_SETS +
|
||||||
|
DESCRIPTOR_SETS_PER_GENERATION * static_cast<u32>(generation_count))} {
|
||||||
for (auto& image : frames) {
|
for (auto& image : frames) {
|
||||||
image = LsfgImage(device, memory_allocator, extent, format);
|
image = LsfgImage(device, memory_allocator, extent, format);
|
||||||
}
|
}
|
||||||
@@ -41,7 +45,7 @@ LsfgChain::LsfgChain(const Device& device, MemoryAllocator& memory_allocator,
|
|||||||
gamma[i] = LsfgGamma(device, memory_allocator, shaders, resources, descriptor_pool,
|
gamma[i] = LsfgGamma(device, memory_allocator, shaders, resources, descriptor_pool,
|
||||||
alpha[level].Outputs(),
|
alpha[level].Outputs(),
|
||||||
beta.Output(std::min(level, LSFG_BETA_OUTPUTS - 1)),
|
beta.Output(std::min(level, LSFG_BETA_OUTPUTS - 1)),
|
||||||
i == 0 ? nullptr : &gamma[i - 1].Output());
|
i == 0 ? nullptr : &gamma[i - 1].Output(), generation_count);
|
||||||
|
|
||||||
if (i < FIRST_DELTA_LEVEL) {
|
if (i < FIRST_DELTA_LEVEL) {
|
||||||
continue;
|
continue;
|
||||||
@@ -52,13 +56,13 @@ LsfgChain::LsfgChain(const Device& device, MemoryAllocator& memory_allocator,
|
|||||||
device, memory_allocator, shaders, resources, descriptor_pool, alpha[level].Outputs(),
|
device, memory_allocator, shaders, resources, descriptor_pool, alpha[level].Outputs(),
|
||||||
beta.Output(level), i == FIRST_DELTA_LEVEL ? nullptr : &gamma[i - 1].Output(),
|
beta.Output(level), i == FIRST_DELTA_LEVEL ? nullptr : &gamma[i - 1].Output(),
|
||||||
i == FIRST_DELTA_LEVEL ? nullptr : &delta[index - 1].Output1(),
|
i == FIRST_DELTA_LEVEL ? nullptr : &delta[index - 1].Output1(),
|
||||||
i == FIRST_DELTA_LEVEL ? nullptr : &delta[index - 1].Output2());
|
i == FIRST_DELTA_LEVEL ? nullptr : &delta[index - 1].Output2(), generation_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
generate = LsfgGenerate(device, memory_allocator, shaders, resources, descriptor_pool, frames,
|
generate = LsfgGenerate(device, memory_allocator, shaders, resources, descriptor_pool, frames,
|
||||||
gamma[LSFG_MIP_LEVELS - 1].Output(),
|
gamma[LSFG_MIP_LEVELS - 1].Output(),
|
||||||
delta[LSFG_DELTA_INSTANCES - 1].Output1(),
|
delta[LSFG_DELTA_INSTANCES - 1].Output1(),
|
||||||
delta[LSFG_DELTA_INSTANCES - 1].Output2(), format);
|
delta[LSFG_DELTA_INSTANCES - 1].Output2(), format, generation_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LsfgChain::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
void LsfgChain::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
||||||
@@ -70,14 +74,15 @@ void LsfgChain::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
|||||||
|
|
||||||
beta.Dispatch(cmdbuf, frame_count);
|
beta.Dispatch(cmdbuf, frame_count);
|
||||||
|
|
||||||
for (size_t i = 0; i < LSFG_MIP_LEVELS; ++i) {
|
for (size_t generation = 0; generation < generation_count; ++generation) {
|
||||||
gamma[i].Dispatch(cmdbuf, frame_count);
|
for (size_t i = 0; i < LSFG_MIP_LEVELS; ++i) {
|
||||||
if (i >= FIRST_DELTA_LEVEL) {
|
gamma[i].Dispatch(cmdbuf, frame_count, generation);
|
||||||
delta[i - FIRST_DELTA_LEVEL].Dispatch(cmdbuf, frame_count);
|
if (i >= FIRST_DELTA_LEVEL) {
|
||||||
|
delta[i - FIRST_DELTA_LEVEL].Dispatch(cmdbuf, frame_count, generation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
generate.Dispatch(cmdbuf, frame_count, generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
generate.Dispatch(cmdbuf, frame_count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ 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);
|
VkExtent2D extent, VkFormat format, f32 flow_scale, bool is_hdr,
|
||||||
|
size_t generation_count_);
|
||||||
|
|
||||||
LsfgChain(const LsfgChain&) = delete;
|
LsfgChain(const LsfgChain&) = delete;
|
||||||
LsfgChain& operator=(const LsfgChain&) = delete;
|
LsfgChain& operator=(const LsfgChain&) = delete;
|
||||||
@@ -35,8 +36,12 @@ public:
|
|||||||
return frames[frame_count % frames.size()];
|
return frames[frame_count % frames.size()];
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] LsfgImage& Output() {
|
[[nodiscard]] LsfgImage& Output(size_t generation) {
|
||||||
return generate.Output();
|
return generate.Output(generation);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] size_t GenerationCount() const {
|
||||||
|
return generation_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] LsfgImage& FlowLevel(size_t level) {
|
[[nodiscard]] LsfgImage& FlowLevel(size_t level) {
|
||||||
@@ -64,6 +69,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
size_t generation_count{};
|
||||||
LsfgResources resources;
|
LsfgResources resources;
|
||||||
vk::DescriptorPool descriptor_pool;
|
vk::DescriptorPool descriptor_pool;
|
||||||
|
|
||||||
|
|||||||
@@ -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 = 0,
|
.advanced_color_kind = is_hdr ? 2u : 0u,
|
||||||
.hdr_support = 0,
|
.hdr_support = is_hdr ? 1u : 0u,
|
||||||
.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,
|
||||||
|
|||||||
@@ -24,8 +24,13 @@ constexpr VkFormat LSFG_FLOW_FORMAT = VK_FORMAT_R8_UNORM;
|
|||||||
constexpr VkFormat LSFG_MOTION_FORMAT = VK_FORMAT_R16G16B16A16_SFLOAT;
|
constexpr VkFormat LSFG_MOTION_FORMAT = VK_FORMAT_R16G16B16A16_SFLOAT;
|
||||||
|
|
||||||
constexpr size_t LSFG_HISTORY_SLOTS = 3;
|
constexpr size_t LSFG_HISTORY_SLOTS = 3;
|
||||||
constexpr size_t LSFG_GENERATION_COUNT = 1;
|
constexpr size_t LSFG_MIN_MULTIPLIER = 2;
|
||||||
constexpr f32 LSFG_TIMESTAMP = 1.0f / static_cast<f32>(LSFG_GENERATION_COUNT + 1);
|
constexpr size_t LSFG_MAX_MULTIPLIER = 4;
|
||||||
|
constexpr size_t LSFG_MAX_GENERATIONS = LSFG_MAX_MULTIPLIER - 1;
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr f32 LsfgTimestamp(size_t generation, size_t generation_count) {
|
||||||
|
return static_cast<f32>(generation + 1) / static_cast<f32>(generation_count + 1);
|
||||||
|
}
|
||||||
|
|
||||||
class LsfgImage {
|
class LsfgImage {
|
||||||
public:
|
public:
|
||||||
@@ -71,8 +76,10 @@ 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_,
|
||||||
: device{&device_}, memory_allocator{&memory_allocator_}, flow_scale{flow_scale_} {}
|
bool is_hdr_)
|
||||||
|
: 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,
|
||||||
@@ -87,6 +94,7 @@ 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;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ LsfgDelta::LsfgDelta(const Device& device, MemoryAllocator& memory_allocator,
|
|||||||
const LsfgShaders& shaders, LsfgResources& resources,
|
const LsfgShaders& shaders, LsfgResources& resources,
|
||||||
vk::DescriptorPool& descriptor_pool, LsfgImageHistory& inputs_,
|
vk::DescriptorPool& descriptor_pool, LsfgImageHistory& inputs_,
|
||||||
LsfgImage& flow_input_, LsfgImage* previous_gamma_, LsfgImage* previous1_,
|
LsfgImage& flow_input_, LsfgImage* previous_gamma_, LsfgImage* previous1_,
|
||||||
LsfgImage* previous2_)
|
LsfgImage* previous2_, size_t generation_count)
|
||||||
: inputs{&inputs_}, flow_input{&flow_input_}, previous_gamma{previous_gamma_},
|
: inputs{&inputs_}, flow_input{&flow_input_}, previous_gamma{previous_gamma_},
|
||||||
previous1{previous1_}, previous2{previous2_} {
|
previous1{previous1_}, previous2{previous2_} {
|
||||||
using namespace VideoCore::FrameGen::PerformanceShader;
|
using namespace VideoCore::FrameGen::PerformanceShader;
|
||||||
@@ -80,115 +80,123 @@ LsfgDelta::LsfgDelta(const Device& device, MemoryAllocator& memory_allocator,
|
|||||||
out_image2 = LsfgImage(device, memory_allocator, extent, LSFG_MOTION_FORMAT);
|
out_image2 = LsfgImage(device, memory_allocator, extent, LSFG_MOTION_FORMAT);
|
||||||
|
|
||||||
std::vector<VkDescriptorSetLayout> layouts;
|
std::vector<VkDescriptorSetLayout> layouts;
|
||||||
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
for (size_t generation = 0; generation < generation_count; ++generation) {
|
||||||
layouts.push_back(passes[0].SetLayout());
|
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
||||||
}
|
layouts.push_back(passes[0].SetLayout());
|
||||||
for (size_t i = 1; i <= 4; ++i) {
|
}
|
||||||
layouts.push_back(passes[i].SetLayout());
|
for (size_t i = 1; i <= 4; ++i) {
|
||||||
}
|
layouts.push_back(passes[i].SetLayout());
|
||||||
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
}
|
||||||
layouts.push_back(passes[5].SetLayout());
|
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
||||||
}
|
layouts.push_back(passes[5].SetLayout());
|
||||||
for (size_t i = 6; i < LSFG_DELTA_STAGES; ++i) {
|
}
|
||||||
layouts.push_back(passes[i].SetLayout());
|
for (size_t i = 6; i < LSFG_DELTA_STAGES; ++i) {
|
||||||
|
layouts.push_back(passes[i].SetLayout());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
owned_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts);
|
owned_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts);
|
||||||
|
|
||||||
size_t next = 0;
|
|
||||||
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
|
||||||
first_descriptor_sets[i] = owned_sets[next++];
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < 4; ++i) {
|
|
||||||
descriptor_sets[i] = owned_sets[next++];
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
|
||||||
sixth_descriptor_sets[i] = owned_sets[next++];
|
|
||||||
}
|
|
||||||
for (size_t i = 4; i < LSFG_DELTA_STAGES - 2; ++i) {
|
|
||||||
descriptor_sets[i] = owned_sets[next++];
|
|
||||||
}
|
|
||||||
|
|
||||||
const VkSampler sampler = resources.GetSampler();
|
const VkSampler sampler = resources.GetSampler();
|
||||||
const VkSampler border_sampler = resources.GetSampler(
|
const VkSampler border_sampler = resources.GetSampler(
|
||||||
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_NEVER, true);
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_NEVER, true);
|
||||||
const VkSampler edge_sampler =
|
const VkSampler edge_sampler =
|
||||||
resources.GetSampler(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS, false);
|
resources.GetSampler(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS, false);
|
||||||
const VkBuffer buffer =
|
generations.resize(generation_count);
|
||||||
resources.GetBuffer(LSFG_TIMESTAMP, false, previous_gamma == nullptr);
|
size_t next = 0;
|
||||||
|
for (size_t generation = 0; generation < generation_count; ++generation) {
|
||||||
|
Generation& pass = generations[generation];
|
||||||
|
const VkBuffer buffer = resources.GetBuffer(
|
||||||
|
LsfgTimestamp(generation, generation_count), false, previous_gamma == nullptr);
|
||||||
|
|
||||||
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
||||||
LsfgDescriptorWriter(first_descriptor_sets[i])
|
pass.first_descriptor_sets[i] = owned_sets[next++];
|
||||||
.AddUniformBuffer(buffer, LsfgResources::BufferSize())
|
}
|
||||||
.AddSampler(border_sampler)
|
for (size_t i = 0; i < 4; ++i) {
|
||||||
.AddSampler(edge_sampler)
|
pass.descriptor_sets[i] = owned_sets[next++];
|
||||||
.AddSampledImages((*inputs)[(i + 2) % LSFG_HISTORY_SLOTS])
|
}
|
||||||
.AddSampledImages((*inputs)[i % LSFG_HISTORY_SLOTS])
|
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
||||||
.AddSampledImage(previous_gamma)
|
pass.sixth_descriptor_sets[i] = owned_sets[next++];
|
||||||
.AddStorageImages(temp1)
|
}
|
||||||
|
for (size_t i = 4; i < LSFG_DELTA_STAGES - 2; ++i) {
|
||||||
|
pass.descriptor_sets[i] = owned_sets[next++];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
||||||
|
LsfgDescriptorWriter(pass.first_descriptor_sets[i])
|
||||||
|
.AddUniformBuffer(buffer, LsfgResources::BufferSize())
|
||||||
|
.AddSampler(border_sampler)
|
||||||
|
.AddSampler(edge_sampler)
|
||||||
|
.AddSampledImages((*inputs)[(i + 2) % LSFG_HISTORY_SLOTS])
|
||||||
|
.AddSampledImages((*inputs)[i % LSFG_HISTORY_SLOTS])
|
||||||
|
.AddSampledImage(previous_gamma)
|
||||||
|
.AddStorageImages(temp1)
|
||||||
|
.Build(device);
|
||||||
|
LsfgDescriptorWriter(pass.sixth_descriptor_sets[i])
|
||||||
|
.AddUniformBuffer(buffer, LsfgResources::BufferSize())
|
||||||
|
.AddSampler(border_sampler)
|
||||||
|
.AddSampler(edge_sampler)
|
||||||
|
.AddSampledImages((*inputs)[(i + 2) % LSFG_HISTORY_SLOTS])
|
||||||
|
.AddSampledImages((*inputs)[i % LSFG_HISTORY_SLOTS])
|
||||||
|
.AddSampledImage(previous_gamma)
|
||||||
|
.AddSampledImage(previous1)
|
||||||
|
.AddStorageImage(temp2[0])
|
||||||
|
.Build(device);
|
||||||
|
}
|
||||||
|
LsfgDescriptorWriter(pass.descriptor_sets[0])
|
||||||
|
.AddSampler(sampler)
|
||||||
|
.AddSampledImages(temp1)
|
||||||
|
.AddStorageImages(temp2)
|
||||||
.Build(device);
|
.Build(device);
|
||||||
LsfgDescriptorWriter(sixth_descriptor_sets[i])
|
LsfgDescriptorWriter(pass.descriptor_sets[1])
|
||||||
|
.AddSampler(sampler)
|
||||||
|
.AddSampledImages(temp2)
|
||||||
|
.AddStorageImage(temp1[0])
|
||||||
|
.AddStorageImage(temp1[1])
|
||||||
|
.Build(device);
|
||||||
|
LsfgDescriptorWriter(pass.descriptor_sets[2])
|
||||||
|
.AddSampler(sampler)
|
||||||
|
.AddSampledImage(temp1[0])
|
||||||
|
.AddSampledImage(temp1[1])
|
||||||
|
.AddStorageImages(temp2)
|
||||||
|
.Build(device);
|
||||||
|
LsfgDescriptorWriter(pass.descriptor_sets[3])
|
||||||
.AddUniformBuffer(buffer, LsfgResources::BufferSize())
|
.AddUniformBuffer(buffer, LsfgResources::BufferSize())
|
||||||
.AddSampler(border_sampler)
|
.AddSampler(sampler)
|
||||||
.AddSampler(edge_sampler)
|
.AddSampler(edge_sampler)
|
||||||
.AddSampledImages((*inputs)[(i + 2) % LSFG_HISTORY_SLOTS])
|
.AddSampledImages(temp2)
|
||||||
.AddSampledImages((*inputs)[i % LSFG_HISTORY_SLOTS])
|
|
||||||
.AddSampledImage(previous_gamma)
|
.AddSampledImage(previous_gamma)
|
||||||
.AddSampledImage(previous1)
|
.AddSampledImage(*flow_input)
|
||||||
|
.AddStorageImage(out_image1)
|
||||||
|
.Build(device);
|
||||||
|
LsfgDescriptorWriter(pass.descriptor_sets[4])
|
||||||
|
.AddSampler(sampler)
|
||||||
|
.AddSampledImage(temp2[0])
|
||||||
|
.AddStorageImage(temp1[0])
|
||||||
|
.Build(device);
|
||||||
|
LsfgDescriptorWriter(pass.descriptor_sets[5])
|
||||||
|
.AddSampler(sampler)
|
||||||
|
.AddSampledImage(temp1[0])
|
||||||
.AddStorageImage(temp2[0])
|
.AddStorageImage(temp2[0])
|
||||||
.Build(device);
|
.Build(device);
|
||||||
|
LsfgDescriptorWriter(pass.descriptor_sets[6])
|
||||||
|
.AddSampler(sampler)
|
||||||
|
.AddSampledImage(temp2[0])
|
||||||
|
.AddStorageImage(temp1[0])
|
||||||
|
.Build(device);
|
||||||
|
LsfgDescriptorWriter(pass.descriptor_sets[7])
|
||||||
|
.AddUniformBuffer(buffer, LsfgResources::BufferSize())
|
||||||
|
.AddSampler(sampler)
|
||||||
|
.AddSampler(edge_sampler)
|
||||||
|
.AddSampledImage(temp1[0])
|
||||||
|
.AddSampledImage(previous2)
|
||||||
|
.AddStorageImage(out_image2)
|
||||||
|
.Build(device);
|
||||||
}
|
}
|
||||||
LsfgDescriptorWriter(descriptor_sets[0])
|
|
||||||
.AddSampler(sampler)
|
|
||||||
.AddSampledImages(temp1)
|
|
||||||
.AddStorageImages(temp2)
|
|
||||||
.Build(device);
|
|
||||||
LsfgDescriptorWriter(descriptor_sets[1])
|
|
||||||
.AddSampler(sampler)
|
|
||||||
.AddSampledImages(temp2)
|
|
||||||
.AddStorageImage(temp1[0])
|
|
||||||
.AddStorageImage(temp1[1])
|
|
||||||
.Build(device);
|
|
||||||
LsfgDescriptorWriter(descriptor_sets[2])
|
|
||||||
.AddSampler(sampler)
|
|
||||||
.AddSampledImage(temp1[0])
|
|
||||||
.AddSampledImage(temp1[1])
|
|
||||||
.AddStorageImages(temp2)
|
|
||||||
.Build(device);
|
|
||||||
LsfgDescriptorWriter(descriptor_sets[3])
|
|
||||||
.AddUniformBuffer(buffer, LsfgResources::BufferSize())
|
|
||||||
.AddSampler(sampler)
|
|
||||||
.AddSampler(edge_sampler)
|
|
||||||
.AddSampledImages(temp2)
|
|
||||||
.AddSampledImage(previous_gamma)
|
|
||||||
.AddSampledImage(*flow_input)
|
|
||||||
.AddStorageImage(out_image1)
|
|
||||||
.Build(device);
|
|
||||||
LsfgDescriptorWriter(descriptor_sets[4])
|
|
||||||
.AddSampler(sampler)
|
|
||||||
.AddSampledImage(temp2[0])
|
|
||||||
.AddStorageImage(temp1[0])
|
|
||||||
.Build(device);
|
|
||||||
LsfgDescriptorWriter(descriptor_sets[5])
|
|
||||||
.AddSampler(sampler)
|
|
||||||
.AddSampledImage(temp1[0])
|
|
||||||
.AddStorageImage(temp2[0])
|
|
||||||
.Build(device);
|
|
||||||
LsfgDescriptorWriter(descriptor_sets[6])
|
|
||||||
.AddSampler(sampler)
|
|
||||||
.AddSampledImage(temp2[0])
|
|
||||||
.AddStorageImage(temp1[0])
|
|
||||||
.Build(device);
|
|
||||||
LsfgDescriptorWriter(descriptor_sets[7])
|
|
||||||
.AddUniformBuffer(buffer, LsfgResources::BufferSize())
|
|
||||||
.AddSampler(sampler)
|
|
||||||
.AddSampler(edge_sampler)
|
|
||||||
.AddSampledImage(temp1[0])
|
|
||||||
.AddSampledImage(previous2)
|
|
||||||
.AddStorageImage(out_image2)
|
|
||||||
.Build(device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LsfgDelta::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
void LsfgDelta::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count, size_t generation) {
|
||||||
|
const Generation& pass = generations[generation];
|
||||||
|
|
||||||
const VkExtent2D extent = temp1[0].Extent();
|
const VkExtent2D extent = temp1[0].Extent();
|
||||||
const u32 groups_x = GroupCount(extent.width);
|
const u32 groups_x = GroupCount(extent.width);
|
||||||
const u32 groups_y = GroupCount(extent.height);
|
const u32 groups_y = GroupCount(extent.height);
|
||||||
@@ -202,19 +210,19 @@ void LsfgDelta::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
|||||||
.WriteToRead(previous_gamma)
|
.WriteToRead(previous_gamma)
|
||||||
.ReadToWriteAll(temp1)
|
.ReadToWriteAll(temp1)
|
||||||
.Build();
|
.Build();
|
||||||
passes[0].Bind(cmdbuf, first_descriptor_sets[slot]);
|
passes[0].Bind(cmdbuf, pass.first_descriptor_sets[slot]);
|
||||||
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
LsfgBarriers(cmdbuf).WriteToReadAll(temp1).ReadToWriteAll(temp2).Build();
|
LsfgBarriers(cmdbuf).WriteToReadAll(temp1).ReadToWriteAll(temp2).Build();
|
||||||
passes[1].Bind(cmdbuf, descriptor_sets[0]);
|
passes[1].Bind(cmdbuf, pass.descriptor_sets[0]);
|
||||||
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
LsfgBarriers(cmdbuf).WriteToReadAll(temp2).ReadToWriteAll(temp1).Build();
|
LsfgBarriers(cmdbuf).WriteToReadAll(temp2).ReadToWriteAll(temp1).Build();
|
||||||
passes[2].Bind(cmdbuf, descriptor_sets[1]);
|
passes[2].Bind(cmdbuf, pass.descriptor_sets[1]);
|
||||||
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
LsfgBarriers(cmdbuf).WriteToReadAll(temp1).ReadToWriteAll(temp2).Build();
|
LsfgBarriers(cmdbuf).WriteToReadAll(temp1).ReadToWriteAll(temp2).Build();
|
||||||
passes[3].Bind(cmdbuf, descriptor_sets[2]);
|
passes[3].Bind(cmdbuf, pass.descriptor_sets[2]);
|
||||||
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
LsfgBarriers(cmdbuf)
|
LsfgBarriers(cmdbuf)
|
||||||
@@ -223,7 +231,7 @@ void LsfgDelta::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
|||||||
.WriteToRead(*flow_input)
|
.WriteToRead(*flow_input)
|
||||||
.ReadToWrite(out_image1)
|
.ReadToWrite(out_image1)
|
||||||
.Build();
|
.Build();
|
||||||
passes[4].Bind(cmdbuf, descriptor_sets[3]);
|
passes[4].Bind(cmdbuf, pass.descriptor_sets[3]);
|
||||||
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
LsfgBarriers(cmdbuf)
|
LsfgBarriers(cmdbuf)
|
||||||
@@ -233,7 +241,7 @@ void LsfgDelta::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
|||||||
.WriteToRead(previous1)
|
.WriteToRead(previous1)
|
||||||
.ReadToWriteAll(temp2)
|
.ReadToWriteAll(temp2)
|
||||||
.Build();
|
.Build();
|
||||||
passes[5].Bind(cmdbuf, sixth_descriptor_sets[slot]);
|
passes[5].Bind(cmdbuf, pass.sixth_descriptor_sets[slot]);
|
||||||
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
LsfgBarriers(cmdbuf)
|
LsfgBarriers(cmdbuf)
|
||||||
@@ -241,7 +249,7 @@ void LsfgDelta::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
|||||||
.ReadToWrite(temp1[0])
|
.ReadToWrite(temp1[0])
|
||||||
.ReadToWrite(temp1[1])
|
.ReadToWrite(temp1[1])
|
||||||
.Build();
|
.Build();
|
||||||
passes[6].Bind(cmdbuf, descriptor_sets[4]);
|
passes[6].Bind(cmdbuf, pass.descriptor_sets[4]);
|
||||||
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
LsfgBarriers(cmdbuf)
|
LsfgBarriers(cmdbuf)
|
||||||
@@ -249,7 +257,7 @@ void LsfgDelta::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
|||||||
.WriteToRead(temp1[1])
|
.WriteToRead(temp1[1])
|
||||||
.ReadToWriteAll(temp2)
|
.ReadToWriteAll(temp2)
|
||||||
.Build();
|
.Build();
|
||||||
passes[7].Bind(cmdbuf, descriptor_sets[5]);
|
passes[7].Bind(cmdbuf, pass.descriptor_sets[5]);
|
||||||
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
LsfgBarriers(cmdbuf)
|
LsfgBarriers(cmdbuf)
|
||||||
@@ -257,7 +265,7 @@ void LsfgDelta::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
|||||||
.ReadToWrite(temp1[0])
|
.ReadToWrite(temp1[0])
|
||||||
.ReadToWrite(temp1[1])
|
.ReadToWrite(temp1[1])
|
||||||
.Build();
|
.Build();
|
||||||
passes[8].Bind(cmdbuf, descriptor_sets[6]);
|
passes[8].Bind(cmdbuf, pass.descriptor_sets[6]);
|
||||||
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
LsfgBarriers(cmdbuf)
|
LsfgBarriers(cmdbuf)
|
||||||
@@ -266,7 +274,7 @@ void LsfgDelta::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
|||||||
.WriteToRead(previous2)
|
.WriteToRead(previous2)
|
||||||
.ReadToWrite(out_image2)
|
.ReadToWrite(out_image2)
|
||||||
.Build();
|
.Build();
|
||||||
passes[9].Bind(cmdbuf, descriptor_sets[7]);
|
passes[9].Bind(cmdbuf, pass.descriptor_sets[7]);
|
||||||
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/renderer_vulkan/present/lsfg_common.h"
|
#include "video_core/renderer_vulkan/present/lsfg_common.h"
|
||||||
@@ -22,9 +23,9 @@ public:
|
|||||||
LsfgDelta(const Device& device, MemoryAllocator& memory_allocator, const LsfgShaders& shaders,
|
LsfgDelta(const Device& device, MemoryAllocator& memory_allocator, const LsfgShaders& shaders,
|
||||||
LsfgResources& resources, vk::DescriptorPool& descriptor_pool,
|
LsfgResources& resources, vk::DescriptorPool& descriptor_pool,
|
||||||
LsfgImageHistory& inputs, LsfgImage& flow_input, LsfgImage* previous_gamma,
|
LsfgImageHistory& inputs, LsfgImage& flow_input, LsfgImage* previous_gamma,
|
||||||
LsfgImage* previous1, LsfgImage* previous2);
|
LsfgImage* previous1, LsfgImage* previous2, size_t generation_count);
|
||||||
|
|
||||||
void Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count);
|
void Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count, size_t generation);
|
||||||
|
|
||||||
[[nodiscard]] LsfgImage& Output1() {
|
[[nodiscard]] LsfgImage& Output1() {
|
||||||
return out_image1;
|
return out_image1;
|
||||||
@@ -35,6 +36,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct Generation {
|
||||||
|
std::array<VkDescriptorSet, LSFG_HISTORY_SLOTS> first_descriptor_sets{};
|
||||||
|
std::array<VkDescriptorSet, LSFG_HISTORY_SLOTS> sixth_descriptor_sets{};
|
||||||
|
std::array<VkDescriptorSet, LSFG_DELTA_STAGES - 2> descriptor_sets{};
|
||||||
|
};
|
||||||
|
|
||||||
LsfgImageHistory* inputs{};
|
LsfgImageHistory* inputs{};
|
||||||
LsfgImage* flow_input{};
|
LsfgImage* flow_input{};
|
||||||
LsfgImage* previous_gamma{};
|
LsfgImage* previous_gamma{};
|
||||||
@@ -42,9 +49,7 @@ private:
|
|||||||
LsfgImage* previous2{};
|
LsfgImage* previous2{};
|
||||||
|
|
||||||
std::array<LsfgPass, LSFG_DELTA_STAGES> passes;
|
std::array<LsfgPass, LSFG_DELTA_STAGES> passes;
|
||||||
std::array<VkDescriptorSet, LSFG_HISTORY_SLOTS> first_descriptor_sets{};
|
std::vector<Generation> generations;
|
||||||
std::array<VkDescriptorSet, LSFG_HISTORY_SLOTS> sixth_descriptor_sets{};
|
|
||||||
std::array<VkDescriptorSet, LSFG_DELTA_STAGES - 2> descriptor_sets{};
|
|
||||||
vk::DescriptorSets owned_sets;
|
vk::DescriptorSets owned_sets;
|
||||||
|
|
||||||
std::array<LsfgImage, LSFG_DELTA_TEMPS> temp1;
|
std::array<LsfgImage, LSFG_DELTA_TEMPS> temp1;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ constexpr u32 DISPATCH_TILE_SHIFT = 3;
|
|||||||
LsfgGamma::LsfgGamma(const Device& device, MemoryAllocator& memory_allocator,
|
LsfgGamma::LsfgGamma(const Device& device, MemoryAllocator& memory_allocator,
|
||||||
const LsfgShaders& shaders, LsfgResources& resources,
|
const LsfgShaders& shaders, LsfgResources& resources,
|
||||||
vk::DescriptorPool& descriptor_pool, LsfgImageHistory& inputs_,
|
vk::DescriptorPool& descriptor_pool, LsfgImageHistory& inputs_,
|
||||||
LsfgImage& flow_input_, LsfgImage* previous_)
|
LsfgImage& flow_input_, LsfgImage* previous_, size_t generation_count)
|
||||||
: inputs{&inputs_}, flow_input{&flow_input_}, previous{previous_} {
|
: inputs{&inputs_}, flow_input{&flow_input_}, previous{previous_} {
|
||||||
using namespace VideoCore::FrameGen::PerformanceShader;
|
using namespace VideoCore::FrameGen::PerformanceShader;
|
||||||
|
|
||||||
@@ -61,68 +61,79 @@ LsfgGamma::LsfgGamma(const Device& device, MemoryAllocator& memory_allocator,
|
|||||||
out_image = LsfgImage(device, memory_allocator, extent, LSFG_MOTION_FORMAT);
|
out_image = LsfgImage(device, memory_allocator, extent, LSFG_MOTION_FORMAT);
|
||||||
|
|
||||||
std::vector<VkDescriptorSetLayout> layouts;
|
std::vector<VkDescriptorSetLayout> layouts;
|
||||||
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
for (size_t generation = 0; generation < generation_count; ++generation) {
|
||||||
layouts.push_back(passes[0].SetLayout());
|
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
||||||
}
|
layouts.push_back(passes[0].SetLayout());
|
||||||
for (size_t i = 1; i < LSFG_GAMMA_STAGES; ++i) {
|
}
|
||||||
layouts.push_back(passes[i].SetLayout());
|
for (size_t i = 1; i < LSFG_GAMMA_STAGES; ++i) {
|
||||||
|
layouts.push_back(passes[i].SetLayout());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
owned_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts);
|
owned_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts);
|
||||||
|
|
||||||
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
|
||||||
first_descriptor_sets[i] = owned_sets[i];
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < LSFG_GAMMA_STAGES - 1; ++i) {
|
|
||||||
descriptor_sets[i] = owned_sets[LSFG_HISTORY_SLOTS + i];
|
|
||||||
}
|
|
||||||
|
|
||||||
const VkSampler sampler = resources.GetSampler();
|
const VkSampler sampler = resources.GetSampler();
|
||||||
const VkSampler border_sampler = resources.GetSampler(
|
const VkSampler border_sampler = resources.GetSampler(
|
||||||
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_NEVER, true);
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_NEVER, true);
|
||||||
const VkSampler edge_sampler =
|
const VkSampler edge_sampler =
|
||||||
resources.GetSampler(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS, false);
|
resources.GetSampler(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS, false);
|
||||||
const VkBuffer buffer = resources.GetBuffer(LSFG_TIMESTAMP, previous == nullptr);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
generations.resize(generation_count);
|
||||||
LsfgDescriptorWriter(first_descriptor_sets[i])
|
size_t next = 0;
|
||||||
|
for (size_t generation = 0; generation < generation_count; ++generation) {
|
||||||
|
Generation& pass = generations[generation];
|
||||||
|
const VkBuffer buffer = resources.GetBuffer(
|
||||||
|
LsfgTimestamp(generation, generation_count), previous == nullptr);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
||||||
|
pass.first_descriptor_sets[i] = owned_sets[next++];
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < LSFG_GAMMA_STAGES - 1; ++i) {
|
||||||
|
pass.descriptor_sets[i] = owned_sets[next++];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
||||||
|
LsfgDescriptorWriter(pass.first_descriptor_sets[i])
|
||||||
|
.AddUniformBuffer(buffer, LsfgResources::BufferSize())
|
||||||
|
.AddSampler(border_sampler)
|
||||||
|
.AddSampler(edge_sampler)
|
||||||
|
.AddSampledImages((*inputs)[(i + 2) % LSFG_HISTORY_SLOTS])
|
||||||
|
.AddSampledImages((*inputs)[i % LSFG_HISTORY_SLOTS])
|
||||||
|
.AddSampledImage(previous)
|
||||||
|
.AddStorageImages(temp1)
|
||||||
|
.Build(device);
|
||||||
|
}
|
||||||
|
LsfgDescriptorWriter(pass.descriptor_sets[0])
|
||||||
|
.AddSampler(sampler)
|
||||||
|
.AddSampledImages(temp1)
|
||||||
|
.AddStorageImages(temp2)
|
||||||
|
.Build(device);
|
||||||
|
LsfgDescriptorWriter(pass.descriptor_sets[1])
|
||||||
|
.AddSampler(sampler)
|
||||||
|
.AddSampledImages(temp2)
|
||||||
|
.AddStorageImage(temp1[0])
|
||||||
|
.AddStorageImage(temp1[1])
|
||||||
|
.Build(device);
|
||||||
|
LsfgDescriptorWriter(pass.descriptor_sets[2])
|
||||||
|
.AddSampler(sampler)
|
||||||
|
.AddSampledImage(temp1[0])
|
||||||
|
.AddSampledImage(temp1[1])
|
||||||
|
.AddStorageImages(temp2)
|
||||||
|
.Build(device);
|
||||||
|
LsfgDescriptorWriter(pass.descriptor_sets[3])
|
||||||
.AddUniformBuffer(buffer, LsfgResources::BufferSize())
|
.AddUniformBuffer(buffer, LsfgResources::BufferSize())
|
||||||
.AddSampler(border_sampler)
|
.AddSampler(sampler)
|
||||||
.AddSampler(edge_sampler)
|
.AddSampler(edge_sampler)
|
||||||
.AddSampledImages((*inputs)[(i + 2) % LSFG_HISTORY_SLOTS])
|
.AddSampledImages(temp2)
|
||||||
.AddSampledImages((*inputs)[i % LSFG_HISTORY_SLOTS])
|
|
||||||
.AddSampledImage(previous)
|
.AddSampledImage(previous)
|
||||||
.AddStorageImages(temp1)
|
.AddSampledImage(*flow_input)
|
||||||
|
.AddStorageImage(out_image)
|
||||||
.Build(device);
|
.Build(device);
|
||||||
}
|
}
|
||||||
LsfgDescriptorWriter(descriptor_sets[0])
|
|
||||||
.AddSampler(sampler)
|
|
||||||
.AddSampledImages(temp1)
|
|
||||||
.AddStorageImages(temp2)
|
|
||||||
.Build(device);
|
|
||||||
LsfgDescriptorWriter(descriptor_sets[1])
|
|
||||||
.AddSampler(sampler)
|
|
||||||
.AddSampledImages(temp2)
|
|
||||||
.AddStorageImage(temp1[0])
|
|
||||||
.AddStorageImage(temp1[1])
|
|
||||||
.Build(device);
|
|
||||||
LsfgDescriptorWriter(descriptor_sets[2])
|
|
||||||
.AddSampler(sampler)
|
|
||||||
.AddSampledImage(temp1[0])
|
|
||||||
.AddSampledImage(temp1[1])
|
|
||||||
.AddStorageImages(temp2)
|
|
||||||
.Build(device);
|
|
||||||
LsfgDescriptorWriter(descriptor_sets[3])
|
|
||||||
.AddUniformBuffer(buffer, LsfgResources::BufferSize())
|
|
||||||
.AddSampler(sampler)
|
|
||||||
.AddSampler(edge_sampler)
|
|
||||||
.AddSampledImages(temp2)
|
|
||||||
.AddSampledImage(previous)
|
|
||||||
.AddSampledImage(*flow_input)
|
|
||||||
.AddStorageImage(out_image)
|
|
||||||
.Build(device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LsfgGamma::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
void LsfgGamma::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count, size_t generation) {
|
||||||
|
const Generation& pass = generations[generation];
|
||||||
|
|
||||||
const VkExtent2D extent = temp1[0].Extent();
|
const VkExtent2D extent = temp1[0].Extent();
|
||||||
const u32 groups_x = GroupCount(extent.width);
|
const u32 groups_x = GroupCount(extent.width);
|
||||||
const u32 groups_y = GroupCount(extent.height);
|
const u32 groups_y = GroupCount(extent.height);
|
||||||
@@ -136,11 +147,11 @@ void LsfgGamma::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
|||||||
.WriteToRead(previous)
|
.WriteToRead(previous)
|
||||||
.ReadToWriteAll(temp1)
|
.ReadToWriteAll(temp1)
|
||||||
.Build();
|
.Build();
|
||||||
passes[0].Bind(cmdbuf, first_descriptor_sets[slot]);
|
passes[0].Bind(cmdbuf, pass.first_descriptor_sets[slot]);
|
||||||
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
LsfgBarriers(cmdbuf).WriteToReadAll(temp1).ReadToWriteAll(temp2).Build();
|
LsfgBarriers(cmdbuf).WriteToReadAll(temp1).ReadToWriteAll(temp2).Build();
|
||||||
passes[1].Bind(cmdbuf, descriptor_sets[0]);
|
passes[1].Bind(cmdbuf, pass.descriptor_sets[0]);
|
||||||
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
LsfgBarriers(cmdbuf)
|
LsfgBarriers(cmdbuf)
|
||||||
@@ -148,7 +159,7 @@ void LsfgGamma::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
|||||||
.ReadToWrite(temp1[0])
|
.ReadToWrite(temp1[0])
|
||||||
.ReadToWrite(temp1[1])
|
.ReadToWrite(temp1[1])
|
||||||
.Build();
|
.Build();
|
||||||
passes[2].Bind(cmdbuf, descriptor_sets[1]);
|
passes[2].Bind(cmdbuf, pass.descriptor_sets[1]);
|
||||||
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
LsfgBarriers(cmdbuf)
|
LsfgBarriers(cmdbuf)
|
||||||
@@ -156,7 +167,7 @@ void LsfgGamma::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
|||||||
.WriteToRead(temp1[1])
|
.WriteToRead(temp1[1])
|
||||||
.ReadToWriteAll(temp2)
|
.ReadToWriteAll(temp2)
|
||||||
.Build();
|
.Build();
|
||||||
passes[3].Bind(cmdbuf, descriptor_sets[2]);
|
passes[3].Bind(cmdbuf, pass.descriptor_sets[2]);
|
||||||
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
LsfgBarriers(cmdbuf)
|
LsfgBarriers(cmdbuf)
|
||||||
@@ -165,7 +176,7 @@ void LsfgGamma::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
|||||||
.WriteToRead(*flow_input)
|
.WriteToRead(*flow_input)
|
||||||
.ReadToWrite(out_image)
|
.ReadToWrite(out_image)
|
||||||
.Build();
|
.Build();
|
||||||
passes[4].Bind(cmdbuf, descriptor_sets[3]);
|
passes[4].Bind(cmdbuf, pass.descriptor_sets[3]);
|
||||||
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/renderer_vulkan/present/lsfg_common.h"
|
#include "video_core/renderer_vulkan/present/lsfg_common.h"
|
||||||
@@ -21,22 +22,27 @@ public:
|
|||||||
LsfgGamma() = default;
|
LsfgGamma() = default;
|
||||||
LsfgGamma(const Device& device, MemoryAllocator& memory_allocator, const LsfgShaders& shaders,
|
LsfgGamma(const Device& device, MemoryAllocator& memory_allocator, const LsfgShaders& shaders,
|
||||||
LsfgResources& resources, vk::DescriptorPool& descriptor_pool,
|
LsfgResources& resources, vk::DescriptorPool& descriptor_pool,
|
||||||
LsfgImageHistory& inputs, LsfgImage& flow_input, LsfgImage* previous);
|
LsfgImageHistory& inputs, LsfgImage& flow_input, LsfgImage* previous,
|
||||||
|
size_t generation_count);
|
||||||
|
|
||||||
void Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count);
|
void Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count, size_t generation);
|
||||||
|
|
||||||
[[nodiscard]] LsfgImage& Output() {
|
[[nodiscard]] LsfgImage& Output() {
|
||||||
return out_image;
|
return out_image;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct Generation {
|
||||||
|
std::array<VkDescriptorSet, LSFG_HISTORY_SLOTS> first_descriptor_sets{};
|
||||||
|
std::array<VkDescriptorSet, LSFG_GAMMA_STAGES - 1> descriptor_sets{};
|
||||||
|
};
|
||||||
|
|
||||||
LsfgImageHistory* inputs{};
|
LsfgImageHistory* inputs{};
|
||||||
LsfgImage* flow_input{};
|
LsfgImage* flow_input{};
|
||||||
LsfgImage* previous{};
|
LsfgImage* previous{};
|
||||||
|
|
||||||
std::array<LsfgPass, LSFG_GAMMA_STAGES> passes;
|
std::array<LsfgPass, LSFG_GAMMA_STAGES> passes;
|
||||||
std::array<VkDescriptorSet, LSFG_HISTORY_SLOTS> first_descriptor_sets{};
|
std::vector<Generation> generations;
|
||||||
std::array<VkDescriptorSet, LSFG_GAMMA_STAGES - 1> descriptor_sets{};
|
|
||||||
vk::DescriptorSets owned_sets;
|
vk::DescriptorSets owned_sets;
|
||||||
|
|
||||||
std::array<LsfgImage, LSFG_GAMMA_TEMPS> temp1;
|
std::array<LsfgImage, LSFG_GAMMA_TEMPS> temp1;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ LsfgGenerate::LsfgGenerate(const Device& device, MemoryAllocator& memory_allocat
|
|||||||
const LsfgShaders& shaders, LsfgResources& resources,
|
const LsfgShaders& shaders, LsfgResources& resources,
|
||||||
vk::DescriptorPool& descriptor_pool, LsfgImagePair& frames_,
|
vk::DescriptorPool& descriptor_pool, LsfgImagePair& frames_,
|
||||||
LsfgImage& motion_, LsfgImage& detail1_, LsfgImage& detail2_,
|
LsfgImage& motion_, LsfgImage& detail1_, LsfgImage& detail2_,
|
||||||
VkFormat format)
|
VkFormat format, size_t generation_count)
|
||||||
: frames{&frames_}, motion{&motion_}, detail1{&detail1_}, detail2{&detail2_} {
|
: frames{&frames_}, motion{&motion_}, detail1{&detail1_}, detail2{&detail2_} {
|
||||||
using namespace VideoCore::FrameGen::PerformanceShader;
|
using namespace VideoCore::FrameGen::PerformanceShader;
|
||||||
|
|
||||||
@@ -35,44 +35,54 @@ LsfgGenerate::LsfgGenerate(const Device& device, MemoryAllocator& memory_allocat
|
|||||||
{5, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE},
|
{5, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE},
|
||||||
{1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}});
|
{1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}});
|
||||||
|
|
||||||
out_image = LsfgImage(device, memory_allocator, (*frames)[0].Extent(), format);
|
generations.resize(generation_count);
|
||||||
|
|
||||||
const std::vector<VkDescriptorSetLayout> layouts(descriptor_sets.size(), pass.SetLayout());
|
const std::vector<VkDescriptorSetLayout> layouts(
|
||||||
|
generation_count * generations[0].descriptor_sets.size(), pass.SetLayout());
|
||||||
owned_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts);
|
owned_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts);
|
||||||
|
|
||||||
const VkSampler sampler = resources.GetSampler();
|
const VkSampler sampler = resources.GetSampler();
|
||||||
const VkSampler edge_sampler =
|
const VkSampler edge_sampler =
|
||||||
resources.GetSampler(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS, false);
|
resources.GetSampler(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS, false);
|
||||||
const VkBuffer buffer = resources.GetBuffer(LSFG_TIMESTAMP);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < descriptor_sets.size(); ++i) {
|
size_t next = 0;
|
||||||
descriptor_sets[i] = owned_sets[i];
|
for (size_t generation = 0; generation < generation_count; ++generation) {
|
||||||
LsfgDescriptorWriter(descriptor_sets[i])
|
Generation& target = generations[generation];
|
||||||
.AddUniformBuffer(buffer, LsfgResources::BufferSize())
|
target.out_image = LsfgImage(device, memory_allocator, (*frames)[0].Extent(), format);
|
||||||
.AddSampler(sampler)
|
|
||||||
.AddSampler(edge_sampler)
|
const VkBuffer buffer =
|
||||||
.AddSampledImage((*frames)[1 - i])
|
resources.GetBuffer(LsfgTimestamp(generation, generation_count));
|
||||||
.AddSampledImage((*frames)[i])
|
|
||||||
.AddSampledImage(*motion)
|
for (size_t i = 0; i < target.descriptor_sets.size(); ++i) {
|
||||||
.AddSampledImage(*detail1)
|
target.descriptor_sets[i] = owned_sets[next++];
|
||||||
.AddSampledImage(*detail2)
|
LsfgDescriptorWriter(target.descriptor_sets[i])
|
||||||
.AddStorageImage(out_image)
|
.AddUniformBuffer(buffer, LsfgResources::BufferSize())
|
||||||
.Build(device);
|
.AddSampler(sampler)
|
||||||
|
.AddSampler(edge_sampler)
|
||||||
|
.AddSampledImage((*frames)[1 - i])
|
||||||
|
.AddSampledImage((*frames)[i])
|
||||||
|
.AddSampledImage(*motion)
|
||||||
|
.AddSampledImage(*detail1)
|
||||||
|
.AddSampledImage(*detail2)
|
||||||
|
.AddStorageImage(target.out_image)
|
||||||
|
.Build(device);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LsfgGenerate::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
void LsfgGenerate::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count, size_t generation) {
|
||||||
const VkExtent2D extent = out_image.Extent();
|
Generation& target = generations[generation];
|
||||||
|
const VkExtent2D extent = target.out_image.Extent();
|
||||||
|
|
||||||
LsfgBarriers(cmdbuf)
|
LsfgBarriers(cmdbuf)
|
||||||
.WriteToReadAll(*frames)
|
.WriteToReadAll(*frames)
|
||||||
.WriteToRead(*motion)
|
.WriteToRead(*motion)
|
||||||
.WriteToRead(*detail1)
|
.WriteToRead(*detail1)
|
||||||
.WriteToRead(*detail2)
|
.WriteToRead(*detail2)
|
||||||
.ReadToWrite(out_image)
|
.ReadToWrite(target.out_image)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
pass.Bind(cmdbuf, descriptor_sets[frame_count % descriptor_sets.size()]);
|
pass.Bind(cmdbuf, target.descriptor_sets[frame_count % target.descriptor_sets.size()]);
|
||||||
cmdbuf.Dispatch(GroupCount(extent.width), GroupCount(extent.height), 1);
|
cmdbuf.Dispatch(GroupCount(extent.width), GroupCount(extent.height), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/renderer_vulkan/present/lsfg_common.h"
|
#include "video_core/renderer_vulkan/present/lsfg_common.h"
|
||||||
@@ -19,25 +20,29 @@ public:
|
|||||||
LsfgGenerate(const Device& device, MemoryAllocator& memory_allocator,
|
LsfgGenerate(const Device& device, MemoryAllocator& memory_allocator,
|
||||||
const LsfgShaders& shaders, LsfgResources& resources,
|
const LsfgShaders& shaders, LsfgResources& resources,
|
||||||
vk::DescriptorPool& descriptor_pool, LsfgImagePair& frames, LsfgImage& motion,
|
vk::DescriptorPool& descriptor_pool, LsfgImagePair& frames, LsfgImage& motion,
|
||||||
LsfgImage& detail1, LsfgImage& detail2, VkFormat format);
|
LsfgImage& detail1, LsfgImage& detail2, VkFormat format,
|
||||||
|
size_t generation_count);
|
||||||
|
|
||||||
void Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count);
|
void Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count, size_t generation);
|
||||||
|
|
||||||
[[nodiscard]] LsfgImage& Output() {
|
[[nodiscard]] LsfgImage& Output(size_t generation) {
|
||||||
return out_image;
|
return generations[generation].out_image;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct Generation {
|
||||||
|
std::array<VkDescriptorSet, 2> descriptor_sets{};
|
||||||
|
LsfgImage out_image;
|
||||||
|
};
|
||||||
|
|
||||||
LsfgImagePair* frames{};
|
LsfgImagePair* frames{};
|
||||||
LsfgImage* motion{};
|
LsfgImage* motion{};
|
||||||
LsfgImage* detail1{};
|
LsfgImage* detail1{};
|
||||||
LsfgImage* detail2{};
|
LsfgImage* detail2{};
|
||||||
|
|
||||||
LsfgPass pass;
|
LsfgPass pass;
|
||||||
std::array<VkDescriptorSet, 2> descriptor_sets{};
|
std::vector<Generation> generations;
|
||||||
vk::DescriptorSets owned_sets;
|
vk::DescriptorSets owned_sets;
|
||||||
|
|
||||||
LsfgImage out_image;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|||||||
@@ -195,10 +195,15 @@ void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebu
|
|||||||
|
|
||||||
frame_gen.Process(device, frame, swapchain.GetImageFormat());
|
frame_gen.Process(device, frame, swapchain.GetImageFormat());
|
||||||
|
|
||||||
if (frame_gen.HasGeneratedFrame() && present_manager.CanQueueExtraFrame()) {
|
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();
|
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);
|
frame_gen.CopyToFrame(generated, generation);
|
||||||
scheduler.Flush(*generated->render_ready);
|
scheduler.Flush(*generated->render_ready);
|
||||||
present_manager.Present(generated);
|
present_manager.Present(generated);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ namespace Vulkan {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr size_t FRAME_GEN_EXTRA_FRAMES = 2;
|
||||||
|
|
||||||
bool CanBlitToSwapchain(const vk::PhysicalDevice& physical_device, VkFormat format) {
|
bool CanBlitToSwapchain(const vk::PhysicalDevice& physical_device, VkFormat format) {
|
||||||
const VkFormatProperties props{physical_device.GetFormatProperties(format)};
|
const VkFormatProperties props{physical_device.GetFormatProperties(format)};
|
||||||
return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT);
|
return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT);
|
||||||
@@ -180,12 +182,8 @@ void PresentManager::Present(Frame* frame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool PresentManager::CanQueueExtraFrame() {
|
bool PresentManager::CanQueueExtraFrame() {
|
||||||
if (!use_present_thread) {
|
std::scoped_lock lock{free_mutex};
|
||||||
return false;
|
return !free_queue.empty();
|
||||||
}
|
|
||||||
|
|
||||||
std::scoped_lock lock{queue_mutex, free_mutex};
|
|
||||||
return present_queue.empty() && !free_queue.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
@@ -311,7 +309,11 @@ void PresentManager::SetImageCount() {
|
|||||||
// We cannot have more than 7 images in flight at any given time.
|
// We cannot have more than 7 images in flight at any given time.
|
||||||
// FRAMES_IN_FLIGHT is 8, and the cache TICKS_TO_DESTROY is 8.
|
// FRAMES_IN_FLIGHT is 8, and the cache TICKS_TO_DESTROY is 8.
|
||||||
// Mali drivers will give us 6.
|
// Mali drivers will give us 6.
|
||||||
image_count = std::min<size_t>(swapchain.GetImageCount(), 7);
|
const size_t generated =
|
||||||
|
Settings::values.frame_gen.GetValue()
|
||||||
|
? Settings::values.frame_gen_multiplier.GetValue() * FRAME_GEN_EXTRA_FRAMES
|
||||||
|
: 0;
|
||||||
|
image_count = std::min<size_t>(swapchain.GetImageCount() + generated, 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PresentManager::CopyToSwapchain(Frame* frame) {
|
void PresentManager::CopyToSwapchain(Frame* frame) {
|
||||||
|
|||||||
Reference in New Issue
Block a user