// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/common_types.h" #include "video_core/host_shaders/fxaa_frag_spv.h" #include "video_core/host_shaders/fxaa_vert_spv.h" #include "video_core/renderer_vulkan/present/fxaa.h" #include "video_core/renderer_vulkan/present/util.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_shader_util.h" #include "video_core/vulkan_common/vulkan_device.h" namespace Vulkan { FXAA::FXAA(const Device& device, MemoryAllocator& allocator, size_t image_count, VkExtent2D extent) : m_device(device), m_allocator(allocator), m_extent(extent), m_image_count(static_cast(image_count)) { CreateImages(); CreateRenderPasses(); CreateSampler(); CreateShaders(); CreateDescriptorPool(); CreateDescriptorSetLayouts(); CreateDescriptorSets(); CreatePipelineLayouts(); CreatePipelines(); } FXAA::~FXAA() = default; void FXAA::CreateImages() { for (u32 i = 0; i < m_image_count; i++) { Image& image = m_dynamic_images.emplace_back(); image.image = CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT); image.image_view = CreateWrappedImageView(m_device, image.image, VK_FORMAT_R16G16B16A16_SFLOAT); } } void FXAA::CreateRenderPasses() { m_renderpass = CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16B16A16_SFLOAT); for (auto& image : m_dynamic_images) { image.framebuffer = CreateWrappedFramebuffer(m_device, m_renderpass, image.image_view, m_extent); } } void FXAA::CreateSampler() { m_sampler = CreateWrappedSampler(m_device); } void FXAA::CreateShaders() { m_vertex_shader = CreateWrappedShaderModule(m_device, FXAA_VERT_SPV); m_fragment_shader = CreateWrappedShaderModule(m_device, FXAA_FRAG_SPV); } void FXAA::CreateDescriptorPool() { // 2 descriptors, 1 descriptor set per image m_descriptor_pool = CreateWrappedDescriptorPool(m_device, 2 * m_image_count, m_image_count); } void FXAA::CreateDescriptorSetLayouts() { m_descriptor_set_layout = CreateWrappedDescriptorSetLayout(m_device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER}); } void FXAA::CreateDescriptorSets() { VkDescriptorSetLayout layout = *m_descriptor_set_layout; for (auto& images : m_dynamic_images) { images.descriptor_sets = CreateWrappedDescriptorSets(m_descriptor_pool, {layout}); } } void FXAA::CreatePipelineLayouts() { m_pipeline_layout = CreateWrappedPipelineLayout(m_device, m_descriptor_set_layout); } void FXAA::CreatePipelines() { m_pipeline = CreateWrappedPipeline(m_device, m_renderpass, m_pipeline_layout, std::tie(m_vertex_shader, m_fragment_shader)); } void FXAA::UpdateDescriptorSets(VkImageView image_view, size_t image_index) { Image& image = m_dynamic_images[image_index]; std::vector image_infos; std::vector updates; image_infos.reserve(2); updates.push_back( CreateWriteDescriptorSet(image_infos, *m_sampler, image_view, image.descriptor_sets[0], 0)); updates.push_back( CreateWriteDescriptorSet(image_infos, *m_sampler, image_view, image.descriptor_sets[0], 1)); m_device.GetLogical().UpdateDescriptorSets(updates, {}); } void FXAA::UploadImages(Scheduler& scheduler) { if (m_images_ready) { return; } scheduler.Record([&](vk::CommandBuffer cmdbuf) { for (auto& image : m_dynamic_images) { ClearColorImage(cmdbuf, *image.image); } }); scheduler.Finish(); m_images_ready = true; } void FXAA::Draw(Scheduler& scheduler, size_t image_index, VkImage* inout_image, VkImageView* inout_image_view) { const Image& image{m_dynamic_images[image_index]}; const VkImage input_image{*inout_image}; const VkImage output_image{*image.image}; const VkDescriptorSet descriptor_set{image.descriptor_sets[0]}; const VkFramebuffer framebuffer{*image.framebuffer}; const VkRenderPass renderpass{*m_renderpass}; const VkPipeline pipeline{*m_pipeline}; const VkPipelineLayout layout{*m_pipeline_layout}; const VkExtent2D extent{m_extent}; UploadImages(scheduler); UpdateDescriptorSets(*inout_image_view, image_index); scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([=](vk::CommandBuffer cmdbuf) { TransitionImageLayout(cmdbuf, input_image, VK_IMAGE_LAYOUT_GENERAL); TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL); BeginRenderPass(cmdbuf, renderpass, framebuffer, extent); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, {}); cmdbuf.Draw(3, 1, 0, 0); cmdbuf.EndRenderPass(); TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL); }); *inout_image = *image.image; *inout_image_view = *image.image_view; } } // namespace Vulkan