diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index b687c95115..d3d52a7cb9 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -127,6 +127,10 @@ add_library(video_core STATIC renderer_vulkan/present/filters.h renderer_vulkan/present/frame_gen.cpp renderer_vulkan/present/frame_gen.h + renderer_vulkan/present/lsfg_alpha.cpp + renderer_vulkan/present/lsfg_alpha.h + renderer_vulkan/present/lsfg_common.cpp + renderer_vulkan/present/lsfg_common.h renderer_vulkan/present/lsfg_mipmaps.cpp renderer_vulkan/present/lsfg_mipmaps.h renderer_vulkan/present/lsfg_shaders.cpp diff --git a/src/video_core/renderer_vulkan/present/frame_gen.cpp b/src/video_core/renderer_vulkan/present/frame_gen.cpp index 92737017e1..0386c5687a 100644 --- a/src/video_core/renderer_vulkan/present/frame_gen.cpp +++ b/src/video_core/renderer_vulkan/present/frame_gen.cpp @@ -63,7 +63,7 @@ void FrameGen::Process(const Device& device, Frame* frame) { Rebuild(device, extent); } - mipmaps->Dispatch(device, scheduler, *frame->image_view, frame_count); + mipmaps->Dispatch(device, scheduler, *frame->image, *frame->image_view, frame_count); ++frame_count; const bool dump_requested = Settings::values.frame_gen_dump_flow.GetValue(); diff --git a/src/video_core/renderer_vulkan/present/lsfg_alpha.cpp b/src/video_core/renderer_vulkan/present/lsfg_alpha.cpp new file mode 100644 index 0000000000..b309441514 --- /dev/null +++ b/src/video_core/renderer_vulkan/present/lsfg_alpha.cpp @@ -0,0 +1,133 @@ +// 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_alpha.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; + +[[nodiscard]] u32 GroupCount(u32 size) { + return (size + (1u << DISPATCH_TILE_SHIFT) - 1) >> DISPATCH_TILE_SHIFT; +} + +[[nodiscard]] VkExtent2D HalveExtent(VkExtent2D extent) { + return VkExtent2D{ + .width = (extent.width + 1) >> 1, + .height = (extent.height + 1) >> 1, + }; +} + +} // Anonymous namespace + +LsfgAlpha::LsfgAlpha(const Device& device, MemoryAllocator& memory_allocator, + const LsfgShaders& shaders, vk::DescriptorPool& descriptor_pool, + vk::Sampler& sampler, const LsfgImage& input_) + : input{&input_} { + using namespace VideoCore::FrameGen::PerformanceShader; + + passes[0] = LsfgPass(device, shaders, ALPHA[0], + {{1, VK_DESCRIPTOR_TYPE_SAMPLER}, + {1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE}, + {1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}}); + passes[1] = LsfgPass(device, shaders, ALPHA[1], + {{1, VK_DESCRIPTOR_TYPE_SAMPLER}, + {1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE}, + {1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}}); + passes[2] = LsfgPass(device, shaders, ALPHA[2], + {{1, VK_DESCRIPTOR_TYPE_SAMPLER}, + {1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE}, + {2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}}); + passes[3] = LsfgPass(device, shaders, ALPHA[3], + {{1, VK_DESCRIPTOR_TYPE_SAMPLER}, + {2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE}, + {2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}}); + + const VkExtent2D half_extent = HalveExtent(input->Extent()); + const VkExtent2D quarter_extent = HalveExtent(half_extent); + + temp1 = LsfgImage(device, memory_allocator, half_extent); + temp2 = LsfgImage(device, memory_allocator, half_extent); + for (size_t i = 0; i < LSFG_ALPHA_OUTPUTS; ++i) { + temp3[i] = LsfgImage(device, memory_allocator, quarter_extent); + for (size_t j = 0; j < LSFG_ALPHA_HISTORY; ++j) { + out_images[j][i] = LsfgImage(device, memory_allocator, quarter_extent); + } + } + + std::vector layouts; + for (size_t i = 0; i < LSFG_ALPHA_STAGES - 1; ++i) { + layouts.push_back(passes[i].SetLayout()); + } + for (size_t i = 0; i < LSFG_ALPHA_HISTORY; ++i) { + layouts.push_back(passes[3].SetLayout()); + } + owned_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts); + + for (size_t i = 0; i < LSFG_ALPHA_STAGES - 1; ++i) { + descriptor_sets[i] = owned_sets[i]; + } + for (size_t i = 0; i < LSFG_ALPHA_HISTORY; ++i) { + last_descriptor_sets[i] = owned_sets[LSFG_ALPHA_STAGES - 1 + i]; + } + + LsfgDescriptorWriter(descriptor_sets[0]) + .AddSampler(*sampler) + .AddSampledImage(*input) + .AddStorageImage(temp1) + .Build(device); + LsfgDescriptorWriter(descriptor_sets[1]) + .AddSampler(*sampler) + .AddSampledImage(temp1) + .AddStorageImage(temp2) + .Build(device); + LsfgDescriptorWriter(descriptor_sets[2]) + .AddSampler(*sampler) + .AddSampledImage(temp2) + .AddStorageImages(temp3) + .Build(device); + for (size_t i = 0; i < LSFG_ALPHA_HISTORY; ++i) { + LsfgDescriptorWriter(last_descriptor_sets[i]) + .AddSampler(*sampler) + .AddSampledImages(temp3) + .AddStorageImages(out_images[i]) + .Build(device); + } +} + +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); + + LsfgBarriers(cmdbuf).ReadToWrite(temp1).Build(); + passes[0].Bind(cmdbuf, descriptor_sets[0]); + cmdbuf.Dispatch(groups_x, groups_y, 1); + + 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_ALPHA_HISTORY; + LsfgBarriers(cmdbuf).WriteToReadAll(temp3).ReadToWriteAll(out_images[slot]).Build(); + passes[3].Bind(cmdbuf, last_descriptor_sets[slot]); + cmdbuf.Dispatch(groups_x, groups_y, 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 new file mode 100644 index 0000000000..4505e5d332 --- /dev/null +++ b/src/video_core/renderer_vulkan/present/lsfg_alpha.h @@ -0,0 +1,53 @@ +// 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; +class Scheduler; + +constexpr size_t LSFG_ALPHA_STAGES = 4; +constexpr size_t LSFG_ALPHA_HISTORY = 3; +constexpr size_t LSFG_ALPHA_OUTPUTS = 2; + +using LsfgAlphaOutputs = std::array; + +class LsfgAlpha { +public: + LsfgAlpha() = default; + LsfgAlpha(const Device& device, MemoryAllocator& memory_allocator, const LsfgShaders& shaders, + vk::DescriptorPool& descriptor_pool, vk::Sampler& sampler, const LsfgImage& input); + + void Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count); + + [[nodiscard]] const LsfgAlphaOutputs& GetOutputs(u64 frame_count) const { + return out_images[frame_count % LSFG_ALPHA_HISTORY]; + } + + [[nodiscard]] const std::array& GetAllOutputs() const { + return out_images; + } + +private: + const LsfgImage* input{}; + + std::array passes; + std::array descriptor_sets{}; + std::array last_descriptor_sets{}; + vk::DescriptorSets owned_sets; + + LsfgImage temp1; + LsfgImage temp2; + std::array temp3; + std::array out_images; +}; + +} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/present/lsfg_common.cpp b/src/video_core/renderer_vulkan/present/lsfg_common.cpp new file mode 100644 index 0000000000..775a48c691 --- /dev/null +++ b/src/video_core/renderer_vulkan/present/lsfg_common.cpp @@ -0,0 +1,187 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include + +#include "video_core/renderer_vulkan/present/lsfg_common.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 DESCRIPTORS_PER_TYPE = 4096; + +VkImageMemoryBarrier MakeBarrier(const LsfgImage& image, VkAccessFlags src_access, + VkAccessFlags dst_access) { + return VkImageMemoryBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = src_access, + .dstAccessMask = dst_access, + .oldLayout = image.Layout(), + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = image.Handle(), + .subresourceRange{ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; +} + +} // Anonymous namespace + +LsfgImage::LsfgImage(const Device& device, MemoryAllocator& memory_allocator, VkExtent2D extent_, + VkFormat format) + : extent{std::max(1u, extent_.width), std::max(1u, extent_.height)} { + image = CreateWrappedImage(memory_allocator, extent, format); + view = CreateWrappedImageView(device, image, format); +} + +LsfgBarriers& LsfgBarriers::Push(LsfgImage& image, VkAccessFlags src_access, + VkAccessFlags dst_access) { + barriers.push_back(MakeBarrier(image, src_access, dst_access)); + image.SetLayout(VK_IMAGE_LAYOUT_GENERAL); + return *this; +} + +LsfgBarriers& LsfgBarriers::WriteToRead(LsfgImage& image) { + return Push(image, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); +} + +LsfgBarriers& LsfgBarriers::ReadToWrite(LsfgImage& image) { + return Push(image, VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_SHADER_WRITE_BIT); +} + +void LsfgBarriers::Build() { + if (barriers.empty()) { + return; + } + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, {}, {}, barriers); + barriers.clear(); +} + +LsfgDescriptorWriter& LsfgDescriptorWriter::PushImage(VkDescriptorType type, VkSampler sampler, + VkImageView view) { + image_infos.push_back(VkDescriptorImageInfo{ + .sampler = sampler, + .imageView = view, + .imageLayout = view == VK_NULL_HANDLE ? VK_IMAGE_LAYOUT_UNDEFINED + : VK_IMAGE_LAYOUT_GENERAL, + }); + writes.push_back(VkWriteDescriptorSet{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = set, + .dstBinding = binding++, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = type, + .pImageInfo = &image_infos.back(), + .pBufferInfo = nullptr, + .pTexelBufferView = nullptr, + }); + return *this; +} + +LsfgDescriptorWriter& LsfgDescriptorWriter::AddSampler(VkSampler sampler) { + return PushImage(VK_DESCRIPTOR_TYPE_SAMPLER, sampler, VK_NULL_HANDLE); +} + +LsfgDescriptorWriter& LsfgDescriptorWriter::AddSampledImage(const LsfgImage& image) { + return PushImage(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_NULL_HANDLE, image.View()); +} + +LsfgDescriptorWriter& LsfgDescriptorWriter::AddStorageImage(const LsfgImage& image) { + return PushImage(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_NULL_HANDLE, image.View()); +} + +LsfgDescriptorWriter& LsfgDescriptorWriter::AddUniformBuffer(VkBuffer buffer, VkDeviceSize size) { + buffer_infos.push_back(VkDescriptorBufferInfo{ + .buffer = buffer, + .offset = 0, + .range = size, + }); + writes.push_back(VkWriteDescriptorSet{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = set, + .dstBinding = binding++, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .pImageInfo = nullptr, + .pBufferInfo = &buffer_infos.back(), + .pTexelBufferView = nullptr, + }); + return *this; +} + +void LsfgDescriptorWriter::Build(const Device& device) { + if (writes.empty()) { + return; + } + device.GetLogical().UpdateDescriptorSets(writes, {}); + writes.clear(); +} + +LsfgPass::LsfgPass(const Device& device, const LsfgShaders& shaders, u32 shader_id, + LsfgBindings bindings) { + std::vector types; + for (const auto& [count, type] : bindings) { + types.insert(types.end(), count, type); + } + descriptor_count = static_cast(types.size()); + + descriptor_set_layout = CreateWrappedDescriptorSetLayout( + device, std::span{types}, VK_SHADER_STAGE_COMPUTE_BIT); + pipeline_layout = CreateWrappedPipelineLayout(device, descriptor_set_layout); + pipeline = CreateWrappedComputePipeline(device, pipeline_layout, shaders.Get(shader_id)); +} + +void LsfgPass::Bind(vk::CommandBuffer cmdbuf, VkDescriptorSet set) const { + cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline); + cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline_layout, 0, set, {}); +} + +vk::DescriptorPool CreateLsfgDescriptorPool(const Device& device, u32 max_sets) { + return CreateWrappedDescriptorPool( + device, DESCRIPTORS_PER_TYPE, max_sets, + {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_SAMPLER, + VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}); +} + +vk::Sampler CreateLsfgSampler(const Device& device, VkSamplerAddressMode address_mode, + VkCompareOp compare_op, bool white_border) { + return device.GetLogical().CreateSampler(VkSamplerCreateInfo{ + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .magFilter = VK_FILTER_LINEAR, + .minFilter = VK_FILTER_LINEAR, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, + .addressModeU = address_mode, + .addressModeV = address_mode, + .addressModeW = address_mode, + .mipLodBias = 0.0f, + .anisotropyEnable = VK_FALSE, + .maxAnisotropy = 0.0f, + .compareEnable = VK_FALSE, + .compareOp = compare_op, + .minLod = 0.0f, + .maxLod = VK_LOD_CLAMP_NONE, + .borderColor = white_border ? VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE + : VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, + .unnormalizedCoordinates = VK_FALSE, + }); +} + +} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/present/lsfg_common.h b/src/video_core/renderer_vulkan/present/lsfg_common.h new file mode 100644 index 0000000000..30c489eb82 --- /dev/null +++ b/src/video_core/renderer_vulkan/present/lsfg_common.h @@ -0,0 +1,154 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include +#include + +#include "common/common_types.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" + +namespace Vulkan { + +class Device; +class LsfgShaders; + +constexpr VkFormat LSFG_DEFAULT_FORMAT = VK_FORMAT_R8G8B8A8_UNORM; + +class LsfgImage { +public: + LsfgImage() = default; + LsfgImage(const Device& device, MemoryAllocator& memory_allocator, VkExtent2D extent_, + VkFormat format = LSFG_DEFAULT_FORMAT); + + [[nodiscard]] VkImage Handle() const { + return *image; + } + + [[nodiscard]] VkImageView View() const { + return *view; + } + + [[nodiscard]] VkExtent2D Extent() const { + return extent; + } + + [[nodiscard]] VkImageLayout Layout() const { + return layout; + } + + void SetLayout(VkImageLayout new_layout) { + layout = new_layout; + } + +private: + vk::Image image; + vk::ImageView view; + VkExtent2D extent{}; + VkImageLayout layout{VK_IMAGE_LAYOUT_UNDEFINED}; +}; + +class LsfgBarriers { +public: + explicit LsfgBarriers(vk::CommandBuffer cmdbuf_) : cmdbuf{cmdbuf_} {} + + LsfgBarriers& WriteToRead(LsfgImage& image); + LsfgBarriers& ReadToWrite(LsfgImage& image); + + template + LsfgBarriers& WriteToReadAll(Range& images) { + for (auto& image : images) { + WriteToRead(image); + } + return *this; + } + + template + LsfgBarriers& ReadToWriteAll(Range& images) { + for (auto& image : images) { + ReadToWrite(image); + } + return *this; + } + + void Build(); + +private: + LsfgBarriers& Push(LsfgImage& image, VkAccessFlags src_access, VkAccessFlags dst_access); + + vk::CommandBuffer cmdbuf; + std::vector barriers; +}; + +class LsfgDescriptorWriter { +public: + explicit LsfgDescriptorWriter(VkDescriptorSet set_) : set{set_} {} + + LsfgDescriptorWriter& AddSampler(VkSampler sampler); + LsfgDescriptorWriter& AddSampledImage(const LsfgImage& image); + LsfgDescriptorWriter& AddStorageImage(const LsfgImage& image); + LsfgDescriptorWriter& AddUniformBuffer(VkBuffer buffer, VkDeviceSize size); + + template + LsfgDescriptorWriter& AddSampledImages(const Range& images) { + for (const auto& image : images) { + AddSampledImage(image); + } + return *this; + } + + template + LsfgDescriptorWriter& AddStorageImages(const Range& images) { + for (const auto& image : images) { + AddStorageImage(image); + } + return *this; + } + + void Build(const Device& device); + +private: + LsfgDescriptorWriter& PushImage(VkDescriptorType type, VkSampler sampler, VkImageView view); + + VkDescriptorSet set; + u32 binding{}; + std::deque image_infos; + std::deque buffer_infos; + std::vector writes; +}; + +using LsfgBindings = std::initializer_list>; + +class LsfgPass { +public: + LsfgPass() = default; + LsfgPass(const Device& device, const LsfgShaders& shaders, u32 shader_id, + LsfgBindings bindings); + + [[nodiscard]] VkDescriptorSetLayout SetLayout() const { + return *descriptor_set_layout; + } + + [[nodiscard]] u32 DescriptorCount() const { + return descriptor_count; + } + + void Bind(vk::CommandBuffer cmdbuf, VkDescriptorSet set) const; + +private: + vk::DescriptorSetLayout descriptor_set_layout; + vk::PipelineLayout pipeline_layout; + vk::Pipeline pipeline; + u32 descriptor_count{}; +}; + +[[nodiscard]] vk::DescriptorPool CreateLsfgDescriptorPool(const Device& device, u32 max_sets); + +[[nodiscard]] vk::Sampler CreateLsfgSampler(const Device& device, VkSamplerAddressMode address_mode, + VkCompareOp compare_op, bool white_border); + +} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/present/lsfg_mipmaps.cpp b/src/video_core/renderer_vulkan/present/lsfg_mipmaps.cpp index 9388fa574c..230f4a3d5c 100644 --- a/src/video_core/renderer_vulkan/present/lsfg_mipmaps.cpp +++ b/src/video_core/renderer_vulkan/present/lsfg_mipmaps.cpp @@ -128,8 +128,8 @@ void LsfgMipmaps::CreateUniformBuffer(f32 flow_scale) { uniform_buffer.Flush(); } -void LsfgMipmaps::Dispatch(const Device& device, Scheduler& scheduler, VkImageView current_view, - u64 frame_count) { +void LsfgMipmaps::Dispatch(const Device& device, Scheduler& scheduler, VkImage current_image, + VkImageView current_view, u64 frame_count) { const size_t set_index = frame_count % DESCRIPTOR_SET_COUNT; const VkDescriptorSet set = descriptor_sets[set_index]; @@ -196,8 +196,30 @@ void LsfgMipmaps::Dispatch(const Device& device, Scheduler& scheduler, VkImageVi } scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([raw_images, set, groups_x, groups_y, layout = *pipeline_layout, + scheduler.Record([raw_images, current_image, set, groups_x, groups_y, + layout = *pipeline_layout, compute_pipeline = *pipeline](vk::CommandBuffer cmdbuf) { + const VkImageMemoryBarrier input_barrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_GENERAL, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = current_image, + .subresourceRange{ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, {}, {}, input_barrier); + for (const VkImage image : raw_images) { TransitionImageLayout(cmdbuf, image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_UNDEFINED); diff --git a/src/video_core/renderer_vulkan/present/lsfg_mipmaps.h b/src/video_core/renderer_vulkan/present/lsfg_mipmaps.h index a43adff44e..955d61e552 100644 --- a/src/video_core/renderer_vulkan/present/lsfg_mipmaps.h +++ b/src/video_core/renderer_vulkan/present/lsfg_mipmaps.h @@ -22,8 +22,8 @@ public: explicit LsfgMipmaps(const Device& device, MemoryAllocator& memory_allocator, const LsfgShaders& shaders, VkExtent2D input_extent, f32 flow_scale); - void Dispatch(const Device& device, Scheduler& scheduler, VkImageView current_view, - u64 frame_count); + void Dispatch(const Device& device, Scheduler& scheduler, VkImage current_image, + VkImageView current_view, u64 frame_count); [[nodiscard]] VkImageView GetLevelView(size_t level) const { return *image_views[level];