summaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/CMakeLists.txt12
-rw-r--r--src/video_core/renderer_vulkan/present/anti_alias_pass.h27
-rw-r--r--src/video_core/renderer_vulkan/present/fsr.cpp (renamed from src/video_core/renderer_vulkan/vk_fsr.cpp)2
-rw-r--r--src/video_core/renderer_vulkan/present/fsr.h (renamed from src/video_core/renderer_vulkan/vk_fsr.h)0
-rw-r--r--src/video_core/renderer_vulkan/present/fxaa.cpp144
-rw-r--r--src/video_core/renderer_vulkan/present/fxaa.h63
-rw-r--r--src/video_core/renderer_vulkan/present/smaa.cpp270
-rw-r--r--src/video_core/renderer_vulkan/present/smaa.h (renamed from src/video_core/renderer_vulkan/vk_smaa.h)7
-rw-r--r--src/video_core/renderer_vulkan/present/util.cpp (renamed from src/video_core/renderer_vulkan/vk_smaa.cpp)282
-rw-r--r--src/video_core/renderer_vulkan/present/util.h46
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp372
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h16
12 files changed, 590 insertions, 651 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index c158970f2..240b80c6e 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -158,6 +158,14 @@ add_library(video_core STATIC
158 renderer_opengl/renderer_opengl.h 158 renderer_opengl/renderer_opengl.h
159 renderer_opengl/util_shaders.cpp 159 renderer_opengl/util_shaders.cpp
160 renderer_opengl/util_shaders.h 160 renderer_opengl/util_shaders.h
161 renderer_vulkan/present/fsr.cpp
162 renderer_vulkan/present/fsr.h
163 renderer_vulkan/present/fxaa.cpp
164 renderer_vulkan/present/fxaa.h
165 renderer_vulkan/present/smaa.cpp
166 renderer_vulkan/present/smaa.h
167 renderer_vulkan/present/util.cpp
168 renderer_vulkan/present/util.h
161 renderer_vulkan/blit_image.cpp 169 renderer_vulkan/blit_image.cpp
162 renderer_vulkan/blit_image.h 170 renderer_vulkan/blit_image.h
163 renderer_vulkan/fixed_pipeline_state.cpp 171 renderer_vulkan/fixed_pipeline_state.cpp
@@ -184,8 +192,6 @@ add_library(video_core STATIC
184 renderer_vulkan/vk_descriptor_pool.h 192 renderer_vulkan/vk_descriptor_pool.h
185 renderer_vulkan/vk_fence_manager.cpp 193 renderer_vulkan/vk_fence_manager.cpp
186 renderer_vulkan/vk_fence_manager.h 194 renderer_vulkan/vk_fence_manager.h
187 renderer_vulkan/vk_fsr.cpp
188 renderer_vulkan/vk_fsr.h
189 renderer_vulkan/vk_graphics_pipeline.cpp 195 renderer_vulkan/vk_graphics_pipeline.cpp
190 renderer_vulkan/vk_graphics_pipeline.h 196 renderer_vulkan/vk_graphics_pipeline.h
191 renderer_vulkan/vk_master_semaphore.cpp 197 renderer_vulkan/vk_master_semaphore.cpp
@@ -206,8 +212,6 @@ add_library(video_core STATIC
206 renderer_vulkan/vk_scheduler.h 212 renderer_vulkan/vk_scheduler.h
207 renderer_vulkan/vk_shader_util.cpp 213 renderer_vulkan/vk_shader_util.cpp
208 renderer_vulkan/vk_shader_util.h 214 renderer_vulkan/vk_shader_util.h
209 renderer_vulkan/vk_smaa.cpp
210 renderer_vulkan/vk_smaa.h
211 renderer_vulkan/vk_staging_buffer_pool.cpp 215 renderer_vulkan/vk_staging_buffer_pool.cpp
212 renderer_vulkan/vk_staging_buffer_pool.h 216 renderer_vulkan/vk_staging_buffer_pool.h
213 renderer_vulkan/vk_state_tracker.cpp 217 renderer_vulkan/vk_state_tracker.cpp
diff --git a/src/video_core/renderer_vulkan/present/anti_alias_pass.h b/src/video_core/renderer_vulkan/present/anti_alias_pass.h
new file mode 100644
index 000000000..c1ec0b9a0
--- /dev/null
+++ b/src/video_core/renderer_vulkan/present/anti_alias_pass.h
@@ -0,0 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "video_core/vulkan_common/vulkan_wrapper.h"
7
8namespace Vulkan {
9
10class Scheduler;
11
12class AntiAliasPass {
13public:
14 virtual ~AntiAliasPass() = default;
15 virtual VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImage source_image,
16 VkImageView source_image_view) = 0;
17};
18
19class NoAA final : public AntiAliasPass {
20public:
21 virtual VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImage source_image,
22 VkImageView source_image_view) {
23 return source_image_view;
24 }
25};
26
27} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_fsr.cpp b/src/video_core/renderer_vulkan/present/fsr.cpp
index f7a05fbc0..30a16a785 100644
--- a/src/video_core/renderer_vulkan/vk_fsr.cpp
+++ b/src/video_core/renderer_vulkan/present/fsr.cpp
@@ -10,7 +10,7 @@
10#include "video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp32_comp_spv.h" 10#include "video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp32_comp_spv.h"
11#include "video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp16_comp_spv.h" 11#include "video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp16_comp_spv.h"
12#include "video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp32_comp_spv.h" 12#include "video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp32_comp_spv.h"
13#include "video_core/renderer_vulkan/vk_fsr.h" 13#include "video_core/renderer_vulkan/present/fsr.h"
14#include "video_core/renderer_vulkan/vk_scheduler.h" 14#include "video_core/renderer_vulkan/vk_scheduler.h"
15#include "video_core/renderer_vulkan/vk_shader_util.h" 15#include "video_core/renderer_vulkan/vk_shader_util.h"
16#include "video_core/vulkan_common/vulkan_device.h" 16#include "video_core/vulkan_common/vulkan_device.h"
diff --git a/src/video_core/renderer_vulkan/vk_fsr.h b/src/video_core/renderer_vulkan/present/fsr.h
index 3505c1416..3505c1416 100644
--- a/src/video_core/renderer_vulkan/vk_fsr.h
+++ b/src/video_core/renderer_vulkan/present/fsr.h
diff --git a/src/video_core/renderer_vulkan/present/fxaa.cpp b/src/video_core/renderer_vulkan/present/fxaa.cpp
new file mode 100644
index 000000000..6f87ddebb
--- /dev/null
+++ b/src/video_core/renderer_vulkan/present/fxaa.cpp
@@ -0,0 +1,144 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/common_types.h"
5
6#include "video_core/host_shaders/fxaa_frag_spv.h"
7#include "video_core/host_shaders/fxaa_vert_spv.h"
8#include "video_core/renderer_vulkan/present/fxaa.h"
9#include "video_core/renderer_vulkan/present/util.h"
10#include "video_core/renderer_vulkan/vk_scheduler.h"
11#include "video_core/renderer_vulkan/vk_shader_util.h"
12#include "video_core/vulkan_common/vulkan_device.h"
13
14namespace Vulkan {
15
16FXAA::FXAA(const Device& device, MemoryAllocator& allocator, size_t image_count, VkExtent2D extent)
17 : m_device(device), m_allocator(allocator), m_extent(extent),
18 m_image_count(static_cast<u32>(image_count)) {
19 CreateImages();
20 CreateRenderPasses();
21 CreateSampler();
22 CreateShaders();
23 CreateDescriptorPool();
24 CreateDescriptorSetLayouts();
25 CreateDescriptorSets();
26 CreatePipelineLayouts();
27 CreatePipelines();
28}
29
30FXAA::~FXAA() = default;
31
32void FXAA::CreateImages() {
33 for (u32 i = 0; i < m_image_count; i++) {
34 Image& image = m_dynamic_images.emplace_back();
35
36 image.image = CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
37 image.image_view =
38 CreateWrappedImageView(m_device, image.image, VK_FORMAT_R16G16B16A16_SFLOAT);
39 }
40}
41
42void FXAA::CreateRenderPasses() {
43 m_renderpass = CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16B16A16_SFLOAT);
44
45 for (auto& image : m_dynamic_images) {
46 image.framebuffer =
47 CreateWrappedFramebuffer(m_device, m_renderpass, image.image_view, m_extent);
48 }
49}
50
51void FXAA::CreateSampler() {
52 m_sampler = CreateWrappedSampler(m_device);
53}
54
55void FXAA::CreateShaders() {
56 m_vertex_shader = CreateWrappedShaderModule(m_device, FXAA_VERT_SPV);
57 m_fragment_shader = CreateWrappedShaderModule(m_device, FXAA_FRAG_SPV);
58}
59
60void FXAA::CreateDescriptorPool() {
61 // 2 descriptors, 1 descriptor set per image
62 m_descriptor_pool = CreateWrappedDescriptorPool(m_device, 2 * m_image_count, m_image_count);
63}
64
65void FXAA::CreateDescriptorSetLayouts() {
66 m_descriptor_set_layout = CreateWrappedDescriptorSetLayout(m_device, 2);
67}
68
69void FXAA::CreateDescriptorSets() {
70 VkDescriptorSetLayout layout = *m_descriptor_set_layout;
71
72 for (auto& images : m_dynamic_images) {
73 images.descriptor_sets = CreateWrappedDescriptorSets(m_descriptor_pool, {layout});
74 }
75}
76
77void FXAA::CreatePipelineLayouts() {
78 m_pipeline_layout = CreateWrappedPipelineLayout(m_device, m_descriptor_set_layout);
79}
80
81void FXAA::CreatePipelines() {
82 m_pipeline = CreateWrappedPipeline(m_device, m_renderpass, m_pipeline_layout,
83 std::tie(m_vertex_shader, m_fragment_shader));
84}
85
86void FXAA::UpdateDescriptorSets(VkImageView image_view, size_t image_index) {
87 Image& image = m_dynamic_images[image_index];
88 std::vector<VkDescriptorImageInfo> image_infos;
89 std::vector<VkWriteDescriptorSet> updates;
90 image_infos.reserve(2);
91
92 updates.push_back(
93 CreateWriteDescriptorSet(image_infos, *m_sampler, image_view, image.descriptor_sets[0], 0));
94 updates.push_back(
95 CreateWriteDescriptorSet(image_infos, *m_sampler, image_view, image.descriptor_sets[0], 1));
96
97 m_device.GetLogical().UpdateDescriptorSets(updates, {});
98}
99
100void FXAA::UploadImages(Scheduler& scheduler) {
101 if (m_images_ready) {
102 return;
103 }
104
105 scheduler.Record([&](vk::CommandBuffer cmdbuf) {
106 for (auto& image : m_dynamic_images) {
107 ClearColorImage(cmdbuf, *image.image);
108 }
109 });
110 scheduler.Finish();
111
112 m_images_ready = true;
113}
114
115VkImageView FXAA::Draw(Scheduler& scheduler, size_t image_index, VkImage source_image,
116 VkImageView source_image_view) {
117 const Image& image{m_dynamic_images[image_index]};
118 const VkImage output_image{*image.image};
119 const VkDescriptorSet descriptor_set{image.descriptor_sets[0]};
120 const VkFramebuffer framebuffer{*image.framebuffer};
121 const VkRenderPass renderpass{*m_renderpass};
122 const VkPipeline pipeline{*m_pipeline};
123 const VkPipelineLayout layout{*m_pipeline_layout};
124 const VkExtent2D extent{m_extent};
125
126 UploadImages(scheduler);
127 UpdateDescriptorSets(source_image_view, image_index);
128
129 scheduler.RequestOutsideRenderPassOperationContext();
130 scheduler.Record([=](vk::CommandBuffer cmdbuf) {
131 TransitionImageLayout(cmdbuf, source_image, VK_IMAGE_LAYOUT_GENERAL);
132 TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL);
133 BeginRenderPass(cmdbuf, renderpass, framebuffer, extent);
134 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
135 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, {});
136 cmdbuf.Draw(4, 1, 0, 0);
137 cmdbuf.EndRenderPass();
138 TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL);
139 });
140
141 return *image.image_view;
142}
143
144} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/present/fxaa.h b/src/video_core/renderer_vulkan/present/fxaa.h
new file mode 100644
index 000000000..c083f3ff0
--- /dev/null
+++ b/src/video_core/renderer_vulkan/present/fxaa.h
@@ -0,0 +1,63 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "video_core/renderer_vulkan/present/anti_alias_pass.h"
7#include "video_core/vulkan_common/vulkan_memory_allocator.h"
8#include "video_core/vulkan_common/vulkan_wrapper.h"
9
10namespace Vulkan {
11
12class Device;
13class Scheduler;
14class StagingBufferPool;
15
16class FXAA final : public AntiAliasPass {
17public:
18 explicit FXAA(const Device& device, MemoryAllocator& allocator, size_t image_count,
19 VkExtent2D extent);
20 ~FXAA() override;
21
22 VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImage source_image,
23 VkImageView source_image_view) override;
24
25private:
26 void CreateImages();
27 void CreateRenderPasses();
28 void CreateSampler();
29 void CreateShaders();
30 void CreateDescriptorPool();
31 void CreateDescriptorSetLayouts();
32 void CreateDescriptorSets();
33 void CreatePipelineLayouts();
34 void CreatePipelines();
35 void UpdateDescriptorSets(VkImageView image_view, size_t image_index);
36 void UploadImages(Scheduler& scheduler);
37
38 const Device& m_device;
39 MemoryAllocator& m_allocator;
40 const VkExtent2D m_extent;
41 const u32 m_image_count;
42
43 vk::ShaderModule m_vertex_shader{};
44 vk::ShaderModule m_fragment_shader{};
45 vk::DescriptorPool m_descriptor_pool{};
46 vk::DescriptorSetLayout m_descriptor_set_layout{};
47 vk::PipelineLayout m_pipeline_layout{};
48 vk::Pipeline m_pipeline{};
49 vk::RenderPass m_renderpass{};
50
51 struct Image {
52 vk::DescriptorSets descriptor_sets{};
53 vk::Framebuffer framebuffer{};
54 vk::Image image{};
55 vk::ImageView image_view{};
56 };
57 std::vector<Image> m_dynamic_images{};
58 bool m_images_ready{};
59
60 vk::Sampler m_sampler{};
61};
62
63} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/present/smaa.cpp b/src/video_core/renderer_vulkan/present/smaa.cpp
new file mode 100644
index 000000000..68cd22b08
--- /dev/null
+++ b/src/video_core/renderer_vulkan/present/smaa.cpp
@@ -0,0 +1,270 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <list>
5
6#include "common/assert.h"
7#include "common/polyfill_ranges.h"
8
9#include "video_core/renderer_vulkan/present/smaa.h"
10#include "video_core/renderer_vulkan/present/util.h"
11#include "video_core/renderer_vulkan/vk_scheduler.h"
12#include "video_core/renderer_vulkan/vk_shader_util.h"
13#include "video_core/smaa_area_tex.h"
14#include "video_core/smaa_search_tex.h"
15#include "video_core/vulkan_common/vulkan_device.h"
16
17#include "video_core/host_shaders/smaa_blending_weight_calculation_frag_spv.h"
18#include "video_core/host_shaders/smaa_blending_weight_calculation_vert_spv.h"
19#include "video_core/host_shaders/smaa_edge_detection_frag_spv.h"
20#include "video_core/host_shaders/smaa_edge_detection_vert_spv.h"
21#include "video_core/host_shaders/smaa_neighborhood_blending_frag_spv.h"
22#include "video_core/host_shaders/smaa_neighborhood_blending_vert_spv.h"
23
24namespace Vulkan {
25
26SMAA::SMAA(const Device& device, MemoryAllocator& allocator, size_t image_count, VkExtent2D extent)
27 : m_device(device), m_allocator(allocator), m_extent(extent),
28 m_image_count(static_cast<u32>(image_count)) {
29 CreateImages();
30 CreateRenderPasses();
31 CreateSampler();
32 CreateShaders();
33 CreateDescriptorPool();
34 CreateDescriptorSetLayouts();
35 CreateDescriptorSets();
36 CreatePipelineLayouts();
37 CreatePipelines();
38}
39
40SMAA::~SMAA() = default;
41
42void SMAA::CreateImages() {
43 static constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT};
44 static constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT};
45
46 m_static_images[Area] = CreateWrappedImage(m_allocator, area_extent, VK_FORMAT_R8G8_UNORM);
47 m_static_images[Search] = CreateWrappedImage(m_allocator, search_extent, VK_FORMAT_R8_UNORM);
48
49 m_static_image_views[Area] =
50 CreateWrappedImageView(m_device, m_static_images[Area], VK_FORMAT_R8G8_UNORM);
51 m_static_image_views[Search] =
52 CreateWrappedImageView(m_device, m_static_images[Search], VK_FORMAT_R8_UNORM);
53
54 for (u32 i = 0; i < m_image_count; i++) {
55 Images& images = m_dynamic_images.emplace_back();
56
57 images.images[Blend] =
58 CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
59 images.images[Edges] = CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16_SFLOAT);
60 images.images[Output] =
61 CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
62
63 images.image_views[Blend] =
64 CreateWrappedImageView(m_device, images.images[Blend], VK_FORMAT_R16G16B16A16_SFLOAT);
65 images.image_views[Edges] =
66 CreateWrappedImageView(m_device, images.images[Edges], VK_FORMAT_R16G16_SFLOAT);
67 images.image_views[Output] =
68 CreateWrappedImageView(m_device, images.images[Output], VK_FORMAT_R16G16B16A16_SFLOAT);
69 }
70}
71
72void SMAA::CreateRenderPasses() {
73 m_renderpasses[EdgeDetection] = CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16_SFLOAT);
74 m_renderpasses[BlendingWeightCalculation] =
75 CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16B16A16_SFLOAT);
76 m_renderpasses[NeighborhoodBlending] =
77 CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16B16A16_SFLOAT);
78
79 for (auto& images : m_dynamic_images) {
80 images.framebuffers[EdgeDetection] = CreateWrappedFramebuffer(
81 m_device, m_renderpasses[EdgeDetection], images.image_views[Edges], m_extent);
82
83 images.framebuffers[BlendingWeightCalculation] =
84 CreateWrappedFramebuffer(m_device, m_renderpasses[BlendingWeightCalculation],
85 images.image_views[Blend], m_extent);
86
87 images.framebuffers[NeighborhoodBlending] = CreateWrappedFramebuffer(
88 m_device, m_renderpasses[NeighborhoodBlending], images.image_views[Output], m_extent);
89 }
90}
91
92void SMAA::CreateSampler() {
93 m_sampler = CreateWrappedSampler(m_device);
94}
95
96void SMAA::CreateShaders() {
97 // These match the order of the SMAAStage enum
98 static constexpr std::array vert_shader_sources{
99 ARRAY_TO_SPAN(SMAA_EDGE_DETECTION_VERT_SPV),
100 ARRAY_TO_SPAN(SMAA_BLENDING_WEIGHT_CALCULATION_VERT_SPV),
101 ARRAY_TO_SPAN(SMAA_NEIGHBORHOOD_BLENDING_VERT_SPV),
102 };
103 static constexpr std::array frag_shader_sources{
104 ARRAY_TO_SPAN(SMAA_EDGE_DETECTION_FRAG_SPV),
105 ARRAY_TO_SPAN(SMAA_BLENDING_WEIGHT_CALCULATION_FRAG_SPV),
106 ARRAY_TO_SPAN(SMAA_NEIGHBORHOOD_BLENDING_FRAG_SPV),
107 };
108
109 for (size_t i = 0; i < MaxSMAAStage; i++) {
110 m_vertex_shaders[i] = CreateWrappedShaderModule(m_device, vert_shader_sources[i]);
111 m_fragment_shaders[i] = CreateWrappedShaderModule(m_device, frag_shader_sources[i]);
112 }
113}
114
115void SMAA::CreateDescriptorPool() {
116 // Edge detection: 1 descriptor
117 // Blending weight calculation: 3 descriptors
118 // Neighborhood blending: 2 descriptors
119
120 // 6 descriptors, 3 descriptor sets per image
121 m_descriptor_pool = CreateWrappedDescriptorPool(m_device, 6 * m_image_count, 3 * m_image_count);
122}
123
124void SMAA::CreateDescriptorSetLayouts() {
125 m_descriptor_set_layouts[EdgeDetection] = CreateWrappedDescriptorSetLayout(m_device, 1);
126 m_descriptor_set_layouts[BlendingWeightCalculation] =
127 CreateWrappedDescriptorSetLayout(m_device, 3);
128 m_descriptor_set_layouts[NeighborhoodBlending] = CreateWrappedDescriptorSetLayout(m_device, 2);
129}
130
131void SMAA::CreateDescriptorSets() {
132 std::vector<VkDescriptorSetLayout> layouts(m_descriptor_set_layouts.size());
133 std::ranges::transform(m_descriptor_set_layouts, layouts.begin(),
134 [](auto& layout) { return *layout; });
135
136 for (auto& images : m_dynamic_images) {
137 images.descriptor_sets = CreateWrappedDescriptorSets(m_descriptor_pool, layouts);
138 }
139}
140
141void SMAA::CreatePipelineLayouts() {
142 for (size_t i = 0; i < MaxSMAAStage; i++) {
143 m_pipeline_layouts[i] = CreateWrappedPipelineLayout(m_device, m_descriptor_set_layouts[i]);
144 }
145}
146
147void SMAA::CreatePipelines() {
148 for (size_t i = 0; i < MaxSMAAStage; i++) {
149 m_pipelines[i] =
150 CreateWrappedPipeline(m_device, m_renderpasses[i], m_pipeline_layouts[i],
151 std::tie(m_vertex_shaders[i], m_fragment_shaders[i]));
152 }
153}
154
155void SMAA::UpdateDescriptorSets(VkImageView image_view, size_t image_index) {
156 Images& images = m_dynamic_images[image_index];
157 std::vector<VkDescriptorImageInfo> image_infos;
158 std::vector<VkWriteDescriptorSet> updates;
159 image_infos.reserve(6);
160
161 updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, image_view,
162 images.descriptor_sets[EdgeDetection], 0));
163
164 updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *images.image_views[Edges],
165 images.descriptor_sets[BlendingWeightCalculation],
166 0));
167 updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *m_static_image_views[Area],
168 images.descriptor_sets[BlendingWeightCalculation],
169 1));
170 updates.push_back(
171 CreateWriteDescriptorSet(image_infos, *m_sampler, *m_static_image_views[Search],
172 images.descriptor_sets[BlendingWeightCalculation], 2));
173
174 updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, image_view,
175 images.descriptor_sets[NeighborhoodBlending], 0));
176 updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *images.image_views[Blend],
177 images.descriptor_sets[NeighborhoodBlending], 1));
178
179 m_device.GetLogical().UpdateDescriptorSets(updates, {});
180}
181
182void SMAA::UploadImages(Scheduler& scheduler) {
183 if (m_images_ready) {
184 return;
185 }
186
187 static constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT};
188 static constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT};
189
190 UploadImage(m_device, m_allocator, scheduler, m_static_images[Area], area_extent,
191 VK_FORMAT_R8G8_UNORM, ARRAY_TO_SPAN(areaTexBytes));
192 UploadImage(m_device, m_allocator, scheduler, m_static_images[Search], search_extent,
193 VK_FORMAT_R8_UNORM, ARRAY_TO_SPAN(searchTexBytes));
194
195 scheduler.Record([&](vk::CommandBuffer cmdbuf) {
196 for (auto& images : m_dynamic_images) {
197 for (size_t i = 0; i < MaxDynamicImage; i++) {
198 ClearColorImage(cmdbuf, *images.images[i]);
199 }
200 }
201 });
202 scheduler.Finish();
203
204 m_images_ready = true;
205}
206
207VkImageView SMAA::Draw(Scheduler& scheduler, size_t image_index, VkImage source_image,
208 VkImageView source_image_view) {
209 Images& images = m_dynamic_images[image_index];
210
211 VkImage output_image = *images.images[Output];
212 VkImage edges_image = *images.images[Edges];
213 VkImage blend_image = *images.images[Blend];
214
215 VkDescriptorSet edge_detection_descriptor_set = images.descriptor_sets[EdgeDetection];
216 VkDescriptorSet blending_weight_calculation_descriptor_set =
217 images.descriptor_sets[BlendingWeightCalculation];
218 VkDescriptorSet neighborhood_blending_descriptor_set =
219 images.descriptor_sets[NeighborhoodBlending];
220
221 VkFramebuffer edge_detection_framebuffer = *images.framebuffers[EdgeDetection];
222 VkFramebuffer blending_weight_calculation_framebuffer =
223 *images.framebuffers[BlendingWeightCalculation];
224 VkFramebuffer neighborhood_blending_framebuffer = *images.framebuffers[NeighborhoodBlending];
225
226 UploadImages(scheduler);
227 UpdateDescriptorSets(source_image_view, image_index);
228
229 scheduler.RequestOutsideRenderPassOperationContext();
230 scheduler.Record([=, this](vk::CommandBuffer cmdbuf) {
231 TransitionImageLayout(cmdbuf, source_image, VK_IMAGE_LAYOUT_GENERAL);
232 TransitionImageLayout(cmdbuf, edges_image, VK_IMAGE_LAYOUT_GENERAL);
233 BeginRenderPass(cmdbuf, *m_renderpasses[EdgeDetection], edge_detection_framebuffer,
234 m_extent);
235 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelines[EdgeDetection]);
236 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS,
237 *m_pipeline_layouts[EdgeDetection], 0,
238 edge_detection_descriptor_set, {});
239 cmdbuf.Draw(3, 1, 0, 0);
240 cmdbuf.EndRenderPass();
241
242 TransitionImageLayout(cmdbuf, edges_image, VK_IMAGE_LAYOUT_GENERAL);
243 TransitionImageLayout(cmdbuf, blend_image, VK_IMAGE_LAYOUT_GENERAL);
244 BeginRenderPass(cmdbuf, *m_renderpasses[BlendingWeightCalculation],
245 blending_weight_calculation_framebuffer, m_extent);
246 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS,
247 *m_pipelines[BlendingWeightCalculation]);
248 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS,
249 *m_pipeline_layouts[BlendingWeightCalculation], 0,
250 blending_weight_calculation_descriptor_set, {});
251 cmdbuf.Draw(3, 1, 0, 0);
252 cmdbuf.EndRenderPass();
253
254 TransitionImageLayout(cmdbuf, blend_image, VK_IMAGE_LAYOUT_GENERAL);
255 TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL);
256 BeginRenderPass(cmdbuf, *m_renderpasses[NeighborhoodBlending],
257 neighborhood_blending_framebuffer, m_extent);
258 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelines[NeighborhoodBlending]);
259 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS,
260 *m_pipeline_layouts[NeighborhoodBlending], 0,
261 neighborhood_blending_descriptor_set, {});
262 cmdbuf.Draw(3, 1, 0, 0);
263 cmdbuf.EndRenderPass();
264 TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL);
265 });
266
267 return *images.image_views[Output];
268}
269
270} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_smaa.h b/src/video_core/renderer_vulkan/present/smaa.h
index 0e214258a..3d6707d48 100644
--- a/src/video_core/renderer_vulkan/vk_smaa.h
+++ b/src/video_core/renderer_vulkan/present/smaa.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include <array> 6#include <array>
7#include "video_core/renderer_vulkan/present/anti_alias_pass.h"
7#include "video_core/vulkan_common/vulkan_memory_allocator.h" 8#include "video_core/vulkan_common/vulkan_memory_allocator.h"
8#include "video_core/vulkan_common/vulkan_wrapper.h" 9#include "video_core/vulkan_common/vulkan_wrapper.h"
9 10
@@ -13,12 +14,14 @@ class Device;
13class Scheduler; 14class Scheduler;
14class StagingBufferPool; 15class StagingBufferPool;
15 16
16class SMAA { 17class SMAA final : public AntiAliasPass {
17public: 18public:
18 explicit SMAA(const Device& device, MemoryAllocator& allocator, size_t image_count, 19 explicit SMAA(const Device& device, MemoryAllocator& allocator, size_t image_count,
19 VkExtent2D extent); 20 VkExtent2D extent);
21 ~SMAA() override;
22
20 VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImage source_image, 23 VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImage source_image,
21 VkImageView source_image_view); 24 VkImageView source_image_view) override;
22 25
23private: 26private:
24 enum SMAAStage { 27 enum SMAAStage {
diff --git a/src/video_core/renderer_vulkan/vk_smaa.cpp b/src/video_core/renderer_vulkan/present/util.cpp
index 70644ea82..a445b213e 100644
--- a/src/video_core/renderer_vulkan/vk_smaa.cpp
+++ b/src/video_core/renderer_vulkan/present/util.cpp
@@ -1,29 +1,11 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <list>
5
6#include "common/assert.h" 4#include "common/assert.h"
7#include "common/polyfill_ranges.h" 5#include "common/polyfill_ranges.h"
8 6#include "video_core/renderer_vulkan/present/util.h"
9#include "video_core/renderer_vulkan/vk_scheduler.h"
10#include "video_core/renderer_vulkan/vk_shader_util.h"
11#include "video_core/renderer_vulkan/vk_smaa.h"
12#include "video_core/smaa_area_tex.h"
13#include "video_core/smaa_search_tex.h"
14#include "video_core/vulkan_common/vulkan_device.h"
15
16#include "video_core/host_shaders/smaa_blending_weight_calculation_frag_spv.h"
17#include "video_core/host_shaders/smaa_blending_weight_calculation_vert_spv.h"
18#include "video_core/host_shaders/smaa_edge_detection_frag_spv.h"
19#include "video_core/host_shaders/smaa_edge_detection_vert_spv.h"
20#include "video_core/host_shaders/smaa_neighborhood_blending_frag_spv.h"
21#include "video_core/host_shaders/smaa_neighborhood_blending_vert_spv.h"
22 7
23namespace Vulkan { 8namespace Vulkan {
24namespace {
25
26#define ARRAY_TO_SPAN(a) std::span(a, (sizeof(a) / sizeof(a[0])))
27 9
28vk::Image CreateWrappedImage(MemoryAllocator& allocator, VkExtent2D dimensions, VkFormat format) { 10vk::Image CreateWrappedImage(MemoryAllocator& allocator, VkExtent2D dimensions, VkFormat format) {
29 const VkImageCreateInfo image_ci{ 11 const VkImageCreateInfo image_ci{
@@ -48,7 +30,7 @@ vk::Image CreateWrappedImage(MemoryAllocator& allocator, VkExtent2D dimensions,
48} 30}
49 31
50void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout, 32void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout,
51 VkImageLayout source_layout = VK_IMAGE_LAYOUT_GENERAL) { 33 VkImageLayout source_layout) {
52 constexpr VkFlags flags{VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | 34 constexpr VkFlags flags{VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
53 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT}; 35 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT};
54 const VkImageMemoryBarrier barrier{ 36 const VkImageMemoryBarrier barrier{
@@ -75,7 +57,7 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo
75 57
76void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler, 58void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler,
77 vk::Image& image, VkExtent2D dimensions, VkFormat format, 59 vk::Image& image, VkExtent2D dimensions, VkFormat format,
78 std::span<const u8> initial_contents = {}) { 60 std::span<const u8> initial_contents) {
79 const VkBufferCreateInfo upload_ci = { 61 const VkBufferCreateInfo upload_ci = {
80 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 62 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
81 .pNext = nullptr, 63 .pNext = nullptr,
@@ -200,13 +182,13 @@ vk::Framebuffer CreateWrappedFramebuffer(const Device& device, vk::RenderPass& r
200 }); 182 });
201} 183}
202 184
203vk::Sampler CreateWrappedSampler(const Device& device) { 185vk::Sampler CreateWrappedSampler(const Device& device, VkFilter filter) {
204 return device.GetLogical().CreateSampler(VkSamplerCreateInfo{ 186 return device.GetLogical().CreateSampler(VkSamplerCreateInfo{
205 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, 187 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
206 .pNext = nullptr, 188 .pNext = nullptr,
207 .flags = 0, 189 .flags = 0,
208 .magFilter = VK_FILTER_LINEAR, 190 .magFilter = filter,
209 .minFilter = VK_FILTER_LINEAR, 191 .minFilter = filter,
210 .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, 192 .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
211 .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 193 .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
212 .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 194 .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
@@ -471,12 +453,12 @@ void ClearColorImage(vk::CommandBuffer& cmdbuf, VkImage image) {
471 cmdbuf.ClearColorImage(image, VK_IMAGE_LAYOUT_GENERAL, {}, subresources); 453 cmdbuf.ClearColorImage(image, VK_IMAGE_LAYOUT_GENERAL, {}, subresources);
472} 454}
473 455
474void BeginRenderPass(vk::CommandBuffer& cmdbuf, vk::RenderPass& render_pass, 456void BeginRenderPass(vk::CommandBuffer& cmdbuf, VkRenderPass render_pass, VkFramebuffer framebuffer,
475 VkFramebuffer framebuffer, VkExtent2D extent) { 457 VkExtent2D extent) {
476 const VkRenderPassBeginInfo renderpass_bi{ 458 const VkRenderPassBeginInfo renderpass_bi{
477 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 459 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
478 .pNext = nullptr, 460 .pNext = nullptr,
479 .renderPass = *render_pass, 461 .renderPass = render_pass,
480 .framebuffer = framebuffer, 462 .framebuffer = framebuffer,
481 .renderArea{ 463 .renderArea{
482 .offset{}, 464 .offset{},
@@ -503,248 +485,4 @@ void BeginRenderPass(vk::CommandBuffer& cmdbuf, vk::RenderPass& render_pass,
503 cmdbuf.SetScissor(0, scissor); 485 cmdbuf.SetScissor(0, scissor);
504} 486}
505 487
506} // Anonymous namespace
507
508SMAA::SMAA(const Device& device, MemoryAllocator& allocator, size_t image_count, VkExtent2D extent)
509 : m_device(device), m_allocator(allocator), m_extent(extent),
510 m_image_count(static_cast<u32>(image_count)) {
511 CreateImages();
512 CreateRenderPasses();
513 CreateSampler();
514 CreateShaders();
515 CreateDescriptorPool();
516 CreateDescriptorSetLayouts();
517 CreateDescriptorSets();
518 CreatePipelineLayouts();
519 CreatePipelines();
520}
521
522void SMAA::CreateImages() {
523 static constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT};
524 static constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT};
525
526 m_static_images[Area] = CreateWrappedImage(m_allocator, area_extent, VK_FORMAT_R8G8_UNORM);
527 m_static_images[Search] = CreateWrappedImage(m_allocator, search_extent, VK_FORMAT_R8_UNORM);
528
529 m_static_image_views[Area] =
530 CreateWrappedImageView(m_device, m_static_images[Area], VK_FORMAT_R8G8_UNORM);
531 m_static_image_views[Search] =
532 CreateWrappedImageView(m_device, m_static_images[Search], VK_FORMAT_R8_UNORM);
533
534 for (u32 i = 0; i < m_image_count; i++) {
535 Images& images = m_dynamic_images.emplace_back();
536
537 images.images[Blend] =
538 CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
539 images.images[Edges] = CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16_SFLOAT);
540 images.images[Output] =
541 CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
542
543 images.image_views[Blend] =
544 CreateWrappedImageView(m_device, images.images[Blend], VK_FORMAT_R16G16B16A16_SFLOAT);
545 images.image_views[Edges] =
546 CreateWrappedImageView(m_device, images.images[Edges], VK_FORMAT_R16G16_SFLOAT);
547 images.image_views[Output] =
548 CreateWrappedImageView(m_device, images.images[Output], VK_FORMAT_R16G16B16A16_SFLOAT);
549 }
550}
551
552void SMAA::CreateRenderPasses() {
553 m_renderpasses[EdgeDetection] = CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16_SFLOAT);
554 m_renderpasses[BlendingWeightCalculation] =
555 CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16B16A16_SFLOAT);
556 m_renderpasses[NeighborhoodBlending] =
557 CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16B16A16_SFLOAT);
558
559 for (auto& images : m_dynamic_images) {
560 images.framebuffers[EdgeDetection] = CreateWrappedFramebuffer(
561 m_device, m_renderpasses[EdgeDetection], images.image_views[Edges], m_extent);
562
563 images.framebuffers[BlendingWeightCalculation] =
564 CreateWrappedFramebuffer(m_device, m_renderpasses[BlendingWeightCalculation],
565 images.image_views[Blend], m_extent);
566
567 images.framebuffers[NeighborhoodBlending] = CreateWrappedFramebuffer(
568 m_device, m_renderpasses[NeighborhoodBlending], images.image_views[Output], m_extent);
569 }
570}
571
572void SMAA::CreateSampler() {
573 m_sampler = CreateWrappedSampler(m_device);
574}
575
576void SMAA::CreateShaders() {
577 // These match the order of the SMAAStage enum
578 static constexpr std::array vert_shader_sources{
579 ARRAY_TO_SPAN(SMAA_EDGE_DETECTION_VERT_SPV),
580 ARRAY_TO_SPAN(SMAA_BLENDING_WEIGHT_CALCULATION_VERT_SPV),
581 ARRAY_TO_SPAN(SMAA_NEIGHBORHOOD_BLENDING_VERT_SPV),
582 };
583 static constexpr std::array frag_shader_sources{
584 ARRAY_TO_SPAN(SMAA_EDGE_DETECTION_FRAG_SPV),
585 ARRAY_TO_SPAN(SMAA_BLENDING_WEIGHT_CALCULATION_FRAG_SPV),
586 ARRAY_TO_SPAN(SMAA_NEIGHBORHOOD_BLENDING_FRAG_SPV),
587 };
588
589 for (size_t i = 0; i < MaxSMAAStage; i++) {
590 m_vertex_shaders[i] = CreateWrappedShaderModule(m_device, vert_shader_sources[i]);
591 m_fragment_shaders[i] = CreateWrappedShaderModule(m_device, frag_shader_sources[i]);
592 }
593}
594
595void SMAA::CreateDescriptorPool() {
596 // Edge detection: 1 descriptor
597 // Blending weight calculation: 3 descriptors
598 // Neighborhood blending: 2 descriptors
599
600 // 6 descriptors, 3 descriptor sets per image
601 m_descriptor_pool = CreateWrappedDescriptorPool(m_device, 6 * m_image_count, 3 * m_image_count);
602}
603
604void SMAA::CreateDescriptorSetLayouts() {
605 m_descriptor_set_layouts[EdgeDetection] = CreateWrappedDescriptorSetLayout(m_device, 1);
606 m_descriptor_set_layouts[BlendingWeightCalculation] =
607 CreateWrappedDescriptorSetLayout(m_device, 3);
608 m_descriptor_set_layouts[NeighborhoodBlending] = CreateWrappedDescriptorSetLayout(m_device, 2);
609}
610
611void SMAA::CreateDescriptorSets() {
612 std::vector<VkDescriptorSetLayout> layouts(m_descriptor_set_layouts.size());
613 std::ranges::transform(m_descriptor_set_layouts, layouts.begin(),
614 [](auto& layout) { return *layout; });
615
616 for (auto& images : m_dynamic_images) {
617 images.descriptor_sets = CreateWrappedDescriptorSets(m_descriptor_pool, layouts);
618 }
619}
620
621void SMAA::CreatePipelineLayouts() {
622 for (size_t i = 0; i < MaxSMAAStage; i++) {
623 m_pipeline_layouts[i] = CreateWrappedPipelineLayout(m_device, m_descriptor_set_layouts[i]);
624 }
625}
626
627void SMAA::CreatePipelines() {
628 for (size_t i = 0; i < MaxSMAAStage; i++) {
629 m_pipelines[i] =
630 CreateWrappedPipeline(m_device, m_renderpasses[i], m_pipeline_layouts[i],
631 std::tie(m_vertex_shaders[i], m_fragment_shaders[i]));
632 }
633}
634
635void SMAA::UpdateDescriptorSets(VkImageView image_view, size_t image_index) {
636 Images& images = m_dynamic_images[image_index];
637 std::vector<VkDescriptorImageInfo> image_infos;
638 std::vector<VkWriteDescriptorSet> updates;
639 image_infos.reserve(6);
640
641 updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, image_view,
642 images.descriptor_sets[EdgeDetection], 0));
643
644 updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *images.image_views[Edges],
645 images.descriptor_sets[BlendingWeightCalculation],
646 0));
647 updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *m_static_image_views[Area],
648 images.descriptor_sets[BlendingWeightCalculation],
649 1));
650 updates.push_back(
651 CreateWriteDescriptorSet(image_infos, *m_sampler, *m_static_image_views[Search],
652 images.descriptor_sets[BlendingWeightCalculation], 2));
653
654 updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, image_view,
655 images.descriptor_sets[NeighborhoodBlending], 0));
656 updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *images.image_views[Blend],
657 images.descriptor_sets[NeighborhoodBlending], 1));
658
659 m_device.GetLogical().UpdateDescriptorSets(updates, {});
660}
661
662void SMAA::UploadImages(Scheduler& scheduler) {
663 if (m_images_ready) {
664 return;
665 }
666
667 static constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT};
668 static constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT};
669
670 UploadImage(m_device, m_allocator, scheduler, m_static_images[Area], area_extent,
671 VK_FORMAT_R8G8_UNORM, ARRAY_TO_SPAN(areaTexBytes));
672 UploadImage(m_device, m_allocator, scheduler, m_static_images[Search], search_extent,
673 VK_FORMAT_R8_UNORM, ARRAY_TO_SPAN(searchTexBytes));
674
675 scheduler.Record([&](vk::CommandBuffer cmdbuf) {
676 for (auto& images : m_dynamic_images) {
677 for (size_t i = 0; i < MaxDynamicImage; i++) {
678 ClearColorImage(cmdbuf, *images.images[i]);
679 }
680 }
681 });
682 scheduler.Finish();
683
684 m_images_ready = true;
685}
686
687VkImageView SMAA::Draw(Scheduler& scheduler, size_t image_index, VkImage source_image,
688 VkImageView source_image_view) {
689 Images& images = m_dynamic_images[image_index];
690
691 VkImage output_image = *images.images[Output];
692 VkImage edges_image = *images.images[Edges];
693 VkImage blend_image = *images.images[Blend];
694
695 VkDescriptorSet edge_detection_descriptor_set = images.descriptor_sets[EdgeDetection];
696 VkDescriptorSet blending_weight_calculation_descriptor_set =
697 images.descriptor_sets[BlendingWeightCalculation];
698 VkDescriptorSet neighborhood_blending_descriptor_set =
699 images.descriptor_sets[NeighborhoodBlending];
700
701 VkFramebuffer edge_detection_framebuffer = *images.framebuffers[EdgeDetection];
702 VkFramebuffer blending_weight_calculation_framebuffer =
703 *images.framebuffers[BlendingWeightCalculation];
704 VkFramebuffer neighborhood_blending_framebuffer = *images.framebuffers[NeighborhoodBlending];
705
706 UploadImages(scheduler);
707 UpdateDescriptorSets(source_image_view, image_index);
708
709 scheduler.RequestOutsideRenderPassOperationContext();
710 scheduler.Record([=, this](vk::CommandBuffer cmdbuf) {
711 TransitionImageLayout(cmdbuf, source_image, VK_IMAGE_LAYOUT_GENERAL);
712 TransitionImageLayout(cmdbuf, edges_image, VK_IMAGE_LAYOUT_GENERAL);
713 BeginRenderPass(cmdbuf, m_renderpasses[EdgeDetection], edge_detection_framebuffer,
714 m_extent);
715 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelines[EdgeDetection]);
716 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS,
717 *m_pipeline_layouts[EdgeDetection], 0,
718 edge_detection_descriptor_set, {});
719 cmdbuf.Draw(3, 1, 0, 0);
720 cmdbuf.EndRenderPass();
721
722 TransitionImageLayout(cmdbuf, edges_image, VK_IMAGE_LAYOUT_GENERAL);
723 TransitionImageLayout(cmdbuf, blend_image, VK_IMAGE_LAYOUT_GENERAL);
724 BeginRenderPass(cmdbuf, m_renderpasses[BlendingWeightCalculation],
725 blending_weight_calculation_framebuffer, m_extent);
726 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS,
727 *m_pipelines[BlendingWeightCalculation]);
728 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS,
729 *m_pipeline_layouts[BlendingWeightCalculation], 0,
730 blending_weight_calculation_descriptor_set, {});
731 cmdbuf.Draw(3, 1, 0, 0);
732 cmdbuf.EndRenderPass();
733
734 TransitionImageLayout(cmdbuf, blend_image, VK_IMAGE_LAYOUT_GENERAL);
735 TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL);
736 BeginRenderPass(cmdbuf, m_renderpasses[NeighborhoodBlending],
737 neighborhood_blending_framebuffer, m_extent);
738 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelines[NeighborhoodBlending]);
739 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS,
740 *m_pipeline_layouts[NeighborhoodBlending], 0,
741 neighborhood_blending_descriptor_set, {});
742 cmdbuf.Draw(3, 1, 0, 0);
743 cmdbuf.EndRenderPass();
744 TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL);
745 });
746
747 return *images.image_views[Output];
748}
749
750} // namespace Vulkan 488} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/present/util.h b/src/video_core/renderer_vulkan/present/util.h
new file mode 100644
index 000000000..93cfdd16b
--- /dev/null
+++ b/src/video_core/renderer_vulkan/present/util.h
@@ -0,0 +1,46 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "video_core/renderer_vulkan/vk_scheduler.h"
7#include "video_core/vulkan_common/vulkan_memory_allocator.h"
8#include "video_core/vulkan_common/vulkan_wrapper.h"
9
10namespace Vulkan {
11
12#define ARRAY_TO_SPAN(a) std::span(a, (sizeof(a) / sizeof(a[0])))
13
14vk::Image CreateWrappedImage(MemoryAllocator& allocator, VkExtent2D dimensions, VkFormat format);
15void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout,
16 VkImageLayout source_layout = VK_IMAGE_LAYOUT_GENERAL);
17void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler,
18 vk::Image& image, VkExtent2D dimensions, VkFormat format,
19 std::span<const u8> initial_contents = {});
20void ClearColorImage(vk::CommandBuffer& cmdbuf, VkImage image);
21
22vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format);
23vk::RenderPass CreateWrappedRenderPass(const Device& device, VkFormat format);
24vk::Framebuffer CreateWrappedFramebuffer(const Device& device, vk::RenderPass& render_pass,
25 vk::ImageView& dest_image, VkExtent2D extent);
26vk::Sampler CreateWrappedSampler(const Device& device, VkFilter filter = VK_FILTER_LINEAR);
27vk::ShaderModule CreateWrappedShaderModule(const Device& device, std::span<const u32> code);
28vk::DescriptorPool CreateWrappedDescriptorPool(const Device& device, u32 max_sampler_bindings,
29 u32 max_sets);
30vk::DescriptorSetLayout CreateWrappedDescriptorSetLayout(const Device& device,
31 u32 max_sampler_bindings);
32vk::DescriptorSets CreateWrappedDescriptorSets(vk::DescriptorPool& pool,
33 vk::Span<VkDescriptorSetLayout> layouts);
34vk::PipelineLayout CreateWrappedPipelineLayout(const Device& device,
35 vk::DescriptorSetLayout& layout);
36vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass,
37 vk::PipelineLayout& layout,
38 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders);
39VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images,
40 VkSampler sampler, VkImageView view,
41 VkDescriptorSet set, u32 binding);
42
43void BeginRenderPass(vk::CommandBuffer& cmdbuf, VkRenderPass render_pass, VkFramebuffer framebuffer,
44 VkExtent2D extent);
45
46} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index 24781860b..fe1a7b0cd 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -16,20 +16,19 @@
16#include "core/frontend/emu_window.h" 16#include "core/frontend/emu_window.h"
17#include "video_core/gpu.h" 17#include "video_core/gpu.h"
18#include "video_core/host1x/gpu_device_memory_manager.h" 18#include "video_core/host1x/gpu_device_memory_manager.h"
19#include "video_core/host_shaders/fxaa_frag_spv.h"
20#include "video_core/host_shaders/fxaa_vert_spv.h"
21#include "video_core/host_shaders/present_bicubic_frag_spv.h" 19#include "video_core/host_shaders/present_bicubic_frag_spv.h"
22#include "video_core/host_shaders/present_gaussian_frag_spv.h" 20#include "video_core/host_shaders/present_gaussian_frag_spv.h"
23#include "video_core/host_shaders/vulkan_present_frag_spv.h" 21#include "video_core/host_shaders/vulkan_present_frag_spv.h"
24#include "video_core/host_shaders/vulkan_present_scaleforce_fp16_frag_spv.h" 22#include "video_core/host_shaders/vulkan_present_scaleforce_fp16_frag_spv.h"
25#include "video_core/host_shaders/vulkan_present_scaleforce_fp32_frag_spv.h" 23#include "video_core/host_shaders/vulkan_present_scaleforce_fp32_frag_spv.h"
26#include "video_core/host_shaders/vulkan_present_vert_spv.h" 24#include "video_core/host_shaders/vulkan_present_vert_spv.h"
25#include "video_core/renderer_vulkan/present/fsr.h"
26#include "video_core/renderer_vulkan/present/fxaa.h"
27#include "video_core/renderer_vulkan/present/smaa.h"
27#include "video_core/renderer_vulkan/renderer_vulkan.h" 28#include "video_core/renderer_vulkan/renderer_vulkan.h"
28#include "video_core/renderer_vulkan/vk_blit_screen.h" 29#include "video_core/renderer_vulkan/vk_blit_screen.h"
29#include "video_core/renderer_vulkan/vk_fsr.h"
30#include "video_core/renderer_vulkan/vk_scheduler.h" 30#include "video_core/renderer_vulkan/vk_scheduler.h"
31#include "video_core/renderer_vulkan/vk_shader_util.h" 31#include "video_core/renderer_vulkan/vk_shader_util.h"
32#include "video_core/renderer_vulkan/vk_smaa.h"
33#include "video_core/renderer_vulkan/vk_swapchain.h" 32#include "video_core/renderer_vulkan/vk_swapchain.h"
34#include "video_core/surface.h" 33#include "video_core/surface.h"
35#include "video_core/textures/decoders.h" 34#include "video_core/textures/decoders.h"
@@ -252,103 +251,17 @@ void BlitScreen::Draw(RasterizerVulkan& rasterizer, const Tegra::FramebufferConf
252 251
253 const auto anti_alias_pass = Settings::values.anti_aliasing.GetValue(); 252 const auto anti_alias_pass = Settings::values.anti_aliasing.GetValue();
254 if (use_accelerated && anti_alias_pass == Settings::AntiAliasing::Fxaa) { 253 if (use_accelerated && anti_alias_pass == Settings::AntiAliasing::Fxaa) {
255 UpdateAADescriptorSet(source_image_view, false); 254 if (!fxaa) {
256 const u32 up_scale = Settings::values.resolution_info.up_scale; 255 const u32 up_scale = Settings::values.resolution_info.up_scale;
257 const u32 down_shift = Settings::values.resolution_info.down_shift; 256 const u32 down_shift = Settings::values.resolution_info.down_shift;
258 VkExtent2D size{ 257 const VkExtent2D fxaa_size{
259 .width = (up_scale * framebuffer.width) >> down_shift, 258 .width = (up_scale * framebuffer.width) >> down_shift,
260 .height = (up_scale * framebuffer.height) >> down_shift, 259 .height = (up_scale * framebuffer.height) >> down_shift,
261 };
262 scheduler.Record([this, index = image_index, size,
263 anti_alias_pass](vk::CommandBuffer cmdbuf) {
264 const VkImageMemoryBarrier base_barrier{
265 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
266 .pNext = nullptr,
267 .srcAccessMask = 0,
268 .dstAccessMask = 0,
269 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
270 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
271 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
272 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
273 .image = {},
274 .subresourceRange =
275 {
276 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
277 .baseMipLevel = 0,
278 .levelCount = 1,
279 .baseArrayLayer = 0,
280 .layerCount = 1,
281 },
282 };
283
284 {
285 VkImageMemoryBarrier fsr_write_barrier = base_barrier;
286 fsr_write_barrier.image = *aa_image;
287 fsr_write_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
288 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
289 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, fsr_write_barrier);
290 }
291
292 const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f;
293 const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f;
294 const f32 bg_blue = Settings::values.bg_blue.GetValue() / 255.0f;
295 const VkClearValue clear_color{
296 .color = {.float32 = {bg_red, bg_green, bg_blue, 1.0f}},
297 };
298 const VkRenderPassBeginInfo renderpass_bi{
299 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
300 .pNext = nullptr,
301 .renderPass = *aa_renderpass,
302 .framebuffer = *aa_framebuffer,
303 .renderArea =
304 {
305 .offset = {0, 0},
306 .extent = size,
307 },
308 .clearValueCount = 1,
309 .pClearValues = &clear_color,
310 };
311 const VkViewport viewport{
312 .x = 0.0f,
313 .y = 0.0f,
314 .width = static_cast<float>(size.width),
315 .height = static_cast<float>(size.height),
316 .minDepth = 0.0f,
317 .maxDepth = 1.0f,
318 };
319 const VkRect2D scissor{
320 .offset = {0, 0},
321 .extent = size,
322 }; 260 };
323 cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); 261 fxaa = std::make_unique<FXAA>(device, memory_allocator, image_count, fxaa_size);
324 switch (anti_alias_pass) { 262 }
325 case Settings::AntiAliasing::Fxaa:
326 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *aa_pipeline);
327 break;
328 default:
329 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *aa_pipeline);
330 break;
331 }
332 cmdbuf.SetViewport(0, viewport);
333 cmdbuf.SetScissor(0, scissor);
334
335 cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices));
336 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *aa_pipeline_layout, 0,
337 aa_descriptor_sets[index], {});
338 cmdbuf.Draw(4, 1, 0, 0);
339 cmdbuf.EndRenderPass();
340
341 {
342 VkImageMemoryBarrier blit_read_barrier = base_barrier;
343 blit_read_barrier.image = *aa_image;
344 blit_read_barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
345 blit_read_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
346 263
347 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 264 source_image_view = fxaa->Draw(scheduler, image_index, source_image, source_image_view);
348 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, blit_read_barrier);
349 }
350 });
351 source_image_view = *aa_image_view;
352 } 265 }
353 if (use_accelerated && anti_alias_pass == Settings::AntiAliasing::Smaa) { 266 if (use_accelerated && anti_alias_pass == Settings::AntiAliasing::Smaa) {
354 if (!smaa) { 267 if (!smaa) {
@@ -496,6 +409,7 @@ void BlitScreen::CreateDynamicResources() {
496 CreateRenderPass(); 409 CreateRenderPass();
497 CreateGraphicsPipeline(); 410 CreateGraphicsPipeline();
498 fsr.reset(); 411 fsr.reset();
412 fxaa.reset();
499 smaa.reset(); 413 smaa.reset();
500 if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { 414 if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) {
501 CreateFSR(); 415 CreateFSR();
@@ -520,6 +434,7 @@ void BlitScreen::RefreshResources(const Tegra::FramebufferConfig& framebuffer) {
520 raw_height = framebuffer.height; 434 raw_height = framebuffer.height;
521 pixel_format = framebuffer.pixel_format; 435 pixel_format = framebuffer.pixel_format;
522 436
437 fxaa.reset();
523 smaa.reset(); 438 smaa.reset();
524 ReleaseRawImages(); 439 ReleaseRawImages();
525 440
@@ -529,8 +444,6 @@ void BlitScreen::RefreshResources(const Tegra::FramebufferConfig& framebuffer) {
529 444
530void BlitScreen::CreateShaders() { 445void BlitScreen::CreateShaders() {
531 vertex_shader = BuildShader(device, VULKAN_PRESENT_VERT_SPV); 446 vertex_shader = BuildShader(device, VULKAN_PRESENT_VERT_SPV);
532 fxaa_vertex_shader = BuildShader(device, FXAA_VERT_SPV);
533 fxaa_fragment_shader = BuildShader(device, FXAA_FRAG_SPV);
534 bilinear_fragment_shader = BuildShader(device, VULKAN_PRESENT_FRAG_SPV); 447 bilinear_fragment_shader = BuildShader(device, VULKAN_PRESENT_FRAG_SPV);
535 bicubic_fragment_shader = BuildShader(device, PRESENT_BICUBIC_FRAG_SPV); 448 bicubic_fragment_shader = BuildShader(device, PRESENT_BICUBIC_FRAG_SPV);
536 gaussian_fragment_shader = BuildShader(device, PRESENT_GAUSSIAN_FRAG_SPV); 449 gaussian_fragment_shader = BuildShader(device, PRESENT_GAUSSIAN_FRAG_SPV);
@@ -553,13 +466,6 @@ void BlitScreen::CreateDescriptorPool() {
553 }, 466 },
554 }}; 467 }};
555 468
556 const std::array<VkDescriptorPoolSize, 1> pool_sizes_aa{{
557 {
558 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
559 .descriptorCount = static_cast<u32>(image_count * 2),
560 },
561 }};
562
563 const VkDescriptorPoolCreateInfo ci{ 469 const VkDescriptorPoolCreateInfo ci{
564 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 470 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
565 .pNext = nullptr, 471 .pNext = nullptr,
@@ -569,16 +475,6 @@ void BlitScreen::CreateDescriptorPool() {
569 .pPoolSizes = pool_sizes.data(), 475 .pPoolSizes = pool_sizes.data(),
570 }; 476 };
571 descriptor_pool = device.GetLogical().CreateDescriptorPool(ci); 477 descriptor_pool = device.GetLogical().CreateDescriptorPool(ci);
572
573 const VkDescriptorPoolCreateInfo ci_aa{
574 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
575 .pNext = nullptr,
576 .flags = 0,
577 .maxSets = static_cast<u32>(image_count),
578 .poolSizeCount = static_cast<u32>(pool_sizes_aa.size()),
579 .pPoolSizes = pool_sizes_aa.data(),
580 };
581 aa_descriptor_pool = device.GetLogical().CreateDescriptorPool(ci_aa);
582} 478}
583 479
584void BlitScreen::CreateRenderPass() { 480void BlitScreen::CreateRenderPass() {
@@ -659,23 +555,6 @@ void BlitScreen::CreateDescriptorSetLayout() {
659 }, 555 },
660 }}; 556 }};
661 557
662 const std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings_aa{{
663 {
664 .binding = 0,
665 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
666 .descriptorCount = 1,
667 .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
668 .pImmutableSamplers = nullptr,
669 },
670 {
671 .binding = 1,
672 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
673 .descriptorCount = 1,
674 .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
675 .pImmutableSamplers = nullptr,
676 },
677 }};
678
679 const VkDescriptorSetLayoutCreateInfo ci{ 558 const VkDescriptorSetLayoutCreateInfo ci{
680 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 559 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
681 .pNext = nullptr, 560 .pNext = nullptr,
@@ -684,21 +563,11 @@ void BlitScreen::CreateDescriptorSetLayout() {
684 .pBindings = layout_bindings.data(), 563 .pBindings = layout_bindings.data(),
685 }; 564 };
686 565
687 const VkDescriptorSetLayoutCreateInfo ci_aa{
688 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
689 .pNext = nullptr,
690 .flags = 0,
691 .bindingCount = static_cast<u32>(layout_bindings_aa.size()),
692 .pBindings = layout_bindings_aa.data(),
693 };
694
695 descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(ci); 566 descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(ci);
696 aa_descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(ci_aa);
697} 567}
698 568
699void BlitScreen::CreateDescriptorSets() { 569void BlitScreen::CreateDescriptorSets() {
700 const std::vector layouts(image_count, *descriptor_set_layout); 570 const std::vector layouts(image_count, *descriptor_set_layout);
701 const std::vector layouts_aa(image_count, *aa_descriptor_set_layout);
702 571
703 const VkDescriptorSetAllocateInfo ai{ 572 const VkDescriptorSetAllocateInfo ai{
704 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, 573 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
@@ -708,16 +577,7 @@ void BlitScreen::CreateDescriptorSets() {
708 .pSetLayouts = layouts.data(), 577 .pSetLayouts = layouts.data(),
709 }; 578 };
710 579
711 const VkDescriptorSetAllocateInfo ai_aa{
712 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
713 .pNext = nullptr,
714 .descriptorPool = *aa_descriptor_pool,
715 .descriptorSetCount = static_cast<u32>(image_count),
716 .pSetLayouts = layouts_aa.data(),
717 };
718
719 descriptor_sets = descriptor_pool.Allocate(ai); 580 descriptor_sets = descriptor_pool.Allocate(ai);
720 aa_descriptor_sets = aa_descriptor_pool.Allocate(ai_aa);
721} 581}
722 582
723void BlitScreen::CreatePipelineLayout() { 583void BlitScreen::CreatePipelineLayout() {
@@ -730,17 +590,7 @@ void BlitScreen::CreatePipelineLayout() {
730 .pushConstantRangeCount = 0, 590 .pushConstantRangeCount = 0,
731 .pPushConstantRanges = nullptr, 591 .pPushConstantRanges = nullptr,
732 }; 592 };
733 const VkPipelineLayoutCreateInfo ci_aa{
734 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
735 .pNext = nullptr,
736 .flags = 0,
737 .setLayoutCount = 1,
738 .pSetLayouts = aa_descriptor_set_layout.address(),
739 .pushConstantRangeCount = 0,
740 .pPushConstantRanges = nullptr,
741 };
742 pipeline_layout = device.GetLogical().CreatePipelineLayout(ci); 593 pipeline_layout = device.GetLogical().CreatePipelineLayout(ci);
743 aa_pipeline_layout = device.GetLogical().CreatePipelineLayout(ci_aa);
744} 594}
745 595
746void BlitScreen::CreateGraphicsPipeline() { 596void BlitScreen::CreateGraphicsPipeline() {
@@ -1068,8 +918,6 @@ void BlitScreen::ReleaseRawImages() {
1068 scheduler.Wait(tick); 918 scheduler.Wait(tick);
1069 } 919 }
1070 raw_images.clear(); 920 raw_images.clear();
1071 aa_image_view.reset();
1072 aa_image.reset();
1073 buffer.reset(); 921 buffer.reset();
1074} 922}
1075 923
@@ -1150,198 +998,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
1150 raw_images[i] = create_image(); 998 raw_images[i] = create_image();
1151 raw_image_views[i] = create_image_view(raw_images[i]); 999 raw_image_views[i] = create_image_view(raw_images[i]);
1152 } 1000 }
1153
1154 // AA Resources
1155 const u32 up_scale = Settings::values.resolution_info.up_scale;
1156 const u32 down_shift = Settings::values.resolution_info.down_shift;
1157 aa_image = create_image(true, up_scale, down_shift);
1158 aa_image_view = create_image_view(aa_image, true);
1159 VkExtent2D size{
1160 .width = (up_scale * framebuffer.width) >> down_shift,
1161 .height = (up_scale * framebuffer.height) >> down_shift,
1162 };
1163 if (aa_renderpass) {
1164 aa_framebuffer = CreateFramebuffer(*aa_image_view, size, aa_renderpass);
1165 return;
1166 }
1167 aa_renderpass = CreateRenderPassImpl(VK_FORMAT_R16G16B16A16_SFLOAT);
1168 aa_framebuffer = CreateFramebuffer(*aa_image_view, size, aa_renderpass);
1169
1170 const std::array<VkPipelineShaderStageCreateInfo, 2> fxaa_shader_stages{{
1171 {
1172 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
1173 .pNext = nullptr,
1174 .flags = 0,
1175 .stage = VK_SHADER_STAGE_VERTEX_BIT,
1176 .module = *fxaa_vertex_shader,
1177 .pName = "main",
1178 .pSpecializationInfo = nullptr,
1179 },
1180 {
1181 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
1182 .pNext = nullptr,
1183 .flags = 0,
1184 .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
1185 .module = *fxaa_fragment_shader,
1186 .pName = "main",
1187 .pSpecializationInfo = nullptr,
1188 },
1189 }};
1190
1191 const auto vertex_binding_description = ScreenRectVertex::GetDescription();
1192 const auto vertex_attrs_description = ScreenRectVertex::GetAttributes();
1193
1194 const VkPipelineVertexInputStateCreateInfo vertex_input_ci{
1195 .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
1196 .pNext = nullptr,
1197 .flags = 0,
1198 .vertexBindingDescriptionCount = 1,
1199 .pVertexBindingDescriptions = &vertex_binding_description,
1200 .vertexAttributeDescriptionCount = u32{vertex_attrs_description.size()},
1201 .pVertexAttributeDescriptions = vertex_attrs_description.data(),
1202 };
1203
1204 const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{
1205 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
1206 .pNext = nullptr,
1207 .flags = 0,
1208 .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
1209 .primitiveRestartEnable = VK_FALSE,
1210 };
1211
1212 const VkPipelineViewportStateCreateInfo viewport_state_ci{
1213 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
1214 .pNext = nullptr,
1215 .flags = 0,
1216 .viewportCount = 1,
1217 .pViewports = nullptr,
1218 .scissorCount = 1,
1219 .pScissors = nullptr,
1220 };
1221
1222 const VkPipelineRasterizationStateCreateInfo rasterization_ci{
1223 .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
1224 .pNext = nullptr,
1225 .flags = 0,
1226 .depthClampEnable = VK_FALSE,
1227 .rasterizerDiscardEnable = VK_FALSE,
1228 .polygonMode = VK_POLYGON_MODE_FILL,
1229 .cullMode = VK_CULL_MODE_NONE,
1230 .frontFace = VK_FRONT_FACE_CLOCKWISE,
1231 .depthBiasEnable = VK_FALSE,
1232 .depthBiasConstantFactor = 0.0f,
1233 .depthBiasClamp = 0.0f,
1234 .depthBiasSlopeFactor = 0.0f,
1235 .lineWidth = 1.0f,
1236 };
1237
1238 const VkPipelineMultisampleStateCreateInfo multisampling_ci{
1239 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
1240 .pNext = nullptr,
1241 .flags = 0,
1242 .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
1243 .sampleShadingEnable = VK_FALSE,
1244 .minSampleShading = 0.0f,
1245 .pSampleMask = nullptr,
1246 .alphaToCoverageEnable = VK_FALSE,
1247 .alphaToOneEnable = VK_FALSE,
1248 };
1249
1250 const VkPipelineColorBlendAttachmentState color_blend_attachment{
1251 .blendEnable = VK_FALSE,
1252 .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
1253 .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
1254 .colorBlendOp = VK_BLEND_OP_ADD,
1255 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
1256 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
1257 .alphaBlendOp = VK_BLEND_OP_ADD,
1258 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
1259 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
1260 };
1261
1262 const VkPipelineColorBlendStateCreateInfo color_blend_ci{
1263 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
1264 .pNext = nullptr,
1265 .flags = 0,
1266 .logicOpEnable = VK_FALSE,
1267 .logicOp = VK_LOGIC_OP_COPY,
1268 .attachmentCount = 1,
1269 .pAttachments = &color_blend_attachment,
1270 .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
1271 };
1272
1273 static constexpr std::array dynamic_states{
1274 VK_DYNAMIC_STATE_VIEWPORT,
1275 VK_DYNAMIC_STATE_SCISSOR,
1276 };
1277 const VkPipelineDynamicStateCreateInfo dynamic_state_ci{
1278 .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
1279 .pNext = nullptr,
1280 .flags = 0,
1281 .dynamicStateCount = static_cast<u32>(dynamic_states.size()),
1282 .pDynamicStates = dynamic_states.data(),
1283 };
1284
1285 const VkGraphicsPipelineCreateInfo fxaa_pipeline_ci{
1286 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
1287 .pNext = nullptr,
1288 .flags = 0,
1289 .stageCount = static_cast<u32>(fxaa_shader_stages.size()),
1290 .pStages = fxaa_shader_stages.data(),
1291 .pVertexInputState = &vertex_input_ci,
1292 .pInputAssemblyState = &input_assembly_ci,
1293 .pTessellationState = nullptr,
1294 .pViewportState = &viewport_state_ci,
1295 .pRasterizationState = &rasterization_ci,
1296 .pMultisampleState = &multisampling_ci,
1297 .pDepthStencilState = nullptr,
1298 .pColorBlendState = &color_blend_ci,
1299 .pDynamicState = &dynamic_state_ci,
1300 .layout = *aa_pipeline_layout,
1301 .renderPass = *aa_renderpass,
1302 .subpass = 0,
1303 .basePipelineHandle = 0,
1304 .basePipelineIndex = 0,
1305 };
1306
1307 // AA
1308 aa_pipeline = device.GetLogical().CreateGraphicsPipeline(fxaa_pipeline_ci);
1309}
1310
1311void BlitScreen::UpdateAADescriptorSet(VkImageView image_view, bool nn) const {
1312 const VkDescriptorImageInfo image_info{
1313 .sampler = nn ? *nn_sampler : *sampler,
1314 .imageView = image_view,
1315 .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
1316 };
1317
1318 const VkWriteDescriptorSet sampler_write{
1319 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
1320 .pNext = nullptr,
1321 .dstSet = aa_descriptor_sets[image_index],
1322 .dstBinding = 0,
1323 .dstArrayElement = 0,
1324 .descriptorCount = 1,
1325 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1326 .pImageInfo = &image_info,
1327 .pBufferInfo = nullptr,
1328 .pTexelBufferView = nullptr,
1329 };
1330
1331 const VkWriteDescriptorSet sampler_write_2{
1332 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
1333 .pNext = nullptr,
1334 .dstSet = aa_descriptor_sets[image_index],
1335 .dstBinding = 1,
1336 .dstArrayElement = 0,
1337 .descriptorCount = 1,
1338 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1339 .pImageInfo = &image_info,
1340 .pBufferInfo = nullptr,
1341 .pTexelBufferView = nullptr,
1342 };
1343
1344 device.GetLogical().UpdateDescriptorSets(std::array{sampler_write, sampler_write_2}, {});
1345} 1001}
1346 1002
1347void BlitScreen::UpdateDescriptorSet(VkImageView image_view, bool nn) const { 1003void BlitScreen::UpdateDescriptorSet(VkImageView image_view, bool nn) const {
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h
index 56ac47f08..d7f8effa2 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.h
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.h
@@ -34,6 +34,7 @@ namespace Vulkan {
34 34
35class Device; 35class Device;
36class FSR; 36class FSR;
37class FXAA;
37class RasterizerVulkan; 38class RasterizerVulkan;
38class Scheduler; 39class Scheduler;
39class SMAA; 40class SMAA;
@@ -96,7 +97,6 @@ private:
96 void CreateRawImages(const Tegra::FramebufferConfig& framebuffer); 97 void CreateRawImages(const Tegra::FramebufferConfig& framebuffer);
97 98
98 void UpdateDescriptorSet(VkImageView image_view, bool nn) const; 99 void UpdateDescriptorSet(VkImageView image_view, bool nn) const;
99 void UpdateAADescriptorSet(VkImageView image_view, bool nn) const;
100 void SetUniformData(BufferData& data, const Layout::FramebufferLayout layout) const; 100 void SetUniformData(BufferData& data, const Layout::FramebufferLayout layout) const;
101 void SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, 101 void SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer,
102 const Layout::FramebufferLayout layout, u32 texture_width, 102 const Layout::FramebufferLayout layout, u32 texture_width,
@@ -119,8 +119,6 @@ private:
119 std::size_t image_index{}; 119 std::size_t image_index{};
120 120
121 vk::ShaderModule vertex_shader; 121 vk::ShaderModule vertex_shader;
122 vk::ShaderModule fxaa_vertex_shader;
123 vk::ShaderModule fxaa_fragment_shader;
124 vk::ShaderModule bilinear_fragment_shader; 122 vk::ShaderModule bilinear_fragment_shader;
125 vk::ShaderModule bicubic_fragment_shader; 123 vk::ShaderModule bicubic_fragment_shader;
126 vk::ShaderModule gaussian_fragment_shader; 124 vk::ShaderModule gaussian_fragment_shader;
@@ -128,7 +126,6 @@ private:
128 vk::DescriptorPool descriptor_pool; 126 vk::DescriptorPool descriptor_pool;
129 vk::DescriptorSetLayout descriptor_set_layout; 127 vk::DescriptorSetLayout descriptor_set_layout;
130 vk::PipelineLayout pipeline_layout; 128 vk::PipelineLayout pipeline_layout;
131 vk::Pipeline nearest_neighbor_pipeline;
132 vk::Pipeline bilinear_pipeline; 129 vk::Pipeline bilinear_pipeline;
133 vk::Pipeline bicubic_pipeline; 130 vk::Pipeline bicubic_pipeline;
134 vk::Pipeline gaussian_pipeline; 131 vk::Pipeline gaussian_pipeline;
@@ -145,16 +142,6 @@ private:
145 std::vector<vk::Image> raw_images; 142 std::vector<vk::Image> raw_images;
146 std::vector<vk::ImageView> raw_image_views; 143 std::vector<vk::ImageView> raw_image_views;
147 144
148 vk::DescriptorPool aa_descriptor_pool;
149 vk::DescriptorSetLayout aa_descriptor_set_layout;
150 vk::PipelineLayout aa_pipeline_layout;
151 vk::Pipeline aa_pipeline;
152 vk::RenderPass aa_renderpass;
153 vk::Framebuffer aa_framebuffer;
154 vk::DescriptorSets aa_descriptor_sets;
155 vk::Image aa_image;
156 vk::ImageView aa_image_view;
157
158 u32 raw_width = 0; 145 u32 raw_width = 0;
159 u32 raw_height = 0; 146 u32 raw_height = 0;
160 Service::android::PixelFormat pixel_format{}; 147 Service::android::PixelFormat pixel_format{};
@@ -163,6 +150,7 @@ private:
163 150
164 std::unique_ptr<FSR> fsr; 151 std::unique_ptr<FSR> fsr;
165 std::unique_ptr<SMAA> smaa; 152 std::unique_ptr<SMAA> smaa;
153 std::unique_ptr<FXAA> fxaa;
166}; 154};
167 155
168} // namespace Vulkan 156} // namespace Vulkan