diff options
| author | 2024-02-02 15:08:06 +0100 | |
|---|---|---|
| committer | 2024-02-02 15:08:06 +0100 | |
| commit | 58cf2ee1f93ebfa0e6b25b71d349ad2ad7895f53 (patch) | |
| tree | a6efdfb4de7a7bac87926f6f1e93e7275634c731 /src/video_core/renderer_vulkan | |
| parent | Merge pull request #12878 from zhaobot/tx-update-20240201020554 (diff) | |
| parent | hardware_composer: implement speed limit extensions (diff) | |
| download | yuzu-58cf2ee1f93ebfa0e6b25b71d349ad2ad7895f53.tar.gz yuzu-58cf2ee1f93ebfa0e6b25b71d349ad2ad7895f53.tar.xz yuzu-58cf2ee1f93ebfa0e6b25b71d349ad2ad7895f53.zip | |
Merge pull request #12761 from liamwhite/mp-composite
video_core: rewrite presentation for layer composition
Diffstat (limited to 'src/video_core/renderer_vulkan')
24 files changed, 1969 insertions, 2490 deletions
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..1f20fbd7f --- /dev/null +++ b/src/video_core/renderer_vulkan/present/anti_alias_pass.h | |||
| @@ -0,0 +1,25 @@ | |||
| 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 | |||
| 8 | namespace Vulkan { | ||
| 9 | |||
| 10 | class Scheduler; | ||
| 11 | |||
| 12 | class AntiAliasPass { | ||
| 13 | public: | ||
| 14 | virtual ~AntiAliasPass() = default; | ||
| 15 | virtual void Draw(Scheduler& scheduler, size_t image_index, VkImage* inout_image, | ||
| 16 | VkImageView* inout_image_view) = 0; | ||
| 17 | }; | ||
| 18 | |||
| 19 | class NoAA final : public AntiAliasPass { | ||
| 20 | public: | ||
| 21 | void Draw(Scheduler& scheduler, size_t image_index, VkImage* inout_image, | ||
| 22 | VkImageView* inout_image_view) override {} | ||
| 23 | }; | ||
| 24 | |||
| 25 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/present/filters.cpp b/src/video_core/renderer_vulkan/present/filters.cpp new file mode 100644 index 000000000..b5e08938e --- /dev/null +++ b/src/video_core/renderer_vulkan/present/filters.cpp | |||
| @@ -0,0 +1,56 @@ | |||
| 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/present_bicubic_frag_spv.h" | ||
| 7 | #include "video_core/host_shaders/present_gaussian_frag_spv.h" | ||
| 8 | #include "video_core/host_shaders/vulkan_present_frag_spv.h" | ||
| 9 | #include "video_core/host_shaders/vulkan_present_scaleforce_fp16_frag_spv.h" | ||
| 10 | #include "video_core/host_shaders/vulkan_present_scaleforce_fp32_frag_spv.h" | ||
| 11 | #include "video_core/renderer_vulkan/present/filters.h" | ||
| 12 | #include "video_core/renderer_vulkan/present/util.h" | ||
| 13 | #include "video_core/renderer_vulkan/vk_shader_util.h" | ||
| 14 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 15 | |||
| 16 | namespace Vulkan { | ||
| 17 | |||
| 18 | namespace { | ||
| 19 | |||
| 20 | vk::ShaderModule SelectScaleForceShader(const Device& device) { | ||
| 21 | if (device.IsFloat16Supported()) { | ||
| 22 | return BuildShader(device, VULKAN_PRESENT_SCALEFORCE_FP16_FRAG_SPV); | ||
| 23 | } else { | ||
| 24 | return BuildShader(device, VULKAN_PRESENT_SCALEFORCE_FP32_FRAG_SPV); | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | } // Anonymous namespace | ||
| 29 | |||
| 30 | std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device, VkFormat frame_format) { | ||
| 31 | return std::make_unique<WindowAdaptPass>(device, frame_format, | ||
| 32 | CreateNearestNeighborSampler(device), | ||
| 33 | BuildShader(device, VULKAN_PRESENT_FRAG_SPV)); | ||
| 34 | } | ||
| 35 | |||
| 36 | std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device, VkFormat frame_format) { | ||
| 37 | return std::make_unique<WindowAdaptPass>(device, frame_format, CreateBilinearSampler(device), | ||
| 38 | BuildShader(device, VULKAN_PRESENT_FRAG_SPV)); | ||
| 39 | } | ||
| 40 | |||
| 41 | std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device, VkFormat frame_format) { | ||
| 42 | return std::make_unique<WindowAdaptPass>(device, frame_format, CreateBilinearSampler(device), | ||
| 43 | BuildShader(device, PRESENT_BICUBIC_FRAG_SPV)); | ||
| 44 | } | ||
| 45 | |||
| 46 | std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device, VkFormat frame_format) { | ||
| 47 | return std::make_unique<WindowAdaptPass>(device, frame_format, CreateBilinearSampler(device), | ||
| 48 | BuildShader(device, PRESENT_GAUSSIAN_FRAG_SPV)); | ||
| 49 | } | ||
| 50 | |||
| 51 | std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device, VkFormat frame_format) { | ||
| 52 | return std::make_unique<WindowAdaptPass>(device, frame_format, CreateBilinearSampler(device), | ||
| 53 | SelectScaleForceShader(device)); | ||
| 54 | } | ||
| 55 | |||
| 56 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/present/filters.h b/src/video_core/renderer_vulkan/present/filters.h new file mode 100644 index 000000000..6c83726dd --- /dev/null +++ b/src/video_core/renderer_vulkan/present/filters.h | |||
| @@ -0,0 +1,18 @@ | |||
| 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/window_adapt_pass.h" | ||
| 7 | |||
| 8 | namespace Vulkan { | ||
| 9 | |||
| 10 | class MemoryAllocator; | ||
| 11 | |||
| 12 | std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device, VkFormat frame_format); | ||
| 13 | std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device, VkFormat frame_format); | ||
| 14 | std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device, VkFormat frame_format); | ||
| 15 | std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device, VkFormat frame_format); | ||
| 16 | std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device, VkFormat frame_format); | ||
| 17 | |||
| 18 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/present/fsr.cpp b/src/video_core/renderer_vulkan/present/fsr.cpp new file mode 100644 index 000000000..3f708be70 --- /dev/null +++ b/src/video_core/renderer_vulkan/present/fsr.cpp | |||
| @@ -0,0 +1,226 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/common_types.h" | ||
| 5 | #include "common/div_ceil.h" | ||
| 6 | #include "common/settings.h" | ||
| 7 | |||
| 8 | #include "video_core/fsr.h" | ||
| 9 | #include "video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp16_frag_spv.h" | ||
| 10 | #include "video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp32_frag_spv.h" | ||
| 11 | #include "video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp16_frag_spv.h" | ||
| 12 | #include "video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp32_frag_spv.h" | ||
| 13 | #include "video_core/host_shaders/vulkan_fidelityfx_fsr_vert_spv.h" | ||
| 14 | #include "video_core/renderer_vulkan/present/fsr.h" | ||
| 15 | #include "video_core/renderer_vulkan/present/util.h" | ||
| 16 | #include "video_core/renderer_vulkan/vk_scheduler.h" | ||
| 17 | #include "video_core/renderer_vulkan/vk_shader_util.h" | ||
| 18 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 19 | |||
| 20 | namespace Vulkan { | ||
| 21 | using namespace FSR; | ||
| 22 | |||
| 23 | using PushConstants = std::array<u32, 4 * 4>; | ||
| 24 | |||
| 25 | FSR::FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count, | ||
| 26 | VkExtent2D extent) | ||
| 27 | : m_device{device}, m_memory_allocator{memory_allocator}, | ||
| 28 | m_image_count{image_count}, m_extent{extent} { | ||
| 29 | |||
| 30 | CreateImages(); | ||
| 31 | CreateRenderPasses(); | ||
| 32 | CreateSampler(); | ||
| 33 | CreateShaders(); | ||
| 34 | CreateDescriptorPool(); | ||
| 35 | CreateDescriptorSetLayout(); | ||
| 36 | CreateDescriptorSets(); | ||
| 37 | CreatePipelineLayouts(); | ||
| 38 | CreatePipelines(); | ||
| 39 | } | ||
| 40 | |||
| 41 | void FSR::CreateImages() { | ||
| 42 | m_dynamic_images.resize(m_image_count); | ||
| 43 | for (auto& images : m_dynamic_images) { | ||
| 44 | images.images[Easu] = | ||
| 45 | CreateWrappedImage(m_memory_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT); | ||
| 46 | images.images[Rcas] = | ||
| 47 | CreateWrappedImage(m_memory_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT); | ||
| 48 | images.image_views[Easu] = | ||
| 49 | CreateWrappedImageView(m_device, images.images[Easu], VK_FORMAT_R16G16B16A16_SFLOAT); | ||
| 50 | images.image_views[Rcas] = | ||
| 51 | CreateWrappedImageView(m_device, images.images[Rcas], VK_FORMAT_R16G16B16A16_SFLOAT); | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | void FSR::CreateRenderPasses() { | ||
| 56 | m_renderpass = CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16B16A16_SFLOAT); | ||
| 57 | |||
| 58 | for (auto& images : m_dynamic_images) { | ||
| 59 | images.framebuffers[Easu] = | ||
| 60 | CreateWrappedFramebuffer(m_device, m_renderpass, images.image_views[Easu], m_extent); | ||
| 61 | images.framebuffers[Rcas] = | ||
| 62 | CreateWrappedFramebuffer(m_device, m_renderpass, images.image_views[Rcas], m_extent); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | void FSR::CreateSampler() { | ||
| 67 | m_sampler = CreateBilinearSampler(m_device); | ||
| 68 | } | ||
| 69 | |||
| 70 | void FSR::CreateShaders() { | ||
| 71 | m_vert_shader = BuildShader(m_device, VULKAN_FIDELITYFX_FSR_VERT_SPV); | ||
| 72 | |||
| 73 | if (m_device.IsFloat16Supported()) { | ||
| 74 | m_easu_shader = BuildShader(m_device, VULKAN_FIDELITYFX_FSR_EASU_FP16_FRAG_SPV); | ||
| 75 | m_rcas_shader = BuildShader(m_device, VULKAN_FIDELITYFX_FSR_RCAS_FP16_FRAG_SPV); | ||
| 76 | } else { | ||
| 77 | m_easu_shader = BuildShader(m_device, VULKAN_FIDELITYFX_FSR_EASU_FP32_FRAG_SPV); | ||
| 78 | m_rcas_shader = BuildShader(m_device, VULKAN_FIDELITYFX_FSR_RCAS_FP32_FRAG_SPV); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | void FSR::CreateDescriptorPool() { | ||
| 83 | // EASU: 1 descriptor | ||
| 84 | // RCAS: 1 descriptor | ||
| 85 | // 2 descriptors, 2 descriptor sets per invocation | ||
| 86 | m_descriptor_pool = CreateWrappedDescriptorPool(m_device, 2 * m_image_count, 2 * m_image_count); | ||
| 87 | } | ||
| 88 | |||
| 89 | void FSR::CreateDescriptorSetLayout() { | ||
| 90 | m_descriptor_set_layout = | ||
| 91 | CreateWrappedDescriptorSetLayout(m_device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER}); | ||
| 92 | } | ||
| 93 | |||
| 94 | void FSR::CreateDescriptorSets() { | ||
| 95 | std::vector<VkDescriptorSetLayout> layouts(MaxFsrStage, *m_descriptor_set_layout); | ||
| 96 | |||
| 97 | for (auto& images : m_dynamic_images) { | ||
| 98 | images.descriptor_sets = CreateWrappedDescriptorSets(m_descriptor_pool, layouts); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | void FSR::CreatePipelineLayouts() { | ||
| 103 | const VkPushConstantRange range{ | ||
| 104 | .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 105 | .offset = 0, | ||
| 106 | .size = sizeof(PushConstants), | ||
| 107 | }; | ||
| 108 | VkPipelineLayoutCreateInfo ci{ | ||
| 109 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | ||
| 110 | .pNext = nullptr, | ||
| 111 | .flags = 0, | ||
| 112 | .setLayoutCount = 1, | ||
| 113 | .pSetLayouts = m_descriptor_set_layout.address(), | ||
| 114 | .pushConstantRangeCount = 1, | ||
| 115 | .pPushConstantRanges = &range, | ||
| 116 | }; | ||
| 117 | |||
| 118 | m_pipeline_layout = m_device.GetLogical().CreatePipelineLayout(ci); | ||
| 119 | } | ||
| 120 | |||
| 121 | void FSR::CreatePipelines() { | ||
| 122 | m_easu_pipeline = CreateWrappedPipeline(m_device, m_renderpass, m_pipeline_layout, | ||
| 123 | std::tie(m_vert_shader, m_easu_shader)); | ||
| 124 | m_rcas_pipeline = CreateWrappedPipeline(m_device, m_renderpass, m_pipeline_layout, | ||
| 125 | std::tie(m_vert_shader, m_rcas_shader)); | ||
| 126 | } | ||
| 127 | |||
| 128 | void FSR::UpdateDescriptorSets(VkImageView image_view, size_t image_index) { | ||
| 129 | Images& images = m_dynamic_images[image_index]; | ||
| 130 | std::vector<VkDescriptorImageInfo> image_infos; | ||
| 131 | std::vector<VkWriteDescriptorSet> updates; | ||
| 132 | image_infos.reserve(2); | ||
| 133 | |||
| 134 | updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, image_view, | ||
| 135 | images.descriptor_sets[Easu], 0)); | ||
| 136 | updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *images.image_views[Easu], | ||
| 137 | images.descriptor_sets[Rcas], 0)); | ||
| 138 | |||
| 139 | m_device.GetLogical().UpdateDescriptorSets(updates, {}); | ||
| 140 | } | ||
| 141 | |||
| 142 | void FSR::UploadImages(Scheduler& scheduler) { | ||
| 143 | if (m_images_ready) { | ||
| 144 | return; | ||
| 145 | } | ||
| 146 | |||
| 147 | scheduler.Record([&](vk::CommandBuffer cmdbuf) { | ||
| 148 | for (auto& image : m_dynamic_images) { | ||
| 149 | ClearColorImage(cmdbuf, *image.images[Easu]); | ||
| 150 | ClearColorImage(cmdbuf, *image.images[Rcas]); | ||
| 151 | } | ||
| 152 | }); | ||
| 153 | scheduler.Finish(); | ||
| 154 | |||
| 155 | m_images_ready = true; | ||
| 156 | } | ||
| 157 | |||
| 158 | VkImageView FSR::Draw(Scheduler& scheduler, size_t image_index, VkImage source_image, | ||
| 159 | VkImageView source_image_view, VkExtent2D input_image_extent, | ||
| 160 | const Common::Rectangle<f32>& crop_rect) { | ||
| 161 | Images& images = m_dynamic_images[image_index]; | ||
| 162 | |||
| 163 | VkImage easu_image = *images.images[Easu]; | ||
| 164 | VkImage rcas_image = *images.images[Rcas]; | ||
| 165 | VkDescriptorSet easu_descriptor_set = images.descriptor_sets[Easu]; | ||
| 166 | VkDescriptorSet rcas_descriptor_set = images.descriptor_sets[Rcas]; | ||
| 167 | VkFramebuffer easu_framebuffer = *images.framebuffers[Easu]; | ||
| 168 | VkFramebuffer rcas_framebuffer = *images.framebuffers[Rcas]; | ||
| 169 | VkPipeline easu_pipeline = *m_easu_pipeline; | ||
| 170 | VkPipeline rcas_pipeline = *m_rcas_pipeline; | ||
| 171 | VkPipelineLayout pipeline_layout = *m_pipeline_layout; | ||
| 172 | VkRenderPass renderpass = *m_renderpass; | ||
| 173 | VkExtent2D extent = m_extent; | ||
| 174 | |||
| 175 | const f32 input_image_width = static_cast<f32>(input_image_extent.width); | ||
| 176 | const f32 input_image_height = static_cast<f32>(input_image_extent.height); | ||
| 177 | const f32 output_image_width = static_cast<f32>(extent.width); | ||
| 178 | const f32 output_image_height = static_cast<f32>(extent.height); | ||
| 179 | const f32 viewport_width = (crop_rect.right - crop_rect.left) * input_image_width; | ||
| 180 | const f32 viewport_x = crop_rect.left * input_image_width; | ||
| 181 | const f32 viewport_height = (crop_rect.bottom - crop_rect.top) * input_image_height; | ||
| 182 | const f32 viewport_y = crop_rect.top * input_image_height; | ||
| 183 | |||
| 184 | PushConstants easu_con{}; | ||
| 185 | PushConstants rcas_con{}; | ||
| 186 | FsrEasuConOffset(easu_con.data() + 0, easu_con.data() + 4, easu_con.data() + 8, | ||
| 187 | easu_con.data() + 12, viewport_width, viewport_height, input_image_width, | ||
| 188 | input_image_height, output_image_width, output_image_height, viewport_x, | ||
| 189 | viewport_y); | ||
| 190 | |||
| 191 | const float sharpening = | ||
| 192 | static_cast<float>(Settings::values.fsr_sharpening_slider.GetValue()) / 100.0f; | ||
| 193 | FsrRcasCon(rcas_con.data(), sharpening); | ||
| 194 | |||
| 195 | UploadImages(scheduler); | ||
| 196 | UpdateDescriptorSets(source_image_view, image_index); | ||
| 197 | |||
| 198 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 199 | scheduler.Record([=](vk::CommandBuffer cmdbuf) { | ||
| 200 | TransitionImageLayout(cmdbuf, source_image, VK_IMAGE_LAYOUT_GENERAL); | ||
| 201 | TransitionImageLayout(cmdbuf, easu_image, VK_IMAGE_LAYOUT_GENERAL); | ||
| 202 | BeginRenderPass(cmdbuf, renderpass, easu_framebuffer, extent); | ||
| 203 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, easu_pipeline); | ||
| 204 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, | ||
| 205 | easu_descriptor_set, {}); | ||
| 206 | cmdbuf.PushConstants(pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, easu_con); | ||
| 207 | cmdbuf.Draw(3, 1, 0, 0); | ||
| 208 | cmdbuf.EndRenderPass(); | ||
| 209 | |||
| 210 | TransitionImageLayout(cmdbuf, easu_image, VK_IMAGE_LAYOUT_GENERAL); | ||
| 211 | TransitionImageLayout(cmdbuf, rcas_image, VK_IMAGE_LAYOUT_GENERAL); | ||
| 212 | BeginRenderPass(cmdbuf, renderpass, rcas_framebuffer, extent); | ||
| 213 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, rcas_pipeline); | ||
| 214 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, | ||
| 215 | rcas_descriptor_set, {}); | ||
| 216 | cmdbuf.PushConstants(pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, rcas_con); | ||
| 217 | cmdbuf.Draw(3, 1, 0, 0); | ||
| 218 | cmdbuf.EndRenderPass(); | ||
| 219 | |||
| 220 | TransitionImageLayout(cmdbuf, rcas_image, VK_IMAGE_LAYOUT_GENERAL); | ||
| 221 | }); | ||
| 222 | |||
| 223 | return *images.image_views[Rcas]; | ||
| 224 | } | ||
| 225 | |||
| 226 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/present/fsr.h b/src/video_core/renderer_vulkan/present/fsr.h new file mode 100644 index 000000000..8602e8146 --- /dev/null +++ b/src/video_core/renderer_vulkan/present/fsr.h | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/math_util.h" | ||
| 7 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 8 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 9 | |||
| 10 | namespace Vulkan { | ||
| 11 | |||
| 12 | class Device; | ||
| 13 | class Scheduler; | ||
| 14 | |||
| 15 | class FSR { | ||
| 16 | public: | ||
| 17 | explicit FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count, | ||
| 18 | VkExtent2D extent); | ||
| 19 | VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImage source_image, | ||
| 20 | VkImageView source_image_view, VkExtent2D input_image_extent, | ||
| 21 | const Common::Rectangle<f32>& crop_rect); | ||
| 22 | |||
| 23 | private: | ||
| 24 | void CreateImages(); | ||
| 25 | void CreateRenderPasses(); | ||
| 26 | void CreateSampler(); | ||
| 27 | void CreateShaders(); | ||
| 28 | void CreateDescriptorPool(); | ||
| 29 | void CreateDescriptorSetLayout(); | ||
| 30 | void CreateDescriptorSets(); | ||
| 31 | void CreatePipelineLayouts(); | ||
| 32 | void CreatePipelines(); | ||
| 33 | |||
| 34 | void UploadImages(Scheduler& scheduler); | ||
| 35 | void UpdateDescriptorSets(VkImageView image_view, size_t image_index); | ||
| 36 | |||
| 37 | const Device& m_device; | ||
| 38 | MemoryAllocator& m_memory_allocator; | ||
| 39 | const size_t m_image_count; | ||
| 40 | const VkExtent2D m_extent; | ||
| 41 | |||
| 42 | enum FsrStage { | ||
| 43 | Easu, | ||
| 44 | Rcas, | ||
| 45 | MaxFsrStage, | ||
| 46 | }; | ||
| 47 | |||
| 48 | vk::DescriptorPool m_descriptor_pool; | ||
| 49 | vk::DescriptorSetLayout m_descriptor_set_layout; | ||
| 50 | vk::PipelineLayout m_pipeline_layout; | ||
| 51 | vk::ShaderModule m_vert_shader; | ||
| 52 | vk::ShaderModule m_easu_shader; | ||
| 53 | vk::ShaderModule m_rcas_shader; | ||
| 54 | vk::Pipeline m_easu_pipeline; | ||
| 55 | vk::Pipeline m_rcas_pipeline; | ||
| 56 | vk::RenderPass m_renderpass; | ||
| 57 | vk::Sampler m_sampler; | ||
| 58 | |||
| 59 | struct Images { | ||
| 60 | vk::DescriptorSets descriptor_sets; | ||
| 61 | std::array<vk::Image, MaxFsrStage> images; | ||
| 62 | std::array<vk::ImageView, MaxFsrStage> image_views; | ||
| 63 | std::array<vk::Framebuffer, MaxFsrStage> framebuffers; | ||
| 64 | }; | ||
| 65 | std::vector<Images> m_dynamic_images; | ||
| 66 | bool m_images_ready{}; | ||
| 67 | }; | ||
| 68 | |||
| 69 | } // namespace Vulkan | ||
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..bdafd1f4d --- /dev/null +++ b/src/video_core/renderer_vulkan/present/fxaa.cpp | |||
| @@ -0,0 +1,148 @@ | |||
| 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 | |||
| 14 | namespace Vulkan { | ||
| 15 | |||
| 16 | FXAA::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 | |||
| 30 | FXAA::~FXAA() = default; | ||
| 31 | |||
| 32 | void 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 | |||
| 42 | void 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 | |||
| 51 | void FXAA::CreateSampler() { | ||
| 52 | m_sampler = CreateWrappedSampler(m_device); | ||
| 53 | } | ||
| 54 | |||
| 55 | void FXAA::CreateShaders() { | ||
| 56 | m_vertex_shader = CreateWrappedShaderModule(m_device, FXAA_VERT_SPV); | ||
| 57 | m_fragment_shader = CreateWrappedShaderModule(m_device, FXAA_FRAG_SPV); | ||
| 58 | } | ||
| 59 | |||
| 60 | void 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 | |||
| 65 | void FXAA::CreateDescriptorSetLayouts() { | ||
| 66 | m_descriptor_set_layout = | ||
| 67 | CreateWrappedDescriptorSetLayout(m_device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 68 | VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER}); | ||
| 69 | } | ||
| 70 | |||
| 71 | void FXAA::CreateDescriptorSets() { | ||
| 72 | VkDescriptorSetLayout layout = *m_descriptor_set_layout; | ||
| 73 | |||
| 74 | for (auto& images : m_dynamic_images) { | ||
| 75 | images.descriptor_sets = CreateWrappedDescriptorSets(m_descriptor_pool, {layout}); | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | void FXAA::CreatePipelineLayouts() { | ||
| 80 | m_pipeline_layout = CreateWrappedPipelineLayout(m_device, m_descriptor_set_layout); | ||
| 81 | } | ||
| 82 | |||
| 83 | void FXAA::CreatePipelines() { | ||
| 84 | m_pipeline = CreateWrappedPipeline(m_device, m_renderpass, m_pipeline_layout, | ||
| 85 | std::tie(m_vertex_shader, m_fragment_shader)); | ||
| 86 | } | ||
| 87 | |||
| 88 | void FXAA::UpdateDescriptorSets(VkImageView image_view, size_t image_index) { | ||
| 89 | Image& image = m_dynamic_images[image_index]; | ||
| 90 | std::vector<VkDescriptorImageInfo> image_infos; | ||
| 91 | std::vector<VkWriteDescriptorSet> updates; | ||
| 92 | image_infos.reserve(2); | ||
| 93 | |||
| 94 | updates.push_back( | ||
| 95 | CreateWriteDescriptorSet(image_infos, *m_sampler, image_view, image.descriptor_sets[0], 0)); | ||
| 96 | updates.push_back( | ||
| 97 | CreateWriteDescriptorSet(image_infos, *m_sampler, image_view, image.descriptor_sets[0], 1)); | ||
| 98 | |||
| 99 | m_device.GetLogical().UpdateDescriptorSets(updates, {}); | ||
| 100 | } | ||
| 101 | |||
| 102 | void FXAA::UploadImages(Scheduler& scheduler) { | ||
| 103 | if (m_images_ready) { | ||
| 104 | return; | ||
| 105 | } | ||
| 106 | |||
| 107 | scheduler.Record([&](vk::CommandBuffer cmdbuf) { | ||
| 108 | for (auto& image : m_dynamic_images) { | ||
| 109 | ClearColorImage(cmdbuf, *image.image); | ||
| 110 | } | ||
| 111 | }); | ||
| 112 | scheduler.Finish(); | ||
| 113 | |||
| 114 | m_images_ready = true; | ||
| 115 | } | ||
| 116 | |||
| 117 | void FXAA::Draw(Scheduler& scheduler, size_t image_index, VkImage* inout_image, | ||
| 118 | VkImageView* inout_image_view) { | ||
| 119 | const Image& image{m_dynamic_images[image_index]}; | ||
| 120 | const VkImage input_image{*inout_image}; | ||
| 121 | const VkImage output_image{*image.image}; | ||
| 122 | const VkDescriptorSet descriptor_set{image.descriptor_sets[0]}; | ||
| 123 | const VkFramebuffer framebuffer{*image.framebuffer}; | ||
| 124 | const VkRenderPass renderpass{*m_renderpass}; | ||
| 125 | const VkPipeline pipeline{*m_pipeline}; | ||
| 126 | const VkPipelineLayout layout{*m_pipeline_layout}; | ||
| 127 | const VkExtent2D extent{m_extent}; | ||
| 128 | |||
| 129 | UploadImages(scheduler); | ||
| 130 | UpdateDescriptorSets(*inout_image_view, image_index); | ||
| 131 | |||
| 132 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 133 | scheduler.Record([=](vk::CommandBuffer cmdbuf) { | ||
| 134 | TransitionImageLayout(cmdbuf, input_image, VK_IMAGE_LAYOUT_GENERAL); | ||
| 135 | TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL); | ||
| 136 | BeginRenderPass(cmdbuf, renderpass, framebuffer, extent); | ||
| 137 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); | ||
| 138 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, {}); | ||
| 139 | cmdbuf.Draw(3, 1, 0, 0); | ||
| 140 | cmdbuf.EndRenderPass(); | ||
| 141 | TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL); | ||
| 142 | }); | ||
| 143 | |||
| 144 | *inout_image = *image.image; | ||
| 145 | *inout_image_view = *image.image_view; | ||
| 146 | } | ||
| 147 | |||
| 148 | } // 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..97a2e5c1c --- /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 | |||
| 10 | namespace Vulkan { | ||
| 11 | |||
| 12 | class Device; | ||
| 13 | class Scheduler; | ||
| 14 | class StagingBufferPool; | ||
| 15 | |||
| 16 | class FXAA final : public AntiAliasPass { | ||
| 17 | public: | ||
| 18 | explicit FXAA(const Device& device, MemoryAllocator& allocator, size_t image_count, | ||
| 19 | VkExtent2D extent); | ||
| 20 | ~FXAA() override; | ||
| 21 | |||
| 22 | void Draw(Scheduler& scheduler, size_t image_index, VkImage* inout_image, | ||
| 23 | VkImageView* inout_image_view) override; | ||
| 24 | |||
| 25 | private: | ||
| 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/layer.cpp b/src/video_core/renderer_vulkan/present/layer.cpp new file mode 100644 index 000000000..cfc04be44 --- /dev/null +++ b/src/video_core/renderer_vulkan/present/layer.cpp | |||
| @@ -0,0 +1,336 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | ||
| 5 | |||
| 6 | #include "common/settings.h" | ||
| 7 | #include "video_core/framebuffer_config.h" | ||
| 8 | #include "video_core/renderer_vulkan/present/fsr.h" | ||
| 9 | #include "video_core/renderer_vulkan/present/fxaa.h" | ||
| 10 | #include "video_core/renderer_vulkan/present/layer.h" | ||
| 11 | #include "video_core/renderer_vulkan/present/present_push_constants.h" | ||
| 12 | #include "video_core/renderer_vulkan/present/smaa.h" | ||
| 13 | #include "video_core/renderer_vulkan/present/util.h" | ||
| 14 | #include "video_core/renderer_vulkan/vk_blit_screen.h" | ||
| 15 | #include "video_core/textures/decoders.h" | ||
| 16 | |||
| 17 | namespace Vulkan { | ||
| 18 | |||
| 19 | namespace { | ||
| 20 | |||
| 21 | u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) { | ||
| 22 | using namespace VideoCore::Surface; | ||
| 23 | return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)); | ||
| 24 | } | ||
| 25 | |||
| 26 | std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) { | ||
| 27 | return static_cast<std::size_t>(framebuffer.stride) * | ||
| 28 | static_cast<std::size_t>(framebuffer.height) * GetBytesPerPixel(framebuffer); | ||
| 29 | } | ||
| 30 | |||
| 31 | VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) { | ||
| 32 | switch (framebuffer.pixel_format) { | ||
| 33 | case Service::android::PixelFormat::Rgba8888: | ||
| 34 | case Service::android::PixelFormat::Rgbx8888: | ||
| 35 | return VK_FORMAT_A8B8G8R8_UNORM_PACK32; | ||
| 36 | case Service::android::PixelFormat::Rgb565: | ||
| 37 | return VK_FORMAT_R5G6B5_UNORM_PACK16; | ||
| 38 | case Service::android::PixelFormat::Bgra8888: | ||
| 39 | return VK_FORMAT_B8G8R8A8_UNORM; | ||
| 40 | default: | ||
| 41 | UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", | ||
| 42 | static_cast<u32>(framebuffer.pixel_format)); | ||
| 43 | return VK_FORMAT_A8B8G8R8_UNORM_PACK32; | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | } // Anonymous namespace | ||
| 48 | |||
| 49 | Layer::Layer(const Device& device_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_, | ||
| 50 | Tegra::MaxwellDeviceMemoryManager& device_memory_, size_t image_count_, | ||
| 51 | VkExtent2D output_size, VkDescriptorSetLayout layout) | ||
| 52 | : device(device_), memory_allocator(memory_allocator_), scheduler(scheduler_), | ||
| 53 | device_memory(device_memory_), image_count(image_count_) { | ||
| 54 | CreateDescriptorPool(); | ||
| 55 | CreateDescriptorSets(layout); | ||
| 56 | if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { | ||
| 57 | CreateFSR(output_size); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | Layer::~Layer() { | ||
| 62 | ReleaseRawImages(); | ||
| 63 | } | ||
| 64 | |||
| 65 | void Layer::ConfigureDraw(PresentPushConstants* out_push_constants, | ||
| 66 | VkDescriptorSet* out_descriptor_set, RasterizerVulkan& rasterizer, | ||
| 67 | VkSampler sampler, size_t image_index, | ||
| 68 | const Tegra::FramebufferConfig& framebuffer, | ||
| 69 | const Layout::FramebufferLayout& layout) { | ||
| 70 | const auto texture_info = rasterizer.AccelerateDisplay( | ||
| 71 | framebuffer, framebuffer.address + framebuffer.offset, framebuffer.stride); | ||
| 72 | const u32 texture_width = texture_info ? texture_info->width : framebuffer.width; | ||
| 73 | const u32 texture_height = texture_info ? texture_info->height : framebuffer.height; | ||
| 74 | const u32 scaled_width = texture_info ? texture_info->scaled_width : texture_width; | ||
| 75 | const u32 scaled_height = texture_info ? texture_info->scaled_height : texture_height; | ||
| 76 | const bool use_accelerated = texture_info.has_value(); | ||
| 77 | |||
| 78 | RefreshResources(framebuffer); | ||
| 79 | SetAntiAliasPass(); | ||
| 80 | |||
| 81 | // Finish any pending renderpass | ||
| 82 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 83 | scheduler.Wait(resource_ticks[image_index]); | ||
| 84 | SCOPE_EXIT({ resource_ticks[image_index] = scheduler.CurrentTick(); }); | ||
| 85 | |||
| 86 | if (!use_accelerated) { | ||
| 87 | UpdateRawImage(framebuffer, image_index); | ||
| 88 | } | ||
| 89 | |||
| 90 | VkImage source_image = texture_info ? texture_info->image : *raw_images[image_index]; | ||
| 91 | VkImageView source_image_view = | ||
| 92 | texture_info ? texture_info->image_view : *raw_image_views[image_index]; | ||
| 93 | |||
| 94 | anti_alias->Draw(scheduler, image_index, &source_image, &source_image_view); | ||
| 95 | |||
| 96 | auto crop_rect = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height); | ||
| 97 | const VkExtent2D render_extent{ | ||
| 98 | .width = scaled_width, | ||
| 99 | .height = scaled_height, | ||
| 100 | }; | ||
| 101 | |||
| 102 | if (fsr) { | ||
| 103 | source_image_view = fsr->Draw(scheduler, image_index, source_image, source_image_view, | ||
| 104 | render_extent, crop_rect); | ||
| 105 | crop_rect = {0, 0, 1, 1}; | ||
| 106 | } | ||
| 107 | |||
| 108 | SetMatrixData(*out_push_constants, layout); | ||
| 109 | SetVertexData(*out_push_constants, layout, crop_rect); | ||
| 110 | |||
| 111 | UpdateDescriptorSet(source_image_view, sampler, image_index); | ||
| 112 | *out_descriptor_set = descriptor_sets[image_index]; | ||
| 113 | } | ||
| 114 | |||
| 115 | void Layer::CreateDescriptorPool() { | ||
| 116 | descriptor_pool = CreateWrappedDescriptorPool(device, image_count, image_count); | ||
| 117 | } | ||
| 118 | |||
| 119 | void Layer::CreateDescriptorSets(VkDescriptorSetLayout layout) { | ||
| 120 | const std::vector layouts(image_count, layout); | ||
| 121 | descriptor_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts); | ||
| 122 | } | ||
| 123 | |||
| 124 | void Layer::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { | ||
| 125 | const VkBufferCreateInfo ci{ | ||
| 126 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | ||
| 127 | .pNext = nullptr, | ||
| 128 | .flags = 0, | ||
| 129 | .size = CalculateBufferSize(framebuffer), | ||
| 130 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | | ||
| 131 | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, | ||
| 132 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 133 | .queueFamilyIndexCount = 0, | ||
| 134 | .pQueueFamilyIndices = nullptr, | ||
| 135 | }; | ||
| 136 | |||
| 137 | buffer = memory_allocator.CreateBuffer(ci, MemoryUsage::Upload); | ||
| 138 | } | ||
| 139 | |||
| 140 | void Layer::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | ||
| 141 | const auto format = GetFormat(framebuffer); | ||
| 142 | resource_ticks.resize(image_count); | ||
| 143 | raw_images.resize(image_count); | ||
| 144 | raw_image_views.resize(image_count); | ||
| 145 | |||
| 146 | for (size_t i = 0; i < image_count; ++i) { | ||
| 147 | raw_images[i] = | ||
| 148 | CreateWrappedImage(memory_allocator, {framebuffer.width, framebuffer.height}, format); | ||
| 149 | raw_image_views[i] = CreateWrappedImageView(device, raw_images[i], format); | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | void Layer::CreateFSR(VkExtent2D output_size) { | ||
| 154 | fsr = std::make_unique<FSR>(device, memory_allocator, image_count, output_size); | ||
| 155 | } | ||
| 156 | |||
| 157 | void Layer::RefreshResources(const Tegra::FramebufferConfig& framebuffer) { | ||
| 158 | if (framebuffer.width == raw_width && framebuffer.height == raw_height && | ||
| 159 | framebuffer.pixel_format == pixel_format && !raw_images.empty()) { | ||
| 160 | return; | ||
| 161 | } | ||
| 162 | |||
| 163 | raw_width = framebuffer.width; | ||
| 164 | raw_height = framebuffer.height; | ||
| 165 | pixel_format = framebuffer.pixel_format; | ||
| 166 | anti_alias.reset(); | ||
| 167 | |||
| 168 | ReleaseRawImages(); | ||
| 169 | CreateStagingBuffer(framebuffer); | ||
| 170 | CreateRawImages(framebuffer); | ||
| 171 | } | ||
| 172 | |||
| 173 | void Layer::SetAntiAliasPass() { | ||
| 174 | if (anti_alias && anti_alias_setting == Settings::values.anti_aliasing.GetValue()) { | ||
| 175 | return; | ||
| 176 | } | ||
| 177 | |||
| 178 | anti_alias_setting = Settings::values.anti_aliasing.GetValue(); | ||
| 179 | |||
| 180 | const VkExtent2D render_area{ | ||
| 181 | .width = Settings::values.resolution_info.ScaleUp(raw_width), | ||
| 182 | .height = Settings::values.resolution_info.ScaleUp(raw_height), | ||
| 183 | }; | ||
| 184 | |||
| 185 | switch (anti_alias_setting) { | ||
| 186 | case Settings::AntiAliasing::Fxaa: | ||
| 187 | anti_alias = std::make_unique<FXAA>(device, memory_allocator, image_count, render_area); | ||
| 188 | break; | ||
| 189 | case Settings::AntiAliasing::Smaa: | ||
| 190 | anti_alias = std::make_unique<SMAA>(device, memory_allocator, image_count, render_area); | ||
| 191 | break; | ||
| 192 | default: | ||
| 193 | anti_alias = std::make_unique<NoAA>(); | ||
| 194 | break; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | void Layer::ReleaseRawImages() { | ||
| 199 | for (const u64 tick : resource_ticks) { | ||
| 200 | scheduler.Wait(tick); | ||
| 201 | } | ||
| 202 | raw_images.clear(); | ||
| 203 | buffer.reset(); | ||
| 204 | } | ||
| 205 | |||
| 206 | u64 Layer::CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const { | ||
| 207 | return GetSizeInBytes(framebuffer) * image_count; | ||
| 208 | } | ||
| 209 | |||
| 210 | u64 Layer::GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer, | ||
| 211 | size_t image_index) const { | ||
| 212 | return GetSizeInBytes(framebuffer) * image_index; | ||
| 213 | } | ||
| 214 | |||
| 215 | void Layer::SetMatrixData(PresentPushConstants& data, | ||
| 216 | const Layout::FramebufferLayout& layout) const { | ||
| 217 | data.modelview_matrix = | ||
| 218 | MakeOrthographicMatrix(static_cast<f32>(layout.width), static_cast<f32>(layout.height)); | ||
| 219 | } | ||
| 220 | |||
| 221 | void Layer::SetVertexData(PresentPushConstants& data, const Layout::FramebufferLayout& layout, | ||
| 222 | const Common::Rectangle<f32>& crop) const { | ||
| 223 | // Map the coordinates to the screen. | ||
| 224 | const auto& screen = layout.screen; | ||
| 225 | const auto x = static_cast<f32>(screen.left); | ||
| 226 | const auto y = static_cast<f32>(screen.top); | ||
| 227 | const auto w = static_cast<f32>(screen.GetWidth()); | ||
| 228 | const auto h = static_cast<f32>(screen.GetHeight()); | ||
| 229 | |||
| 230 | data.vertices[0] = ScreenRectVertex(x, y, crop.left, crop.top); | ||
| 231 | data.vertices[1] = ScreenRectVertex(x + w, y, crop.right, crop.top); | ||
| 232 | data.vertices[2] = ScreenRectVertex(x, y + h, crop.left, crop.bottom); | ||
| 233 | data.vertices[3] = ScreenRectVertex(x + w, y + h, crop.right, crop.bottom); | ||
| 234 | } | ||
| 235 | |||
| 236 | void Layer::UpdateDescriptorSet(VkImageView image_view, VkSampler sampler, size_t image_index) { | ||
| 237 | const VkDescriptorImageInfo image_info{ | ||
| 238 | .sampler = sampler, | ||
| 239 | .imageView = image_view, | ||
| 240 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 241 | }; | ||
| 242 | |||
| 243 | const VkWriteDescriptorSet sampler_write{ | ||
| 244 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 245 | .pNext = nullptr, | ||
| 246 | .dstSet = descriptor_sets[image_index], | ||
| 247 | .dstBinding = 0, | ||
| 248 | .dstArrayElement = 0, | ||
| 249 | .descriptorCount = 1, | ||
| 250 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 251 | .pImageInfo = &image_info, | ||
| 252 | .pBufferInfo = nullptr, | ||
| 253 | .pTexelBufferView = nullptr, | ||
| 254 | }; | ||
| 255 | |||
| 256 | device.GetLogical().UpdateDescriptorSets(std::array{sampler_write}, {}); | ||
| 257 | } | ||
| 258 | |||
| 259 | void Layer::UpdateRawImage(const Tegra::FramebufferConfig& framebuffer, size_t image_index) { | ||
| 260 | const std::span<u8> mapped_span = buffer.Mapped(); | ||
| 261 | |||
| 262 | const u64 image_offset = GetRawImageOffset(framebuffer, image_index); | ||
| 263 | |||
| 264 | const DAddr framebuffer_addr = framebuffer.address + framebuffer.offset; | ||
| 265 | const u8* const host_ptr = device_memory.GetPointer<u8>(framebuffer_addr); | ||
| 266 | |||
| 267 | // TODO(Rodrigo): Read this from HLE | ||
| 268 | constexpr u32 block_height_log2 = 4; | ||
| 269 | const u32 bytes_per_pixel = GetBytesPerPixel(framebuffer); | ||
| 270 | const u64 linear_size{GetSizeInBytes(framebuffer)}; | ||
| 271 | const u64 tiled_size{Tegra::Texture::CalculateSize( | ||
| 272 | true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; | ||
| 273 | Tegra::Texture::UnswizzleTexture( | ||
| 274 | mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size), | ||
| 275 | bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); | ||
| 276 | |||
| 277 | const VkBufferImageCopy copy{ | ||
| 278 | .bufferOffset = image_offset, | ||
| 279 | .bufferRowLength = 0, | ||
| 280 | .bufferImageHeight = 0, | ||
| 281 | .imageSubresource = | ||
| 282 | { | ||
| 283 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 284 | .mipLevel = 0, | ||
| 285 | .baseArrayLayer = 0, | ||
| 286 | .layerCount = 1, | ||
| 287 | }, | ||
| 288 | .imageOffset = {.x = 0, .y = 0, .z = 0}, | ||
| 289 | .imageExtent = | ||
| 290 | { | ||
| 291 | .width = framebuffer.width, | ||
| 292 | .height = framebuffer.height, | ||
| 293 | .depth = 1, | ||
| 294 | }, | ||
| 295 | }; | ||
| 296 | scheduler.Record([this, copy, index = image_index](vk::CommandBuffer cmdbuf) { | ||
| 297 | const VkImage image = *raw_images[index]; | ||
| 298 | const VkImageMemoryBarrier base_barrier{ | ||
| 299 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 300 | .pNext = nullptr, | ||
| 301 | .srcAccessMask = 0, | ||
| 302 | .dstAccessMask = 0, | ||
| 303 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 304 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 305 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 306 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 307 | .image = image, | ||
| 308 | .subresourceRange{ | ||
| 309 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 310 | .baseMipLevel = 0, | ||
| 311 | .levelCount = 1, | ||
| 312 | .baseArrayLayer = 0, | ||
| 313 | .layerCount = 1, | ||
| 314 | }, | ||
| 315 | }; | ||
| 316 | VkImageMemoryBarrier read_barrier = base_barrier; | ||
| 317 | read_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | ||
| 318 | read_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||
| 319 | read_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; | ||
| 320 | |||
| 321 | VkImageMemoryBarrier write_barrier = base_barrier; | ||
| 322 | write_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | ||
| 323 | write_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; | ||
| 324 | write_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; | ||
| 325 | |||
| 326 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, | ||
| 327 | read_barrier); | ||
| 328 | cmdbuf.CopyBufferToImage(*buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); | ||
| 329 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 330 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | | ||
| 331 | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | ||
| 332 | 0, write_barrier); | ||
| 333 | }); | ||
| 334 | } | ||
| 335 | |||
| 336 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/present/layer.h b/src/video_core/renderer_vulkan/present/layer.h new file mode 100644 index 000000000..88d43fc5f --- /dev/null +++ b/src/video_core/renderer_vulkan/present/layer.h | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/math_util.h" | ||
| 7 | #include "video_core/host1x/gpu_device_memory_manager.h" | ||
| 8 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 9 | |||
| 10 | namespace Layout { | ||
| 11 | struct FramebufferLayout; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace Tegra { | ||
| 15 | struct FramebufferConfig; | ||
| 16 | } | ||
| 17 | |||
| 18 | namespace Service::android { | ||
| 19 | enum class PixelFormat : u32; | ||
| 20 | } | ||
| 21 | |||
| 22 | namespace Settings { | ||
| 23 | enum class AntiAliasing : u32; | ||
| 24 | } | ||
| 25 | |||
| 26 | namespace Vulkan { | ||
| 27 | |||
| 28 | class AntiAliasPass; | ||
| 29 | class Device; | ||
| 30 | class FSR; | ||
| 31 | class MemoryAllocator; | ||
| 32 | struct PresentPushConstants; | ||
| 33 | class RasterizerVulkan; | ||
| 34 | class Scheduler; | ||
| 35 | |||
| 36 | class Layer final { | ||
| 37 | public: | ||
| 38 | explicit Layer(const Device& device, MemoryAllocator& memory_allocator, Scheduler& scheduler, | ||
| 39 | Tegra::MaxwellDeviceMemoryManager& device_memory, size_t image_count, | ||
| 40 | VkExtent2D output_size, VkDescriptorSetLayout layout); | ||
| 41 | ~Layer(); | ||
| 42 | |||
| 43 | void ConfigureDraw(PresentPushConstants* out_push_constants, | ||
| 44 | VkDescriptorSet* out_descriptor_set, RasterizerVulkan& rasterizer, | ||
| 45 | VkSampler sampler, size_t image_index, | ||
| 46 | const Tegra::FramebufferConfig& framebuffer, | ||
| 47 | const Layout::FramebufferLayout& layout); | ||
| 48 | |||
| 49 | private: | ||
| 50 | void CreateDescriptorPool(); | ||
| 51 | void CreateDescriptorSets(VkDescriptorSetLayout layout); | ||
| 52 | void CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer); | ||
| 53 | void CreateRawImages(const Tegra::FramebufferConfig& framebuffer); | ||
| 54 | void CreateFSR(VkExtent2D output_size); | ||
| 55 | |||
| 56 | void RefreshResources(const Tegra::FramebufferConfig& framebuffer); | ||
| 57 | void SetAntiAliasPass(); | ||
| 58 | void ReleaseRawImages(); | ||
| 59 | |||
| 60 | u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const; | ||
| 61 | u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer, size_t image_index) const; | ||
| 62 | |||
| 63 | void SetMatrixData(PresentPushConstants& data, const Layout::FramebufferLayout& layout) const; | ||
| 64 | void SetVertexData(PresentPushConstants& data, const Layout::FramebufferLayout& layout, | ||
| 65 | const Common::Rectangle<f32>& crop) const; | ||
| 66 | void UpdateDescriptorSet(VkImageView image_view, VkSampler sampler, size_t image_index); | ||
| 67 | void UpdateRawImage(const Tegra::FramebufferConfig& framebuffer, size_t image_index); | ||
| 68 | |||
| 69 | private: | ||
| 70 | const Device& device; | ||
| 71 | MemoryAllocator& memory_allocator; | ||
| 72 | Scheduler& scheduler; | ||
| 73 | Tegra::MaxwellDeviceMemoryManager& device_memory; | ||
| 74 | const size_t image_count{}; | ||
| 75 | vk::DescriptorPool descriptor_pool{}; | ||
| 76 | vk::DescriptorSets descriptor_sets{}; | ||
| 77 | |||
| 78 | vk::Buffer buffer{}; | ||
| 79 | std::vector<vk::Image> raw_images{}; | ||
| 80 | std::vector<vk::ImageView> raw_image_views{}; | ||
| 81 | u32 raw_width{}; | ||
| 82 | u32 raw_height{}; | ||
| 83 | Service::android::PixelFormat pixel_format{}; | ||
| 84 | |||
| 85 | Settings::AntiAliasing anti_alias_setting{}; | ||
| 86 | std::unique_ptr<AntiAliasPass> anti_alias{}; | ||
| 87 | |||
| 88 | std::unique_ptr<FSR> fsr{}; | ||
| 89 | std::vector<u64> resource_ticks{}; | ||
| 90 | }; | ||
| 91 | |||
| 92 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/present/present_push_constants.h b/src/video_core/renderer_vulkan/present/present_push_constants.h new file mode 100644 index 000000000..f1949e7aa --- /dev/null +++ b/src/video_core/renderer_vulkan/present/present_push_constants.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | |||
| 8 | namespace Vulkan { | ||
| 9 | |||
| 10 | struct ScreenRectVertex { | ||
| 11 | ScreenRectVertex() = default; | ||
| 12 | explicit ScreenRectVertex(f32 x, f32 y, f32 u, f32 v) : position{{x, y}}, tex_coord{{u, v}} {} | ||
| 13 | |||
| 14 | std::array<f32, 2> position; | ||
| 15 | std::array<f32, 2> tex_coord; | ||
| 16 | }; | ||
| 17 | |||
| 18 | static inline std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) { | ||
| 19 | // clang-format off | ||
| 20 | return { 2.f / width, 0.f, 0.f, 0.f, | ||
| 21 | 0.f, 2.f / height, 0.f, 0.f, | ||
| 22 | 0.f, 0.f, 1.f, 0.f, | ||
| 23 | -1.f, -1.f, 0.f, 1.f}; | ||
| 24 | // clang-format on | ||
| 25 | } | ||
| 26 | |||
| 27 | struct PresentPushConstants { | ||
| 28 | std::array<f32, 4 * 4> modelview_matrix; | ||
| 29 | std::array<ScreenRectVertex, 4> vertices; | ||
| 30 | }; | ||
| 31 | |||
| 32 | static_assert(sizeof(PresentPushConstants) <= 128, "Push constants are too large"); | ||
| 33 | |||
| 34 | } // 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..39645fd1d --- /dev/null +++ b/src/video_core/renderer_vulkan/present/smaa.cpp | |||
| @@ -0,0 +1,277 @@ | |||
| 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 | |||
| 24 | namespace Vulkan { | ||
| 25 | |||
| 26 | SMAA::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 | |||
| 40 | SMAA::~SMAA() = default; | ||
| 41 | |||
| 42 | void 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 | |||
| 72 | void 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 | |||
| 92 | void SMAA::CreateSampler() { | ||
| 93 | m_sampler = CreateWrappedSampler(m_device); | ||
| 94 | } | ||
| 95 | |||
| 96 | void 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 | |||
| 115 | void 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 | |||
| 124 | void SMAA::CreateDescriptorSetLayouts() { | ||
| 125 | m_descriptor_set_layouts[EdgeDetection] = | ||
| 126 | CreateWrappedDescriptorSetLayout(m_device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER}); | ||
| 127 | m_descriptor_set_layouts[BlendingWeightCalculation] = | ||
| 128 | CreateWrappedDescriptorSetLayout(m_device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 129 | VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 130 | VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER}); | ||
| 131 | m_descriptor_set_layouts[NeighborhoodBlending] = | ||
| 132 | CreateWrappedDescriptorSetLayout(m_device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 133 | VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER}); | ||
| 134 | } | ||
| 135 | |||
| 136 | void SMAA::CreateDescriptorSets() { | ||
| 137 | std::vector<VkDescriptorSetLayout> layouts(m_descriptor_set_layouts.size()); | ||
| 138 | std::ranges::transform(m_descriptor_set_layouts, layouts.begin(), | ||
| 139 | [](auto& layout) { return *layout; }); | ||
| 140 | |||
| 141 | for (auto& images : m_dynamic_images) { | ||
| 142 | images.descriptor_sets = CreateWrappedDescriptorSets(m_descriptor_pool, layouts); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | void SMAA::CreatePipelineLayouts() { | ||
| 147 | for (size_t i = 0; i < MaxSMAAStage; i++) { | ||
| 148 | m_pipeline_layouts[i] = CreateWrappedPipelineLayout(m_device, m_descriptor_set_layouts[i]); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | void SMAA::CreatePipelines() { | ||
| 153 | for (size_t i = 0; i < MaxSMAAStage; i++) { | ||
| 154 | m_pipelines[i] = | ||
| 155 | CreateWrappedPipeline(m_device, m_renderpasses[i], m_pipeline_layouts[i], | ||
| 156 | std::tie(m_vertex_shaders[i], m_fragment_shaders[i])); | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | void SMAA::UpdateDescriptorSets(VkImageView image_view, size_t image_index) { | ||
| 161 | Images& images = m_dynamic_images[image_index]; | ||
| 162 | std::vector<VkDescriptorImageInfo> image_infos; | ||
| 163 | std::vector<VkWriteDescriptorSet> updates; | ||
| 164 | image_infos.reserve(6); | ||
| 165 | |||
| 166 | updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, image_view, | ||
| 167 | images.descriptor_sets[EdgeDetection], 0)); | ||
| 168 | |||
| 169 | updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *images.image_views[Edges], | ||
| 170 | images.descriptor_sets[BlendingWeightCalculation], | ||
| 171 | 0)); | ||
| 172 | updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *m_static_image_views[Area], | ||
| 173 | images.descriptor_sets[BlendingWeightCalculation], | ||
| 174 | 1)); | ||
| 175 | updates.push_back( | ||
| 176 | CreateWriteDescriptorSet(image_infos, *m_sampler, *m_static_image_views[Search], | ||
| 177 | images.descriptor_sets[BlendingWeightCalculation], 2)); | ||
| 178 | |||
| 179 | updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, image_view, | ||
| 180 | images.descriptor_sets[NeighborhoodBlending], 0)); | ||
| 181 | updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *images.image_views[Blend], | ||
| 182 | images.descriptor_sets[NeighborhoodBlending], 1)); | ||
| 183 | |||
| 184 | m_device.GetLogical().UpdateDescriptorSets(updates, {}); | ||
| 185 | } | ||
| 186 | |||
| 187 | void SMAA::UploadImages(Scheduler& scheduler) { | ||
| 188 | if (m_images_ready) { | ||
| 189 | return; | ||
| 190 | } | ||
| 191 | |||
| 192 | static constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT}; | ||
| 193 | static constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT}; | ||
| 194 | |||
| 195 | UploadImage(m_device, m_allocator, scheduler, m_static_images[Area], area_extent, | ||
| 196 | VK_FORMAT_R8G8_UNORM, ARRAY_TO_SPAN(areaTexBytes)); | ||
| 197 | UploadImage(m_device, m_allocator, scheduler, m_static_images[Search], search_extent, | ||
| 198 | VK_FORMAT_R8_UNORM, ARRAY_TO_SPAN(searchTexBytes)); | ||
| 199 | |||
| 200 | scheduler.Record([&](vk::CommandBuffer cmdbuf) { | ||
| 201 | for (auto& images : m_dynamic_images) { | ||
| 202 | for (size_t i = 0; i < MaxDynamicImage; i++) { | ||
| 203 | ClearColorImage(cmdbuf, *images.images[i]); | ||
| 204 | } | ||
| 205 | } | ||
| 206 | }); | ||
| 207 | scheduler.Finish(); | ||
| 208 | |||
| 209 | m_images_ready = true; | ||
| 210 | } | ||
| 211 | |||
| 212 | void SMAA::Draw(Scheduler& scheduler, size_t image_index, VkImage* inout_image, | ||
| 213 | VkImageView* inout_image_view) { | ||
| 214 | Images& images = m_dynamic_images[image_index]; | ||
| 215 | |||
| 216 | VkImage input_image = *inout_image; | ||
| 217 | VkImage output_image = *images.images[Output]; | ||
| 218 | VkImage edges_image = *images.images[Edges]; | ||
| 219 | VkImage blend_image = *images.images[Blend]; | ||
| 220 | |||
| 221 | VkDescriptorSet edge_detection_descriptor_set = images.descriptor_sets[EdgeDetection]; | ||
| 222 | VkDescriptorSet blending_weight_calculation_descriptor_set = | ||
| 223 | images.descriptor_sets[BlendingWeightCalculation]; | ||
| 224 | VkDescriptorSet neighborhood_blending_descriptor_set = | ||
| 225 | images.descriptor_sets[NeighborhoodBlending]; | ||
| 226 | |||
| 227 | VkFramebuffer edge_detection_framebuffer = *images.framebuffers[EdgeDetection]; | ||
| 228 | VkFramebuffer blending_weight_calculation_framebuffer = | ||
| 229 | *images.framebuffers[BlendingWeightCalculation]; | ||
| 230 | VkFramebuffer neighborhood_blending_framebuffer = *images.framebuffers[NeighborhoodBlending]; | ||
| 231 | |||
| 232 | UploadImages(scheduler); | ||
| 233 | UpdateDescriptorSets(*inout_image_view, image_index); | ||
| 234 | |||
| 235 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 236 | scheduler.Record([=, this](vk::CommandBuffer cmdbuf) { | ||
| 237 | TransitionImageLayout(cmdbuf, input_image, VK_IMAGE_LAYOUT_GENERAL); | ||
| 238 | TransitionImageLayout(cmdbuf, edges_image, VK_IMAGE_LAYOUT_GENERAL); | ||
| 239 | BeginRenderPass(cmdbuf, *m_renderpasses[EdgeDetection], edge_detection_framebuffer, | ||
| 240 | m_extent); | ||
| 241 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelines[EdgeDetection]); | ||
| 242 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, | ||
| 243 | *m_pipeline_layouts[EdgeDetection], 0, | ||
| 244 | edge_detection_descriptor_set, {}); | ||
| 245 | cmdbuf.Draw(3, 1, 0, 0); | ||
| 246 | cmdbuf.EndRenderPass(); | ||
| 247 | |||
| 248 | TransitionImageLayout(cmdbuf, edges_image, VK_IMAGE_LAYOUT_GENERAL); | ||
| 249 | TransitionImageLayout(cmdbuf, blend_image, VK_IMAGE_LAYOUT_GENERAL); | ||
| 250 | BeginRenderPass(cmdbuf, *m_renderpasses[BlendingWeightCalculation], | ||
| 251 | blending_weight_calculation_framebuffer, m_extent); | ||
| 252 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, | ||
| 253 | *m_pipelines[BlendingWeightCalculation]); | ||
| 254 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, | ||
| 255 | *m_pipeline_layouts[BlendingWeightCalculation], 0, | ||
| 256 | blending_weight_calculation_descriptor_set, {}); | ||
| 257 | cmdbuf.Draw(3, 1, 0, 0); | ||
| 258 | cmdbuf.EndRenderPass(); | ||
| 259 | |||
| 260 | TransitionImageLayout(cmdbuf, blend_image, VK_IMAGE_LAYOUT_GENERAL); | ||
| 261 | TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL); | ||
| 262 | BeginRenderPass(cmdbuf, *m_renderpasses[NeighborhoodBlending], | ||
| 263 | neighborhood_blending_framebuffer, m_extent); | ||
| 264 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelines[NeighborhoodBlending]); | ||
| 265 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, | ||
| 266 | *m_pipeline_layouts[NeighborhoodBlending], 0, | ||
| 267 | neighborhood_blending_descriptor_set, {}); | ||
| 268 | cmdbuf.Draw(3, 1, 0, 0); | ||
| 269 | cmdbuf.EndRenderPass(); | ||
| 270 | TransitionImageLayout(cmdbuf, output_image, VK_IMAGE_LAYOUT_GENERAL); | ||
| 271 | }); | ||
| 272 | |||
| 273 | *inout_image = *images.images[Output]; | ||
| 274 | *inout_image_view = *images.image_views[Output]; | ||
| 275 | } | ||
| 276 | |||
| 277 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_smaa.h b/src/video_core/renderer_vulkan/present/smaa.h index 0e214258a..fdf6def07 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; | |||
| 13 | class Scheduler; | 14 | class Scheduler; |
| 14 | class StagingBufferPool; | 15 | class StagingBufferPool; |
| 15 | 16 | ||
| 16 | class SMAA { | 17 | class SMAA final : public AntiAliasPass { |
| 17 | public: | 18 | public: |
| 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); |
| 20 | VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImage source_image, | 21 | ~SMAA() override; |
| 21 | VkImageView source_image_view); | 22 | |
| 23 | void Draw(Scheduler& scheduler, size_t image_index, VkImage* inout_image, | ||
| 24 | VkImageView* inout_image_view) override; | ||
| 22 | 25 | ||
| 23 | private: | 26 | private: |
| 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..6ee16595d 100644 --- a/src/video_core/renderer_vulkan/vk_smaa.cpp +++ b/src/video_core/renderer_vulkan/present/util.cpp | |||
| @@ -1,29 +1,25 @@ | |||
| 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 | ||
| 23 | namespace Vulkan { | 8 | namespace Vulkan { |
| 24 | namespace { | ||
| 25 | 9 | ||
| 26 | #define ARRAY_TO_SPAN(a) std::span(a, (sizeof(a) / sizeof(a[0]))) | 10 | vk::Buffer CreateWrappedBuffer(MemoryAllocator& allocator, VkDeviceSize size, MemoryUsage usage) { |
| 11 | const VkBufferCreateInfo dst_buffer_info{ | ||
| 12 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | ||
| 13 | .pNext = nullptr, | ||
| 14 | .flags = 0, | ||
| 15 | .size = size, | ||
| 16 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, | ||
| 17 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 18 | .queueFamilyIndexCount = 0, | ||
| 19 | .pQueueFamilyIndices = nullptr, | ||
| 20 | }; | ||
| 21 | return allocator.CreateBuffer(dst_buffer_info, usage); | ||
| 22 | } | ||
| 27 | 23 | ||
| 28 | vk::Image CreateWrappedImage(MemoryAllocator& allocator, VkExtent2D dimensions, VkFormat format) { | 24 | vk::Image CreateWrappedImage(MemoryAllocator& allocator, VkExtent2D dimensions, VkFormat format) { |
| 29 | const VkImageCreateInfo image_ci{ | 25 | const VkImageCreateInfo image_ci{ |
| @@ -48,7 +44,7 @@ vk::Image CreateWrappedImage(MemoryAllocator& allocator, VkExtent2D dimensions, | |||
| 48 | } | 44 | } |
| 49 | 45 | ||
| 50 | void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout, | 46 | void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout, |
| 51 | VkImageLayout source_layout = VK_IMAGE_LAYOUT_GENERAL) { | 47 | VkImageLayout source_layout) { |
| 52 | constexpr VkFlags flags{VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | | 48 | constexpr VkFlags flags{VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | |
| 53 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT}; | 49 | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT}; |
| 54 | const VkImageMemoryBarrier barrier{ | 50 | const VkImageMemoryBarrier barrier{ |
| @@ -75,7 +71,7 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo | |||
| 75 | 71 | ||
| 76 | void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler, | 72 | void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler, |
| 77 | vk::Image& image, VkExtent2D dimensions, VkFormat format, | 73 | vk::Image& image, VkExtent2D dimensions, VkFormat format, |
| 78 | std::span<const u8> initial_contents = {}) { | 74 | std::span<const u8> initial_contents) { |
| 79 | const VkBufferCreateInfo upload_ci = { | 75 | const VkBufferCreateInfo upload_ci = { |
| 80 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 76 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 81 | .pNext = nullptr, | 77 | .pNext = nullptr, |
| @@ -114,6 +110,70 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc | |||
| 114 | scheduler.Finish(); | 110 | scheduler.Finish(); |
| 115 | } | 111 | } |
| 116 | 112 | ||
| 113 | void DownloadColorImage(vk::CommandBuffer& cmdbuf, VkImage image, VkBuffer buffer, | ||
| 114 | VkExtent3D extent) { | ||
| 115 | const VkImageMemoryBarrier read_barrier{ | ||
| 116 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 117 | .pNext = nullptr, | ||
| 118 | .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 119 | .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, | ||
| 120 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 121 | .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, | ||
| 122 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 123 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 124 | .image = image, | ||
| 125 | .subresourceRange{ | ||
| 126 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 127 | .baseMipLevel = 0, | ||
| 128 | .levelCount = VK_REMAINING_MIP_LEVELS, | ||
| 129 | .baseArrayLayer = 0, | ||
| 130 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 131 | }, | ||
| 132 | }; | ||
| 133 | const VkImageMemoryBarrier image_write_barrier{ | ||
| 134 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 135 | .pNext = nullptr, | ||
| 136 | .srcAccessMask = 0, | ||
| 137 | .dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 138 | .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, | ||
| 139 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 140 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 141 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 142 | .image = image, | ||
| 143 | .subresourceRange{ | ||
| 144 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 145 | .baseMipLevel = 0, | ||
| 146 | .levelCount = VK_REMAINING_MIP_LEVELS, | ||
| 147 | .baseArrayLayer = 0, | ||
| 148 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 149 | }, | ||
| 150 | }; | ||
| 151 | static constexpr VkMemoryBarrier memory_write_barrier{ | ||
| 152 | .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, | ||
| 153 | .pNext = nullptr, | ||
| 154 | .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 155 | .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 156 | }; | ||
| 157 | const VkBufferImageCopy copy{ | ||
| 158 | .bufferOffset = 0, | ||
| 159 | .bufferRowLength = 0, | ||
| 160 | .bufferImageHeight = 0, | ||
| 161 | .imageSubresource{ | ||
| 162 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 163 | .mipLevel = 0, | ||
| 164 | .baseArrayLayer = 0, | ||
| 165 | .layerCount = 1, | ||
| 166 | }, | ||
| 167 | .imageOffset{.x = 0, .y = 0, .z = 0}, | ||
| 168 | .imageExtent{extent}, | ||
| 169 | }; | ||
| 170 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, | ||
| 171 | read_barrier); | ||
| 172 | cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, copy); | ||
| 173 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, | ||
| 174 | memory_write_barrier, nullptr, image_write_barrier); | ||
| 175 | } | ||
| 176 | |||
| 117 | vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format) { | 177 | vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format) { |
| 118 | return device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | 178 | return device.GetLogical().CreateImageView(VkImageViewCreateInfo{ |
| 119 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 179 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| @@ -131,16 +191,18 @@ vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkF | |||
| 131 | }); | 191 | }); |
| 132 | } | 192 | } |
| 133 | 193 | ||
| 134 | vk::RenderPass CreateWrappedRenderPass(const Device& device, VkFormat format) { | 194 | vk::RenderPass CreateWrappedRenderPass(const Device& device, VkFormat format, |
| 195 | VkImageLayout initial_layout) { | ||
| 135 | const VkAttachmentDescription attachment{ | 196 | const VkAttachmentDescription attachment{ |
| 136 | .flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, | 197 | .flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, |
| 137 | .format = format, | 198 | .format = format, |
| 138 | .samples = VK_SAMPLE_COUNT_1_BIT, | 199 | .samples = VK_SAMPLE_COUNT_1_BIT, |
| 139 | .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, | 200 | .loadOp = initial_layout == VK_IMAGE_LAYOUT_UNDEFINED ? VK_ATTACHMENT_LOAD_OP_DONT_CARE |
| 201 | : VK_ATTACHMENT_LOAD_OP_LOAD, | ||
| 140 | .storeOp = VK_ATTACHMENT_STORE_OP_STORE, | 202 | .storeOp = VK_ATTACHMENT_STORE_OP_STORE, |
| 141 | .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD, | 203 | .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD, |
| 142 | .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, | 204 | .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, |
| 143 | .initialLayout = VK_IMAGE_LAYOUT_GENERAL, | 205 | .initialLayout = initial_layout, |
| 144 | .finalLayout = VK_IMAGE_LAYOUT_GENERAL, | 206 | .finalLayout = VK_IMAGE_LAYOUT_GENERAL, |
| 145 | }; | 207 | }; |
| 146 | 208 | ||
| @@ -200,13 +262,13 @@ vk::Framebuffer CreateWrappedFramebuffer(const Device& device, vk::RenderPass& r | |||
| 200 | }); | 262 | }); |
| 201 | } | 263 | } |
| 202 | 264 | ||
| 203 | vk::Sampler CreateWrappedSampler(const Device& device) { | 265 | vk::Sampler CreateWrappedSampler(const Device& device, VkFilter filter) { |
| 204 | return device.GetLogical().CreateSampler(VkSamplerCreateInfo{ | 266 | return device.GetLogical().CreateSampler(VkSamplerCreateInfo{ |
| 205 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, | 267 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, |
| 206 | .pNext = nullptr, | 268 | .pNext = nullptr, |
| 207 | .flags = 0, | 269 | .flags = 0, |
| 208 | .magFilter = VK_FILTER_LINEAR, | 270 | .magFilter = filter, |
| 209 | .minFilter = VK_FILTER_LINEAR, | 271 | .minFilter = filter, |
| 210 | .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, | 272 | .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, |
| 211 | .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, | 273 | .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, |
| 212 | .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, | 274 | .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, |
| @@ -233,30 +295,34 @@ vk::ShaderModule CreateWrappedShaderModule(const Device& device, std::span<const | |||
| 233 | }); | 295 | }); |
| 234 | } | 296 | } |
| 235 | 297 | ||
| 236 | vk::DescriptorPool CreateWrappedDescriptorPool(const Device& device, u32 max_descriptors, | 298 | vk::DescriptorPool CreateWrappedDescriptorPool(const Device& device, size_t max_descriptors, |
| 237 | u32 max_sets) { | 299 | size_t max_sets, |
| 238 | const VkDescriptorPoolSize pool_size{ | 300 | std::initializer_list<VkDescriptorType> types) { |
| 239 | .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | 301 | std::vector<VkDescriptorPoolSize> pool_sizes(types.size()); |
| 240 | .descriptorCount = static_cast<u32>(max_descriptors), | 302 | for (u32 i = 0; i < types.size(); i++) { |
| 241 | }; | 303 | pool_sizes[i] = VkDescriptorPoolSize{ |
| 304 | .type = std::data(types)[i], | ||
| 305 | .descriptorCount = static_cast<u32>(max_descriptors), | ||
| 306 | }; | ||
| 307 | } | ||
| 242 | 308 | ||
| 243 | return device.GetLogical().CreateDescriptorPool(VkDescriptorPoolCreateInfo{ | 309 | return device.GetLogical().CreateDescriptorPool(VkDescriptorPoolCreateInfo{ |
| 244 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, | 310 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, |
| 245 | .pNext = nullptr, | 311 | .pNext = nullptr, |
| 246 | .flags = 0, | 312 | .flags = 0, |
| 247 | .maxSets = max_sets, | 313 | .maxSets = static_cast<u32>(max_sets), |
| 248 | .poolSizeCount = 1, | 314 | .poolSizeCount = static_cast<u32>(pool_sizes.size()), |
| 249 | .pPoolSizes = &pool_size, | 315 | .pPoolSizes = pool_sizes.data(), |
| 250 | }); | 316 | }); |
| 251 | } | 317 | } |
| 252 | 318 | ||
| 253 | vk::DescriptorSetLayout CreateWrappedDescriptorSetLayout(const Device& device, | 319 | vk::DescriptorSetLayout CreateWrappedDescriptorSetLayout( |
| 254 | u32 max_sampler_bindings) { | 320 | const Device& device, std::initializer_list<VkDescriptorType> types) { |
| 255 | std::vector<VkDescriptorSetLayoutBinding> bindings(max_sampler_bindings); | 321 | std::vector<VkDescriptorSetLayoutBinding> bindings(types.size()); |
| 256 | for (u32 i = 0; i < max_sampler_bindings; i++) { | 322 | for (size_t i = 0; i < types.size(); i++) { |
| 257 | bindings[i] = { | 323 | bindings[i] = { |
| 258 | .binding = i, | 324 | .binding = static_cast<u32>(i), |
| 259 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | 325 | .descriptorType = std::data(types)[i], |
| 260 | .descriptorCount = 1, | 326 | .descriptorCount = 1, |
| 261 | .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, | 327 | .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, |
| 262 | .pImmutableSamplers = nullptr, | 328 | .pImmutableSamplers = nullptr, |
| @@ -298,7 +364,8 @@ vk::PipelineLayout CreateWrappedPipelineLayout(const Device& device, | |||
| 298 | 364 | ||
| 299 | vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass, | 365 | vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass, |
| 300 | vk::PipelineLayout& layout, | 366 | vk::PipelineLayout& layout, |
| 301 | std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders) { | 367 | std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders, |
| 368 | bool enable_blending) { | ||
| 302 | const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{ | 369 | const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{ |
| 303 | { | 370 | { |
| 304 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | 371 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, |
| @@ -376,7 +443,7 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp | |||
| 376 | .alphaToOneEnable = VK_FALSE, | 443 | .alphaToOneEnable = VK_FALSE, |
| 377 | }; | 444 | }; |
| 378 | 445 | ||
| 379 | constexpr VkPipelineColorBlendAttachmentState color_blend_attachment{ | 446 | constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_disabled{ |
| 380 | .blendEnable = VK_FALSE, | 447 | .blendEnable = VK_FALSE, |
| 381 | .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO, | 448 | .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO, |
| 382 | .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, | 449 | .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, |
| @@ -388,6 +455,18 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp | |||
| 388 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, | 455 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, |
| 389 | }; | 456 | }; |
| 390 | 457 | ||
| 458 | constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_enabled{ | ||
| 459 | .blendEnable = VK_TRUE, | ||
| 460 | .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, | ||
| 461 | .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, | ||
| 462 | .colorBlendOp = VK_BLEND_OP_ADD, | ||
| 463 | .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, | ||
| 464 | .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 465 | .alphaBlendOp = VK_BLEND_OP_ADD, | ||
| 466 | .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | | ||
| 467 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, | ||
| 468 | }; | ||
| 469 | |||
| 391 | const VkPipelineColorBlendStateCreateInfo color_blend_ci{ | 470 | const VkPipelineColorBlendStateCreateInfo color_blend_ci{ |
| 392 | .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | 471 | .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, |
| 393 | .pNext = nullptr, | 472 | .pNext = nullptr, |
| @@ -395,7 +474,8 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp | |||
| 395 | .logicOpEnable = VK_FALSE, | 474 | .logicOpEnable = VK_FALSE, |
| 396 | .logicOp = VK_LOGIC_OP_COPY, | 475 | .logicOp = VK_LOGIC_OP_COPY, |
| 397 | .attachmentCount = 1, | 476 | .attachmentCount = 1, |
| 398 | .pAttachments = &color_blend_attachment, | 477 | .pAttachments = |
| 478 | enable_blending ? &color_blend_attachment_enabled : &color_blend_attachment_disabled, | ||
| 399 | .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, | 479 | .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, |
| 400 | }; | 480 | }; |
| 401 | 481 | ||
| @@ -459,6 +539,56 @@ VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo> | |||
| 459 | }; | 539 | }; |
| 460 | } | 540 | } |
| 461 | 541 | ||
| 542 | vk::Sampler CreateBilinearSampler(const Device& device) { | ||
| 543 | const VkSamplerCreateInfo ci{ | ||
| 544 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, | ||
| 545 | .pNext = nullptr, | ||
| 546 | .flags = 0, | ||
| 547 | .magFilter = VK_FILTER_LINEAR, | ||
| 548 | .minFilter = VK_FILTER_LINEAR, | ||
| 549 | .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, | ||
| 550 | .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 551 | .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 552 | .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 553 | .mipLodBias = 0.0f, | ||
| 554 | .anisotropyEnable = VK_FALSE, | ||
| 555 | .maxAnisotropy = 0.0f, | ||
| 556 | .compareEnable = VK_FALSE, | ||
| 557 | .compareOp = VK_COMPARE_OP_NEVER, | ||
| 558 | .minLod = 0.0f, | ||
| 559 | .maxLod = 0.0f, | ||
| 560 | .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, | ||
| 561 | .unnormalizedCoordinates = VK_FALSE, | ||
| 562 | }; | ||
| 563 | |||
| 564 | return device.GetLogical().CreateSampler(ci); | ||
| 565 | } | ||
| 566 | |||
| 567 | vk::Sampler CreateNearestNeighborSampler(const Device& device) { | ||
| 568 | const VkSamplerCreateInfo ci_nn{ | ||
| 569 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, | ||
| 570 | .pNext = nullptr, | ||
| 571 | .flags = 0, | ||
| 572 | .magFilter = VK_FILTER_NEAREST, | ||
| 573 | .minFilter = VK_FILTER_NEAREST, | ||
| 574 | .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, | ||
| 575 | .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 576 | .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 577 | .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 578 | .mipLodBias = 0.0f, | ||
| 579 | .anisotropyEnable = VK_FALSE, | ||
| 580 | .maxAnisotropy = 0.0f, | ||
| 581 | .compareEnable = VK_FALSE, | ||
| 582 | .compareOp = VK_COMPARE_OP_NEVER, | ||
| 583 | .minLod = 0.0f, | ||
| 584 | .maxLod = 0.0f, | ||
| 585 | .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, | ||
| 586 | .unnormalizedCoordinates = VK_FALSE, | ||
| 587 | }; | ||
| 588 | |||
| 589 | return device.GetLogical().CreateSampler(ci_nn); | ||
| 590 | } | ||
| 591 | |||
| 462 | void ClearColorImage(vk::CommandBuffer& cmdbuf, VkImage image) { | 592 | void ClearColorImage(vk::CommandBuffer& cmdbuf, VkImage image) { |
| 463 | static constexpr std::array<VkImageSubresourceRange, 1> subresources{{{ | 593 | static constexpr std::array<VkImageSubresourceRange, 1> subresources{{{ |
| 464 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | 594 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, |
| @@ -471,12 +601,12 @@ void ClearColorImage(vk::CommandBuffer& cmdbuf, VkImage image) { | |||
| 471 | cmdbuf.ClearColorImage(image, VK_IMAGE_LAYOUT_GENERAL, {}, subresources); | 601 | cmdbuf.ClearColorImage(image, VK_IMAGE_LAYOUT_GENERAL, {}, subresources); |
| 472 | } | 602 | } |
| 473 | 603 | ||
| 474 | void BeginRenderPass(vk::CommandBuffer& cmdbuf, vk::RenderPass& render_pass, | 604 | void BeginRenderPass(vk::CommandBuffer& cmdbuf, VkRenderPass render_pass, VkFramebuffer framebuffer, |
| 475 | VkFramebuffer framebuffer, VkExtent2D extent) { | 605 | VkExtent2D extent) { |
| 476 | const VkRenderPassBeginInfo renderpass_bi{ | 606 | const VkRenderPassBeginInfo renderpass_bi{ |
| 477 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, | 607 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, |
| 478 | .pNext = nullptr, | 608 | .pNext = nullptr, |
| 479 | .renderPass = *render_pass, | 609 | .renderPass = render_pass, |
| 480 | .framebuffer = framebuffer, | 610 | .framebuffer = framebuffer, |
| 481 | .renderArea{ | 611 | .renderArea{ |
| 482 | .offset{}, | 612 | .offset{}, |
| @@ -503,248 +633,4 @@ void BeginRenderPass(vk::CommandBuffer& cmdbuf, vk::RenderPass& render_pass, | |||
| 503 | cmdbuf.SetScissor(0, scissor); | 633 | cmdbuf.SetScissor(0, scissor); |
| 504 | } | 634 | } |
| 505 | 635 | ||
| 506 | } // Anonymous namespace | ||
| 507 | |||
| 508 | SMAA::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 | |||
| 522 | void 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 | |||
| 552 | void 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 | |||
| 572 | void SMAA::CreateSampler() { | ||
| 573 | m_sampler = CreateWrappedSampler(m_device); | ||
| 574 | } | ||
| 575 | |||
| 576 | void 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 | |||
| 595 | void 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 | |||
| 604 | void 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 | |||
| 611 | void 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 | |||
| 621 | void 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 | |||
| 627 | void 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 | |||
| 635 | void 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 | |||
| 662 | void 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 | |||
| 687 | VkImageView 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 | 636 | } // 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..1104aaa15 --- /dev/null +++ b/src/video_core/renderer_vulkan/present/util.h | |||
| @@ -0,0 +1,56 @@ | |||
| 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 | |||
| 10 | namespace Vulkan { | ||
| 11 | |||
| 12 | #define ARRAY_TO_SPAN(a) std::span(a, (sizeof(a) / sizeof(a[0]))) | ||
| 13 | |||
| 14 | vk::Buffer CreateWrappedBuffer(MemoryAllocator& allocator, VkDeviceSize size, MemoryUsage usage); | ||
| 15 | |||
| 16 | vk::Image CreateWrappedImage(MemoryAllocator& allocator, VkExtent2D dimensions, VkFormat format); | ||
| 17 | void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout, | ||
| 18 | VkImageLayout source_layout = VK_IMAGE_LAYOUT_GENERAL); | ||
| 19 | void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler, | ||
| 20 | vk::Image& image, VkExtent2D dimensions, VkFormat format, | ||
| 21 | std::span<const u8> initial_contents = {}); | ||
| 22 | void DownloadColorImage(vk::CommandBuffer& cmdbuf, VkImage image, VkBuffer buffer, | ||
| 23 | VkExtent3D extent); | ||
| 24 | void ClearColorImage(vk::CommandBuffer& cmdbuf, VkImage image); | ||
| 25 | |||
| 26 | vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format); | ||
| 27 | vk::RenderPass CreateWrappedRenderPass(const Device& device, VkFormat format, | ||
| 28 | VkImageLayout initial_layout = VK_IMAGE_LAYOUT_GENERAL); | ||
| 29 | vk::Framebuffer CreateWrappedFramebuffer(const Device& device, vk::RenderPass& render_pass, | ||
| 30 | vk::ImageView& dest_image, VkExtent2D extent); | ||
| 31 | vk::Sampler CreateWrappedSampler(const Device& device, VkFilter filter = VK_FILTER_LINEAR); | ||
| 32 | vk::ShaderModule CreateWrappedShaderModule(const Device& device, std::span<const u32> code); | ||
| 33 | vk::DescriptorPool CreateWrappedDescriptorPool(const Device& device, size_t max_descriptors, | ||
| 34 | size_t max_sets, | ||
| 35 | std::initializer_list<VkDescriptorType> types = { | ||
| 36 | VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER}); | ||
| 37 | vk::DescriptorSetLayout CreateWrappedDescriptorSetLayout( | ||
| 38 | const Device& device, std::initializer_list<VkDescriptorType> types); | ||
| 39 | vk::DescriptorSets CreateWrappedDescriptorSets(vk::DescriptorPool& pool, | ||
| 40 | vk::Span<VkDescriptorSetLayout> layouts); | ||
| 41 | vk::PipelineLayout CreateWrappedPipelineLayout(const Device& device, | ||
| 42 | vk::DescriptorSetLayout& layout); | ||
| 43 | vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass, | ||
| 44 | vk::PipelineLayout& layout, | ||
| 45 | std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders, | ||
| 46 | bool enable_blending = false); | ||
| 47 | VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images, | ||
| 48 | VkSampler sampler, VkImageView view, | ||
| 49 | VkDescriptorSet set, u32 binding); | ||
| 50 | vk::Sampler CreateBilinearSampler(const Device& device); | ||
| 51 | vk::Sampler CreateNearestNeighborSampler(const Device& device); | ||
| 52 | |||
| 53 | void BeginRenderPass(vk::CommandBuffer& cmdbuf, VkRenderPass render_pass, VkFramebuffer framebuffer, | ||
| 54 | VkExtent2D extent); | ||
| 55 | |||
| 56 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp new file mode 100644 index 000000000..c5db0230d --- /dev/null +++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/frontend/framebuffer_layout.h" | ||
| 5 | #include "video_core/framebuffer_config.h" | ||
| 6 | #include "video_core/host_shaders/vulkan_present_vert_spv.h" | ||
| 7 | #include "video_core/renderer_vulkan/present/layer.h" | ||
| 8 | #include "video_core/renderer_vulkan/present/present_push_constants.h" | ||
| 9 | #include "video_core/renderer_vulkan/present/util.h" | ||
| 10 | #include "video_core/renderer_vulkan/present/window_adapt_pass.h" | ||
| 11 | #include "video_core/renderer_vulkan/vk_present_manager.h" | ||
| 12 | #include "video_core/renderer_vulkan/vk_shader_util.h" | ||
| 13 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 14 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 15 | |||
| 16 | namespace Vulkan { | ||
| 17 | |||
| 18 | WindowAdaptPass::WindowAdaptPass(const Device& device_, VkFormat frame_format, | ||
| 19 | vk::Sampler&& sampler_, vk::ShaderModule&& fragment_shader_) | ||
| 20 | : device(device_), sampler(std::move(sampler_)), fragment_shader(std::move(fragment_shader_)) { | ||
| 21 | CreateDescriptorSetLayout(); | ||
| 22 | CreatePipelineLayout(); | ||
| 23 | CreateVertexShader(); | ||
| 24 | CreateRenderPass(frame_format); | ||
| 25 | CreatePipeline(); | ||
| 26 | } | ||
| 27 | |||
| 28 | WindowAdaptPass::~WindowAdaptPass() = default; | ||
| 29 | |||
| 30 | void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, size_t image_index, | ||
| 31 | std::list<Layer>& layers, | ||
| 32 | std::span<const Tegra::FramebufferConfig> configs, | ||
| 33 | const Layout::FramebufferLayout& layout, Frame* dst) { | ||
| 34 | |||
| 35 | const VkFramebuffer host_framebuffer{*dst->framebuffer}; | ||
| 36 | const VkRenderPass renderpass{*render_pass}; | ||
| 37 | const VkPipeline graphics_pipeline{*pipeline}; | ||
| 38 | const VkPipelineLayout graphics_pipeline_layout{*pipeline_layout}; | ||
| 39 | const VkExtent2D render_area{ | ||
| 40 | .width = dst->width, | ||
| 41 | .height = dst->height, | ||
| 42 | }; | ||
| 43 | |||
| 44 | const size_t layer_count = configs.size(); | ||
| 45 | std::vector<PresentPushConstants> push_constants(layer_count); | ||
| 46 | std::vector<VkDescriptorSet> descriptor_sets(layer_count); | ||
| 47 | |||
| 48 | auto layer_it = layers.begin(); | ||
| 49 | for (size_t i = 0; i < layer_count; i++) { | ||
| 50 | layer_it->ConfigureDraw(&push_constants[i], &descriptor_sets[i], rasterizer, *sampler, | ||
| 51 | image_index, configs[i], layout); | ||
| 52 | layer_it++; | ||
| 53 | } | ||
| 54 | |||
| 55 | scheduler.Record([=](vk::CommandBuffer cmdbuf) { | ||
| 56 | const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f; | ||
| 57 | const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f; | ||
| 58 | const f32 bg_blue = Settings::values.bg_blue.GetValue() / 255.0f; | ||
| 59 | const VkClearAttachment clear_attachment{ | ||
| 60 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 61 | .colorAttachment = 0, | ||
| 62 | .clearValue = | ||
| 63 | { | ||
| 64 | .color = {.float32 = {bg_red, bg_green, bg_blue, 1.0f}}, | ||
| 65 | }, | ||
| 66 | }; | ||
| 67 | const VkClearRect clear_rect{ | ||
| 68 | .rect = | ||
| 69 | { | ||
| 70 | .offset = {0, 0}, | ||
| 71 | .extent = render_area, | ||
| 72 | }, | ||
| 73 | .baseArrayLayer = 0, | ||
| 74 | .layerCount = 1, | ||
| 75 | }; | ||
| 76 | |||
| 77 | BeginRenderPass(cmdbuf, renderpass, host_framebuffer, render_area); | ||
| 78 | cmdbuf.ClearAttachments({clear_attachment}, {clear_rect}); | ||
| 79 | |||
| 80 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline); | ||
| 81 | for (size_t i = 0; i < layer_count; i++) { | ||
| 82 | cmdbuf.PushConstants(graphics_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, | ||
| 83 | push_constants[i]); | ||
| 84 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_layout, 0, | ||
| 85 | descriptor_sets[i], {}); | ||
| 86 | cmdbuf.Draw(4, 1, 0, 0); | ||
| 87 | } | ||
| 88 | |||
| 89 | cmdbuf.EndRenderPass(); | ||
| 90 | }); | ||
| 91 | } | ||
| 92 | |||
| 93 | VkDescriptorSetLayout WindowAdaptPass::GetDescriptorSetLayout() { | ||
| 94 | return *descriptor_set_layout; | ||
| 95 | } | ||
| 96 | |||
| 97 | VkRenderPass WindowAdaptPass::GetRenderPass() { | ||
| 98 | return *render_pass; | ||
| 99 | } | ||
| 100 | |||
| 101 | void WindowAdaptPass::CreateDescriptorSetLayout() { | ||
| 102 | descriptor_set_layout = | ||
| 103 | CreateWrappedDescriptorSetLayout(device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER}); | ||
| 104 | } | ||
| 105 | |||
| 106 | void WindowAdaptPass::CreatePipelineLayout() { | ||
| 107 | const VkPushConstantRange range{ | ||
| 108 | .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 109 | .offset = 0, | ||
| 110 | .size = sizeof(PresentPushConstants), | ||
| 111 | }; | ||
| 112 | |||
| 113 | pipeline_layout = device.GetLogical().CreatePipelineLayout(VkPipelineLayoutCreateInfo{ | ||
| 114 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | ||
| 115 | .pNext = nullptr, | ||
| 116 | .flags = 0, | ||
| 117 | .setLayoutCount = 1, | ||
| 118 | .pSetLayouts = descriptor_set_layout.address(), | ||
| 119 | .pushConstantRangeCount = 1, | ||
| 120 | .pPushConstantRanges = &range, | ||
| 121 | }); | ||
| 122 | } | ||
| 123 | |||
| 124 | void WindowAdaptPass::CreateVertexShader() { | ||
| 125 | vertex_shader = BuildShader(device, VULKAN_PRESENT_VERT_SPV); | ||
| 126 | } | ||
| 127 | |||
| 128 | void WindowAdaptPass::CreateRenderPass(VkFormat frame_format) { | ||
| 129 | render_pass = CreateWrappedRenderPass(device, frame_format, VK_IMAGE_LAYOUT_UNDEFINED); | ||
| 130 | } | ||
| 131 | |||
| 132 | void WindowAdaptPass::CreatePipeline() { | ||
| 133 | pipeline = CreateWrappedPipeline(device, render_pass, pipeline_layout, | ||
| 134 | std::tie(vertex_shader, fragment_shader), false); | ||
| 135 | } | ||
| 136 | |||
| 137 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/present/window_adapt_pass.h b/src/video_core/renderer_vulkan/present/window_adapt_pass.h new file mode 100644 index 000000000..0e2edfc31 --- /dev/null +++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.h | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <list> | ||
| 7 | |||
| 8 | #include "common/math_util.h" | ||
| 9 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 10 | |||
| 11 | namespace Layout { | ||
| 12 | struct FramebufferLayout; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Tegra { | ||
| 16 | struct FramebufferConfig; | ||
| 17 | } | ||
| 18 | |||
| 19 | namespace Vulkan { | ||
| 20 | |||
| 21 | class Device; | ||
| 22 | struct Frame; | ||
| 23 | class Layer; | ||
| 24 | class Scheduler; | ||
| 25 | class RasterizerVulkan; | ||
| 26 | |||
| 27 | class WindowAdaptPass final { | ||
| 28 | public: | ||
| 29 | explicit WindowAdaptPass(const Device& device, VkFormat frame_format, vk::Sampler&& sampler, | ||
| 30 | vk::ShaderModule&& fragment_shader); | ||
| 31 | ~WindowAdaptPass(); | ||
| 32 | |||
| 33 | void Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, size_t image_index, | ||
| 34 | std::list<Layer>& layers, std::span<const Tegra::FramebufferConfig> configs, | ||
| 35 | const Layout::FramebufferLayout& layout, Frame* dst); | ||
| 36 | |||
| 37 | VkDescriptorSetLayout GetDescriptorSetLayout(); | ||
| 38 | VkRenderPass GetRenderPass(); | ||
| 39 | |||
| 40 | private: | ||
| 41 | void CreateDescriptorSetLayout(); | ||
| 42 | void CreatePipelineLayout(); | ||
| 43 | void CreateVertexShader(); | ||
| 44 | void CreateRenderPass(VkFormat frame_format); | ||
| 45 | void CreatePipeline(); | ||
| 46 | |||
| 47 | private: | ||
| 48 | const Device& device; | ||
| 49 | vk::DescriptorSetLayout descriptor_set_layout; | ||
| 50 | vk::PipelineLayout pipeline_layout; | ||
| 51 | vk::Sampler sampler; | ||
| 52 | vk::ShaderModule vertex_shader; | ||
| 53 | vk::ShaderModule fragment_shader; | ||
| 54 | vk::RenderPass render_pass; | ||
| 55 | vk::Pipeline pipeline; | ||
| 56 | }; | ||
| 57 | |||
| 58 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 1631276c6..48a105327 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -20,12 +20,14 @@ | |||
| 20 | #include "core/frontend/graphics_context.h" | 20 | #include "core/frontend/graphics_context.h" |
| 21 | #include "core/telemetry_session.h" | 21 | #include "core/telemetry_session.h" |
| 22 | #include "video_core/gpu.h" | 22 | #include "video_core/gpu.h" |
| 23 | #include "video_core/renderer_vulkan/present/util.h" | ||
| 23 | #include "video_core/renderer_vulkan/renderer_vulkan.h" | 24 | #include "video_core/renderer_vulkan/renderer_vulkan.h" |
| 24 | #include "video_core/renderer_vulkan/vk_blit_screen.h" | 25 | #include "video_core/renderer_vulkan/vk_blit_screen.h" |
| 25 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | 26 | #include "video_core/renderer_vulkan/vk_rasterizer.h" |
| 26 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 27 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 27 | #include "video_core/renderer_vulkan/vk_state_tracker.h" | 28 | #include "video_core/renderer_vulkan/vk_state_tracker.h" |
| 28 | #include "video_core/renderer_vulkan/vk_swapchain.h" | 29 | #include "video_core/renderer_vulkan/vk_swapchain.h" |
| 30 | #include "video_core/textures/decoders.h" | ||
| 29 | #include "video_core/vulkan_common/vulkan_debug_callback.h" | 31 | #include "video_core/vulkan_common/vulkan_debug_callback.h" |
| 30 | #include "video_core/vulkan_common/vulkan_device.h" | 32 | #include "video_core/vulkan_common/vulkan_device.h" |
| 31 | #include "video_core/vulkan_common/vulkan_instance.h" | 33 | #include "video_core/vulkan_common/vulkan_instance.h" |
| @@ -97,10 +99,10 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, | |||
| 97 | render_window.GetFramebufferLayout().height), | 99 | render_window.GetFramebufferLayout().height), |
| 98 | present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, | 100 | present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, |
| 99 | surface), | 101 | surface), |
| 100 | blit_screen(device_memory, render_window, device, memory_allocator, swapchain, | 102 | blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler), |
| 101 | present_manager, scheduler, screen_info), | 103 | blit_screenshot(device_memory, device, memory_allocator, present_manager, scheduler), |
| 102 | rasterizer(render_window, gpu, device_memory, screen_info, device, memory_allocator, | 104 | rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, |
| 103 | state_tracker, scheduler) { | 105 | scheduler) { |
| 104 | if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { | 106 | if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { |
| 105 | turbo_mode.emplace(instance, dld); | 107 | turbo_mode.emplace(instance, dld); |
| 106 | scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); }); | 108 | scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); }); |
| @@ -116,25 +118,22 @@ RendererVulkan::~RendererVulkan() { | |||
| 116 | void(device.GetLogical().WaitIdle()); | 118 | void(device.GetLogical().WaitIdle()); |
| 117 | } | 119 | } |
| 118 | 120 | ||
| 119 | void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | 121 | void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebuffers) { |
| 120 | if (!framebuffer) { | 122 | if (framebuffers.empty()) { |
| 121 | return; | 123 | return; |
| 122 | } | 124 | } |
| 125 | |||
| 123 | SCOPE_EXIT({ render_window.OnFrameDisplayed(); }); | 126 | SCOPE_EXIT({ render_window.OnFrameDisplayed(); }); |
| 127 | |||
| 124 | if (!render_window.IsShown()) { | 128 | if (!render_window.IsShown()) { |
| 125 | return; | 129 | return; |
| 126 | } | 130 | } |
| 127 | // Update screen info if the framebuffer size has changed. | ||
| 128 | screen_info.width = framebuffer->width; | ||
| 129 | screen_info.height = framebuffer->height; | ||
| 130 | |||
| 131 | const DAddr framebuffer_addr = framebuffer->address + framebuffer->offset; | ||
| 132 | const bool use_accelerated = | ||
| 133 | rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); | ||
| 134 | RenderScreenshot(*framebuffer, use_accelerated); | ||
| 135 | 131 | ||
| 132 | RenderScreenshot(framebuffers); | ||
| 136 | Frame* frame = present_manager.GetRenderFrame(); | 133 | Frame* frame = present_manager.GetRenderFrame(); |
| 137 | blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated); | 134 | blit_swapchain.DrawToFrame(rasterizer, frame, framebuffers, |
| 135 | render_window.GetFramebufferLayout(), swapchain.GetImageCount(), | ||
| 136 | swapchain.GetImageViewFormat()); | ||
| 138 | scheduler.Flush(*frame->render_ready); | 137 | scheduler.Flush(*frame->render_ready); |
| 139 | present_manager.Present(frame); | 138 | present_manager.Present(frame); |
| 140 | 139 | ||
| @@ -168,143 +167,37 @@ void RendererVulkan::Report() const { | |||
| 168 | telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); | 167 | telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); |
| 169 | } | 168 | } |
| 170 | 169 | ||
| 171 | void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& framebuffer, | 170 | void Vulkan::RendererVulkan::RenderScreenshot( |
| 172 | bool use_accelerated) { | 171 | std::span<const Tegra::FramebufferConfig> framebuffers) { |
| 173 | if (!renderer_settings.screenshot_requested) { | 172 | if (!renderer_settings.screenshot_requested) { |
| 174 | return; | 173 | return; |
| 175 | } | 174 | } |
| 175 | |||
| 176 | constexpr VkFormat ScreenshotFormat{VK_FORMAT_B8G8R8A8_UNORM}; | ||
| 176 | const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; | 177 | const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; |
| 177 | vk::Image staging_image = memory_allocator.CreateImage(VkImageCreateInfo{ | ||
| 178 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | ||
| 179 | .pNext = nullptr, | ||
| 180 | .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, | ||
| 181 | .imageType = VK_IMAGE_TYPE_2D, | ||
| 182 | .format = VK_FORMAT_B8G8R8A8_UNORM, | ||
| 183 | .extent = | ||
| 184 | { | ||
| 185 | .width = layout.width, | ||
| 186 | .height = layout.height, | ||
| 187 | .depth = 1, | ||
| 188 | }, | ||
| 189 | .mipLevels = 1, | ||
| 190 | .arrayLayers = 1, | ||
| 191 | .samples = VK_SAMPLE_COUNT_1_BIT, | ||
| 192 | .tiling = VK_IMAGE_TILING_OPTIMAL, | ||
| 193 | .usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | | ||
| 194 | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, | ||
| 195 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 196 | .queueFamilyIndexCount = 0, | ||
| 197 | .pQueueFamilyIndices = nullptr, | ||
| 198 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | ||
| 199 | }); | ||
| 200 | 178 | ||
| 201 | const vk::ImageView dst_view = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | 179 | auto frame = [&]() { |
| 202 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 180 | Frame f{}; |
| 203 | .pNext = nullptr, | 181 | f.image = CreateWrappedImage(memory_allocator, VkExtent2D{layout.width, layout.height}, |
| 204 | .flags = 0, | 182 | ScreenshotFormat); |
| 205 | .image = *staging_image, | 183 | f.image_view = CreateWrappedImageView(device, f.image, ScreenshotFormat); |
| 206 | .viewType = VK_IMAGE_VIEW_TYPE_2D, | 184 | f.framebuffer = blit_screenshot.CreateFramebuffer(layout, *f.image_view, ScreenshotFormat); |
| 207 | .format = VK_FORMAT_B8G8R8A8_UNORM, | 185 | return f; |
| 208 | .components{ | 186 | }(); |
| 209 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 210 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 211 | .b = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 212 | .a = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 213 | }, | ||
| 214 | .subresourceRange{ | ||
| 215 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 216 | .baseMipLevel = 0, | ||
| 217 | .levelCount = 1, | ||
| 218 | .baseArrayLayer = 0, | ||
| 219 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 220 | }, | ||
| 221 | }); | ||
| 222 | const VkExtent2D render_area{.width = layout.width, .height = layout.height}; | ||
| 223 | const vk::Framebuffer screenshot_fb = blit_screen.CreateFramebuffer(*dst_view, render_area); | ||
| 224 | blit_screen.Draw(framebuffer, *screenshot_fb, layout, render_area, use_accelerated); | ||
| 225 | 187 | ||
| 226 | const auto buffer_size = static_cast<VkDeviceSize>(layout.width * layout.height * 4); | 188 | blit_screenshot.DrawToFrame(rasterizer, &frame, framebuffers, layout, 1, |
| 227 | const VkBufferCreateInfo dst_buffer_info{ | 189 | VK_FORMAT_B8G8R8A8_UNORM); |
| 228 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 190 | |
| 229 | .pNext = nullptr, | 191 | const auto dst_buffer = CreateWrappedBuffer( |
| 230 | .flags = 0, | 192 | memory_allocator, static_cast<VkDeviceSize>(layout.width * layout.height * 4), |
| 231 | .size = buffer_size, | 193 | MemoryUsage::Download); |
| 232 | .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT, | ||
| 233 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 234 | .queueFamilyIndexCount = 0, | ||
| 235 | .pQueueFamilyIndices = nullptr, | ||
| 236 | }; | ||
| 237 | const vk::Buffer dst_buffer = | ||
| 238 | memory_allocator.CreateBuffer(dst_buffer_info, MemoryUsage::Download); | ||
| 239 | 194 | ||
| 240 | scheduler.RequestOutsideRenderPassOperationContext(); | 195 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 241 | scheduler.Record([&](vk::CommandBuffer cmdbuf) { | 196 | scheduler.Record([&](vk::CommandBuffer cmdbuf) { |
| 242 | const VkImageMemoryBarrier read_barrier{ | 197 | DownloadColorImage(cmdbuf, *frame.image, *dst_buffer, |
| 243 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | 198 | VkExtent3D{layout.width, layout.height, 1}); |
| 244 | .pNext = nullptr, | ||
| 245 | .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 246 | .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, | ||
| 247 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 248 | .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, | ||
| 249 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 250 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 251 | .image = *staging_image, | ||
| 252 | .subresourceRange{ | ||
| 253 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 254 | .baseMipLevel = 0, | ||
| 255 | .levelCount = VK_REMAINING_MIP_LEVELS, | ||
| 256 | .baseArrayLayer = 0, | ||
| 257 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 258 | }, | ||
| 259 | }; | ||
| 260 | const VkImageMemoryBarrier image_write_barrier{ | ||
| 261 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 262 | .pNext = nullptr, | ||
| 263 | .srcAccessMask = 0, | ||
| 264 | .dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 265 | .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, | ||
| 266 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 267 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 268 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 269 | .image = *staging_image, | ||
| 270 | .subresourceRange{ | ||
| 271 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 272 | .baseMipLevel = 0, | ||
| 273 | .levelCount = VK_REMAINING_MIP_LEVELS, | ||
| 274 | .baseArrayLayer = 0, | ||
| 275 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 276 | }, | ||
| 277 | }; | ||
| 278 | static constexpr VkMemoryBarrier memory_write_barrier{ | ||
| 279 | .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, | ||
| 280 | .pNext = nullptr, | ||
| 281 | .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 282 | .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 283 | }; | ||
| 284 | const VkBufferImageCopy copy{ | ||
| 285 | .bufferOffset = 0, | ||
| 286 | .bufferRowLength = 0, | ||
| 287 | .bufferImageHeight = 0, | ||
| 288 | .imageSubresource{ | ||
| 289 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 290 | .mipLevel = 0, | ||
| 291 | .baseArrayLayer = 0, | ||
| 292 | .layerCount = 1, | ||
| 293 | }, | ||
| 294 | .imageOffset{.x = 0, .y = 0, .z = 0}, | ||
| 295 | .imageExtent{ | ||
| 296 | .width = layout.width, | ||
| 297 | .height = layout.height, | ||
| 298 | .depth = 1, | ||
| 299 | }, | ||
| 300 | }; | ||
| 301 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 302 | 0, read_barrier); | ||
| 303 | cmdbuf.CopyImageToBuffer(*staging_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *dst_buffer, | ||
| 304 | copy); | ||
| 305 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 306 | 0, memory_write_barrier, nullptr, image_write_barrier); | ||
| 307 | }); | 199 | }); |
| 200 | |||
| 308 | // Ensure the copy is fully completed before saving the screenshot | 201 | // Ensure the copy is fully completed before saving the screenshot |
| 309 | scheduler.Finish(); | 202 | scheduler.Finish(); |
| 310 | 203 | ||
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 11c52287a..c6d8a0f21 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h | |||
| @@ -46,7 +46,7 @@ public: | |||
| 46 | std::unique_ptr<Core::Frontend::GraphicsContext> context_); | 46 | std::unique_ptr<Core::Frontend::GraphicsContext> context_); |
| 47 | ~RendererVulkan() override; | 47 | ~RendererVulkan() override; |
| 48 | 48 | ||
| 49 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; | 49 | void Composite(std::span<const Tegra::FramebufferConfig> framebuffers) override; |
| 50 | 50 | ||
| 51 | VideoCore::RasterizerInterface* ReadRasterizer() override { | 51 | VideoCore::RasterizerInterface* ReadRasterizer() override { |
| 52 | return &rasterizer; | 52 | return &rasterizer; |
| @@ -59,7 +59,7 @@ public: | |||
| 59 | private: | 59 | private: |
| 60 | void Report() const; | 60 | void Report() const; |
| 61 | 61 | ||
| 62 | void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer, bool use_accelerated); | 62 | void RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers); |
| 63 | 63 | ||
| 64 | Core::TelemetrySession& telemetry_session; | 64 | Core::TelemetrySession& telemetry_session; |
| 65 | Tegra::MaxwellDeviceMemoryManager& device_memory; | 65 | Tegra::MaxwellDeviceMemoryManager& device_memory; |
| @@ -72,15 +72,14 @@ private: | |||
| 72 | vk::DebugUtilsMessenger debug_messenger; | 72 | vk::DebugUtilsMessenger debug_messenger; |
| 73 | vk::SurfaceKHR surface; | 73 | vk::SurfaceKHR surface; |
| 74 | 74 | ||
| 75 | ScreenInfo screen_info; | ||
| 76 | |||
| 77 | Device device; | 75 | Device device; |
| 78 | MemoryAllocator memory_allocator; | 76 | MemoryAllocator memory_allocator; |
| 79 | StateTracker state_tracker; | 77 | StateTracker state_tracker; |
| 80 | Scheduler scheduler; | 78 | Scheduler scheduler; |
| 81 | Swapchain swapchain; | 79 | Swapchain swapchain; |
| 82 | PresentManager present_manager; | 80 | PresentManager present_manager; |
| 83 | BlitScreen blit_screen; | 81 | BlitScreen blit_swapchain; |
| 82 | BlitScreen blit_screenshot; | ||
| 84 | RasterizerVulkan rasterizer; | 83 | RasterizerVulkan rasterizer; |
| 85 | std::optional<TurboMode> turbo_mode; | 84 | std::optional<TurboMode> turbo_mode; |
| 86 | }; | 85 | }; |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 610f27c84..2275fcc46 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -1,522 +1,143 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2018 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 <algorithm> | 4 | #include "video_core/framebuffer_config.h" |
| 5 | #include <array> | 5 | #include "video_core/renderer_vulkan/present/filters.h" |
| 6 | #include <cstring> | 6 | #include "video_core/renderer_vulkan/present/layer.h" |
| 7 | #include <memory> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/assert.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "common/math_util.h" | ||
| 13 | #include "common/polyfill_ranges.h" | ||
| 14 | #include "common/settings.h" | ||
| 15 | #include "core/core.h" | ||
| 16 | #include "core/frontend/emu_window.h" | ||
| 17 | #include "video_core/gpu.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" | ||
| 22 | #include "video_core/host_shaders/present_gaussian_frag_spv.h" | ||
| 23 | #include "video_core/host_shaders/vulkan_present_frag_spv.h" | ||
| 24 | #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" | ||
| 26 | #include "video_core/host_shaders/vulkan_present_vert_spv.h" | ||
| 27 | #include "video_core/renderer_vulkan/renderer_vulkan.h" | ||
| 28 | #include "video_core/renderer_vulkan/vk_blit_screen.h" | 7 | #include "video_core/renderer_vulkan/vk_blit_screen.h" |
| 29 | #include "video_core/renderer_vulkan/vk_fsr.h" | 8 | #include "video_core/renderer_vulkan/vk_present_manager.h" |
| 30 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 9 | #include "video_core/renderer_vulkan/vk_scheduler.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" | ||
| 34 | #include "video_core/surface.h" | ||
| 35 | #include "video_core/textures/decoders.h" | ||
| 36 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 37 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 38 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 39 | 10 | ||
| 40 | namespace Vulkan { | 11 | namespace Vulkan { |
| 41 | 12 | ||
| 42 | namespace { | 13 | BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, const Device& device_, |
| 43 | 14 | MemoryAllocator& memory_allocator_, PresentManager& present_manager_, | |
| 44 | struct ScreenRectVertex { | 15 | Scheduler& scheduler_) |
| 45 | ScreenRectVertex() = default; | 16 | : device_memory{device_memory_}, device{device_}, memory_allocator{memory_allocator_}, |
| 46 | explicit ScreenRectVertex(f32 x, f32 y, f32 u, f32 v) : position{{x, y}}, tex_coord{{u, v}} {} | 17 | present_manager{present_manager_}, scheduler{scheduler_}, image_count{1}, |
| 47 | 18 | swapchain_view_format{VK_FORMAT_B8G8R8A8_UNORM} {} | |
| 48 | std::array<f32, 2> position; | ||
| 49 | std::array<f32, 2> tex_coord; | ||
| 50 | |||
| 51 | static VkVertexInputBindingDescription GetDescription() { | ||
| 52 | return { | ||
| 53 | .binding = 0, | ||
| 54 | .stride = sizeof(ScreenRectVertex), | ||
| 55 | .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, | ||
| 56 | }; | ||
| 57 | } | ||
| 58 | |||
| 59 | static std::array<VkVertexInputAttributeDescription, 2> GetAttributes() { | ||
| 60 | return {{ | ||
| 61 | { | ||
| 62 | .location = 0, | ||
| 63 | .binding = 0, | ||
| 64 | .format = VK_FORMAT_R32G32_SFLOAT, | ||
| 65 | .offset = offsetof(ScreenRectVertex, position), | ||
| 66 | }, | ||
| 67 | { | ||
| 68 | .location = 1, | ||
| 69 | .binding = 0, | ||
| 70 | .format = VK_FORMAT_R32G32_SFLOAT, | ||
| 71 | .offset = offsetof(ScreenRectVertex, tex_coord), | ||
| 72 | }, | ||
| 73 | }}; | ||
| 74 | } | ||
| 75 | }; | ||
| 76 | 19 | ||
| 77 | std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) { | 20 | BlitScreen::~BlitScreen() = default; |
| 78 | // clang-format off | ||
| 79 | return { 2.f / width, 0.f, 0.f, 0.f, | ||
| 80 | 0.f, 2.f / height, 0.f, 0.f, | ||
| 81 | 0.f, 0.f, 1.f, 0.f, | ||
| 82 | -1.f, -1.f, 0.f, 1.f}; | ||
| 83 | // clang-format on | ||
| 84 | } | ||
| 85 | |||
| 86 | u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) { | ||
| 87 | using namespace VideoCore::Surface; | ||
| 88 | return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)); | ||
| 89 | } | ||
| 90 | 21 | ||
| 91 | std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) { | 22 | void BlitScreen::WaitIdle() { |
| 92 | return static_cast<std::size_t>(framebuffer.stride) * | 23 | present_manager.WaitPresent(); |
| 93 | static_cast<std::size_t>(framebuffer.height) * GetBytesPerPixel(framebuffer); | 24 | scheduler.Finish(); |
| 25 | device.GetLogical().WaitIdle(); | ||
| 94 | } | 26 | } |
| 95 | 27 | ||
| 96 | VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) { | 28 | void BlitScreen::SetWindowAdaptPass() { |
| 97 | switch (framebuffer.pixel_format) { | 29 | layers.clear(); |
| 98 | case Service::android::PixelFormat::Rgba8888: | 30 | scaling_filter = Settings::values.scaling_filter.GetValue(); |
| 99 | case Service::android::PixelFormat::Rgbx8888: | 31 | |
| 100 | return VK_FORMAT_A8B8G8R8_UNORM_PACK32; | 32 | switch (scaling_filter) { |
| 101 | case Service::android::PixelFormat::Rgb565: | 33 | case Settings::ScalingFilter::NearestNeighbor: |
| 102 | return VK_FORMAT_R5G6B5_UNORM_PACK16; | 34 | window_adapt = MakeNearestNeighbor(device, swapchain_view_format); |
| 103 | case Service::android::PixelFormat::Bgra8888: | 35 | break; |
| 104 | return VK_FORMAT_B8G8R8A8_UNORM; | 36 | case Settings::ScalingFilter::Bicubic: |
| 37 | window_adapt = MakeBicubic(device, swapchain_view_format); | ||
| 38 | break; | ||
| 39 | case Settings::ScalingFilter::Gaussian: | ||
| 40 | window_adapt = MakeGaussian(device, swapchain_view_format); | ||
| 41 | break; | ||
| 42 | case Settings::ScalingFilter::ScaleForce: | ||
| 43 | window_adapt = MakeScaleForce(device, swapchain_view_format); | ||
| 44 | break; | ||
| 45 | case Settings::ScalingFilter::Fsr: | ||
| 46 | case Settings::ScalingFilter::Bilinear: | ||
| 105 | default: | 47 | default: |
| 106 | UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", | 48 | window_adapt = MakeBilinear(device, swapchain_view_format); |
| 107 | static_cast<u32>(framebuffer.pixel_format)); | 49 | break; |
| 108 | return VK_FORMAT_A8B8G8R8_UNORM_PACK32; | ||
| 109 | } | 50 | } |
| 110 | } | 51 | } |
| 111 | 52 | ||
| 112 | } // Anonymous namespace | 53 | void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame, |
| 113 | 54 | std::span<const Tegra::FramebufferConfig> framebuffers, | |
| 114 | struct BlitScreen::BufferData { | 55 | const Layout::FramebufferLayout& layout, |
| 115 | struct { | 56 | size_t current_swapchain_image_count, |
| 116 | std::array<f32, 4 * 4> modelview_matrix; | 57 | VkFormat current_swapchain_view_format) { |
| 117 | } uniform; | 58 | bool resource_update_required = false; |
| 118 | 59 | bool presentation_recreate_required = false; | |
| 119 | std::array<ScreenRectVertex, 4> vertices; | ||
| 120 | |||
| 121 | // Unaligned image data goes here | ||
| 122 | }; | ||
| 123 | |||
| 124 | BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, | ||
| 125 | Core::Frontend::EmuWindow& render_window_, const Device& device_, | ||
| 126 | MemoryAllocator& memory_allocator_, Swapchain& swapchain_, | ||
| 127 | PresentManager& present_manager_, Scheduler& scheduler_, | ||
| 128 | const ScreenInfo& screen_info_) | ||
| 129 | : device_memory{device_memory_}, render_window{render_window_}, device{device_}, | ||
| 130 | memory_allocator{memory_allocator_}, swapchain{swapchain_}, present_manager{present_manager_}, | ||
| 131 | scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { | ||
| 132 | resource_ticks.resize(image_count); | ||
| 133 | swapchain_view_format = swapchain.GetImageViewFormat(); | ||
| 134 | |||
| 135 | CreateStaticResources(); | ||
| 136 | CreateDynamicResources(); | ||
| 137 | } | ||
| 138 | |||
| 139 | BlitScreen::~BlitScreen() = default; | ||
| 140 | |||
| 141 | static Common::Rectangle<f32> NormalizeCrop(const Tegra::FramebufferConfig& framebuffer, | ||
| 142 | const ScreenInfo& screen_info) { | ||
| 143 | f32 left, top, right, bottom; | ||
| 144 | |||
| 145 | if (!framebuffer.crop_rect.IsEmpty()) { | ||
| 146 | // If crop rectangle is not empty, apply properties from rectangle. | ||
| 147 | left = static_cast<f32>(framebuffer.crop_rect.left); | ||
| 148 | top = static_cast<f32>(framebuffer.crop_rect.top); | ||
| 149 | right = static_cast<f32>(framebuffer.crop_rect.right); | ||
| 150 | bottom = static_cast<f32>(framebuffer.crop_rect.bottom); | ||
| 151 | } else { | ||
| 152 | // Otherwise, fall back to framebuffer dimensions. | ||
| 153 | left = 0; | ||
| 154 | top = 0; | ||
| 155 | right = static_cast<f32>(framebuffer.width); | ||
| 156 | bottom = static_cast<f32>(framebuffer.height); | ||
| 157 | } | ||
| 158 | |||
| 159 | // Apply transformation flags. | ||
| 160 | auto framebuffer_transform_flags = framebuffer.transform_flags; | ||
| 161 | 60 | ||
| 162 | if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipH)) { | 61 | // Recreate dynamic resources if the adapting filter changed |
| 163 | // Switch left and right. | 62 | if (!window_adapt || scaling_filter != Settings::values.scaling_filter.GetValue()) { |
| 164 | std::swap(left, right); | 63 | resource_update_required = true; |
| 165 | } | ||
| 166 | if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipV)) { | ||
| 167 | // Switch top and bottom. | ||
| 168 | std::swap(top, bottom); | ||
| 169 | } | 64 | } |
| 170 | 65 | ||
| 171 | framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipH; | 66 | // Recreate dynamic resources if the image count changed |
| 172 | framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipV; | 67 | const size_t old_swapchain_image_count = |
| 173 | if (True(framebuffer_transform_flags)) { | 68 | std::exchange(image_count, current_swapchain_image_count); |
| 174 | UNIMPLEMENTED_MSG("Unsupported framebuffer_transform_flags={}", | 69 | if (old_swapchain_image_count != current_swapchain_image_count) { |
| 175 | static_cast<u32>(framebuffer_transform_flags)); | 70 | resource_update_required = true; |
| 176 | } | 71 | } |
| 177 | 72 | ||
| 178 | // Get the screen properties. | 73 | // Recreate the presentation frame if the format or dimensions of the window changed |
| 179 | const f32 screen_width = static_cast<f32>(screen_info.width); | 74 | const VkFormat old_swapchain_view_format = |
| 180 | const f32 screen_height = static_cast<f32>(screen_info.height); | 75 | std::exchange(swapchain_view_format, current_swapchain_view_format); |
| 181 | 76 | if (old_swapchain_view_format != current_swapchain_view_format || | |
| 182 | // Normalize coordinate space. | 77 | layout.width != frame->width || layout.height != frame->height) { |
| 183 | left /= screen_width; | 78 | resource_update_required = true; |
| 184 | top /= screen_height; | 79 | presentation_recreate_required = true; |
| 185 | right /= screen_width; | ||
| 186 | bottom /= screen_height; | ||
| 187 | |||
| 188 | return Common::Rectangle<f32>(left, top, right, bottom); | ||
| 189 | } | ||
| 190 | |||
| 191 | void BlitScreen::Recreate() { | ||
| 192 | present_manager.WaitPresent(); | ||
| 193 | scheduler.Finish(); | ||
| 194 | device.GetLogical().WaitIdle(); | ||
| 195 | CreateDynamicResources(); | ||
| 196 | } | ||
| 197 | |||
| 198 | void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | ||
| 199 | const VkFramebuffer& host_framebuffer, const Layout::FramebufferLayout layout, | ||
| 200 | VkExtent2D render_area, bool use_accelerated) { | ||
| 201 | RefreshResources(framebuffer); | ||
| 202 | |||
| 203 | // Finish any pending renderpass | ||
| 204 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 205 | |||
| 206 | scheduler.Wait(resource_ticks[image_index]); | ||
| 207 | resource_ticks[image_index] = scheduler.CurrentTick(); | ||
| 208 | |||
| 209 | VkImage source_image = use_accelerated ? screen_info.image : *raw_images[image_index]; | ||
| 210 | VkImageView source_image_view = | ||
| 211 | use_accelerated ? screen_info.image_view : *raw_image_views[image_index]; | ||
| 212 | |||
| 213 | BufferData data; | ||
| 214 | SetUniformData(data, layout); | ||
| 215 | SetVertexData(data, framebuffer, layout); | ||
| 216 | |||
| 217 | const std::span<u8> mapped_span = buffer.Mapped(); | ||
| 218 | std::memcpy(mapped_span.data(), &data, sizeof(data)); | ||
| 219 | |||
| 220 | if (!use_accelerated) { | ||
| 221 | const u64 image_offset = GetRawImageOffset(framebuffer); | ||
| 222 | |||
| 223 | const DAddr framebuffer_addr = framebuffer.address + framebuffer.offset; | ||
| 224 | const u8* const host_ptr = device_memory.GetPointer<u8>(framebuffer_addr); | ||
| 225 | |||
| 226 | // TODO(Rodrigo): Read this from HLE | ||
| 227 | constexpr u32 block_height_log2 = 4; | ||
| 228 | const u32 bytes_per_pixel = GetBytesPerPixel(framebuffer); | ||
| 229 | const u64 linear_size{GetSizeInBytes(framebuffer)}; | ||
| 230 | const u64 tiled_size{Tegra::Texture::CalculateSize(true, bytes_per_pixel, | ||
| 231 | framebuffer.stride, framebuffer.height, | ||
| 232 | 1, block_height_log2, 0)}; | ||
| 233 | Tegra::Texture::UnswizzleTexture( | ||
| 234 | mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size), | ||
| 235 | bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); | ||
| 236 | |||
| 237 | const VkBufferImageCopy copy{ | ||
| 238 | .bufferOffset = image_offset, | ||
| 239 | .bufferRowLength = 0, | ||
| 240 | .bufferImageHeight = 0, | ||
| 241 | .imageSubresource = | ||
| 242 | { | ||
| 243 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 244 | .mipLevel = 0, | ||
| 245 | .baseArrayLayer = 0, | ||
| 246 | .layerCount = 1, | ||
| 247 | }, | ||
| 248 | .imageOffset = {.x = 0, .y = 0, .z = 0}, | ||
| 249 | .imageExtent = | ||
| 250 | { | ||
| 251 | .width = framebuffer.width, | ||
| 252 | .height = framebuffer.height, | ||
| 253 | .depth = 1, | ||
| 254 | }, | ||
| 255 | }; | ||
| 256 | scheduler.Record([this, copy, index = image_index](vk::CommandBuffer cmdbuf) { | ||
| 257 | const VkImage image = *raw_images[index]; | ||
| 258 | const VkImageMemoryBarrier base_barrier{ | ||
| 259 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 260 | .pNext = nullptr, | ||
| 261 | .srcAccessMask = 0, | ||
| 262 | .dstAccessMask = 0, | ||
| 263 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 264 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 265 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 266 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 267 | .image = image, | ||
| 268 | .subresourceRange{ | ||
| 269 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 270 | .baseMipLevel = 0, | ||
| 271 | .levelCount = 1, | ||
| 272 | .baseArrayLayer = 0, | ||
| 273 | .layerCount = 1, | ||
| 274 | }, | ||
| 275 | }; | ||
| 276 | VkImageMemoryBarrier read_barrier = base_barrier; | ||
| 277 | read_barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; | ||
| 278 | read_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | ||
| 279 | read_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||
| 280 | |||
| 281 | VkImageMemoryBarrier write_barrier = base_barrier; | ||
| 282 | write_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | ||
| 283 | write_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; | ||
| 284 | |||
| 285 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, | ||
| 286 | read_barrier); | ||
| 287 | cmdbuf.CopyBufferToImage(*buffer, image, VK_IMAGE_LAYOUT_GENERAL, copy); | ||
| 288 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 289 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | | ||
| 290 | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | ||
| 291 | 0, write_barrier); | ||
| 292 | }); | ||
| 293 | } | 80 | } |
| 294 | 81 | ||
| 295 | const auto anti_alias_pass = Settings::values.anti_aliasing.GetValue(); | 82 | // If we have a pending resource update, perform it |
| 296 | if (use_accelerated && anti_alias_pass == Settings::AntiAliasing::Fxaa) { | 83 | if (resource_update_required) { |
| 297 | UpdateAADescriptorSet(source_image_view, false); | 84 | // Wait for idle to ensure no resources are in use |
| 298 | const u32 up_scale = Settings::values.resolution_info.up_scale; | 85 | WaitIdle(); |
| 299 | const u32 down_shift = Settings::values.resolution_info.down_shift; | ||
| 300 | VkExtent2D size{ | ||
| 301 | .width = (up_scale * framebuffer.width) >> down_shift, | ||
| 302 | .height = (up_scale * framebuffer.height) >> down_shift, | ||
| 303 | }; | ||
| 304 | scheduler.Record([this, index = image_index, size, | ||
| 305 | anti_alias_pass](vk::CommandBuffer cmdbuf) { | ||
| 306 | const VkImageMemoryBarrier base_barrier{ | ||
| 307 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 308 | .pNext = nullptr, | ||
| 309 | .srcAccessMask = 0, | ||
| 310 | .dstAccessMask = 0, | ||
| 311 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 312 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 313 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 314 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 315 | .image = {}, | ||
| 316 | .subresourceRange = | ||
| 317 | { | ||
| 318 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 319 | .baseMipLevel = 0, | ||
| 320 | .levelCount = 1, | ||
| 321 | .baseArrayLayer = 0, | ||
| 322 | .layerCount = 1, | ||
| 323 | }, | ||
| 324 | }; | ||
| 325 | |||
| 326 | { | ||
| 327 | VkImageMemoryBarrier fsr_write_barrier = base_barrier; | ||
| 328 | fsr_write_barrier.image = *aa_image; | ||
| 329 | fsr_write_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||
| 330 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 331 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, fsr_write_barrier); | ||
| 332 | } | ||
| 333 | 86 | ||
| 334 | const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f; | 87 | // Update window adapt pass |
| 335 | const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f; | 88 | SetWindowAdaptPass(); |
| 336 | const f32 bg_blue = Settings::values.bg_blue.GetValue() / 255.0f; | ||
| 337 | const VkClearValue clear_color{ | ||
| 338 | .color = {.float32 = {bg_red, bg_green, bg_blue, 1.0f}}, | ||
| 339 | }; | ||
| 340 | const VkRenderPassBeginInfo renderpass_bi{ | ||
| 341 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, | ||
| 342 | .pNext = nullptr, | ||
| 343 | .renderPass = *aa_renderpass, | ||
| 344 | .framebuffer = *aa_framebuffer, | ||
| 345 | .renderArea = | ||
| 346 | { | ||
| 347 | .offset = {0, 0}, | ||
| 348 | .extent = size, | ||
| 349 | }, | ||
| 350 | .clearValueCount = 1, | ||
| 351 | .pClearValues = &clear_color, | ||
| 352 | }; | ||
| 353 | const VkViewport viewport{ | ||
| 354 | .x = 0.0f, | ||
| 355 | .y = 0.0f, | ||
| 356 | .width = static_cast<float>(size.width), | ||
| 357 | .height = static_cast<float>(size.height), | ||
| 358 | .minDepth = 0.0f, | ||
| 359 | .maxDepth = 1.0f, | ||
| 360 | }; | ||
| 361 | const VkRect2D scissor{ | ||
| 362 | .offset = {0, 0}, | ||
| 363 | .extent = size, | ||
| 364 | }; | ||
| 365 | cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); | ||
| 366 | switch (anti_alias_pass) { | ||
| 367 | case Settings::AntiAliasing::Fxaa: | ||
| 368 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *aa_pipeline); | ||
| 369 | break; | ||
| 370 | default: | ||
| 371 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *aa_pipeline); | ||
| 372 | break; | ||
| 373 | } | ||
| 374 | cmdbuf.SetViewport(0, viewport); | ||
| 375 | cmdbuf.SetScissor(0, scissor); | ||
| 376 | 89 | ||
| 377 | cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices)); | 90 | // Update frame format if needed |
| 378 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *aa_pipeline_layout, 0, | 91 | if (presentation_recreate_required) { |
| 379 | aa_descriptor_sets[index], {}); | 92 | present_manager.RecreateFrame(frame, layout.width, layout.height, swapchain_view_format, |
| 380 | cmdbuf.Draw(4, 1, 0, 0); | 93 | window_adapt->GetRenderPass()); |
| 381 | cmdbuf.EndRenderPass(); | ||
| 382 | |||
| 383 | { | ||
| 384 | VkImageMemoryBarrier blit_read_barrier = base_barrier; | ||
| 385 | blit_read_barrier.image = *aa_image; | ||
| 386 | blit_read_barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; | ||
| 387 | blit_read_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; | ||
| 388 | |||
| 389 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | ||
| 390 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, blit_read_barrier); | ||
| 391 | } | ||
| 392 | }); | ||
| 393 | source_image_view = *aa_image_view; | ||
| 394 | } | ||
| 395 | if (use_accelerated && anti_alias_pass == Settings::AntiAliasing::Smaa) { | ||
| 396 | if (!smaa) { | ||
| 397 | const u32 up_scale = Settings::values.resolution_info.up_scale; | ||
| 398 | const u32 down_shift = Settings::values.resolution_info.down_shift; | ||
| 399 | const VkExtent2D smaa_size{ | ||
| 400 | .width = (up_scale * framebuffer.width) >> down_shift, | ||
| 401 | .height = (up_scale * framebuffer.height) >> down_shift, | ||
| 402 | }; | ||
| 403 | CreateSMAA(smaa_size); | ||
| 404 | } | 94 | } |
| 405 | source_image_view = smaa->Draw(scheduler, image_index, source_image, source_image_view); | ||
| 406 | } | 95 | } |
| 407 | if (fsr) { | ||
| 408 | const auto crop_rect = NormalizeCrop(framebuffer, screen_info); | ||
| 409 | const VkExtent2D fsr_input_size{ | ||
| 410 | .width = Settings::values.resolution_info.ScaleUp(screen_info.width), | ||
| 411 | .height = Settings::values.resolution_info.ScaleUp(screen_info.height), | ||
| 412 | }; | ||
| 413 | VkImageView fsr_image_view = | ||
| 414 | fsr->Draw(scheduler, image_index, source_image_view, fsr_input_size, crop_rect); | ||
| 415 | UpdateDescriptorSet(fsr_image_view, true); | ||
| 416 | } else { | ||
| 417 | const bool is_nn = | ||
| 418 | Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::NearestNeighbor; | ||
| 419 | UpdateDescriptorSet(source_image_view, is_nn); | ||
| 420 | } | ||
| 421 | |||
| 422 | scheduler.Record([this, host_framebuffer, index = image_index, | ||
| 423 | size = render_area](vk::CommandBuffer cmdbuf) { | ||
| 424 | const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f; | ||
| 425 | const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f; | ||
| 426 | const f32 bg_blue = Settings::values.bg_blue.GetValue() / 255.0f; | ||
| 427 | const VkClearValue clear_color{ | ||
| 428 | .color = {.float32 = {bg_red, bg_green, bg_blue, 1.0f}}, | ||
| 429 | }; | ||
| 430 | const VkRenderPassBeginInfo renderpass_bi{ | ||
| 431 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, | ||
| 432 | .pNext = nullptr, | ||
| 433 | .renderPass = *renderpass, | ||
| 434 | .framebuffer = host_framebuffer, | ||
| 435 | .renderArea = | ||
| 436 | { | ||
| 437 | .offset = {0, 0}, | ||
| 438 | .extent = size, | ||
| 439 | }, | ||
| 440 | .clearValueCount = 1, | ||
| 441 | .pClearValues = &clear_color, | ||
| 442 | }; | ||
| 443 | const VkViewport viewport{ | ||
| 444 | .x = 0.0f, | ||
| 445 | .y = 0.0f, | ||
| 446 | .width = static_cast<float>(size.width), | ||
| 447 | .height = static_cast<float>(size.height), | ||
| 448 | .minDepth = 0.0f, | ||
| 449 | .maxDepth = 1.0f, | ||
| 450 | }; | ||
| 451 | const VkRect2D scissor{ | ||
| 452 | .offset = {0, 0}, | ||
| 453 | .extent = size, | ||
| 454 | }; | ||
| 455 | cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); | ||
| 456 | auto graphics_pipeline = [this]() { | ||
| 457 | switch (Settings::values.scaling_filter.GetValue()) { | ||
| 458 | case Settings::ScalingFilter::NearestNeighbor: | ||
| 459 | case Settings::ScalingFilter::Bilinear: | ||
| 460 | return *bilinear_pipeline; | ||
| 461 | case Settings::ScalingFilter::Bicubic: | ||
| 462 | return *bicubic_pipeline; | ||
| 463 | case Settings::ScalingFilter::Gaussian: | ||
| 464 | return *gaussian_pipeline; | ||
| 465 | case Settings::ScalingFilter::ScaleForce: | ||
| 466 | return *scaleforce_pipeline; | ||
| 467 | default: | ||
| 468 | return *bilinear_pipeline; | ||
| 469 | } | ||
| 470 | }(); | ||
| 471 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline); | ||
| 472 | cmdbuf.SetViewport(0, viewport); | ||
| 473 | cmdbuf.SetScissor(0, scissor); | ||
| 474 | 96 | ||
| 475 | cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices)); | 97 | // Add additional layers if needed |
| 476 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline_layout, 0, | 98 | const VkExtent2D window_size{ |
| 477 | descriptor_sets[index], {}); | 99 | .width = layout.screen.GetWidth(), |
| 478 | cmdbuf.Draw(4, 1, 0, 0); | 100 | .height = layout.screen.GetHeight(), |
| 479 | cmdbuf.EndRenderPass(); | 101 | }; |
| 480 | }); | ||
| 481 | } | ||
| 482 | 102 | ||
| 483 | void BlitScreen::DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer, | 103 | while (layers.size() < framebuffers.size()) { |
| 484 | bool use_accelerated) { | 104 | layers.emplace_back(device, memory_allocator, scheduler, device_memory, image_count, |
| 485 | // Recreate dynamic resources if the the image count or input format changed | 105 | window_size, window_adapt->GetDescriptorSetLayout()); |
| 486 | const VkFormat current_framebuffer_format = | ||
| 487 | std::exchange(framebuffer_view_format, GetFormat(framebuffer)); | ||
| 488 | if (const std::size_t swapchain_images = swapchain.GetImageCount(); | ||
| 489 | swapchain_images != image_count || current_framebuffer_format != framebuffer_view_format) { | ||
| 490 | image_count = swapchain_images; | ||
| 491 | Recreate(); | ||
| 492 | } | 106 | } |
| 493 | 107 | ||
| 494 | // Recreate the presentation frame if the dimensions of the window changed | 108 | // Perform the draw |
| 495 | const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); | 109 | window_adapt->Draw(rasterizer, scheduler, image_index, layers, framebuffers, layout, frame); |
| 496 | if (layout.width != frame->width || layout.height != frame->height) { | ||
| 497 | Recreate(); | ||
| 498 | present_manager.RecreateFrame(frame, layout.width, layout.height, swapchain_view_format, | ||
| 499 | *renderpass); | ||
| 500 | } | ||
| 501 | 110 | ||
| 502 | const VkExtent2D render_area{frame->width, frame->height}; | 111 | // Advance to next image |
| 503 | Draw(framebuffer, *frame->framebuffer, layout, render_area, use_accelerated); | ||
| 504 | if (++image_index >= image_count) { | 112 | if (++image_index >= image_count) { |
| 505 | image_index = 0; | 113 | image_index = 0; |
| 506 | } | 114 | } |
| 507 | } | 115 | } |
| 508 | 116 | ||
| 509 | vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent) { | 117 | vk::Framebuffer BlitScreen::CreateFramebuffer(const Layout::FramebufferLayout& layout, |
| 510 | return CreateFramebuffer(image_view, extent, renderpass); | 118 | VkImageView image_view, |
| 119 | VkFormat current_view_format) { | ||
| 120 | const bool format_updated = | ||
| 121 | std::exchange(swapchain_view_format, current_view_format) != current_view_format; | ||
| 122 | if (!window_adapt || scaling_filter != Settings::values.scaling_filter.GetValue() || | ||
| 123 | format_updated) { | ||
| 124 | WaitIdle(); | ||
| 125 | SetWindowAdaptPass(); | ||
| 126 | } | ||
| 127 | const VkExtent2D extent{ | ||
| 128 | .width = layout.width, | ||
| 129 | .height = layout.height, | ||
| 130 | }; | ||
| 131 | return CreateFramebuffer(image_view, extent, window_adapt->GetRenderPass()); | ||
| 511 | } | 132 | } |
| 512 | 133 | ||
| 513 | vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent, | 134 | vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent, |
| 514 | vk::RenderPass& rd) { | 135 | VkRenderPass render_pass) { |
| 515 | return device.GetLogical().CreateFramebuffer(VkFramebufferCreateInfo{ | 136 | return device.GetLogical().CreateFramebuffer(VkFramebufferCreateInfo{ |
| 516 | .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, | 137 | .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, |
| 517 | .pNext = nullptr, | 138 | .pNext = nullptr, |
| 518 | .flags = 0, | 139 | .flags = 0, |
| 519 | .renderPass = *rd, | 140 | .renderPass = render_pass, |
| 520 | .attachmentCount = 1, | 141 | .attachmentCount = 1, |
| 521 | .pAttachments = &image_view, | 142 | .pAttachments = &image_view, |
| 522 | .width = extent.width, | 143 | .width = extent.width, |
| @@ -525,969 +146,4 @@ vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkE | |||
| 525 | }); | 146 | }); |
| 526 | } | 147 | } |
| 527 | 148 | ||
| 528 | void BlitScreen::CreateStaticResources() { | ||
| 529 | CreateShaders(); | ||
| 530 | CreateSampler(); | ||
| 531 | } | ||
| 532 | |||
| 533 | void BlitScreen::CreateDynamicResources() { | ||
| 534 | CreateDescriptorPool(); | ||
| 535 | CreateDescriptorSetLayout(); | ||
| 536 | CreateDescriptorSets(); | ||
| 537 | CreatePipelineLayout(); | ||
| 538 | CreateRenderPass(); | ||
| 539 | CreateGraphicsPipeline(); | ||
| 540 | fsr.reset(); | ||
| 541 | smaa.reset(); | ||
| 542 | if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { | ||
| 543 | CreateFSR(); | ||
| 544 | } | ||
| 545 | } | ||
| 546 | |||
| 547 | void BlitScreen::RefreshResources(const Tegra::FramebufferConfig& framebuffer) { | ||
| 548 | if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { | ||
| 549 | if (!fsr) { | ||
| 550 | CreateFSR(); | ||
| 551 | } | ||
| 552 | } else { | ||
| 553 | fsr.reset(); | ||
| 554 | } | ||
| 555 | |||
| 556 | if (framebuffer.width == raw_width && framebuffer.height == raw_height && | ||
| 557 | framebuffer.pixel_format == pixel_format && !raw_images.empty()) { | ||
| 558 | return; | ||
| 559 | } | ||
| 560 | |||
| 561 | raw_width = framebuffer.width; | ||
| 562 | raw_height = framebuffer.height; | ||
| 563 | pixel_format = framebuffer.pixel_format; | ||
| 564 | |||
| 565 | smaa.reset(); | ||
| 566 | ReleaseRawImages(); | ||
| 567 | |||
| 568 | CreateStagingBuffer(framebuffer); | ||
| 569 | CreateRawImages(framebuffer); | ||
| 570 | } | ||
| 571 | |||
| 572 | void BlitScreen::CreateShaders() { | ||
| 573 | vertex_shader = BuildShader(device, VULKAN_PRESENT_VERT_SPV); | ||
| 574 | fxaa_vertex_shader = BuildShader(device, FXAA_VERT_SPV); | ||
| 575 | fxaa_fragment_shader = BuildShader(device, FXAA_FRAG_SPV); | ||
| 576 | bilinear_fragment_shader = BuildShader(device, VULKAN_PRESENT_FRAG_SPV); | ||
| 577 | bicubic_fragment_shader = BuildShader(device, PRESENT_BICUBIC_FRAG_SPV); | ||
| 578 | gaussian_fragment_shader = BuildShader(device, PRESENT_GAUSSIAN_FRAG_SPV); | ||
| 579 | if (device.IsFloat16Supported()) { | ||
| 580 | scaleforce_fragment_shader = BuildShader(device, VULKAN_PRESENT_SCALEFORCE_FP16_FRAG_SPV); | ||
| 581 | } else { | ||
| 582 | scaleforce_fragment_shader = BuildShader(device, VULKAN_PRESENT_SCALEFORCE_FP32_FRAG_SPV); | ||
| 583 | } | ||
| 584 | } | ||
| 585 | |||
| 586 | void BlitScreen::CreateDescriptorPool() { | ||
| 587 | const std::array<VkDescriptorPoolSize, 2> pool_sizes{{ | ||
| 588 | { | ||
| 589 | .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, | ||
| 590 | .descriptorCount = static_cast<u32>(image_count), | ||
| 591 | }, | ||
| 592 | { | ||
| 593 | .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 594 | .descriptorCount = static_cast<u32>(image_count), | ||
| 595 | }, | ||
| 596 | }}; | ||
| 597 | |||
| 598 | const std::array<VkDescriptorPoolSize, 1> pool_sizes_aa{{ | ||
| 599 | { | ||
| 600 | .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 601 | .descriptorCount = static_cast<u32>(image_count * 2), | ||
| 602 | }, | ||
| 603 | }}; | ||
| 604 | |||
| 605 | const VkDescriptorPoolCreateInfo ci{ | ||
| 606 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, | ||
| 607 | .pNext = nullptr, | ||
| 608 | .flags = 0, | ||
| 609 | .maxSets = static_cast<u32>(image_count), | ||
| 610 | .poolSizeCount = static_cast<u32>(pool_sizes.size()), | ||
| 611 | .pPoolSizes = pool_sizes.data(), | ||
| 612 | }; | ||
| 613 | descriptor_pool = device.GetLogical().CreateDescriptorPool(ci); | ||
| 614 | |||
| 615 | const VkDescriptorPoolCreateInfo ci_aa{ | ||
| 616 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, | ||
| 617 | .pNext = nullptr, | ||
| 618 | .flags = 0, | ||
| 619 | .maxSets = static_cast<u32>(image_count), | ||
| 620 | .poolSizeCount = static_cast<u32>(pool_sizes_aa.size()), | ||
| 621 | .pPoolSizes = pool_sizes_aa.data(), | ||
| 622 | }; | ||
| 623 | aa_descriptor_pool = device.GetLogical().CreateDescriptorPool(ci_aa); | ||
| 624 | } | ||
| 625 | |||
| 626 | void BlitScreen::CreateRenderPass() { | ||
| 627 | renderpass = CreateRenderPassImpl(swapchain_view_format); | ||
| 628 | } | ||
| 629 | |||
| 630 | vk::RenderPass BlitScreen::CreateRenderPassImpl(VkFormat format) { | ||
| 631 | const VkAttachmentDescription color_attachment{ | ||
| 632 | .flags = 0, | ||
| 633 | .format = format, | ||
| 634 | .samples = VK_SAMPLE_COUNT_1_BIT, | ||
| 635 | .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, | ||
| 636 | .storeOp = VK_ATTACHMENT_STORE_OP_STORE, | ||
| 637 | .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, | ||
| 638 | .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, | ||
| 639 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | ||
| 640 | .finalLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 641 | }; | ||
| 642 | |||
| 643 | const VkAttachmentReference color_attachment_ref{ | ||
| 644 | .attachment = 0, | ||
| 645 | .layout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 646 | }; | ||
| 647 | |||
| 648 | const VkSubpassDescription subpass_description{ | ||
| 649 | .flags = 0, | ||
| 650 | .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, | ||
| 651 | .inputAttachmentCount = 0, | ||
| 652 | .pInputAttachments = nullptr, | ||
| 653 | .colorAttachmentCount = 1, | ||
| 654 | .pColorAttachments = &color_attachment_ref, | ||
| 655 | .pResolveAttachments = nullptr, | ||
| 656 | .pDepthStencilAttachment = nullptr, | ||
| 657 | .preserveAttachmentCount = 0, | ||
| 658 | .pPreserveAttachments = nullptr, | ||
| 659 | }; | ||
| 660 | |||
| 661 | const VkSubpassDependency dependency{ | ||
| 662 | .srcSubpass = VK_SUBPASS_EXTERNAL, | ||
| 663 | .dstSubpass = 0, | ||
| 664 | .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | ||
| 665 | .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | ||
| 666 | .srcAccessMask = 0, | ||
| 667 | .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, | ||
| 668 | .dependencyFlags = 0, | ||
| 669 | }; | ||
| 670 | |||
| 671 | const VkRenderPassCreateInfo renderpass_ci{ | ||
| 672 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, | ||
| 673 | .pNext = nullptr, | ||
| 674 | .flags = 0, | ||
| 675 | .attachmentCount = 1, | ||
| 676 | .pAttachments = &color_attachment, | ||
| 677 | .subpassCount = 1, | ||
| 678 | .pSubpasses = &subpass_description, | ||
| 679 | .dependencyCount = 1, | ||
| 680 | .pDependencies = &dependency, | ||
| 681 | }; | ||
| 682 | |||
| 683 | return device.GetLogical().CreateRenderPass(renderpass_ci); | ||
| 684 | } | ||
| 685 | |||
| 686 | void BlitScreen::CreateDescriptorSetLayout() { | ||
| 687 | const std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings{{ | ||
| 688 | { | ||
| 689 | .binding = 0, | ||
| 690 | .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, | ||
| 691 | .descriptorCount = 1, | ||
| 692 | .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 693 | .pImmutableSamplers = nullptr, | ||
| 694 | }, | ||
| 695 | { | ||
| 696 | .binding = 1, | ||
| 697 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 698 | .descriptorCount = 1, | ||
| 699 | .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 700 | .pImmutableSamplers = nullptr, | ||
| 701 | }, | ||
| 702 | }}; | ||
| 703 | |||
| 704 | const std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings_aa{{ | ||
| 705 | { | ||
| 706 | .binding = 0, | ||
| 707 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 708 | .descriptorCount = 1, | ||
| 709 | .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 710 | .pImmutableSamplers = nullptr, | ||
| 711 | }, | ||
| 712 | { | ||
| 713 | .binding = 1, | ||
| 714 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 715 | .descriptorCount = 1, | ||
| 716 | .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 717 | .pImmutableSamplers = nullptr, | ||
| 718 | }, | ||
| 719 | }}; | ||
| 720 | |||
| 721 | const VkDescriptorSetLayoutCreateInfo ci{ | ||
| 722 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, | ||
| 723 | .pNext = nullptr, | ||
| 724 | .flags = 0, | ||
| 725 | .bindingCount = static_cast<u32>(layout_bindings.size()), | ||
| 726 | .pBindings = layout_bindings.data(), | ||
| 727 | }; | ||
| 728 | |||
| 729 | const VkDescriptorSetLayoutCreateInfo ci_aa{ | ||
| 730 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, | ||
| 731 | .pNext = nullptr, | ||
| 732 | .flags = 0, | ||
| 733 | .bindingCount = static_cast<u32>(layout_bindings_aa.size()), | ||
| 734 | .pBindings = layout_bindings_aa.data(), | ||
| 735 | }; | ||
| 736 | |||
| 737 | descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(ci); | ||
| 738 | aa_descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(ci_aa); | ||
| 739 | } | ||
| 740 | |||
| 741 | void BlitScreen::CreateDescriptorSets() { | ||
| 742 | const std::vector layouts(image_count, *descriptor_set_layout); | ||
| 743 | const std::vector layouts_aa(image_count, *aa_descriptor_set_layout); | ||
| 744 | |||
| 745 | const VkDescriptorSetAllocateInfo ai{ | ||
| 746 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, | ||
| 747 | .pNext = nullptr, | ||
| 748 | .descriptorPool = *descriptor_pool, | ||
| 749 | .descriptorSetCount = static_cast<u32>(image_count), | ||
| 750 | .pSetLayouts = layouts.data(), | ||
| 751 | }; | ||
| 752 | |||
| 753 | const VkDescriptorSetAllocateInfo ai_aa{ | ||
| 754 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, | ||
| 755 | .pNext = nullptr, | ||
| 756 | .descriptorPool = *aa_descriptor_pool, | ||
| 757 | .descriptorSetCount = static_cast<u32>(image_count), | ||
| 758 | .pSetLayouts = layouts_aa.data(), | ||
| 759 | }; | ||
| 760 | |||
| 761 | descriptor_sets = descriptor_pool.Allocate(ai); | ||
| 762 | aa_descriptor_sets = aa_descriptor_pool.Allocate(ai_aa); | ||
| 763 | } | ||
| 764 | |||
| 765 | void BlitScreen::CreatePipelineLayout() { | ||
| 766 | const VkPipelineLayoutCreateInfo ci{ | ||
| 767 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | ||
| 768 | .pNext = nullptr, | ||
| 769 | .flags = 0, | ||
| 770 | .setLayoutCount = 1, | ||
| 771 | .pSetLayouts = descriptor_set_layout.address(), | ||
| 772 | .pushConstantRangeCount = 0, | ||
| 773 | .pPushConstantRanges = nullptr, | ||
| 774 | }; | ||
| 775 | const VkPipelineLayoutCreateInfo ci_aa{ | ||
| 776 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | ||
| 777 | .pNext = nullptr, | ||
| 778 | .flags = 0, | ||
| 779 | .setLayoutCount = 1, | ||
| 780 | .pSetLayouts = aa_descriptor_set_layout.address(), | ||
| 781 | .pushConstantRangeCount = 0, | ||
| 782 | .pPushConstantRanges = nullptr, | ||
| 783 | }; | ||
| 784 | pipeline_layout = device.GetLogical().CreatePipelineLayout(ci); | ||
| 785 | aa_pipeline_layout = device.GetLogical().CreatePipelineLayout(ci_aa); | ||
| 786 | } | ||
| 787 | |||
| 788 | void BlitScreen::CreateGraphicsPipeline() { | ||
| 789 | const std::array<VkPipelineShaderStageCreateInfo, 2> bilinear_shader_stages{{ | ||
| 790 | { | ||
| 791 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 792 | .pNext = nullptr, | ||
| 793 | .flags = 0, | ||
| 794 | .stage = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 795 | .module = *vertex_shader, | ||
| 796 | .pName = "main", | ||
| 797 | .pSpecializationInfo = nullptr, | ||
| 798 | }, | ||
| 799 | { | ||
| 800 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 801 | .pNext = nullptr, | ||
| 802 | .flags = 0, | ||
| 803 | .stage = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 804 | .module = *bilinear_fragment_shader, | ||
| 805 | .pName = "main", | ||
| 806 | .pSpecializationInfo = nullptr, | ||
| 807 | }, | ||
| 808 | }}; | ||
| 809 | |||
| 810 | const std::array<VkPipelineShaderStageCreateInfo, 2> bicubic_shader_stages{{ | ||
| 811 | { | ||
| 812 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 813 | .pNext = nullptr, | ||
| 814 | .flags = 0, | ||
| 815 | .stage = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 816 | .module = *vertex_shader, | ||
| 817 | .pName = "main", | ||
| 818 | .pSpecializationInfo = nullptr, | ||
| 819 | }, | ||
| 820 | { | ||
| 821 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 822 | .pNext = nullptr, | ||
| 823 | .flags = 0, | ||
| 824 | .stage = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 825 | .module = *bicubic_fragment_shader, | ||
| 826 | .pName = "main", | ||
| 827 | .pSpecializationInfo = nullptr, | ||
| 828 | }, | ||
| 829 | }}; | ||
| 830 | |||
| 831 | const std::array<VkPipelineShaderStageCreateInfo, 2> gaussian_shader_stages{{ | ||
| 832 | { | ||
| 833 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 834 | .pNext = nullptr, | ||
| 835 | .flags = 0, | ||
| 836 | .stage = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 837 | .module = *vertex_shader, | ||
| 838 | .pName = "main", | ||
| 839 | .pSpecializationInfo = nullptr, | ||
| 840 | }, | ||
| 841 | { | ||
| 842 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 843 | .pNext = nullptr, | ||
| 844 | .flags = 0, | ||
| 845 | .stage = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 846 | .module = *gaussian_fragment_shader, | ||
| 847 | .pName = "main", | ||
| 848 | .pSpecializationInfo = nullptr, | ||
| 849 | }, | ||
| 850 | }}; | ||
| 851 | |||
| 852 | const std::array<VkPipelineShaderStageCreateInfo, 2> scaleforce_shader_stages{{ | ||
| 853 | { | ||
| 854 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 855 | .pNext = nullptr, | ||
| 856 | .flags = 0, | ||
| 857 | .stage = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 858 | .module = *vertex_shader, | ||
| 859 | .pName = "main", | ||
| 860 | .pSpecializationInfo = nullptr, | ||
| 861 | }, | ||
| 862 | { | ||
| 863 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 864 | .pNext = nullptr, | ||
| 865 | .flags = 0, | ||
| 866 | .stage = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 867 | .module = *scaleforce_fragment_shader, | ||
| 868 | .pName = "main", | ||
| 869 | .pSpecializationInfo = nullptr, | ||
| 870 | }, | ||
| 871 | }}; | ||
| 872 | |||
| 873 | const auto vertex_binding_description = ScreenRectVertex::GetDescription(); | ||
| 874 | const auto vertex_attrs_description = ScreenRectVertex::GetAttributes(); | ||
| 875 | |||
| 876 | const VkPipelineVertexInputStateCreateInfo vertex_input_ci{ | ||
| 877 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | ||
| 878 | .pNext = nullptr, | ||
| 879 | .flags = 0, | ||
| 880 | .vertexBindingDescriptionCount = 1, | ||
| 881 | .pVertexBindingDescriptions = &vertex_binding_description, | ||
| 882 | .vertexAttributeDescriptionCount = u32{vertex_attrs_description.size()}, | ||
| 883 | .pVertexAttributeDescriptions = vertex_attrs_description.data(), | ||
| 884 | }; | ||
| 885 | |||
| 886 | const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ | ||
| 887 | .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | ||
| 888 | .pNext = nullptr, | ||
| 889 | .flags = 0, | ||
| 890 | .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, | ||
| 891 | .primitiveRestartEnable = VK_FALSE, | ||
| 892 | }; | ||
| 893 | |||
| 894 | const VkPipelineViewportStateCreateInfo viewport_state_ci{ | ||
| 895 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| 896 | .pNext = nullptr, | ||
| 897 | .flags = 0, | ||
| 898 | .viewportCount = 1, | ||
| 899 | .pViewports = nullptr, | ||
| 900 | .scissorCount = 1, | ||
| 901 | .pScissors = nullptr, | ||
| 902 | }; | ||
| 903 | |||
| 904 | const VkPipelineRasterizationStateCreateInfo rasterization_ci{ | ||
| 905 | .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | ||
| 906 | .pNext = nullptr, | ||
| 907 | .flags = 0, | ||
| 908 | .depthClampEnable = VK_FALSE, | ||
| 909 | .rasterizerDiscardEnable = VK_FALSE, | ||
| 910 | .polygonMode = VK_POLYGON_MODE_FILL, | ||
| 911 | .cullMode = VK_CULL_MODE_NONE, | ||
| 912 | .frontFace = VK_FRONT_FACE_CLOCKWISE, | ||
| 913 | .depthBiasEnable = VK_FALSE, | ||
| 914 | .depthBiasConstantFactor = 0.0f, | ||
| 915 | .depthBiasClamp = 0.0f, | ||
| 916 | .depthBiasSlopeFactor = 0.0f, | ||
| 917 | .lineWidth = 1.0f, | ||
| 918 | }; | ||
| 919 | |||
| 920 | const VkPipelineMultisampleStateCreateInfo multisampling_ci{ | ||
| 921 | .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||
| 922 | .pNext = nullptr, | ||
| 923 | .flags = 0, | ||
| 924 | .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, | ||
| 925 | .sampleShadingEnable = VK_FALSE, | ||
| 926 | .minSampleShading = 0.0f, | ||
| 927 | .pSampleMask = nullptr, | ||
| 928 | .alphaToCoverageEnable = VK_FALSE, | ||
| 929 | .alphaToOneEnable = VK_FALSE, | ||
| 930 | }; | ||
| 931 | |||
| 932 | const VkPipelineColorBlendAttachmentState color_blend_attachment{ | ||
| 933 | .blendEnable = VK_FALSE, | ||
| 934 | .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 935 | .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 936 | .colorBlendOp = VK_BLEND_OP_ADD, | ||
| 937 | .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 938 | .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 939 | .alphaBlendOp = VK_BLEND_OP_ADD, | ||
| 940 | .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | | ||
| 941 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, | ||
| 942 | }; | ||
| 943 | |||
| 944 | const VkPipelineColorBlendStateCreateInfo color_blend_ci{ | ||
| 945 | .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | ||
| 946 | .pNext = nullptr, | ||
| 947 | .flags = 0, | ||
| 948 | .logicOpEnable = VK_FALSE, | ||
| 949 | .logicOp = VK_LOGIC_OP_COPY, | ||
| 950 | .attachmentCount = 1, | ||
| 951 | .pAttachments = &color_blend_attachment, | ||
| 952 | .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, | ||
| 953 | }; | ||
| 954 | |||
| 955 | static constexpr std::array dynamic_states{ | ||
| 956 | VK_DYNAMIC_STATE_VIEWPORT, | ||
| 957 | VK_DYNAMIC_STATE_SCISSOR, | ||
| 958 | }; | ||
| 959 | const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ | ||
| 960 | .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||
| 961 | .pNext = nullptr, | ||
| 962 | .flags = 0, | ||
| 963 | .dynamicStateCount = static_cast<u32>(dynamic_states.size()), | ||
| 964 | .pDynamicStates = dynamic_states.data(), | ||
| 965 | }; | ||
| 966 | |||
| 967 | const VkGraphicsPipelineCreateInfo bilinear_pipeline_ci{ | ||
| 968 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 969 | .pNext = nullptr, | ||
| 970 | .flags = 0, | ||
| 971 | .stageCount = static_cast<u32>(bilinear_shader_stages.size()), | ||
| 972 | .pStages = bilinear_shader_stages.data(), | ||
| 973 | .pVertexInputState = &vertex_input_ci, | ||
| 974 | .pInputAssemblyState = &input_assembly_ci, | ||
| 975 | .pTessellationState = nullptr, | ||
| 976 | .pViewportState = &viewport_state_ci, | ||
| 977 | .pRasterizationState = &rasterization_ci, | ||
| 978 | .pMultisampleState = &multisampling_ci, | ||
| 979 | .pDepthStencilState = nullptr, | ||
| 980 | .pColorBlendState = &color_blend_ci, | ||
| 981 | .pDynamicState = &dynamic_state_ci, | ||
| 982 | .layout = *pipeline_layout, | ||
| 983 | .renderPass = *renderpass, | ||
| 984 | .subpass = 0, | ||
| 985 | .basePipelineHandle = 0, | ||
| 986 | .basePipelineIndex = 0, | ||
| 987 | }; | ||
| 988 | |||
| 989 | const VkGraphicsPipelineCreateInfo bicubic_pipeline_ci{ | ||
| 990 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 991 | .pNext = nullptr, | ||
| 992 | .flags = 0, | ||
| 993 | .stageCount = static_cast<u32>(bicubic_shader_stages.size()), | ||
| 994 | .pStages = bicubic_shader_stages.data(), | ||
| 995 | .pVertexInputState = &vertex_input_ci, | ||
| 996 | .pInputAssemblyState = &input_assembly_ci, | ||
| 997 | .pTessellationState = nullptr, | ||
| 998 | .pViewportState = &viewport_state_ci, | ||
| 999 | .pRasterizationState = &rasterization_ci, | ||
| 1000 | .pMultisampleState = &multisampling_ci, | ||
| 1001 | .pDepthStencilState = nullptr, | ||
| 1002 | .pColorBlendState = &color_blend_ci, | ||
| 1003 | .pDynamicState = &dynamic_state_ci, | ||
| 1004 | .layout = *pipeline_layout, | ||
| 1005 | .renderPass = *renderpass, | ||
| 1006 | .subpass = 0, | ||
| 1007 | .basePipelineHandle = 0, | ||
| 1008 | .basePipelineIndex = 0, | ||
| 1009 | }; | ||
| 1010 | |||
| 1011 | const VkGraphicsPipelineCreateInfo gaussian_pipeline_ci{ | ||
| 1012 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 1013 | .pNext = nullptr, | ||
| 1014 | .flags = 0, | ||
| 1015 | .stageCount = static_cast<u32>(gaussian_shader_stages.size()), | ||
| 1016 | .pStages = gaussian_shader_stages.data(), | ||
| 1017 | .pVertexInputState = &vertex_input_ci, | ||
| 1018 | .pInputAssemblyState = &input_assembly_ci, | ||
| 1019 | .pTessellationState = nullptr, | ||
| 1020 | .pViewportState = &viewport_state_ci, | ||
| 1021 | .pRasterizationState = &rasterization_ci, | ||
| 1022 | .pMultisampleState = &multisampling_ci, | ||
| 1023 | .pDepthStencilState = nullptr, | ||
| 1024 | .pColorBlendState = &color_blend_ci, | ||
| 1025 | .pDynamicState = &dynamic_state_ci, | ||
| 1026 | .layout = *pipeline_layout, | ||
| 1027 | .renderPass = *renderpass, | ||
| 1028 | .subpass = 0, | ||
| 1029 | .basePipelineHandle = 0, | ||
| 1030 | .basePipelineIndex = 0, | ||
| 1031 | }; | ||
| 1032 | |||
| 1033 | const VkGraphicsPipelineCreateInfo scaleforce_pipeline_ci{ | ||
| 1034 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 1035 | .pNext = nullptr, | ||
| 1036 | .flags = 0, | ||
| 1037 | .stageCount = static_cast<u32>(scaleforce_shader_stages.size()), | ||
| 1038 | .pStages = scaleforce_shader_stages.data(), | ||
| 1039 | .pVertexInputState = &vertex_input_ci, | ||
| 1040 | .pInputAssemblyState = &input_assembly_ci, | ||
| 1041 | .pTessellationState = nullptr, | ||
| 1042 | .pViewportState = &viewport_state_ci, | ||
| 1043 | .pRasterizationState = &rasterization_ci, | ||
| 1044 | .pMultisampleState = &multisampling_ci, | ||
| 1045 | .pDepthStencilState = nullptr, | ||
| 1046 | .pColorBlendState = &color_blend_ci, | ||
| 1047 | .pDynamicState = &dynamic_state_ci, | ||
| 1048 | .layout = *pipeline_layout, | ||
| 1049 | .renderPass = *renderpass, | ||
| 1050 | .subpass = 0, | ||
| 1051 | .basePipelineHandle = 0, | ||
| 1052 | .basePipelineIndex = 0, | ||
| 1053 | }; | ||
| 1054 | |||
| 1055 | bilinear_pipeline = device.GetLogical().CreateGraphicsPipeline(bilinear_pipeline_ci); | ||
| 1056 | bicubic_pipeline = device.GetLogical().CreateGraphicsPipeline(bicubic_pipeline_ci); | ||
| 1057 | gaussian_pipeline = device.GetLogical().CreateGraphicsPipeline(gaussian_pipeline_ci); | ||
| 1058 | scaleforce_pipeline = device.GetLogical().CreateGraphicsPipeline(scaleforce_pipeline_ci); | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | void BlitScreen::CreateSampler() { | ||
| 1062 | const VkSamplerCreateInfo ci{ | ||
| 1063 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, | ||
| 1064 | .pNext = nullptr, | ||
| 1065 | .flags = 0, | ||
| 1066 | .magFilter = VK_FILTER_LINEAR, | ||
| 1067 | .minFilter = VK_FILTER_LINEAR, | ||
| 1068 | .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, | ||
| 1069 | .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 1070 | .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 1071 | .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 1072 | .mipLodBias = 0.0f, | ||
| 1073 | .anisotropyEnable = VK_FALSE, | ||
| 1074 | .maxAnisotropy = 0.0f, | ||
| 1075 | .compareEnable = VK_FALSE, | ||
| 1076 | .compareOp = VK_COMPARE_OP_NEVER, | ||
| 1077 | .minLod = 0.0f, | ||
| 1078 | .maxLod = 0.0f, | ||
| 1079 | .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, | ||
| 1080 | .unnormalizedCoordinates = VK_FALSE, | ||
| 1081 | }; | ||
| 1082 | |||
| 1083 | const VkSamplerCreateInfo ci_nn{ | ||
| 1084 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, | ||
| 1085 | .pNext = nullptr, | ||
| 1086 | .flags = 0, | ||
| 1087 | .magFilter = VK_FILTER_NEAREST, | ||
| 1088 | .minFilter = VK_FILTER_NEAREST, | ||
| 1089 | .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, | ||
| 1090 | .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 1091 | .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 1092 | .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 1093 | .mipLodBias = 0.0f, | ||
| 1094 | .anisotropyEnable = VK_FALSE, | ||
| 1095 | .maxAnisotropy = 0.0f, | ||
| 1096 | .compareEnable = VK_FALSE, | ||
| 1097 | .compareOp = VK_COMPARE_OP_NEVER, | ||
| 1098 | .minLod = 0.0f, | ||
| 1099 | .maxLod = 0.0f, | ||
| 1100 | .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, | ||
| 1101 | .unnormalizedCoordinates = VK_FALSE, | ||
| 1102 | }; | ||
| 1103 | |||
| 1104 | sampler = device.GetLogical().CreateSampler(ci); | ||
| 1105 | nn_sampler = device.GetLogical().CreateSampler(ci_nn); | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | void BlitScreen::ReleaseRawImages() { | ||
| 1109 | for (const u64 tick : resource_ticks) { | ||
| 1110 | scheduler.Wait(tick); | ||
| 1111 | } | ||
| 1112 | raw_images.clear(); | ||
| 1113 | aa_image_view.reset(); | ||
| 1114 | aa_image.reset(); | ||
| 1115 | buffer.reset(); | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { | ||
| 1119 | const VkBufferCreateInfo ci{ | ||
| 1120 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | ||
| 1121 | .pNext = nullptr, | ||
| 1122 | .flags = 0, | ||
| 1123 | .size = CalculateBufferSize(framebuffer), | ||
| 1124 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | | ||
| 1125 | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, | ||
| 1126 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 1127 | .queueFamilyIndexCount = 0, | ||
| 1128 | .pQueueFamilyIndices = nullptr, | ||
| 1129 | }; | ||
| 1130 | |||
| 1131 | buffer = memory_allocator.CreateBuffer(ci, MemoryUsage::Upload); | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | ||
| 1135 | raw_images.resize(image_count); | ||
| 1136 | raw_image_views.resize(image_count); | ||
| 1137 | |||
| 1138 | const auto create_image = [&](bool used_on_framebuffer = false, u32 up_scale = 1, | ||
| 1139 | u32 down_shift = 0) { | ||
| 1140 | u32 extra_usages = used_on_framebuffer ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | ||
| 1141 | : VK_IMAGE_USAGE_TRANSFER_DST_BIT; | ||
| 1142 | return memory_allocator.CreateImage(VkImageCreateInfo{ | ||
| 1143 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | ||
| 1144 | .pNext = nullptr, | ||
| 1145 | .flags = 0, | ||
| 1146 | .imageType = VK_IMAGE_TYPE_2D, | ||
| 1147 | .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : framebuffer_view_format, | ||
| 1148 | .extent = | ||
| 1149 | { | ||
| 1150 | .width = (up_scale * framebuffer.width) >> down_shift, | ||
| 1151 | .height = (up_scale * framebuffer.height) >> down_shift, | ||
| 1152 | .depth = 1, | ||
| 1153 | }, | ||
| 1154 | .mipLevels = 1, | ||
| 1155 | .arrayLayers = 1, | ||
| 1156 | .samples = VK_SAMPLE_COUNT_1_BIT, | ||
| 1157 | .tiling = used_on_framebuffer ? VK_IMAGE_TILING_OPTIMAL : VK_IMAGE_TILING_LINEAR, | ||
| 1158 | .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | extra_usages, | ||
| 1159 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 1160 | .queueFamilyIndexCount = 0, | ||
| 1161 | .pQueueFamilyIndices = nullptr, | ||
| 1162 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | ||
| 1163 | }); | ||
| 1164 | }; | ||
| 1165 | const auto create_image_view = [&](vk::Image& image, bool used_on_framebuffer = false) { | ||
| 1166 | return device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | ||
| 1167 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | ||
| 1168 | .pNext = nullptr, | ||
| 1169 | .flags = 0, | ||
| 1170 | .image = *image, | ||
| 1171 | .viewType = VK_IMAGE_VIEW_TYPE_2D, | ||
| 1172 | .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : framebuffer_view_format, | ||
| 1173 | .components = | ||
| 1174 | { | ||
| 1175 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 1176 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 1177 | .b = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 1178 | .a = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 1179 | }, | ||
| 1180 | .subresourceRange = | ||
| 1181 | { | ||
| 1182 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 1183 | .baseMipLevel = 0, | ||
| 1184 | .levelCount = 1, | ||
| 1185 | .baseArrayLayer = 0, | ||
| 1186 | .layerCount = 1, | ||
| 1187 | }, | ||
| 1188 | }); | ||
| 1189 | }; | ||
| 1190 | |||
| 1191 | for (size_t i = 0; i < image_count; ++i) { | ||
| 1192 | raw_images[i] = create_image(); | ||
| 1193 | raw_image_views[i] = create_image_view(raw_images[i]); | ||
| 1194 | } | ||
| 1195 | |||
| 1196 | // AA Resources | ||
| 1197 | const u32 up_scale = Settings::values.resolution_info.up_scale; | ||
| 1198 | const u32 down_shift = Settings::values.resolution_info.down_shift; | ||
| 1199 | aa_image = create_image(true, up_scale, down_shift); | ||
| 1200 | aa_image_view = create_image_view(aa_image, true); | ||
| 1201 | VkExtent2D size{ | ||
| 1202 | .width = (up_scale * framebuffer.width) >> down_shift, | ||
| 1203 | .height = (up_scale * framebuffer.height) >> down_shift, | ||
| 1204 | }; | ||
| 1205 | if (aa_renderpass) { | ||
| 1206 | aa_framebuffer = CreateFramebuffer(*aa_image_view, size, aa_renderpass); | ||
| 1207 | return; | ||
| 1208 | } | ||
| 1209 | aa_renderpass = CreateRenderPassImpl(VK_FORMAT_R16G16B16A16_SFLOAT); | ||
| 1210 | aa_framebuffer = CreateFramebuffer(*aa_image_view, size, aa_renderpass); | ||
| 1211 | |||
| 1212 | const std::array<VkPipelineShaderStageCreateInfo, 2> fxaa_shader_stages{{ | ||
| 1213 | { | ||
| 1214 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 1215 | .pNext = nullptr, | ||
| 1216 | .flags = 0, | ||
| 1217 | .stage = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 1218 | .module = *fxaa_vertex_shader, | ||
| 1219 | .pName = "main", | ||
| 1220 | .pSpecializationInfo = nullptr, | ||
| 1221 | }, | ||
| 1222 | { | ||
| 1223 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 1224 | .pNext = nullptr, | ||
| 1225 | .flags = 0, | ||
| 1226 | .stage = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 1227 | .module = *fxaa_fragment_shader, | ||
| 1228 | .pName = "main", | ||
| 1229 | .pSpecializationInfo = nullptr, | ||
| 1230 | }, | ||
| 1231 | }}; | ||
| 1232 | |||
| 1233 | const auto vertex_binding_description = ScreenRectVertex::GetDescription(); | ||
| 1234 | const auto vertex_attrs_description = ScreenRectVertex::GetAttributes(); | ||
| 1235 | |||
| 1236 | const VkPipelineVertexInputStateCreateInfo vertex_input_ci{ | ||
| 1237 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | ||
| 1238 | .pNext = nullptr, | ||
| 1239 | .flags = 0, | ||
| 1240 | .vertexBindingDescriptionCount = 1, | ||
| 1241 | .pVertexBindingDescriptions = &vertex_binding_description, | ||
| 1242 | .vertexAttributeDescriptionCount = u32{vertex_attrs_description.size()}, | ||
| 1243 | .pVertexAttributeDescriptions = vertex_attrs_description.data(), | ||
| 1244 | }; | ||
| 1245 | |||
| 1246 | const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ | ||
| 1247 | .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | ||
| 1248 | .pNext = nullptr, | ||
| 1249 | .flags = 0, | ||
| 1250 | .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, | ||
| 1251 | .primitiveRestartEnable = VK_FALSE, | ||
| 1252 | }; | ||
| 1253 | |||
| 1254 | const VkPipelineViewportStateCreateInfo viewport_state_ci{ | ||
| 1255 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| 1256 | .pNext = nullptr, | ||
| 1257 | .flags = 0, | ||
| 1258 | .viewportCount = 1, | ||
| 1259 | .pViewports = nullptr, | ||
| 1260 | .scissorCount = 1, | ||
| 1261 | .pScissors = nullptr, | ||
| 1262 | }; | ||
| 1263 | |||
| 1264 | const VkPipelineRasterizationStateCreateInfo rasterization_ci{ | ||
| 1265 | .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | ||
| 1266 | .pNext = nullptr, | ||
| 1267 | .flags = 0, | ||
| 1268 | .depthClampEnable = VK_FALSE, | ||
| 1269 | .rasterizerDiscardEnable = VK_FALSE, | ||
| 1270 | .polygonMode = VK_POLYGON_MODE_FILL, | ||
| 1271 | .cullMode = VK_CULL_MODE_NONE, | ||
| 1272 | .frontFace = VK_FRONT_FACE_CLOCKWISE, | ||
| 1273 | .depthBiasEnable = VK_FALSE, | ||
| 1274 | .depthBiasConstantFactor = 0.0f, | ||
| 1275 | .depthBiasClamp = 0.0f, | ||
| 1276 | .depthBiasSlopeFactor = 0.0f, | ||
| 1277 | .lineWidth = 1.0f, | ||
| 1278 | }; | ||
| 1279 | |||
| 1280 | const VkPipelineMultisampleStateCreateInfo multisampling_ci{ | ||
| 1281 | .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||
| 1282 | .pNext = nullptr, | ||
| 1283 | .flags = 0, | ||
| 1284 | .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, | ||
| 1285 | .sampleShadingEnable = VK_FALSE, | ||
| 1286 | .minSampleShading = 0.0f, | ||
| 1287 | .pSampleMask = nullptr, | ||
| 1288 | .alphaToCoverageEnable = VK_FALSE, | ||
| 1289 | .alphaToOneEnable = VK_FALSE, | ||
| 1290 | }; | ||
| 1291 | |||
| 1292 | const VkPipelineColorBlendAttachmentState color_blend_attachment{ | ||
| 1293 | .blendEnable = VK_FALSE, | ||
| 1294 | .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 1295 | .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 1296 | .colorBlendOp = VK_BLEND_OP_ADD, | ||
| 1297 | .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 1298 | .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 1299 | .alphaBlendOp = VK_BLEND_OP_ADD, | ||
| 1300 | .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | | ||
| 1301 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, | ||
| 1302 | }; | ||
| 1303 | |||
| 1304 | const VkPipelineColorBlendStateCreateInfo color_blend_ci{ | ||
| 1305 | .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | ||
| 1306 | .pNext = nullptr, | ||
| 1307 | .flags = 0, | ||
| 1308 | .logicOpEnable = VK_FALSE, | ||
| 1309 | .logicOp = VK_LOGIC_OP_COPY, | ||
| 1310 | .attachmentCount = 1, | ||
| 1311 | .pAttachments = &color_blend_attachment, | ||
| 1312 | .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, | ||
| 1313 | }; | ||
| 1314 | |||
| 1315 | static constexpr std::array dynamic_states{ | ||
| 1316 | VK_DYNAMIC_STATE_VIEWPORT, | ||
| 1317 | VK_DYNAMIC_STATE_SCISSOR, | ||
| 1318 | }; | ||
| 1319 | const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ | ||
| 1320 | .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||
| 1321 | .pNext = nullptr, | ||
| 1322 | .flags = 0, | ||
| 1323 | .dynamicStateCount = static_cast<u32>(dynamic_states.size()), | ||
| 1324 | .pDynamicStates = dynamic_states.data(), | ||
| 1325 | }; | ||
| 1326 | |||
| 1327 | const VkGraphicsPipelineCreateInfo fxaa_pipeline_ci{ | ||
| 1328 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 1329 | .pNext = nullptr, | ||
| 1330 | .flags = 0, | ||
| 1331 | .stageCount = static_cast<u32>(fxaa_shader_stages.size()), | ||
| 1332 | .pStages = fxaa_shader_stages.data(), | ||
| 1333 | .pVertexInputState = &vertex_input_ci, | ||
| 1334 | .pInputAssemblyState = &input_assembly_ci, | ||
| 1335 | .pTessellationState = nullptr, | ||
| 1336 | .pViewportState = &viewport_state_ci, | ||
| 1337 | .pRasterizationState = &rasterization_ci, | ||
| 1338 | .pMultisampleState = &multisampling_ci, | ||
| 1339 | .pDepthStencilState = nullptr, | ||
| 1340 | .pColorBlendState = &color_blend_ci, | ||
| 1341 | .pDynamicState = &dynamic_state_ci, | ||
| 1342 | .layout = *aa_pipeline_layout, | ||
| 1343 | .renderPass = *aa_renderpass, | ||
| 1344 | .subpass = 0, | ||
| 1345 | .basePipelineHandle = 0, | ||
| 1346 | .basePipelineIndex = 0, | ||
| 1347 | }; | ||
| 1348 | |||
| 1349 | // AA | ||
| 1350 | aa_pipeline = device.GetLogical().CreateGraphicsPipeline(fxaa_pipeline_ci); | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | void BlitScreen::UpdateAADescriptorSet(VkImageView image_view, bool nn) const { | ||
| 1354 | const VkDescriptorImageInfo image_info{ | ||
| 1355 | .sampler = nn ? *nn_sampler : *sampler, | ||
| 1356 | .imageView = image_view, | ||
| 1357 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 1358 | }; | ||
| 1359 | |||
| 1360 | const VkWriteDescriptorSet sampler_write{ | ||
| 1361 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 1362 | .pNext = nullptr, | ||
| 1363 | .dstSet = aa_descriptor_sets[image_index], | ||
| 1364 | .dstBinding = 0, | ||
| 1365 | .dstArrayElement = 0, | ||
| 1366 | .descriptorCount = 1, | ||
| 1367 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 1368 | .pImageInfo = &image_info, | ||
| 1369 | .pBufferInfo = nullptr, | ||
| 1370 | .pTexelBufferView = nullptr, | ||
| 1371 | }; | ||
| 1372 | |||
| 1373 | const VkWriteDescriptorSet sampler_write_2{ | ||
| 1374 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 1375 | .pNext = nullptr, | ||
| 1376 | .dstSet = aa_descriptor_sets[image_index], | ||
| 1377 | .dstBinding = 1, | ||
| 1378 | .dstArrayElement = 0, | ||
| 1379 | .descriptorCount = 1, | ||
| 1380 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 1381 | .pImageInfo = &image_info, | ||
| 1382 | .pBufferInfo = nullptr, | ||
| 1383 | .pTexelBufferView = nullptr, | ||
| 1384 | }; | ||
| 1385 | |||
| 1386 | device.GetLogical().UpdateDescriptorSets(std::array{sampler_write, sampler_write_2}, {}); | ||
| 1387 | } | ||
| 1388 | |||
| 1389 | void BlitScreen::UpdateDescriptorSet(VkImageView image_view, bool nn) const { | ||
| 1390 | const VkDescriptorBufferInfo buffer_info{ | ||
| 1391 | .buffer = *buffer, | ||
| 1392 | .offset = offsetof(BufferData, uniform), | ||
| 1393 | .range = sizeof(BufferData::uniform), | ||
| 1394 | }; | ||
| 1395 | |||
| 1396 | const VkWriteDescriptorSet ubo_write{ | ||
| 1397 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 1398 | .pNext = nullptr, | ||
| 1399 | .dstSet = descriptor_sets[image_index], | ||
| 1400 | .dstBinding = 0, | ||
| 1401 | .dstArrayElement = 0, | ||
| 1402 | .descriptorCount = 1, | ||
| 1403 | .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, | ||
| 1404 | .pImageInfo = nullptr, | ||
| 1405 | .pBufferInfo = &buffer_info, | ||
| 1406 | .pTexelBufferView = nullptr, | ||
| 1407 | }; | ||
| 1408 | |||
| 1409 | const VkDescriptorImageInfo image_info{ | ||
| 1410 | .sampler = nn ? *nn_sampler : *sampler, | ||
| 1411 | .imageView = image_view, | ||
| 1412 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 1413 | }; | ||
| 1414 | |||
| 1415 | const VkWriteDescriptorSet sampler_write{ | ||
| 1416 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 1417 | .pNext = nullptr, | ||
| 1418 | .dstSet = descriptor_sets[image_index], | ||
| 1419 | .dstBinding = 1, | ||
| 1420 | .dstArrayElement = 0, | ||
| 1421 | .descriptorCount = 1, | ||
| 1422 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 1423 | .pImageInfo = &image_info, | ||
| 1424 | .pBufferInfo = nullptr, | ||
| 1425 | .pTexelBufferView = nullptr, | ||
| 1426 | }; | ||
| 1427 | |||
| 1428 | device.GetLogical().UpdateDescriptorSets(std::array{ubo_write, sampler_write}, {}); | ||
| 1429 | } | ||
| 1430 | |||
| 1431 | void BlitScreen::SetUniformData(BufferData& data, const Layout::FramebufferLayout layout) const { | ||
| 1432 | data.uniform.modelview_matrix = | ||
| 1433 | MakeOrthographicMatrix(static_cast<f32>(layout.width), static_cast<f32>(layout.height)); | ||
| 1434 | } | ||
| 1435 | |||
| 1436 | void BlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, | ||
| 1437 | const Layout::FramebufferLayout layout) const { | ||
| 1438 | f32 left, top, right, bottom; | ||
| 1439 | |||
| 1440 | if (fsr) { | ||
| 1441 | // FSR has already applied the crop, so we just want to render the image | ||
| 1442 | // it has produced. | ||
| 1443 | left = 0; | ||
| 1444 | top = 0; | ||
| 1445 | right = 1; | ||
| 1446 | bottom = 1; | ||
| 1447 | } else { | ||
| 1448 | // Get the normalized crop rectangle. | ||
| 1449 | const auto crop = NormalizeCrop(framebuffer, screen_info); | ||
| 1450 | |||
| 1451 | // Apply the crop. | ||
| 1452 | left = crop.left; | ||
| 1453 | top = crop.top; | ||
| 1454 | right = crop.right; | ||
| 1455 | bottom = crop.bottom; | ||
| 1456 | } | ||
| 1457 | |||
| 1458 | // Map the coordinates to the screen. | ||
| 1459 | const auto& screen = layout.screen; | ||
| 1460 | const auto x = static_cast<f32>(screen.left); | ||
| 1461 | const auto y = static_cast<f32>(screen.top); | ||
| 1462 | const auto w = static_cast<f32>(screen.GetWidth()); | ||
| 1463 | const auto h = static_cast<f32>(screen.GetHeight()); | ||
| 1464 | |||
| 1465 | data.vertices[0] = ScreenRectVertex(x, y, left, top); | ||
| 1466 | data.vertices[1] = ScreenRectVertex(x + w, y, right, top); | ||
| 1467 | data.vertices[2] = ScreenRectVertex(x, y + h, left, bottom); | ||
| 1468 | data.vertices[3] = ScreenRectVertex(x + w, y + h, right, bottom); | ||
| 1469 | } | ||
| 1470 | |||
| 1471 | void BlitScreen::CreateSMAA(VkExtent2D smaa_size) { | ||
| 1472 | smaa = std::make_unique<SMAA>(device, memory_allocator, image_count, smaa_size); | ||
| 1473 | } | ||
| 1474 | |||
| 1475 | void BlitScreen::CreateFSR() { | ||
| 1476 | const auto& layout = render_window.GetFramebufferLayout(); | ||
| 1477 | const VkExtent2D fsr_size{ | ||
| 1478 | .width = layout.screen.GetWidth(), | ||
| 1479 | .height = layout.screen.GetHeight(), | ||
| 1480 | }; | ||
| 1481 | fsr = std::make_unique<FSR>(device, memory_allocator, image_count, fsr_size); | ||
| 1482 | } | ||
| 1483 | |||
| 1484 | u64 BlitScreen::CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const { | ||
| 1485 | return sizeof(BufferData) + GetSizeInBytes(framebuffer) * image_count; | ||
| 1486 | } | ||
| 1487 | |||
| 1488 | u64 BlitScreen::GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer) const { | ||
| 1489 | constexpr auto first_image_offset = static_cast<u64>(sizeof(BufferData)); | ||
| 1490 | return first_image_offset + GetSizeInBytes(framebuffer) * image_index; | ||
| 1491 | } | ||
| 1492 | |||
| 1493 | } // namespace Vulkan | 149 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 3eff76009..cbdf2d5d0 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h | |||
| @@ -3,10 +3,12 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <list> | ||
| 6 | #include <memory> | 7 | #include <memory> |
| 7 | 8 | ||
| 8 | #include "core/frontend/framebuffer_layout.h" | 9 | #include "core/frontend/framebuffer_layout.h" |
| 9 | #include "video_core/host1x/gpu_device_memory_manager.h" | 10 | #include "video_core/host1x/gpu_device_memory_manager.h" |
| 11 | #include "video_core/renderer_vulkan/present/layer.h" | ||
| 10 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | 12 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" |
| 11 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 12 | 14 | ||
| @@ -14,155 +16,67 @@ namespace Core { | |||
| 14 | class System; | 16 | class System; |
| 15 | } | 17 | } |
| 16 | 18 | ||
| 17 | namespace Core::Frontend { | ||
| 18 | class EmuWindow; | ||
| 19 | } | ||
| 20 | |||
| 21 | namespace Tegra { | 19 | namespace Tegra { |
| 22 | struct FramebufferConfig; | 20 | struct FramebufferConfig; |
| 23 | } | 21 | } |
| 24 | 22 | ||
| 25 | namespace VideoCore { | 23 | namespace Settings { |
| 26 | class RasterizerInterface; | 24 | enum class ScalingFilter : u32; |
| 27 | } | 25 | } // namespace Settings |
| 28 | |||
| 29 | namespace Service::android { | ||
| 30 | enum class PixelFormat : u32; | ||
| 31 | } | ||
| 32 | 26 | ||
| 33 | namespace Vulkan { | 27 | namespace Vulkan { |
| 34 | 28 | ||
| 35 | struct ScreenInfo; | ||
| 36 | |||
| 37 | class Device; | 29 | class Device; |
| 38 | class FSR; | ||
| 39 | class RasterizerVulkan; | 30 | class RasterizerVulkan; |
| 40 | class Scheduler; | 31 | class Scheduler; |
| 41 | class SMAA; | ||
| 42 | class Swapchain; | ||
| 43 | class PresentManager; | 32 | class PresentManager; |
| 33 | class WindowAdaptPass; | ||
| 44 | 34 | ||
| 45 | struct Frame; | 35 | struct Frame; |
| 46 | 36 | ||
| 47 | struct ScreenInfo { | 37 | struct FramebufferTextureInfo { |
| 48 | VkImage image{}; | 38 | VkImage image{}; |
| 49 | VkImageView image_view{}; | 39 | VkImageView image_view{}; |
| 50 | u32 width{}; | 40 | u32 width{}; |
| 51 | u32 height{}; | 41 | u32 height{}; |
| 42 | u32 scaled_width{}; | ||
| 43 | u32 scaled_height{}; | ||
| 52 | }; | 44 | }; |
| 53 | 45 | ||
| 54 | class BlitScreen { | 46 | class BlitScreen { |
| 55 | public: | 47 | public: |
| 56 | explicit BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory, | 48 | explicit BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory, const Device& device, |
| 57 | Core::Frontend::EmuWindow& render_window, const Device& device, | 49 | MemoryAllocator& memory_allocator, PresentManager& present_manager, |
| 58 | MemoryAllocator& memory_manager, Swapchain& swapchain, | 50 | Scheduler& scheduler); |
| 59 | PresentManager& present_manager, Scheduler& scheduler, | ||
| 60 | const ScreenInfo& screen_info); | ||
| 61 | ~BlitScreen(); | 51 | ~BlitScreen(); |
| 62 | 52 | ||
| 63 | void Recreate(); | 53 | void DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame, |
| 64 | 54 | std::span<const Tegra::FramebufferConfig> framebuffers, | |
| 65 | void Draw(const Tegra::FramebufferConfig& framebuffer, const VkFramebuffer& host_framebuffer, | 55 | const Layout::FramebufferLayout& layout, size_t current_swapchain_image_count, |
| 66 | const Layout::FramebufferLayout layout, VkExtent2D render_area, bool use_accelerated); | 56 | VkFormat current_swapchain_view_format); |
| 67 | |||
| 68 | void DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer, | ||
| 69 | bool use_accelerated); | ||
| 70 | 57 | ||
| 71 | [[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, | 58 | [[nodiscard]] vk::Framebuffer CreateFramebuffer(const Layout::FramebufferLayout& layout, |
| 72 | VkExtent2D extent); | 59 | VkImageView image_view, |
| 73 | 60 | VkFormat current_view_format); | |
| 74 | [[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, | ||
| 75 | VkExtent2D extent, vk::RenderPass& rd); | ||
| 76 | 61 | ||
| 77 | private: | 62 | private: |
| 78 | struct BufferData; | 63 | void WaitIdle(); |
| 79 | 64 | void SetWindowAdaptPass(); | |
| 80 | void CreateStaticResources(); | 65 | vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent, |
| 81 | void CreateShaders(); | 66 | VkRenderPass render_pass); |
| 82 | void CreateDescriptorPool(); | ||
| 83 | void CreateRenderPass(); | ||
| 84 | vk::RenderPass CreateRenderPassImpl(VkFormat format); | ||
| 85 | void CreateDescriptorSetLayout(); | ||
| 86 | void CreateDescriptorSets(); | ||
| 87 | void CreatePipelineLayout(); | ||
| 88 | void CreateGraphicsPipeline(); | ||
| 89 | void CreateSampler(); | ||
| 90 | |||
| 91 | void CreateDynamicResources(); | ||
| 92 | |||
| 93 | void RefreshResources(const Tegra::FramebufferConfig& framebuffer); | ||
| 94 | void ReleaseRawImages(); | ||
| 95 | void CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer); | ||
| 96 | void CreateRawImages(const Tegra::FramebufferConfig& framebuffer); | ||
| 97 | |||
| 98 | 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; | ||
| 101 | void SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, | ||
| 102 | const Layout::FramebufferLayout layout) const; | ||
| 103 | |||
| 104 | void CreateSMAA(VkExtent2D smaa_size); | ||
| 105 | void CreateFSR(); | ||
| 106 | |||
| 107 | u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const; | ||
| 108 | u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer) const; | ||
| 109 | 67 | ||
| 110 | Tegra::MaxwellDeviceMemoryManager& device_memory; | 68 | Tegra::MaxwellDeviceMemoryManager& device_memory; |
| 111 | Core::Frontend::EmuWindow& render_window; | ||
| 112 | const Device& device; | 69 | const Device& device; |
| 113 | MemoryAllocator& memory_allocator; | 70 | MemoryAllocator& memory_allocator; |
| 114 | Swapchain& swapchain; | ||
| 115 | PresentManager& present_manager; | 71 | PresentManager& present_manager; |
| 116 | Scheduler& scheduler; | 72 | Scheduler& scheduler; |
| 117 | std::size_t image_count; | 73 | std::size_t image_count{}; |
| 118 | std::size_t image_index{}; | 74 | std::size_t image_index{}; |
| 119 | const ScreenInfo& screen_info; | 75 | VkFormat swapchain_view_format{}; |
| 120 | 76 | ||
| 121 | vk::ShaderModule vertex_shader; | 77 | Settings::ScalingFilter scaling_filter{}; |
| 122 | vk::ShaderModule fxaa_vertex_shader; | 78 | std::unique_ptr<WindowAdaptPass> window_adapt{}; |
| 123 | vk::ShaderModule fxaa_fragment_shader; | 79 | std::list<Layer> layers{}; |
| 124 | vk::ShaderModule bilinear_fragment_shader; | ||
| 125 | vk::ShaderModule bicubic_fragment_shader; | ||
| 126 | vk::ShaderModule gaussian_fragment_shader; | ||
| 127 | vk::ShaderModule scaleforce_fragment_shader; | ||
| 128 | vk::DescriptorPool descriptor_pool; | ||
| 129 | vk::DescriptorSetLayout descriptor_set_layout; | ||
| 130 | vk::PipelineLayout pipeline_layout; | ||
| 131 | vk::Pipeline nearest_neighbor_pipeline; | ||
| 132 | vk::Pipeline bilinear_pipeline; | ||
| 133 | vk::Pipeline bicubic_pipeline; | ||
| 134 | vk::Pipeline gaussian_pipeline; | ||
| 135 | vk::Pipeline scaleforce_pipeline; | ||
| 136 | vk::RenderPass renderpass; | ||
| 137 | vk::DescriptorSets descriptor_sets; | ||
| 138 | vk::Sampler nn_sampler; | ||
| 139 | vk::Sampler sampler; | ||
| 140 | |||
| 141 | vk::Buffer buffer; | ||
| 142 | |||
| 143 | std::vector<u64> resource_ticks; | ||
| 144 | |||
| 145 | std::vector<vk::Image> raw_images; | ||
| 146 | std::vector<vk::ImageView> raw_image_views; | ||
| 147 | |||
| 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; | ||
| 159 | u32 raw_height = 0; | ||
| 160 | Service::android::PixelFormat pixel_format{}; | ||
| 161 | VkFormat framebuffer_view_format; | ||
| 162 | VkFormat swapchain_view_format; | ||
| 163 | |||
| 164 | std::unique_ptr<FSR> fsr; | ||
| 165 | std::unique_ptr<SMAA> smaa; | ||
| 166 | }; | 80 | }; |
| 167 | 81 | ||
| 168 | } // namespace Vulkan | 82 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_fsr.cpp b/src/video_core/renderer_vulkan/vk_fsr.cpp deleted file mode 100644 index f7a05fbc0..000000000 --- a/src/video_core/renderer_vulkan/vk_fsr.cpp +++ /dev/null | |||
| @@ -1,420 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/common_types.h" | ||
| 5 | #include "common/div_ceil.h" | ||
| 6 | #include "common/settings.h" | ||
| 7 | |||
| 8 | #include "video_core/fsr.h" | ||
| 9 | #include "video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp16_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" | ||
| 12 | #include "video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp32_comp_spv.h" | ||
| 13 | #include "video_core/renderer_vulkan/vk_fsr.h" | ||
| 14 | #include "video_core/renderer_vulkan/vk_scheduler.h" | ||
| 15 | #include "video_core/renderer_vulkan/vk_shader_util.h" | ||
| 16 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 17 | |||
| 18 | namespace Vulkan { | ||
| 19 | using namespace FSR; | ||
| 20 | |||
| 21 | FSR::FSR(const Device& device_, MemoryAllocator& memory_allocator_, size_t image_count_, | ||
| 22 | VkExtent2D output_size_) | ||
| 23 | : device{device_}, memory_allocator{memory_allocator_}, image_count{image_count_}, | ||
| 24 | output_size{output_size_} { | ||
| 25 | |||
| 26 | CreateImages(); | ||
| 27 | CreateSampler(); | ||
| 28 | CreateShaders(); | ||
| 29 | CreateDescriptorPool(); | ||
| 30 | CreateDescriptorSetLayout(); | ||
| 31 | CreateDescriptorSets(); | ||
| 32 | CreatePipelineLayout(); | ||
| 33 | CreatePipeline(); | ||
| 34 | } | ||
| 35 | |||
| 36 | VkImageView FSR::Draw(Scheduler& scheduler, size_t image_index, VkImageView image_view, | ||
| 37 | VkExtent2D input_image_extent, const Common::Rectangle<f32>& crop_rect) { | ||
| 38 | |||
| 39 | UpdateDescriptorSet(image_index, image_view); | ||
| 40 | |||
| 41 | scheduler.Record([this, image_index, input_image_extent, crop_rect](vk::CommandBuffer cmdbuf) { | ||
| 42 | const VkImageMemoryBarrier base_barrier{ | ||
| 43 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 44 | .pNext = nullptr, | ||
| 45 | .srcAccessMask = 0, | ||
| 46 | .dstAccessMask = 0, | ||
| 47 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 48 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 49 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 50 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 51 | .image = {}, | ||
| 52 | .subresourceRange = | ||
| 53 | { | ||
| 54 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 55 | .baseMipLevel = 0, | ||
| 56 | .levelCount = 1, | ||
| 57 | .baseArrayLayer = 0, | ||
| 58 | .layerCount = 1, | ||
| 59 | }, | ||
| 60 | }; | ||
| 61 | |||
| 62 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *easu_pipeline); | ||
| 63 | |||
| 64 | const f32 input_image_width = static_cast<f32>(input_image_extent.width); | ||
| 65 | const f32 input_image_height = static_cast<f32>(input_image_extent.height); | ||
| 66 | const f32 output_image_width = static_cast<f32>(output_size.width); | ||
| 67 | const f32 output_image_height = static_cast<f32>(output_size.height); | ||
| 68 | const f32 viewport_width = (crop_rect.right - crop_rect.left) * input_image_width; | ||
| 69 | const f32 viewport_x = crop_rect.left * input_image_width; | ||
| 70 | const f32 viewport_height = (crop_rect.bottom - crop_rect.top) * input_image_height; | ||
| 71 | const f32 viewport_y = crop_rect.top * input_image_height; | ||
| 72 | |||
| 73 | std::array<u32, 4 * 4> push_constants; | ||
| 74 | FsrEasuConOffset(push_constants.data() + 0, push_constants.data() + 4, | ||
| 75 | push_constants.data() + 8, push_constants.data() + 12, | ||
| 76 | |||
| 77 | viewport_width, viewport_height, input_image_width, input_image_height, | ||
| 78 | output_image_width, output_image_height, viewport_x, viewport_y); | ||
| 79 | cmdbuf.PushConstants(*pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, push_constants); | ||
| 80 | |||
| 81 | { | ||
| 82 | VkImageMemoryBarrier fsr_write_barrier = base_barrier; | ||
| 83 | fsr_write_barrier.image = *images[image_index]; | ||
| 84 | fsr_write_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||
| 85 | |||
| 86 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 87 | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, fsr_write_barrier); | ||
| 88 | } | ||
| 89 | |||
| 90 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline_layout, 0, | ||
| 91 | descriptor_sets[image_index * 2], {}); | ||
| 92 | cmdbuf.Dispatch(Common::DivCeil(output_size.width, 16u), | ||
| 93 | Common::DivCeil(output_size.height, 16u), 1); | ||
| 94 | |||
| 95 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *rcas_pipeline); | ||
| 96 | |||
| 97 | const float sharpening = | ||
| 98 | static_cast<float>(Settings::values.fsr_sharpening_slider.GetValue()) / 100.0f; | ||
| 99 | |||
| 100 | FsrRcasCon(push_constants.data(), sharpening); | ||
| 101 | cmdbuf.PushConstants(*pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, push_constants); | ||
| 102 | |||
| 103 | { | ||
| 104 | std::array<VkImageMemoryBarrier, 2> barriers; | ||
| 105 | auto& fsr_read_barrier = barriers[0]; | ||
| 106 | auto& blit_write_barrier = barriers[1]; | ||
| 107 | |||
| 108 | fsr_read_barrier = base_barrier; | ||
| 109 | fsr_read_barrier.image = *images[image_index]; | ||
| 110 | fsr_read_barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; | ||
| 111 | fsr_read_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; | ||
| 112 | |||
| 113 | blit_write_barrier = base_barrier; | ||
| 114 | blit_write_barrier.image = *images[image_count + image_index]; | ||
| 115 | blit_write_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||
| 116 | blit_write_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; | ||
| 117 | |||
| 118 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | ||
| 119 | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, {}, {}, barriers); | ||
| 120 | } | ||
| 121 | |||
| 122 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline_layout, 0, | ||
| 123 | descriptor_sets[image_index * 2 + 1], {}); | ||
| 124 | cmdbuf.Dispatch(Common::DivCeil(output_size.width, 16u), | ||
| 125 | Common::DivCeil(output_size.height, 16u), 1); | ||
| 126 | |||
| 127 | { | ||
| 128 | std::array<VkImageMemoryBarrier, 1> barriers; | ||
| 129 | auto& blit_read_barrier = barriers[0]; | ||
| 130 | |||
| 131 | blit_read_barrier = base_barrier; | ||
| 132 | blit_read_barrier.image = *images[image_count + image_index]; | ||
| 133 | blit_read_barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; | ||
| 134 | blit_read_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; | ||
| 135 | |||
| 136 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | ||
| 137 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, {}, {}, barriers); | ||
| 138 | } | ||
| 139 | }); | ||
| 140 | |||
| 141 | return *image_views[image_count + image_index]; | ||
| 142 | } | ||
| 143 | |||
| 144 | void FSR::CreateDescriptorPool() { | ||
| 145 | const std::array<VkDescriptorPoolSize, 2> pool_sizes{{ | ||
| 146 | { | ||
| 147 | .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 148 | .descriptorCount = static_cast<u32>(image_count * 2), | ||
| 149 | }, | ||
| 150 | { | ||
| 151 | .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, | ||
| 152 | .descriptorCount = static_cast<u32>(image_count * 2), | ||
| 153 | }, | ||
| 154 | }}; | ||
| 155 | |||
| 156 | const VkDescriptorPoolCreateInfo ci{ | ||
| 157 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, | ||
| 158 | .pNext = nullptr, | ||
| 159 | .flags = 0, | ||
| 160 | .maxSets = static_cast<u32>(image_count * 2), | ||
| 161 | .poolSizeCount = static_cast<u32>(pool_sizes.size()), | ||
| 162 | .pPoolSizes = pool_sizes.data(), | ||
| 163 | }; | ||
| 164 | descriptor_pool = device.GetLogical().CreateDescriptorPool(ci); | ||
| 165 | } | ||
| 166 | |||
| 167 | void FSR::CreateDescriptorSetLayout() { | ||
| 168 | const std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings{{ | ||
| 169 | { | ||
| 170 | .binding = 0, | ||
| 171 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 172 | .descriptorCount = 1, | ||
| 173 | .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, | ||
| 174 | .pImmutableSamplers = sampler.address(), | ||
| 175 | }, | ||
| 176 | { | ||
| 177 | .binding = 1, | ||
| 178 | .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, | ||
| 179 | .descriptorCount = 1, | ||
| 180 | .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, | ||
| 181 | .pImmutableSamplers = sampler.address(), | ||
| 182 | }, | ||
| 183 | }}; | ||
| 184 | |||
| 185 | const VkDescriptorSetLayoutCreateInfo ci{ | ||
| 186 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, | ||
| 187 | .pNext = nullptr, | ||
| 188 | .flags = 0, | ||
| 189 | .bindingCount = static_cast<u32>(layout_bindings.size()), | ||
| 190 | .pBindings = layout_bindings.data(), | ||
| 191 | }; | ||
| 192 | |||
| 193 | descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(ci); | ||
| 194 | } | ||
| 195 | |||
| 196 | void FSR::CreateDescriptorSets() { | ||
| 197 | const u32 sets = static_cast<u32>(image_count * 2); | ||
| 198 | const std::vector layouts(sets, *descriptor_set_layout); | ||
| 199 | |||
| 200 | const VkDescriptorSetAllocateInfo ai{ | ||
| 201 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, | ||
| 202 | .pNext = nullptr, | ||
| 203 | .descriptorPool = *descriptor_pool, | ||
| 204 | .descriptorSetCount = sets, | ||
| 205 | .pSetLayouts = layouts.data(), | ||
| 206 | }; | ||
| 207 | |||
| 208 | descriptor_sets = descriptor_pool.Allocate(ai); | ||
| 209 | } | ||
| 210 | |||
| 211 | void FSR::CreateImages() { | ||
| 212 | images.resize(image_count * 2); | ||
| 213 | image_views.resize(image_count * 2); | ||
| 214 | |||
| 215 | for (size_t i = 0; i < image_count * 2; ++i) { | ||
| 216 | images[i] = memory_allocator.CreateImage(VkImageCreateInfo{ | ||
| 217 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | ||
| 218 | .pNext = nullptr, | ||
| 219 | .flags = 0, | ||
| 220 | .imageType = VK_IMAGE_TYPE_2D, | ||
| 221 | .format = VK_FORMAT_R16G16B16A16_SFLOAT, | ||
| 222 | .extent = | ||
| 223 | { | ||
| 224 | .width = output_size.width, | ||
| 225 | .height = output_size.height, | ||
| 226 | .depth = 1, | ||
| 227 | }, | ||
| 228 | .mipLevels = 1, | ||
| 229 | .arrayLayers = 1, | ||
| 230 | .samples = VK_SAMPLE_COUNT_1_BIT, | ||
| 231 | .tiling = VK_IMAGE_TILING_OPTIMAL, | ||
| 232 | .usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT | | ||
| 233 | VK_IMAGE_USAGE_SAMPLED_BIT, | ||
| 234 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 235 | .queueFamilyIndexCount = 0, | ||
| 236 | .pQueueFamilyIndices = nullptr, | ||
| 237 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | ||
| 238 | }); | ||
| 239 | image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | ||
| 240 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | ||
| 241 | .pNext = nullptr, | ||
| 242 | .flags = 0, | ||
| 243 | .image = *images[i], | ||
| 244 | .viewType = VK_IMAGE_VIEW_TYPE_2D, | ||
| 245 | .format = VK_FORMAT_R16G16B16A16_SFLOAT, | ||
| 246 | .components = | ||
| 247 | { | ||
| 248 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 249 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 250 | .b = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 251 | .a = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 252 | }, | ||
| 253 | .subresourceRange = | ||
| 254 | { | ||
| 255 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 256 | .baseMipLevel = 0, | ||
| 257 | .levelCount = 1, | ||
| 258 | .baseArrayLayer = 0, | ||
| 259 | .layerCount = 1, | ||
| 260 | }, | ||
| 261 | }); | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | void FSR::CreatePipelineLayout() { | ||
| 266 | VkPushConstantRange push_const{ | ||
| 267 | .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, | ||
| 268 | .offset = 0, | ||
| 269 | .size = sizeof(std::array<u32, 4 * 4>), | ||
| 270 | }; | ||
| 271 | VkPipelineLayoutCreateInfo ci{ | ||
| 272 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | ||
| 273 | .pNext = nullptr, | ||
| 274 | .flags = 0, | ||
| 275 | .setLayoutCount = 1, | ||
| 276 | .pSetLayouts = descriptor_set_layout.address(), | ||
| 277 | .pushConstantRangeCount = 1, | ||
| 278 | .pPushConstantRanges = &push_const, | ||
| 279 | }; | ||
| 280 | |||
| 281 | pipeline_layout = device.GetLogical().CreatePipelineLayout(ci); | ||
| 282 | } | ||
| 283 | |||
| 284 | void FSR::UpdateDescriptorSet(std::size_t image_index, VkImageView image_view) const { | ||
| 285 | const auto fsr_image_view = *image_views[image_index]; | ||
| 286 | const auto blit_image_view = *image_views[image_count + image_index]; | ||
| 287 | |||
| 288 | const VkDescriptorImageInfo image_info{ | ||
| 289 | .sampler = VK_NULL_HANDLE, | ||
| 290 | .imageView = image_view, | ||
| 291 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 292 | }; | ||
| 293 | const VkDescriptorImageInfo fsr_image_info{ | ||
| 294 | .sampler = VK_NULL_HANDLE, | ||
| 295 | .imageView = fsr_image_view, | ||
| 296 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 297 | }; | ||
| 298 | const VkDescriptorImageInfo blit_image_info{ | ||
| 299 | .sampler = VK_NULL_HANDLE, | ||
| 300 | .imageView = blit_image_view, | ||
| 301 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 302 | }; | ||
| 303 | |||
| 304 | VkWriteDescriptorSet sampler_write{ | ||
| 305 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 306 | .pNext = nullptr, | ||
| 307 | .dstSet = descriptor_sets[image_index * 2], | ||
| 308 | .dstBinding = 0, | ||
| 309 | .dstArrayElement = 0, | ||
| 310 | .descriptorCount = 1, | ||
| 311 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 312 | .pImageInfo = &image_info, | ||
| 313 | .pBufferInfo = nullptr, | ||
| 314 | .pTexelBufferView = nullptr, | ||
| 315 | }; | ||
| 316 | |||
| 317 | VkWriteDescriptorSet output_write{ | ||
| 318 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 319 | .pNext = nullptr, | ||
| 320 | .dstSet = descriptor_sets[image_index * 2], | ||
| 321 | .dstBinding = 1, | ||
| 322 | .dstArrayElement = 0, | ||
| 323 | .descriptorCount = 1, | ||
| 324 | .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, | ||
| 325 | .pImageInfo = &fsr_image_info, | ||
| 326 | .pBufferInfo = nullptr, | ||
| 327 | .pTexelBufferView = nullptr, | ||
| 328 | }; | ||
| 329 | |||
| 330 | device.GetLogical().UpdateDescriptorSets(std::array{sampler_write, output_write}, {}); | ||
| 331 | |||
| 332 | sampler_write.dstSet = descriptor_sets[image_index * 2 + 1]; | ||
| 333 | sampler_write.pImageInfo = &fsr_image_info; | ||
| 334 | output_write.dstSet = descriptor_sets[image_index * 2 + 1]; | ||
| 335 | output_write.pImageInfo = &blit_image_info; | ||
| 336 | |||
| 337 | device.GetLogical().UpdateDescriptorSets(std::array{sampler_write, output_write}, {}); | ||
| 338 | } | ||
| 339 | |||
| 340 | void FSR::CreateSampler() { | ||
| 341 | const VkSamplerCreateInfo ci{ | ||
| 342 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, | ||
| 343 | .pNext = nullptr, | ||
| 344 | .flags = 0, | ||
| 345 | .magFilter = VK_FILTER_LINEAR, | ||
| 346 | .minFilter = VK_FILTER_LINEAR, | ||
| 347 | .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, | ||
| 348 | .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, | ||
| 349 | .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, | ||
| 350 | .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, | ||
| 351 | .mipLodBias = 0.0f, | ||
| 352 | .anisotropyEnable = VK_FALSE, | ||
| 353 | .maxAnisotropy = 0.0f, | ||
| 354 | .compareEnable = VK_FALSE, | ||
| 355 | .compareOp = VK_COMPARE_OP_NEVER, | ||
| 356 | .minLod = 0.0f, | ||
| 357 | .maxLod = 0.0f, | ||
| 358 | .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, | ||
| 359 | .unnormalizedCoordinates = VK_FALSE, | ||
| 360 | }; | ||
| 361 | |||
| 362 | sampler = device.GetLogical().CreateSampler(ci); | ||
| 363 | } | ||
| 364 | |||
| 365 | void FSR::CreateShaders() { | ||
| 366 | if (device.IsFloat16Supported()) { | ||
| 367 | easu_shader = BuildShader(device, VULKAN_FIDELITYFX_FSR_EASU_FP16_COMP_SPV); | ||
| 368 | rcas_shader = BuildShader(device, VULKAN_FIDELITYFX_FSR_RCAS_FP16_COMP_SPV); | ||
| 369 | } else { | ||
| 370 | easu_shader = BuildShader(device, VULKAN_FIDELITYFX_FSR_EASU_FP32_COMP_SPV); | ||
| 371 | rcas_shader = BuildShader(device, VULKAN_FIDELITYFX_FSR_RCAS_FP32_COMP_SPV); | ||
| 372 | } | ||
| 373 | } | ||
| 374 | |||
| 375 | void FSR::CreatePipeline() { | ||
| 376 | VkPipelineShaderStageCreateInfo shader_stage_easu{ | ||
| 377 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 378 | .pNext = nullptr, | ||
| 379 | .flags = 0, | ||
| 380 | .stage = VK_SHADER_STAGE_COMPUTE_BIT, | ||
| 381 | .module = *easu_shader, | ||
| 382 | .pName = "main", | ||
| 383 | .pSpecializationInfo = nullptr, | ||
| 384 | }; | ||
| 385 | |||
| 386 | VkPipelineShaderStageCreateInfo shader_stage_rcas{ | ||
| 387 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 388 | .pNext = nullptr, | ||
| 389 | .flags = 0, | ||
| 390 | .stage = VK_SHADER_STAGE_COMPUTE_BIT, | ||
| 391 | .module = *rcas_shader, | ||
| 392 | .pName = "main", | ||
| 393 | .pSpecializationInfo = nullptr, | ||
| 394 | }; | ||
| 395 | |||
| 396 | VkComputePipelineCreateInfo pipeline_ci_easu{ | ||
| 397 | .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, | ||
| 398 | .pNext = nullptr, | ||
| 399 | .flags = 0, | ||
| 400 | .stage = shader_stage_easu, | ||
| 401 | .layout = *pipeline_layout, | ||
| 402 | .basePipelineHandle = VK_NULL_HANDLE, | ||
| 403 | .basePipelineIndex = 0, | ||
| 404 | }; | ||
| 405 | |||
| 406 | VkComputePipelineCreateInfo pipeline_ci_rcas{ | ||
| 407 | .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, | ||
| 408 | .pNext = nullptr, | ||
| 409 | .flags = 0, | ||
| 410 | .stage = shader_stage_rcas, | ||
| 411 | .layout = *pipeline_layout, | ||
| 412 | .basePipelineHandle = VK_NULL_HANDLE, | ||
| 413 | .basePipelineIndex = 0, | ||
| 414 | }; | ||
| 415 | |||
| 416 | easu_pipeline = device.GetLogical().CreateComputePipeline(pipeline_ci_easu); | ||
| 417 | rcas_pipeline = device.GetLogical().CreateComputePipeline(pipeline_ci_rcas); | ||
| 418 | } | ||
| 419 | |||
| 420 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_fsr.h b/src/video_core/renderer_vulkan/vk_fsr.h deleted file mode 100644 index 3505c1416..000000000 --- a/src/video_core/renderer_vulkan/vk_fsr.h +++ /dev/null | |||
| @@ -1,52 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/math_util.h" | ||
| 7 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 8 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 9 | |||
| 10 | namespace Vulkan { | ||
| 11 | |||
| 12 | class Device; | ||
| 13 | class Scheduler; | ||
| 14 | |||
| 15 | class FSR { | ||
| 16 | public: | ||
| 17 | explicit FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count, | ||
| 18 | VkExtent2D output_size); | ||
| 19 | VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImageView image_view, | ||
| 20 | VkExtent2D input_image_extent, const Common::Rectangle<f32>& crop_rect); | ||
| 21 | |||
| 22 | private: | ||
| 23 | void CreateDescriptorPool(); | ||
| 24 | void CreateDescriptorSetLayout(); | ||
| 25 | void CreateDescriptorSets(); | ||
| 26 | void CreateImages(); | ||
| 27 | void CreateSampler(); | ||
| 28 | void CreateShaders(); | ||
| 29 | void CreatePipeline(); | ||
| 30 | void CreatePipelineLayout(); | ||
| 31 | |||
| 32 | void UpdateDescriptorSet(std::size_t image_index, VkImageView image_view) const; | ||
| 33 | |||
| 34 | const Device& device; | ||
| 35 | MemoryAllocator& memory_allocator; | ||
| 36 | size_t image_count; | ||
| 37 | VkExtent2D output_size; | ||
| 38 | |||
| 39 | vk::DescriptorPool descriptor_pool; | ||
| 40 | vk::DescriptorSetLayout descriptor_set_layout; | ||
| 41 | vk::DescriptorSets descriptor_sets; | ||
| 42 | vk::PipelineLayout pipeline_layout; | ||
| 43 | vk::ShaderModule easu_shader; | ||
| 44 | vk::ShaderModule rcas_shader; | ||
| 45 | vk::Pipeline easu_pipeline; | ||
| 46 | vk::Pipeline rcas_pipeline; | ||
| 47 | vk::Sampler sampler; | ||
| 48 | std::vector<vk::Image> images; | ||
| 49 | std::vector<vk::ImageView> image_views; | ||
| 50 | }; | ||
| 51 | |||
| 52 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 5bf41b81f..aa0a027bb 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -165,10 +165,9 @@ DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances, | |||
| 165 | 165 | ||
| 166 | RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, | 166 | RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, |
| 167 | Tegra::MaxwellDeviceMemoryManager& device_memory_, | 167 | Tegra::MaxwellDeviceMemoryManager& device_memory_, |
| 168 | ScreenInfo& screen_info_, const Device& device_, | 168 | const Device& device_, MemoryAllocator& memory_allocator_, |
| 169 | MemoryAllocator& memory_allocator_, StateTracker& state_tracker_, | 169 | StateTracker& state_tracker_, Scheduler& scheduler_) |
| 170 | Scheduler& scheduler_) | 170 | : gpu{gpu_}, device_memory{device_memory_}, device{device_}, |
| 171 | : gpu{gpu_}, device_memory{device_memory_}, screen_info{screen_info_}, device{device_}, | ||
| 172 | memory_allocator{memory_allocator_}, state_tracker{state_tracker_}, scheduler{scheduler_}, | 171 | memory_allocator{memory_allocator_}, state_tracker{state_tracker_}, scheduler{scheduler_}, |
| 173 | staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler), | 172 | staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler), |
| 174 | guest_descriptor_queue(device, scheduler), compute_pass_descriptor_queue(device, scheduler), | 173 | guest_descriptor_queue(device, scheduler), compute_pass_descriptor_queue(device, scheduler), |
| @@ -783,23 +782,29 @@ void RasterizerVulkan::AccelerateInlineToMemory(GPUVAddr address, size_t copy_si | |||
| 783 | query_cache.InvalidateRegion(*cpu_addr, copy_size); | 782 | query_cache.InvalidateRegion(*cpu_addr, copy_size); |
| 784 | } | 783 | } |
| 785 | 784 | ||
| 786 | bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config, | 785 | std::optional<FramebufferTextureInfo> RasterizerVulkan::AccelerateDisplay( |
| 787 | DAddr framebuffer_addr, u32 pixel_stride) { | 786 | const Tegra::FramebufferConfig& config, DAddr framebuffer_addr, u32 pixel_stride) { |
| 788 | if (!framebuffer_addr) { | 787 | if (!framebuffer_addr) { |
| 789 | return false; | 788 | return {}; |
| 790 | } | 789 | } |
| 791 | std::scoped_lock lock{texture_cache.mutex}; | 790 | std::scoped_lock lock{texture_cache.mutex}; |
| 792 | ImageView* const image_view = | 791 | const auto [image_view, scaled] = |
| 793 | texture_cache.TryFindFramebufferImageView(config, framebuffer_addr); | 792 | texture_cache.TryFindFramebufferImageView(config, framebuffer_addr); |
| 794 | if (!image_view) { | 793 | if (!image_view) { |
| 795 | return false; | 794 | return {}; |
| 796 | } | 795 | } |
| 797 | query_cache.NotifySegment(false); | 796 | query_cache.NotifySegment(false); |
| 798 | screen_info.image = image_view->ImageHandle(); | 797 | |
| 799 | screen_info.image_view = image_view->Handle(Shader::TextureType::Color2D); | 798 | const auto& resolution = Settings::values.resolution_info; |
| 800 | screen_info.width = image_view->size.width; | 799 | |
| 801 | screen_info.height = image_view->size.height; | 800 | FramebufferTextureInfo info{}; |
| 802 | return true; | 801 | info.image = image_view->ImageHandle(); |
| 802 | info.image_view = image_view->Handle(Shader::TextureType::Color2D); | ||
| 803 | info.width = image_view->size.width; | ||
| 804 | info.height = image_view->size.height; | ||
| 805 | info.scaled_width = scaled ? resolution.ScaleUp(info.width) : info.width; | ||
| 806 | info.scaled_height = scaled ? resolution.ScaleUp(info.height) : info.height; | ||
| 807 | return info; | ||
| 803 | } | 808 | } |
| 804 | 809 | ||
| 805 | void RasterizerVulkan::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | 810 | void RasterizerVulkan::LoadDiskResources(u64 title_id, std::stop_token stop_loading, |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 881ee0993..0617b37f0 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h | |||
| @@ -43,7 +43,7 @@ class Maxwell3D; | |||
| 43 | 43 | ||
| 44 | namespace Vulkan { | 44 | namespace Vulkan { |
| 45 | 45 | ||
| 46 | struct ScreenInfo; | 46 | struct FramebufferTextureInfo; |
| 47 | 47 | ||
| 48 | class StateTracker; | 48 | class StateTracker; |
| 49 | 49 | ||
| @@ -78,9 +78,8 @@ class RasterizerVulkan final : public VideoCore::RasterizerInterface, | |||
| 78 | public: | 78 | public: |
| 79 | explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, | 79 | explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, |
| 80 | Tegra::MaxwellDeviceMemoryManager& device_memory_, | 80 | Tegra::MaxwellDeviceMemoryManager& device_memory_, |
| 81 | ScreenInfo& screen_info_, const Device& device_, | 81 | const Device& device_, MemoryAllocator& memory_allocator_, |
| 82 | MemoryAllocator& memory_allocator_, StateTracker& state_tracker_, | 82 | StateTracker& state_tracker_, Scheduler& scheduler_); |
| 83 | Scheduler& scheduler_); | ||
| 84 | ~RasterizerVulkan() override; | 83 | ~RasterizerVulkan() override; |
| 85 | 84 | ||
| 86 | void Draw(bool is_indexed, u32 instance_count) override; | 85 | void Draw(bool is_indexed, u32 instance_count) override; |
| @@ -126,8 +125,6 @@ public: | |||
| 126 | Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; | 125 | Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; |
| 127 | void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, | 126 | void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, |
| 128 | std::span<const u8> memory) override; | 127 | std::span<const u8> memory) override; |
| 129 | bool AccelerateDisplay(const Tegra::FramebufferConfig& config, DAddr framebuffer_addr, | ||
| 130 | u32 pixel_stride) override; | ||
| 131 | void LoadDiskResources(u64 title_id, std::stop_token stop_loading, | 128 | void LoadDiskResources(u64 title_id, std::stop_token stop_loading, |
| 132 | const VideoCore::DiskResourceLoadCallback& callback) override; | 129 | const VideoCore::DiskResourceLoadCallback& callback) override; |
| 133 | 130 | ||
| @@ -137,6 +134,10 @@ public: | |||
| 137 | 134 | ||
| 138 | void ReleaseChannel(s32 channel_id) override; | 135 | void ReleaseChannel(s32 channel_id) override; |
| 139 | 136 | ||
| 137 | std::optional<FramebufferTextureInfo> AccelerateDisplay(const Tegra::FramebufferConfig& config, | ||
| 138 | VAddr framebuffer_addr, | ||
| 139 | u32 pixel_stride); | ||
| 140 | |||
| 140 | private: | 141 | private: |
| 141 | static constexpr size_t MAX_TEXTURES = 192; | 142 | static constexpr size_t MAX_TEXTURES = 192; |
| 142 | static constexpr size_t MAX_IMAGES = 48; | 143 | static constexpr size_t MAX_IMAGES = 48; |
| @@ -182,7 +183,6 @@ private: | |||
| 182 | Tegra::GPU& gpu; | 183 | Tegra::GPU& gpu; |
| 183 | Tegra::MaxwellDeviceMemoryManager& device_memory; | 184 | Tegra::MaxwellDeviceMemoryManager& device_memory; |
| 184 | 185 | ||
| 185 | ScreenInfo& screen_info; | ||
| 186 | const Device& device; | 186 | const Device& device; |
| 187 | MemoryAllocator& memory_allocator; | 187 | MemoryAllocator& memory_allocator; |
| 188 | StateTracker& state_tracker; | 188 | StateTracker& state_tracker; |