From ae395352a74ba032f626930eb8b2fbdf2784bfe9 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Thu, 13 Aug 2026 14:30:03 -0400 Subject: [PATCH] Adjustments to the frames multiplier --- .../renderer_vulkan/present/frame_gen.cpp | 55 +++------ .../renderer_vulkan/present/frame_gen.h | 3 +- .../renderer_vulkan/present/lsfg_alpha.cpp | 60 +++++----- .../renderer_vulkan/present/lsfg_alpha.h | 23 +++- .../renderer_vulkan/present/lsfg_chain.cpp | 39 ++++--- .../renderer_vulkan/present/lsfg_chain.h | 14 ++- .../renderer_vulkan/present/lsfg_common.cpp | 34 ++++++ .../renderer_vulkan/present/lsfg_common.h | 5 + .../renderer_vulkan/present/lsfg_generate.cpp | 104 ++++++++++++------ .../renderer_vulkan/present/lsfg_generate.h | 24 ++-- .../renderer_vulkan/renderer_vulkan.cpp | 2 +- .../renderer_vulkan/vk_present_manager.cpp | 55 ++++++++- .../renderer_vulkan/vk_present_manager.h | 3 + 13 files changed, 280 insertions(+), 141 deletions(-) diff --git a/src/video_core/renderer_vulkan/present/frame_gen.cpp b/src/video_core/renderer_vulkan/present/frame_gen.cpp index d87a3562d4..04fa6857d3 100644 --- a/src/video_core/renderer_vulkan/present/frame_gen.cpp +++ b/src/video_core/renderer_vulkan/present/frame_gen.cpp @@ -189,6 +189,11 @@ void FrameGen::Process(const Device& device, Frame* frame, VkFormat format, bool return; } + if (!frame->storage_view) { + unavailable = true; + return; + } + if (!shaders) { shaders.emplace(device); if (!shaders->IsValid()) { @@ -205,6 +210,7 @@ void FrameGen::Process(const Device& device, Frame* frame, VkFormat format, bool } const u64 count = frame_count++; + last_count = count; generated = generate && count + 1 >= LSFG_REQUIRED_FRAMES; scheduler.RequestOutsideRenderPassOperationContext(); @@ -212,7 +218,7 @@ void FrameGen::Process(const Device& device, Frame* frame, VkFormat format, bool dispatch = generated](vk::CommandBuffer cmdbuf) { CopyPresentedFrame(cmdbuf, source, chain->Input(count), extent); if (dispatch) { - chain->Dispatch(cmdbuf, count); + chain->DispatchShared(cmdbuf, count); } }); @@ -236,43 +242,15 @@ size_t FrameGen::GeneratedFrameCount() const { return generated && chain ? chain->GenerationCount() : 0; } -void FrameGen::CopyToFrame(Frame* destination, size_t generation) { +void FrameGen::GenerateInto(const Device& device, Frame* destination, size_t generation) { + chain->SetTarget(device, generation, destination->index, *destination->storage_view); + + const VkExtent2D extent{.width = destination->width, .height = destination->height}; + scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([this, target = *destination->image, - generation](vk::CommandBuffer cmdbuf) { - LsfgImage& source = chain->Output(generation); - const VkExtent2D extent = source.Extent(); - - const std::array before{ - MakeTransitionBarrier(source.Handle(), VK_ACCESS_SHADER_WRITE_BIT, - VK_ACCESS_TRANSFER_READ_BIT, source.Layout(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL), - MakeTransitionBarrier(target, 0, VK_ACCESS_TRANSFER_WRITE_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL), - }; - cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {}, {}, before); - - cmdbuf.CopyImage(source.Handle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, target, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, MakeCopyRegion(extent)); - - const std::array after{ - MakeTransitionBarrier(source.Handle(), VK_ACCESS_TRANSFER_READ_BIT, - VK_ACCESS_SHADER_WRITE_BIT, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_IMAGE_LAYOUT_GENERAL), - MakeTransitionBarrier(target, VK_ACCESS_TRANSFER_WRITE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_GENERAL), - }; - cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - 0, {}, {}, after); - - source.SetLayout(VK_IMAGE_LAYOUT_GENERAL); + scheduler.Record([this, count = last_count, generation, target = destination->index, + image = *destination->image, extent](vk::CommandBuffer cmdbuf) { + chain->DispatchGeneration(cmdbuf, count, generation, target, image, extent); }); } @@ -349,9 +327,6 @@ void FrameGen::DumpDebugImages(u64 count) { dump("gamma6", chain->GammaOutput(LSFG_MIP_LEVELS - 1)); dump("delta2_out1", chain->DeltaOutput1(LSFG_DELTA_INSTANCES - 1)); dump("delta2_out2", chain->DeltaOutput2(LSFG_DELTA_INSTANCES - 1)); - for (size_t generation = 0; generation < chain->GenerationCount(); ++generation) { - dump("generated" + std::to_string(generation), chain->Output(generation)); - } } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/present/frame_gen.h b/src/video_core/renderer_vulkan/present/frame_gen.h index 93f8cc83ac..e2a490554c 100644 --- a/src/video_core/renderer_vulkan/present/frame_gen.h +++ b/src/video_core/renderer_vulkan/present/frame_gen.h @@ -27,7 +27,7 @@ public: [[nodiscard]] size_t GeneratedFrameCount() const; - void CopyToFrame(Frame* destination, size_t generation); + void GenerateInto(const Device& device, Frame* destination, size_t generation); private: void Rebuild(const Device& device, VkExtent2D extent, VkFormat format); @@ -43,6 +43,7 @@ private: f32 built_flow_scale{}; size_t built_generations{}; u64 frame_count{}; + u64 last_count{}; bool generated{}; bool unavailable{}; bool dumped{}; diff --git a/src/video_core/renderer_vulkan/present/lsfg_alpha.cpp b/src/video_core/renderer_vulkan/present/lsfg_alpha.cpp index 68b08b1b31..a735dd11f4 100644 --- a/src/video_core/renderer_vulkan/present/lsfg_alpha.cpp +++ b/src/video_core/renderer_vulkan/present/lsfg_alpha.cpp @@ -31,10 +31,7 @@ constexpr u32 DISPATCH_TILE_SHIFT = 3; } // Anonymous namespace -LsfgAlpha::LsfgAlpha(const Device& device, MemoryAllocator& memory_allocator, - const LsfgShaders& shaders, LsfgResources& resources, - vk::DescriptorPool& descriptor_pool, LsfgImage& input_) - : input{&input_} { +LsfgAlphaPasses::LsfgAlphaPasses(const Device& device, const LsfgShaders& shaders) { using namespace VideoCore::FrameGen::PerformanceShader; passes[0] = LsfgPass(device, shaders, ALPHA[0], @@ -53,7 +50,12 @@ LsfgAlpha::LsfgAlpha(const Device& device, MemoryAllocator& memory_allocator, {{1, VK_DESCRIPTOR_TYPE_SAMPLER}, {2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE}, {2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}}); +} +LsfgAlpha::LsfgAlpha(const Device& device, MemoryAllocator& memory_allocator, + const LsfgAlphaPasses& passes_, LsfgResources& resources, + vk::DescriptorPool& descriptor_pool, LsfgImage& input_) + : passes{&passes_}, input{&input_} { const VkExtent2D half_extent = HalveExtent(input->Extent()); const VkExtent2D quarter_extent = HalveExtent(half_extent); @@ -68,10 +70,10 @@ LsfgAlpha::LsfgAlpha(const Device& device, MemoryAllocator& memory_allocator, std::vector layouts; for (size_t i = 0; i < LSFG_ALPHA_STAGES - 1; ++i) { - layouts.push_back(passes[i].SetLayout()); + layouts.push_back(passes->Get(i).SetLayout()); } for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) { - layouts.push_back(passes[3].SetLayout()); + layouts.push_back(passes->Get(3).SetLayout()); } owned_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts); @@ -108,31 +110,31 @@ LsfgAlpha::LsfgAlpha(const Device& device, MemoryAllocator& memory_allocator, } } -void LsfgAlpha::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) { - const VkExtent2D half_extent = temp1.Extent(); - u32 groups_x = GroupCount(half_extent.width); - u32 groups_y = GroupCount(half_extent.height); +void LsfgAlpha::PushBarriers(LsfgBarriers& barriers, u64 frame_count, size_t stage) { + switch (stage) { + case 0: + barriers.WriteToRead(*input).ReadToWrite(temp1); + break; + case 1: + barriers.WriteToRead(temp1).ReadToWrite(temp2); + break; + case 2: + barriers.WriteToRead(temp2).ReadToWriteAll(temp3); + break; + default: + barriers.WriteToReadAll(temp3).ReadToWriteAll(out_images[frame_count % LSFG_HISTORY_SLOTS]); + break; + } +} - LsfgBarriers(cmdbuf).WriteToRead(*input).ReadToWrite(temp1).Build(); - passes[0].Bind(cmdbuf, descriptor_sets[0]); - cmdbuf.Dispatch(groups_x, groups_y, 1); +void LsfgAlpha::DispatchStage(vk::CommandBuffer cmdbuf, u64 frame_count, size_t stage) { + const VkExtent2D extent = stage < 2 ? temp1.Extent() : temp3[0].Extent(); + const VkDescriptorSet set = stage < LSFG_ALPHA_STAGES - 1 + ? descriptor_sets[stage] + : last_descriptor_sets[frame_count % LSFG_HISTORY_SLOTS]; - LsfgBarriers(cmdbuf).WriteToRead(temp1).ReadToWrite(temp2).Build(); - passes[1].Bind(cmdbuf, descriptor_sets[1]); - cmdbuf.Dispatch(groups_x, groups_y, 1); - - const VkExtent2D quarter_extent = temp3[0].Extent(); - groups_x = GroupCount(quarter_extent.width); - groups_y = GroupCount(quarter_extent.height); - - LsfgBarriers(cmdbuf).WriteToRead(temp2).ReadToWriteAll(temp3).Build(); - passes[2].Bind(cmdbuf, descriptor_sets[2]); - cmdbuf.Dispatch(groups_x, groups_y, 1); - - const size_t slot = frame_count % LSFG_HISTORY_SLOTS; - LsfgBarriers(cmdbuf).WriteToReadAll(temp3).ReadToWriteAll(out_images[slot]).Build(); - passes[3].Bind(cmdbuf, last_descriptor_sets[slot]); - cmdbuf.Dispatch(groups_x, groups_y, 1); + passes->Get(stage).BindSet(cmdbuf, set); + cmdbuf.Dispatch(GroupCount(extent.width), GroupCount(extent.height), 1); } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/present/lsfg_alpha.h b/src/video_core/renderer_vulkan/present/lsfg_alpha.h index 8d9d230d40..1dc8864431 100644 --- a/src/video_core/renderer_vulkan/present/lsfg_alpha.h +++ b/src/video_core/renderer_vulkan/present/lsfg_alpha.h @@ -18,22 +18,37 @@ class LsfgShaders; constexpr size_t LSFG_ALPHA_STAGES = 4; +class LsfgAlphaPasses { +public: + LsfgAlphaPasses() = default; + LsfgAlphaPasses(const Device& device, const LsfgShaders& shaders); + + [[nodiscard]] const LsfgPass& Get(size_t stage) const { + return passes[stage]; + } + +private: + std::array passes; +}; + class LsfgAlpha { public: LsfgAlpha() = default; - LsfgAlpha(const Device& device, MemoryAllocator& memory_allocator, const LsfgShaders& shaders, - LsfgResources& resources, vk::DescriptorPool& descriptor_pool, LsfgImage& input); + LsfgAlpha(const Device& device, MemoryAllocator& memory_allocator, + const LsfgAlphaPasses& passes_, LsfgResources& resources, + vk::DescriptorPool& descriptor_pool, LsfgImage& input); - void Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count); + void PushBarriers(LsfgBarriers& barriers, u64 frame_count, size_t stage); + void DispatchStage(vk::CommandBuffer cmdbuf, u64 frame_count, size_t stage); [[nodiscard]] LsfgImageHistory& Outputs() { return out_images; } private: + const LsfgAlphaPasses* passes{}; LsfgImage* input{}; - std::array passes; std::array descriptor_sets{}; std::array last_descriptor_sets{}; vk::DescriptorSets owned_sets; diff --git a/src/video_core/renderer_vulkan/present/lsfg_chain.cpp b/src/video_core/renderer_vulkan/present/lsfg_chain.cpp index 3c763e6745..81e9b1c6c9 100644 --- a/src/video_core/renderer_vulkan/present/lsfg_chain.cpp +++ b/src/video_core/renderer_vulkan/present/lsfg_chain.cpp @@ -15,7 +15,7 @@ namespace Vulkan { namespace { constexpr u32 FIXED_DESCRIPTOR_SETS = 64; -constexpr u32 DESCRIPTOR_SETS_PER_GENERATION = 96; +constexpr u32 DESCRIPTOR_SETS_PER_GENERATION = 112; constexpr size_t FIRST_DELTA_LEVEL = 4; } // Anonymous namespace @@ -35,8 +35,9 @@ LsfgChain::LsfgChain(const Device& device, MemoryAllocator& memory_allocator, mipmaps = LsfgMipmaps(device, memory_allocator, shaders, resources, descriptor_pool, frames, flow_scale); + alpha_passes = LsfgAlphaPasses(device, shaders); for (size_t i = 0; i < LSFG_MIP_LEVELS; ++i) { - alpha[i] = LsfgAlpha(device, memory_allocator, shaders, resources, descriptor_pool, + alpha[i] = LsfgAlpha(device, memory_allocator, alpha_passes, resources, descriptor_pool, mipmaps.Output(i)); } @@ -62,30 +63,40 @@ LsfgChain::LsfgChain(const Device& device, MemoryAllocator& memory_allocator, i == FIRST_DELTA_LEVEL ? nullptr : &delta[index - 1].Output2(), generation_count); } - generate = LsfgGenerate(device, memory_allocator, shaders, resources, descriptor_pool, frames, + generate = LsfgGenerate(device, shaders, resources, descriptor_pool, frames, gamma[LSFG_MIP_LEVELS - 1].Output(), delta[LSFG_DELTA_INSTANCES - 1].Output1(), - delta[LSFG_DELTA_INSTANCES - 1].Output2(), format, generation_count); + delta[LSFG_DELTA_INSTANCES - 1].Output2(), generation_count); } -void LsfgChain::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) { +void LsfgChain::DispatchShared(vk::CommandBuffer cmdbuf, u64 frame_count) { mipmaps.Dispatch(cmdbuf, frame_count); - for (size_t i = 0; i < LSFG_MIP_LEVELS; ++i) { - alpha[LSFG_MIP_LEVELS - 1 - i].Dispatch(cmdbuf, frame_count); + for (size_t stage = 0; stage < LSFG_ALPHA_STAGES; ++stage) { + LsfgBarriers barriers(cmdbuf); + for (auto& level : alpha) { + level.PushBarriers(barriers, frame_count, stage); + } + barriers.Build(); + + alpha_passes.Get(stage).BindPipeline(cmdbuf); + for (auto& level : alpha) { + level.DispatchStage(cmdbuf, frame_count, stage); + } } beta.Dispatch(cmdbuf, frame_count); +} - for (size_t generation = 0; generation < generation_count; ++generation) { - for (size_t i = 0; i < LSFG_MIP_LEVELS; ++i) { - gamma[i].Dispatch(cmdbuf, frame_count, generation); - if (i >= FIRST_DELTA_LEVEL) { - delta[i - FIRST_DELTA_LEVEL].Dispatch(cmdbuf, frame_count, generation); - } +void LsfgChain::DispatchGeneration(vk::CommandBuffer cmdbuf, u64 frame_count, size_t generation, + u32 target, VkImage image, VkExtent2D extent) { + for (size_t i = 0; i < LSFG_MIP_LEVELS; ++i) { + gamma[i].Dispatch(cmdbuf, frame_count, generation); + 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, generation, target, image, extent); } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/present/lsfg_chain.h b/src/video_core/renderer_vulkan/present/lsfg_chain.h index 70abf523f9..7208e25387 100644 --- a/src/video_core/renderer_vulkan/present/lsfg_chain.h +++ b/src/video_core/renderer_vulkan/present/lsfg_chain.h @@ -32,16 +32,19 @@ public: LsfgChain(const LsfgChain&) = delete; LsfgChain& operator=(const LsfgChain&) = delete; - void Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count); + void DispatchShared(vk::CommandBuffer cmdbuf, u64 frame_count); + + void DispatchGeneration(vk::CommandBuffer cmdbuf, u64 frame_count, size_t generation, + u32 target, VkImage image, VkExtent2D extent); + + void SetTarget(const Device& device, size_t generation, u32 target, VkImageView view) { + generate.SetTarget(device, generation, target, view); + } [[nodiscard]] LsfgImage& Input(u64 frame_count) { return frames[frame_count % frames.size()]; } - [[nodiscard]] LsfgImage& Output(size_t generation) { - return generate.Output(generation); - } - [[nodiscard]] size_t GenerationCount() const { return generation_count; } @@ -77,6 +80,7 @@ private: LsfgImagePair frames; LsfgMipmaps mipmaps; + LsfgAlphaPasses alpha_passes; std::array alpha; LsfgBeta beta; std::array gamma; diff --git a/src/video_core/renderer_vulkan/present/lsfg_common.cpp b/src/video_core/renderer_vulkan/present/lsfg_common.cpp index f3ffafba1e..d2df2755e5 100644 --- a/src/video_core/renderer_vulkan/present/lsfg_common.cpp +++ b/src/video_core/renderer_vulkan/present/lsfg_common.cpp @@ -121,6 +121,28 @@ LsfgBarriers& LsfgBarriers::ReadToWrite(LsfgImage* image) { return image == nullptr ? *this : ReadToWrite(*image); } +LsfgBarriers& LsfgBarriers::DiscardToWrite(VkImage image) { + barriers.push_back(VkImageMemoryBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = 0, + .dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = image, + .subresourceRange{ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }); + return *this; +} + VkDeviceSize LsfgResources::BufferSize() { return sizeof(LsfgConstants); } @@ -222,6 +244,10 @@ LsfgDescriptorWriter& LsfgDescriptorWriter::AddStorageImage(const LsfgImage& ima return PushImage(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_NULL_HANDLE, image.View()); } +LsfgDescriptorWriter& LsfgDescriptorWriter::AddStorageView(VkImageView view) { + return PushImage(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_NULL_HANDLE, view); +} + LsfgDescriptorWriter& LsfgDescriptorWriter::AddUniformBuffer(VkBuffer buffer, VkDeviceSize size) { buffer_infos.push_back(VkDescriptorBufferInfo{ .buffer = buffer, @@ -266,7 +292,15 @@ LsfgPass::LsfgPass(const Device& device, const LsfgShaders& shaders, u32 shader_ } void LsfgPass::Bind(vk::CommandBuffer cmdbuf, VkDescriptorSet set) const { + BindPipeline(cmdbuf); + BindSet(cmdbuf, set); +} + +void LsfgPass::BindPipeline(vk::CommandBuffer cmdbuf) const { cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline); +} + +void LsfgPass::BindSet(vk::CommandBuffer cmdbuf, VkDescriptorSet set) const { cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline_layout, 0, set, {}); } diff --git a/src/video_core/renderer_vulkan/present/lsfg_common.h b/src/video_core/renderer_vulkan/present/lsfg_common.h index f46b1db0a6..cf683cd138 100644 --- a/src/video_core/renderer_vulkan/present/lsfg_common.h +++ b/src/video_core/renderer_vulkan/present/lsfg_common.h @@ -30,6 +30,7 @@ constexpr size_t LSFG_HISTORY_SLOTS = 3; constexpr size_t LSFG_MIN_MULTIPLIER = 2; constexpr size_t LSFG_MAX_MULTIPLIER = 4; constexpr size_t LSFG_MAX_GENERATIONS = LSFG_MAX_MULTIPLIER - 1; +constexpr size_t LSFG_MAX_TARGETS = 7; [[nodiscard]] constexpr f32 LsfgTimestamp(size_t generation, size_t generation_count) { return static_cast(generation + 1) / static_cast(generation_count + 1); @@ -108,6 +109,7 @@ public: LsfgBarriers& ReadToWrite(LsfgImage& image); LsfgBarriers& WriteToRead(LsfgImage* image); LsfgBarriers& ReadToWrite(LsfgImage* image); + LsfgBarriers& DiscardToWrite(VkImage image); template LsfgBarriers& WriteToReadAll(Range& images) { @@ -142,6 +144,7 @@ public: LsfgDescriptorWriter& AddSampledImage(const LsfgImage& image); LsfgDescriptorWriter& AddSampledImage(const LsfgImage* image); LsfgDescriptorWriter& AddStorageImage(const LsfgImage& image); + LsfgDescriptorWriter& AddStorageView(VkImageView view); LsfgDescriptorWriter& AddUniformBuffer(VkBuffer buffer, VkDeviceSize size); template @@ -189,6 +192,8 @@ public: } void Bind(vk::CommandBuffer cmdbuf, VkDescriptorSet set) const; + void BindPipeline(vk::CommandBuffer cmdbuf) const; + void BindSet(vk::CommandBuffer cmdbuf, VkDescriptorSet set) const; private: vk::DescriptorSetLayout descriptor_set_layout; diff --git a/src/video_core/renderer_vulkan/present/lsfg_generate.cpp b/src/video_core/renderer_vulkan/present/lsfg_generate.cpp index f955a38e3a..bb8e728ee2 100644 --- a/src/video_core/renderer_vulkan/present/lsfg_generate.cpp +++ b/src/video_core/renderer_vulkan/present/lsfg_generate.cpp @@ -22,13 +22,34 @@ constexpr u32 DISPATCH_TILE_SHIFT = 4; return (size + (1u << DISPATCH_TILE_SHIFT) - 1) >> DISPATCH_TILE_SHIFT; } +VkImageMemoryBarrier MakeTargetBarrier(VkImage image, VkAccessFlags src_access, + VkAccessFlags dst_access, VkImageLayout old_layout) { + return VkImageMemoryBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = src_access, + .dstAccessMask = dst_access, + .oldLayout = old_layout, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = image, + .subresourceRange{ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; +} + } // Anonymous namespace -LsfgGenerate::LsfgGenerate(const Device& device, MemoryAllocator& memory_allocator, - const LsfgShaders& shaders, LsfgResources& resources, - vk::DescriptorPool& descriptor_pool, LsfgImagePair& frames_, - LsfgImage& motion_, LsfgImage& detail1_, LsfgImage& detail2_, - VkFormat format, size_t generation_count) +LsfgGenerate::LsfgGenerate(const Device& device, const LsfgShaders& shaders, + LsfgResources& resources, vk::DescriptorPool& descriptor_pool, + LsfgImagePair& frames_, LsfgImage& motion_, LsfgImage& detail1_, + LsfgImage& detail2_, size_t generation_count) : frames{&frames_}, motion{&motion_}, detail1{&detail1_}, detail2{&detail2_} { using namespace VideoCore::FrameGen::PerformanceShader; @@ -38,55 +59,74 @@ LsfgGenerate::LsfgGenerate(const Device& device, MemoryAllocator& memory_allocat {5, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE}, {1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}}); + sampler = resources.GetSampler(); + edge_sampler = + resources.GetSampler(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS, false); + generations.resize(generation_count); const std::vector layouts( - generation_count * generations[0].descriptor_sets.size(), pass.SetLayout()); + generation_count * LSFG_MAX_TARGETS * 2, pass.SetLayout()); owned_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts); - const VkSampler sampler = resources.GetSampler(); - const VkSampler edge_sampler = - resources.GetSampler(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS, false); - size_t next = 0; for (size_t generation = 0; generation < generation_count; ++generation) { Generation& target = generations[generation]; - target.out_image = LsfgImage(device, memory_allocator, (*frames)[0].Extent(), format); + target.buffer = resources.GetBuffer(LsfgTimestamp(generation, generation_count)); - const VkBuffer buffer = - resources.GetBuffer(LsfgTimestamp(generation, generation_count)); - - for (size_t i = 0; i < target.descriptor_sets.size(); ++i) { - target.descriptor_sets[i] = owned_sets[next++]; - LsfgDescriptorWriter(target.descriptor_sets[i]) - .AddUniformBuffer(buffer, LsfgResources::BufferSize()) - .AddSampler(sampler) - .AddSampler(edge_sampler) - .AddSampledImage((*frames)[1 - i]) - .AddSampledImage((*frames)[i]) - .AddSampledImage(*motion) - .AddSampledImage(*detail1) - .AddSampledImage(*detail2) - .AddStorageImage(target.out_image) - .Build(device); + for (auto& slot : target.targets) { + for (auto& set : slot.descriptor_sets) { + set = owned_sets[next++]; + } } } } -void LsfgGenerate::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count, size_t generation) { - Generation& target = generations[generation]; - const VkExtent2D extent = target.out_image.Extent(); +void LsfgGenerate::SetTarget(const Device& device, size_t generation, u32 target, VkImageView view) { + Target& slot = generations[generation].targets[target]; + if (slot.view == view) { + return; + } + slot.view = view; + + for (size_t i = 0; i < slot.descriptor_sets.size(); ++i) { + LsfgDescriptorWriter(slot.descriptor_sets[i]) + .AddUniformBuffer(generations[generation].buffer, LsfgResources::BufferSize()) + .AddSampler(sampler) + .AddSampler(edge_sampler) + .AddSampledImage((*frames)[1 - i]) + .AddSampledImage((*frames)[i]) + .AddSampledImage(*motion) + .AddSampledImage(*detail1) + .AddSampledImage(*detail2) + .AddStorageView(view) + .Build(device); + } +} + +void LsfgGenerate::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count, size_t generation, + u32 target, VkImage image, VkExtent2D extent) { + const Target& slot = generations[generation].targets[target]; LsfgBarriers(cmdbuf) .WriteToReadAll(*frames) .WriteToRead(*motion) .WriteToRead(*detail1) .WriteToRead(*detail2) - .ReadToWrite(target.out_image) + .DiscardToWrite(image) .Build(); - pass.Bind(cmdbuf, target.descriptor_sets[frame_count % target.descriptor_sets.size()]); + pass.Bind(cmdbuf, slot.descriptor_sets[frame_count % slot.descriptor_sets.size()]); cmdbuf.Dispatch(GroupCount(extent.width), GroupCount(extent.height), 1); + + const std::array after{MakeTargetBarrier( + image, VK_ACCESS_SHADER_WRITE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT, + VK_IMAGE_LAYOUT_GENERAL)}; + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, {}, {}, after); } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/present/lsfg_generate.h b/src/video_core/renderer_vulkan/present/lsfg_generate.h index 7d1af26918..2f973c33db 100644 --- a/src/video_core/renderer_vulkan/present/lsfg_generate.h +++ b/src/video_core/renderer_vulkan/present/lsfg_generate.h @@ -20,28 +20,32 @@ class LsfgShaders; class LsfgGenerate { public: LsfgGenerate() = default; - LsfgGenerate(const Device& device, MemoryAllocator& memory_allocator, - const LsfgShaders& shaders, LsfgResources& resources, + LsfgGenerate(const Device& device, const LsfgShaders& shaders, LsfgResources& resources, vk::DescriptorPool& descriptor_pool, LsfgImagePair& frames, LsfgImage& motion, - LsfgImage& detail1, LsfgImage& detail2, VkFormat format, - size_t generation_count); + LsfgImage& detail1, LsfgImage& detail2, size_t generation_count); - void Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count, size_t generation); + void SetTarget(const Device& device, size_t generation, u32 target, VkImageView view); - [[nodiscard]] LsfgImage& Output(size_t generation) { - return generations[generation].out_image; - } + void Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count, size_t generation, u32 target, + VkImage image, VkExtent2D extent); private: - struct Generation { + struct Target { std::array descriptor_sets{}; - LsfgImage out_image; + VkImageView view{}; + }; + + struct Generation { + std::array targets{}; + VkBuffer buffer{}; }; LsfgImagePair* frames{}; LsfgImage* motion{}; LsfgImage* detail1{}; LsfgImage* detail2{}; + VkSampler sampler{}; + VkSampler edge_sampler{}; LsfgPass pass; std::vector generations; diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 463573709c..eeaa46309d 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -202,7 +202,7 @@ void RendererVulkan::Composite(std::span framebu for (size_t generation = 0; generation < generated_frames; ++generation) { Frame* generated = present_manager.GetRenderFrame(); blit_swapchain.PrepareFrame(device, generated, render_window.GetFramebufferLayout()); - frame_gen.CopyToFrame(generated, generation); + frame_gen.GenerateInto(device, generated, generation); scheduler.Flush(*generated->render_ready); present_manager.Present(generated); } diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index 04790afb9f..d7c441fd6a 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp @@ -7,6 +7,7 @@ #include "common/settings.h" #include "common/thread.h" #include "core/frontend/emu_window.h" +#include "video_core/renderer_vulkan/present/lsfg_common.h" #include "video_core/renderer_vulkan/vk_present_manager.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_swapchain.h" @@ -19,7 +20,16 @@ namespace Vulkan { namespace { -constexpr size_t FRAME_GEN_EXTRA_FRAMES = 2; +constexpr size_t MAX_FRAMES_IN_FLIGHT = 7; +static_assert(MAX_FRAMES_IN_FLIGHT <= LSFG_MAX_TARGETS); + +bool CanStoreToFrame(const vk::PhysicalDevice& physical_device, VkFormat format) { + if (!Settings::values.frame_gen.GetValue()) { + return false; + } + const VkFormatProperties props{physical_device.GetFormatProperties(format)}; + return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0; +} bool CanBlitToSwapchain(const vk::PhysicalDevice& physical_device, VkFormat format) { const VkFormatProperties props{physical_device.GetFormatProperties(format)}; @@ -112,6 +122,7 @@ PresentManager::PresentManager(const vk::Instance& instance_, , swapchain{swapchain_} , surface{surface_} , blit_supported{CanBlitToSwapchain(device.GetPhysical(), swapchain.GetImageViewFormat())} + , storage_supported{CanStoreToFrame(device.GetPhysical(), swapchain.GetImageFormat())} , use_present_thread{Settings::values.async_presentation.GetValue()} { SetImageCount(); @@ -129,6 +140,7 @@ PresentManager::PresentManager(const vk::Instance& instance_, frames.resize(image_count); for (u32 i = 0; i < frames.size(); i++) { Frame& frame = frames[i]; + frame.index = i; frame.cmdbuf = vk::CommandBuffer{cmdbuffers[i], device.GetDispatchLoader()}; frame.render_ready = dld.CreateSemaphore({ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, @@ -193,6 +205,9 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat frame->width = width; frame->height = height; + const VkImageUsageFlags storage_usage = + storage_supported ? static_cast(VK_IMAGE_USAGE_STORAGE_BIT) : 0; + frame->image = memory_allocator.CreateImage({ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = nullptr, @@ -210,7 +225,7 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat .samples = VK_SAMPLE_COUNT_1_BIT, .tiling = VK_IMAGE_TILING_OPTIMAL, .usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | storage_usage, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, @@ -241,6 +256,33 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat }, }); + frame->storage_view = vk::ImageView{}; + if (storage_supported) { + frame->storage_view = dld.CreateImageView({ + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .image = *frame->image, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = swapchain.GetImageFormat(), + .components = + { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + }, + .subresourceRange = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }); + } + const VkImageView image_view{*frame->image_view}; frame->framebuffer = dld.CreateFramebuffer({ .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, @@ -309,11 +351,14 @@ void PresentManager::SetImageCount() { // 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. // Mali drivers will give us 6. - const size_t generated = + const size_t generations = Settings::values.frame_gen.GetValue() - ? Settings::values.frame_gen_multiplier.GetValue() * FRAME_GEN_EXTRA_FRAMES + ? static_cast(Settings::values.frame_gen_multiplier.GetValue()) - 1 : 0; - image_count = std::min(swapchain.GetImageCount() + generated, 7); + const size_t frames_per_composite = generations + 1; + image_count = std::min( + std::max(swapchain.GetImageCount() + generations, frames_per_composite * 2), + MAX_FRAMES_IN_FLIGHT); } void PresentManager::CopyToSwapchain(Frame* frame) { diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h index 1470c6c688..25e3e12b6e 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.h +++ b/src/video_core/renderer_vulkan/vk_present_manager.h @@ -28,8 +28,10 @@ class Swapchain; struct Frame { u32 width; u32 height; + u32 index; vk::Image image; vk::ImageView image_view; + vk::ImageView storage_view; vk::Framebuffer framebuffer; vk::CommandBuffer cmdbuf; vk::Semaphore render_ready; @@ -93,6 +95,7 @@ private: std::mutex free_mutex; std::jthread present_thread; bool blit_supported; + bool storage_supported; bool use_present_thread; std::size_t image_count{}; };