From 367e5084da86ae1951c18e98ecb3cbfed872f478 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Wed, 12 Aug 2026 23:38:38 -0400 Subject: [PATCH] Beta pass on lsfg --- src/video_core/CMakeLists.txt | 2 + .../renderer_vulkan/present/lsfg_beta.cpp | 144 ++++++++++++++++++ .../renderer_vulkan/present/lsfg_beta.h | 45 ++++++ 3 files changed, 191 insertions(+) create mode 100644 src/video_core/renderer_vulkan/present/lsfg_beta.cpp create mode 100644 src/video_core/renderer_vulkan/present/lsfg_beta.h diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index d3d52a7cb9..8f1abe7df2 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -129,6 +129,8 @@ add_library(video_core STATIC renderer_vulkan/present/frame_gen.h renderer_vulkan/present/lsfg_alpha.cpp renderer_vulkan/present/lsfg_alpha.h + renderer_vulkan/present/lsfg_beta.cpp + renderer_vulkan/present/lsfg_beta.h renderer_vulkan/present/lsfg_common.cpp renderer_vulkan/present/lsfg_common.h renderer_vulkan/present/lsfg_mipmaps.cpp diff --git a/src/video_core/renderer_vulkan/present/lsfg_beta.cpp b/src/video_core/renderer_vulkan/present/lsfg_beta.cpp new file mode 100644 index 0000000000..049948e761 --- /dev/null +++ b/src/video_core/renderer_vulkan/present/lsfg_beta.cpp @@ -0,0 +1,144 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include + +#include "video_core/frame_gen/lossless_dll.h" +#include "video_core/renderer_vulkan/present/lsfg_beta.h" +#include "video_core/renderer_vulkan/present/lsfg_shaders.h" +#include "video_core/renderer_vulkan/present/util.h" +#include "video_core/vulkan_common/vulkan_device.h" + +namespace Vulkan { + +namespace { + +constexpr u32 DISPATCH_TILE_SHIFT = 3; +constexpr u32 OUTPUT_TILE_SHIFT = 5; + +[[nodiscard]] u32 GroupCount(u32 size, u32 shift) { + return (size + (1u << shift) - 1) >> shift; +} + +} // Anonymous namespace + +LsfgBeta::LsfgBeta(const Device& device, MemoryAllocator& memory_allocator, + const LsfgShaders& shaders, LsfgResources& resources, + vk::DescriptorPool& descriptor_pool, LsfgImageHistory& inputs_) + : inputs{&inputs_} { + using namespace VideoCore::FrameGen::PerformanceShader; + + passes[0] = LsfgPass(device, shaders, BETA[0], + {{1, VK_DESCRIPTOR_TYPE_SAMPLER}, + {6, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE}, + {2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}}); + for (size_t i = 1; i < LSFG_BETA_STAGES - 1; ++i) { + passes[i] = LsfgPass(device, shaders, BETA[i], + {{1, VK_DESCRIPTOR_TYPE_SAMPLER}, + {2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE}, + {2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}}); + } + passes[4] = LsfgPass(device, shaders, BETA[4], + {{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER}, + {1, VK_DESCRIPTOR_TYPE_SAMPLER}, + {2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE}, + {6, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}}); + + const VkExtent2D extent = (*inputs)[0][0].Extent(); + for (size_t i = 0; i < temp1.size(); ++i) { + temp1[i] = LsfgImage(device, memory_allocator, extent); + temp2[i] = LsfgImage(device, memory_allocator, extent); + } + for (size_t i = 0; i < LSFG_BETA_OUTPUTS; ++i) { + const VkExtent2D level_extent{ + .width = extent.width >> i, + .height = extent.height >> i, + }; + out_images[i] = LsfgImage(device, memory_allocator, level_extent, LSFG_FLOW_FORMAT); + } + + std::vector layouts; + for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) { + layouts.push_back(passes[0].SetLayout()); + } + for (size_t i = 1; i < LSFG_BETA_STAGES; ++i) { + layouts.push_back(passes[i].SetLayout()); + } + 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_BETA_STAGES - 1; ++i) { + descriptor_sets[i] = owned_sets[LSFG_HISTORY_SLOTS + i]; + } + + const VkSampler sampler = resources.GetSampler(); + const VkSampler border_sampler = resources.GetSampler( + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_NEVER, true); + + for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) { + LsfgDescriptorWriter(first_descriptor_sets[i]) + .AddSampler(border_sampler) + .AddSampledImages((*inputs)[(i + 1) % LSFG_HISTORY_SLOTS]) + .AddSampledImages((*inputs)[(i + 2) % LSFG_HISTORY_SLOTS]) + .AddSampledImages((*inputs)[i % LSFG_HISTORY_SLOTS]) + .AddStorageImages(temp1) + .Build(device); + } + LsfgDescriptorWriter(descriptor_sets[0]) + .AddSampler(sampler) + .AddSampledImages(temp1) + .AddStorageImages(temp2) + .Build(device); + LsfgDescriptorWriter(descriptor_sets[1]) + .AddSampler(sampler) + .AddSampledImages(temp2) + .AddStorageImages(temp1) + .Build(device); + LsfgDescriptorWriter(descriptor_sets[2]) + .AddSampler(sampler) + .AddSampledImages(temp1) + .AddStorageImages(temp2) + .Build(device); + LsfgDescriptorWriter(descriptor_sets[3]) + .AddUniformBuffer(resources.GetBuffer(LSFG_TIMESTAMP), LsfgResources::BufferSize()) + .AddSampler(sampler) + .AddSampledImages(temp2) + .AddStorageImages(out_images) + .Build(device); +} + +void LsfgBeta::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) { + const VkExtent2D extent = temp1[0].Extent(); + const u32 groups_x = GroupCount(extent.width, DISPATCH_TILE_SHIFT); + const u32 groups_y = GroupCount(extent.height, DISPATCH_TILE_SHIFT); + + LsfgBarriers barriers(cmdbuf); + for (auto& slot : *inputs) { + barriers.WriteToReadAll(slot); + } + barriers.ReadToWriteAll(temp1).Build(); + + passes[0].Bind(cmdbuf, first_descriptor_sets[frame_count % LSFG_HISTORY_SLOTS]); + cmdbuf.Dispatch(groups_x, groups_y, 1); + + LsfgBarriers(cmdbuf).WriteToReadAll(temp1).ReadToWriteAll(temp2).Build(); + passes[1].Bind(cmdbuf, descriptor_sets[0]); + cmdbuf.Dispatch(groups_x, groups_y, 1); + + LsfgBarriers(cmdbuf).WriteToReadAll(temp2).ReadToWriteAll(temp1).Build(); + passes[2].Bind(cmdbuf, descriptor_sets[1]); + cmdbuf.Dispatch(groups_x, groups_y, 1); + + LsfgBarriers(cmdbuf).WriteToReadAll(temp1).ReadToWriteAll(temp2).Build(); + passes[3].Bind(cmdbuf, descriptor_sets[2]); + cmdbuf.Dispatch(groups_x, groups_y, 1); + + LsfgBarriers(cmdbuf).WriteToReadAll(temp2).ReadToWriteAll(out_images).Build(); + passes[4].Bind(cmdbuf, descriptor_sets[3]); + cmdbuf.Dispatch(GroupCount(extent.width, OUTPUT_TILE_SHIFT), + GroupCount(extent.height, OUTPUT_TILE_SHIFT), 1); +} + +} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/present/lsfg_beta.h b/src/video_core/renderer_vulkan/present/lsfg_beta.h new file mode 100644 index 0000000000..097cc6a342 --- /dev/null +++ b/src/video_core/renderer_vulkan/present/lsfg_beta.h @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +#include "common/common_types.h" +#include "video_core/renderer_vulkan/present/lsfg_common.h" + +namespace Vulkan { + +class Device; +class LsfgShaders; + +constexpr size_t LSFG_BETA_STAGES = 5; +constexpr size_t LSFG_BETA_OUTPUTS = 6; + +class LsfgBeta { +public: + LsfgBeta() = default; + LsfgBeta(const Device& device, MemoryAllocator& memory_allocator, const LsfgShaders& shaders, + LsfgResources& resources, vk::DescriptorPool& descriptor_pool, + LsfgImageHistory& inputs); + + void Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count); + + [[nodiscard]] LsfgImage& Output(size_t level) { + return out_images[level]; + } + +private: + LsfgImageHistory* inputs{}; + + std::array passes; + std::array first_descriptor_sets{}; + std::array descriptor_sets{}; + vk::DescriptorSets owned_sets; + + LsfgImagePair temp1; + LsfgImagePair temp2; + std::array out_images; +}; + +} // namespace Vulkan