diff options
| author | 2024-01-14 01:46:19 -0500 | |
|---|---|---|
| committer | 2024-01-31 11:27:20 -0500 | |
| commit | 0c2e5b64c9fb985a40e5afec898d1f370cbad23e (patch) | |
| tree | 682dc3489bf4ae13dfd533d04245749538cd9505 /src/video_core | |
| parent | renderer_vulkan: isolate FXAA from blit screen (diff) | |
| download | yuzu-0c2e5b64c9fb985a40e5afec898d1f370cbad23e.tar.gz yuzu-0c2e5b64c9fb985a40e5afec898d1f370cbad23e.tar.xz yuzu-0c2e5b64c9fb985a40e5afec898d1f370cbad23e.zip | |
renderer_vulkan: split up blit screen resources into separate antialias and window adapt passes
Diffstat (limited to 'src/video_core')
| -rw-r--r-- | src/video_core/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/present/filters.cpp | 70 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/present/filters.h | 30 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/present/util.cpp | 50 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/present/util.h | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/present/window_adapt_pass.cpp | 512 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/present/window_adapt_pass.h | 71 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/renderer_vulkan.cpp | 117 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/renderer_vulkan.h | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_blit_screen.cpp | 945 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_blit_screen.h | 93 |
11 files changed, 985 insertions, 913 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 240b80c6e..825815ebd 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -158,6 +158,9 @@ add_library(video_core STATIC | |||
| 158 | renderer_opengl/renderer_opengl.h | 158 | renderer_opengl/renderer_opengl.h |
| 159 | renderer_opengl/util_shaders.cpp | 159 | renderer_opengl/util_shaders.cpp |
| 160 | renderer_opengl/util_shaders.h | 160 | renderer_opengl/util_shaders.h |
| 161 | renderer_vulkan/present/anti_alias_pass.h | ||
| 162 | renderer_vulkan/present/filters.cpp | ||
| 163 | renderer_vulkan/present/filters.h | ||
| 161 | renderer_vulkan/present/fsr.cpp | 164 | renderer_vulkan/present/fsr.cpp |
| 162 | renderer_vulkan/present/fsr.h | 165 | renderer_vulkan/present/fsr.h |
| 163 | renderer_vulkan/present/fxaa.cpp | 166 | renderer_vulkan/present/fxaa.cpp |
| @@ -166,6 +169,8 @@ add_library(video_core STATIC | |||
| 166 | renderer_vulkan/present/smaa.h | 169 | renderer_vulkan/present/smaa.h |
| 167 | renderer_vulkan/present/util.cpp | 170 | renderer_vulkan/present/util.cpp |
| 168 | renderer_vulkan/present/util.h | 171 | renderer_vulkan/present/util.h |
| 172 | renderer_vulkan/present/window_adapt_pass.cpp | ||
| 173 | renderer_vulkan/present/window_adapt_pass.h | ||
| 169 | renderer_vulkan/blit_image.cpp | 174 | renderer_vulkan/blit_image.cpp |
| 170 | renderer_vulkan/blit_image.h | 175 | renderer_vulkan/blit_image.h |
| 171 | renderer_vulkan/fixed_pipeline_state.cpp | 176 | renderer_vulkan/fixed_pipeline_state.cpp |
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..ee6239cc4 --- /dev/null +++ b/src/video_core/renderer_vulkan/present/filters.cpp | |||
| @@ -0,0 +1,70 @@ | |||
| 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, | ||
| 31 | const MemoryAllocator& memory_allocator, | ||
| 32 | size_t image_count, VkFormat frame_format) { | ||
| 33 | return std::make_unique<WindowAdaptPass>(device, memory_allocator, image_count, frame_format, | ||
| 34 | CreateNearestNeighborSampler(device), | ||
| 35 | BuildShader(device, VULKAN_PRESENT_FRAG_SPV)); | ||
| 36 | } | ||
| 37 | |||
| 38 | std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device, | ||
| 39 | const MemoryAllocator& memory_allocator, | ||
| 40 | size_t image_count, VkFormat frame_format) { | ||
| 41 | return std::make_unique<WindowAdaptPass>(device, memory_allocator, image_count, frame_format, | ||
| 42 | CreateBilinearSampler(device), | ||
| 43 | BuildShader(device, VULKAN_PRESENT_FRAG_SPV)); | ||
| 44 | } | ||
| 45 | |||
| 46 | std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device, | ||
| 47 | const MemoryAllocator& memory_allocator, | ||
| 48 | size_t image_count, VkFormat frame_format) { | ||
| 49 | return std::make_unique<WindowAdaptPass>(device, memory_allocator, image_count, frame_format, | ||
| 50 | CreateBilinearSampler(device), | ||
| 51 | BuildShader(device, PRESENT_BICUBIC_FRAG_SPV)); | ||
| 52 | } | ||
| 53 | |||
| 54 | std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device, | ||
| 55 | const MemoryAllocator& memory_allocator, | ||
| 56 | size_t image_count, VkFormat frame_format) { | ||
| 57 | return std::make_unique<WindowAdaptPass>(device, memory_allocator, image_count, frame_format, | ||
| 58 | CreateBilinearSampler(device), | ||
| 59 | BuildShader(device, PRESENT_GAUSSIAN_FRAG_SPV)); | ||
| 60 | } | ||
| 61 | |||
| 62 | std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device, | ||
| 63 | const MemoryAllocator& memory_allocator, | ||
| 64 | size_t image_count, VkFormat frame_format) { | ||
| 65 | return std::make_unique<WindowAdaptPass>(device, memory_allocator, image_count, frame_format, | ||
| 66 | CreateBilinearSampler(device), | ||
| 67 | SelectScaleForceShader(device)); | ||
| 68 | } | ||
| 69 | |||
| 70 | } // 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..42d7052da --- /dev/null +++ b/src/video_core/renderer_vulkan/present/filters.h | |||
| @@ -0,0 +1,30 @@ | |||
| 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 | std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device, | ||
| 11 | const MemoryAllocator& memory_allocator, | ||
| 12 | size_t image_count, VkFormat frame_format); | ||
| 13 | |||
| 14 | std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device, | ||
| 15 | const MemoryAllocator& memory_allocator, | ||
| 16 | size_t image_count, VkFormat frame_format); | ||
| 17 | |||
| 18 | std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device, | ||
| 19 | const MemoryAllocator& memory_allocator, | ||
| 20 | size_t image_count, VkFormat frame_format); | ||
| 21 | |||
| 22 | std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device, | ||
| 23 | const MemoryAllocator& memory_allocator, | ||
| 24 | size_t image_count, VkFormat frame_format); | ||
| 25 | |||
| 26 | std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device, | ||
| 27 | const MemoryAllocator& memory_allocator, | ||
| 28 | size_t image_count, VkFormat frame_format); | ||
| 29 | |||
| 30 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/present/util.cpp b/src/video_core/renderer_vulkan/present/util.cpp index a445b213e..cd6061101 100644 --- a/src/video_core/renderer_vulkan/present/util.cpp +++ b/src/video_core/renderer_vulkan/present/util.cpp | |||
| @@ -441,6 +441,56 @@ VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo> | |||
| 441 | }; | 441 | }; |
| 442 | } | 442 | } |
| 443 | 443 | ||
| 444 | vk::Sampler CreateBilinearSampler(const Device& device) { | ||
| 445 | const VkSamplerCreateInfo ci{ | ||
| 446 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, | ||
| 447 | .pNext = nullptr, | ||
| 448 | .flags = 0, | ||
| 449 | .magFilter = VK_FILTER_LINEAR, | ||
| 450 | .minFilter = VK_FILTER_LINEAR, | ||
| 451 | .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, | ||
| 452 | .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 453 | .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 454 | .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 455 | .mipLodBias = 0.0f, | ||
| 456 | .anisotropyEnable = VK_FALSE, | ||
| 457 | .maxAnisotropy = 0.0f, | ||
| 458 | .compareEnable = VK_FALSE, | ||
| 459 | .compareOp = VK_COMPARE_OP_NEVER, | ||
| 460 | .minLod = 0.0f, | ||
| 461 | .maxLod = 0.0f, | ||
| 462 | .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, | ||
| 463 | .unnormalizedCoordinates = VK_FALSE, | ||
| 464 | }; | ||
| 465 | |||
| 466 | return device.GetLogical().CreateSampler(ci); | ||
| 467 | } | ||
| 468 | |||
| 469 | vk::Sampler CreateNearestNeighborSampler(const Device& device) { | ||
| 470 | const VkSamplerCreateInfo ci_nn{ | ||
| 471 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, | ||
| 472 | .pNext = nullptr, | ||
| 473 | .flags = 0, | ||
| 474 | .magFilter = VK_FILTER_NEAREST, | ||
| 475 | .minFilter = VK_FILTER_NEAREST, | ||
| 476 | .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, | ||
| 477 | .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 478 | .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 479 | .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 480 | .mipLodBias = 0.0f, | ||
| 481 | .anisotropyEnable = VK_FALSE, | ||
| 482 | .maxAnisotropy = 0.0f, | ||
| 483 | .compareEnable = VK_FALSE, | ||
| 484 | .compareOp = VK_COMPARE_OP_NEVER, | ||
| 485 | .minLod = 0.0f, | ||
| 486 | .maxLod = 0.0f, | ||
| 487 | .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, | ||
| 488 | .unnormalizedCoordinates = VK_FALSE, | ||
| 489 | }; | ||
| 490 | |||
| 491 | return device.GetLogical().CreateSampler(ci_nn); | ||
| 492 | } | ||
| 493 | |||
| 444 | void ClearColorImage(vk::CommandBuffer& cmdbuf, VkImage image) { | 494 | void ClearColorImage(vk::CommandBuffer& cmdbuf, VkImage image) { |
| 445 | static constexpr std::array<VkImageSubresourceRange, 1> subresources{{{ | 495 | static constexpr std::array<VkImageSubresourceRange, 1> subresources{{{ |
| 446 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | 496 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, |
diff --git a/src/video_core/renderer_vulkan/present/util.h b/src/video_core/renderer_vulkan/present/util.h index 93cfdd16b..ea9a26c3d 100644 --- a/src/video_core/renderer_vulkan/present/util.h +++ b/src/video_core/renderer_vulkan/present/util.h | |||
| @@ -39,6 +39,8 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp | |||
| 39 | VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images, | 39 | VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images, |
| 40 | VkSampler sampler, VkImageView view, | 40 | VkSampler sampler, VkImageView view, |
| 41 | VkDescriptorSet set, u32 binding); | 41 | VkDescriptorSet set, u32 binding); |
| 42 | vk::Sampler CreateBilinearSampler(const Device& device); | ||
| 43 | vk::Sampler CreateNearestNeighborSampler(const Device& device); | ||
| 42 | 44 | ||
| 43 | void BeginRenderPass(vk::CommandBuffer& cmdbuf, VkRenderPass render_pass, VkFramebuffer framebuffer, | 45 | void BeginRenderPass(vk::CommandBuffer& cmdbuf, VkRenderPass render_pass, VkFramebuffer framebuffer, |
| 44 | VkExtent2D extent); | 46 | VkExtent2D extent); |
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..7fd9ecd22 --- /dev/null +++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp | |||
| @@ -0,0 +1,512 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <cstring> | ||
| 5 | |||
| 6 | #include "core/frontend/framebuffer_layout.h" | ||
| 7 | #include "video_core/host_shaders/vulkan_present_vert_spv.h" | ||
| 8 | #include "video_core/renderer_vulkan/present/util.h" | ||
| 9 | #include "video_core/renderer_vulkan/present/window_adapt_pass.h" | ||
| 10 | #include "video_core/renderer_vulkan/vk_present_manager.h" | ||
| 11 | #include "video_core/renderer_vulkan/vk_shader_util.h" | ||
| 12 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 13 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 14 | |||
| 15 | namespace Vulkan { | ||
| 16 | |||
| 17 | namespace { | ||
| 18 | |||
| 19 | struct ScreenRectVertex { | ||
| 20 | ScreenRectVertex() = default; | ||
| 21 | explicit ScreenRectVertex(f32 x, f32 y, f32 u, f32 v) : position{{x, y}}, tex_coord{{u, v}} {} | ||
| 22 | |||
| 23 | std::array<f32, 2> position; | ||
| 24 | std::array<f32, 2> tex_coord; | ||
| 25 | |||
| 26 | static VkVertexInputBindingDescription GetDescription() { | ||
| 27 | return { | ||
| 28 | .binding = 0, | ||
| 29 | .stride = sizeof(ScreenRectVertex), | ||
| 30 | .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, | ||
| 31 | }; | ||
| 32 | } | ||
| 33 | |||
| 34 | static std::array<VkVertexInputAttributeDescription, 2> GetAttributes() { | ||
| 35 | return {{ | ||
| 36 | { | ||
| 37 | .location = 0, | ||
| 38 | .binding = 0, | ||
| 39 | .format = VK_FORMAT_R32G32_SFLOAT, | ||
| 40 | .offset = offsetof(ScreenRectVertex, position), | ||
| 41 | }, | ||
| 42 | { | ||
| 43 | .location = 1, | ||
| 44 | .binding = 0, | ||
| 45 | .format = VK_FORMAT_R32G32_SFLOAT, | ||
| 46 | .offset = offsetof(ScreenRectVertex, tex_coord), | ||
| 47 | }, | ||
| 48 | }}; | ||
| 49 | } | ||
| 50 | }; | ||
| 51 | |||
| 52 | std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) { | ||
| 53 | // clang-format off | ||
| 54 | return { 2.f / width, 0.f, 0.f, 0.f, | ||
| 55 | 0.f, 2.f / height, 0.f, 0.f, | ||
| 56 | 0.f, 0.f, 1.f, 0.f, | ||
| 57 | -1.f, -1.f, 0.f, 1.f}; | ||
| 58 | // clang-format on | ||
| 59 | } | ||
| 60 | |||
| 61 | } // Anonymous namespace | ||
| 62 | |||
| 63 | struct WindowAdaptPass::BufferData { | ||
| 64 | struct { | ||
| 65 | std::array<f32, 4 * 4> modelview_matrix; | ||
| 66 | } uniform; | ||
| 67 | |||
| 68 | std::array<ScreenRectVertex, 4> vertices; | ||
| 69 | }; | ||
| 70 | |||
| 71 | WindowAdaptPass::WindowAdaptPass(const Device& device_, const MemoryAllocator& memory_allocator, | ||
| 72 | size_t num_images, VkFormat frame_format, vk::Sampler&& sampler_, | ||
| 73 | vk::ShaderModule&& fragment_shader_) | ||
| 74 | : device(device_), sampler(std::move(sampler_)), fragment_shader(std::move(fragment_shader_)) { | ||
| 75 | CreateDescriptorPool(num_images); | ||
| 76 | CreateDescriptorSetLayout(); | ||
| 77 | CreateDescriptorSets(num_images); | ||
| 78 | CreatePipelineLayout(); | ||
| 79 | CreateVertexShader(); | ||
| 80 | CreateRenderPass(frame_format); | ||
| 81 | CreatePipeline(); | ||
| 82 | CreateBuffer(memory_allocator); | ||
| 83 | } | ||
| 84 | |||
| 85 | WindowAdaptPass::~WindowAdaptPass() = default; | ||
| 86 | |||
| 87 | void WindowAdaptPass::Draw(Scheduler& scheduler, size_t image_index, VkImageView src_image_view, | ||
| 88 | VkExtent2D src_image_extent, const Common::Rectangle<f32>& crop_rect, | ||
| 89 | const Layout::FramebufferLayout& layout, Frame* dst) { | ||
| 90 | ConfigureLayout(image_index, src_image_view, layout, crop_rect); | ||
| 91 | |||
| 92 | const VkFramebuffer host_framebuffer{*dst->framebuffer}; | ||
| 93 | const VkRenderPass renderpass{*render_pass}; | ||
| 94 | const VkPipeline graphics_pipeline{*pipeline}; | ||
| 95 | const VkDescriptorSet descriptor_set{descriptor_sets[image_index]}; | ||
| 96 | const VkExtent2D render_area{ | ||
| 97 | .width = dst->width, | ||
| 98 | .height = dst->height, | ||
| 99 | }; | ||
| 100 | |||
| 101 | scheduler.Record([=](vk::CommandBuffer cmdbuf) { | ||
| 102 | const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f; | ||
| 103 | const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f; | ||
| 104 | const f32 bg_blue = Settings::values.bg_blue.GetValue() / 255.0f; | ||
| 105 | const VkClearValue clear_color{ | ||
| 106 | .color = {.float32 = {bg_red, bg_green, bg_blue, 1.0f}}, | ||
| 107 | }; | ||
| 108 | const VkRenderPassBeginInfo renderpass_bi{ | ||
| 109 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, | ||
| 110 | .pNext = nullptr, | ||
| 111 | .renderPass = renderpass, | ||
| 112 | .framebuffer = host_framebuffer, | ||
| 113 | .renderArea = | ||
| 114 | { | ||
| 115 | .offset = {0, 0}, | ||
| 116 | .extent = render_area, | ||
| 117 | }, | ||
| 118 | .clearValueCount = 1, | ||
| 119 | .pClearValues = &clear_color, | ||
| 120 | }; | ||
| 121 | const VkViewport viewport{ | ||
| 122 | .x = 0.0f, | ||
| 123 | .y = 0.0f, | ||
| 124 | .width = static_cast<float>(render_area.width), | ||
| 125 | .height = static_cast<float>(render_area.height), | ||
| 126 | .minDepth = 0.0f, | ||
| 127 | .maxDepth = 1.0f, | ||
| 128 | }; | ||
| 129 | const VkRect2D scissor{ | ||
| 130 | .offset = {0, 0}, | ||
| 131 | .extent = render_area, | ||
| 132 | }; | ||
| 133 | cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); | ||
| 134 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline); | ||
| 135 | cmdbuf.SetViewport(0, viewport); | ||
| 136 | cmdbuf.SetScissor(0, scissor); | ||
| 137 | cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices)); | ||
| 138 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline_layout, 0, | ||
| 139 | descriptor_set, {}); | ||
| 140 | cmdbuf.Draw(4, 1, 0, 0); | ||
| 141 | cmdbuf.EndRenderPass(); | ||
| 142 | }); | ||
| 143 | } | ||
| 144 | |||
| 145 | VkRenderPass WindowAdaptPass::GetRenderPass() { | ||
| 146 | return *render_pass; | ||
| 147 | } | ||
| 148 | |||
| 149 | void WindowAdaptPass::CreateDescriptorPool(size_t num_images) { | ||
| 150 | const std::array<VkDescriptorPoolSize, 2> pool_sizes{{ | ||
| 151 | { | ||
| 152 | .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, | ||
| 153 | .descriptorCount = static_cast<u32>(num_images), | ||
| 154 | }, | ||
| 155 | { | ||
| 156 | .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 157 | .descriptorCount = static_cast<u32>(num_images), | ||
| 158 | }, | ||
| 159 | }}; | ||
| 160 | |||
| 161 | const VkDescriptorPoolCreateInfo ci{ | ||
| 162 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, | ||
| 163 | .pNext = nullptr, | ||
| 164 | .flags = 0, | ||
| 165 | .maxSets = static_cast<u32>(num_images), | ||
| 166 | .poolSizeCount = static_cast<u32>(pool_sizes.size()), | ||
| 167 | .pPoolSizes = pool_sizes.data(), | ||
| 168 | }; | ||
| 169 | descriptor_pool = device.GetLogical().CreateDescriptorPool(ci); | ||
| 170 | } | ||
| 171 | |||
| 172 | void WindowAdaptPass::CreateDescriptorSetLayout() { | ||
| 173 | const std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings{{ | ||
| 174 | { | ||
| 175 | .binding = 0, | ||
| 176 | .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, | ||
| 177 | .descriptorCount = 1, | ||
| 178 | .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 179 | .pImmutableSamplers = nullptr, | ||
| 180 | }, | ||
| 181 | { | ||
| 182 | .binding = 1, | ||
| 183 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 184 | .descriptorCount = 1, | ||
| 185 | .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 186 | .pImmutableSamplers = nullptr, | ||
| 187 | }, | ||
| 188 | }}; | ||
| 189 | |||
| 190 | const VkDescriptorSetLayoutCreateInfo ci{ | ||
| 191 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, | ||
| 192 | .pNext = nullptr, | ||
| 193 | .flags = 0, | ||
| 194 | .bindingCount = static_cast<u32>(layout_bindings.size()), | ||
| 195 | .pBindings = layout_bindings.data(), | ||
| 196 | }; | ||
| 197 | |||
| 198 | descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(ci); | ||
| 199 | } | ||
| 200 | |||
| 201 | void WindowAdaptPass::CreateDescriptorSets(size_t num_images) { | ||
| 202 | const std::vector layouts(num_images, *descriptor_set_layout); | ||
| 203 | descriptor_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts); | ||
| 204 | } | ||
| 205 | |||
| 206 | void WindowAdaptPass::CreateBuffer(const MemoryAllocator& memory_allocator) { | ||
| 207 | const VkBufferCreateInfo ci{ | ||
| 208 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | ||
| 209 | .pNext = nullptr, | ||
| 210 | .flags = 0, | ||
| 211 | .size = sizeof(BufferData), | ||
| 212 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | | ||
| 213 | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, | ||
| 214 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 215 | .queueFamilyIndexCount = 0, | ||
| 216 | .pQueueFamilyIndices = nullptr, | ||
| 217 | }; | ||
| 218 | |||
| 219 | buffer = memory_allocator.CreateBuffer(ci, MemoryUsage::Upload); | ||
| 220 | } | ||
| 221 | |||
| 222 | void WindowAdaptPass::CreateRenderPass(VkFormat frame_format) { | ||
| 223 | const VkAttachmentDescription color_attachment{ | ||
| 224 | .flags = 0, | ||
| 225 | .format = frame_format, | ||
| 226 | .samples = VK_SAMPLE_COUNT_1_BIT, | ||
| 227 | .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, | ||
| 228 | .storeOp = VK_ATTACHMENT_STORE_OP_STORE, | ||
| 229 | .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, | ||
| 230 | .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, | ||
| 231 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | ||
| 232 | .finalLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 233 | }; | ||
| 234 | |||
| 235 | const VkAttachmentReference color_attachment_ref{ | ||
| 236 | .attachment = 0, | ||
| 237 | .layout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 238 | }; | ||
| 239 | |||
| 240 | const VkSubpassDescription subpass_description{ | ||
| 241 | .flags = 0, | ||
| 242 | .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, | ||
| 243 | .inputAttachmentCount = 0, | ||
| 244 | .pInputAttachments = nullptr, | ||
| 245 | .colorAttachmentCount = 1, | ||
| 246 | .pColorAttachments = &color_attachment_ref, | ||
| 247 | .pResolveAttachments = nullptr, | ||
| 248 | .pDepthStencilAttachment = nullptr, | ||
| 249 | .preserveAttachmentCount = 0, | ||
| 250 | .pPreserveAttachments = nullptr, | ||
| 251 | }; | ||
| 252 | |||
| 253 | const VkSubpassDependency dependency{ | ||
| 254 | .srcSubpass = VK_SUBPASS_EXTERNAL, | ||
| 255 | .dstSubpass = 0, | ||
| 256 | .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | ||
| 257 | .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | ||
| 258 | .srcAccessMask = 0, | ||
| 259 | .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, | ||
| 260 | .dependencyFlags = 0, | ||
| 261 | }; | ||
| 262 | |||
| 263 | const VkRenderPassCreateInfo renderpass_ci{ | ||
| 264 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, | ||
| 265 | .pNext = nullptr, | ||
| 266 | .flags = 0, | ||
| 267 | .attachmentCount = 1, | ||
| 268 | .pAttachments = &color_attachment, | ||
| 269 | .subpassCount = 1, | ||
| 270 | .pSubpasses = &subpass_description, | ||
| 271 | .dependencyCount = 1, | ||
| 272 | .pDependencies = &dependency, | ||
| 273 | }; | ||
| 274 | |||
| 275 | render_pass = device.GetLogical().CreateRenderPass(renderpass_ci); | ||
| 276 | } | ||
| 277 | |||
| 278 | void WindowAdaptPass::CreateVertexShader() { | ||
| 279 | vertex_shader = BuildShader(device, VULKAN_PRESENT_VERT_SPV); | ||
| 280 | } | ||
| 281 | |||
| 282 | void WindowAdaptPass::CreatePipelineLayout() { | ||
| 283 | const VkPipelineLayoutCreateInfo ci{ | ||
| 284 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | ||
| 285 | .pNext = nullptr, | ||
| 286 | .flags = 0, | ||
| 287 | .setLayoutCount = 1, | ||
| 288 | .pSetLayouts = descriptor_set_layout.address(), | ||
| 289 | .pushConstantRangeCount = 0, | ||
| 290 | .pPushConstantRanges = nullptr, | ||
| 291 | }; | ||
| 292 | pipeline_layout = device.GetLogical().CreatePipelineLayout(ci); | ||
| 293 | } | ||
| 294 | |||
| 295 | void WindowAdaptPass::SetUniformData(BufferData& data, | ||
| 296 | const Layout::FramebufferLayout& layout) const { | ||
| 297 | data.uniform.modelview_matrix = | ||
| 298 | MakeOrthographicMatrix(static_cast<f32>(layout.width), static_cast<f32>(layout.height)); | ||
| 299 | } | ||
| 300 | |||
| 301 | void WindowAdaptPass::SetVertexData(BufferData& data, const Layout::FramebufferLayout& layout, | ||
| 302 | const Common::Rectangle<f32>& crop) const { | ||
| 303 | // Map the coordinates to the screen. | ||
| 304 | const auto& screen = layout.screen; | ||
| 305 | const auto x = static_cast<f32>(screen.left); | ||
| 306 | const auto y = static_cast<f32>(screen.top); | ||
| 307 | const auto w = static_cast<f32>(screen.GetWidth()); | ||
| 308 | const auto h = static_cast<f32>(screen.GetHeight()); | ||
| 309 | |||
| 310 | data.vertices[0] = ScreenRectVertex(x, y, crop.left, crop.top); | ||
| 311 | data.vertices[1] = ScreenRectVertex(x + w, y, crop.right, crop.top); | ||
| 312 | data.vertices[2] = ScreenRectVertex(x, y + h, crop.left, crop.bottom); | ||
| 313 | data.vertices[3] = ScreenRectVertex(x + w, y + h, crop.right, crop.bottom); | ||
| 314 | } | ||
| 315 | |||
| 316 | void WindowAdaptPass::UpdateDescriptorSet(size_t image_index, VkImageView image_view) { | ||
| 317 | const VkDescriptorBufferInfo buffer_info{ | ||
| 318 | .buffer = *buffer, | ||
| 319 | .offset = offsetof(BufferData, uniform), | ||
| 320 | .range = sizeof(BufferData::uniform), | ||
| 321 | }; | ||
| 322 | |||
| 323 | const VkWriteDescriptorSet ubo_write{ | ||
| 324 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 325 | .pNext = nullptr, | ||
| 326 | .dstSet = descriptor_sets[image_index], | ||
| 327 | .dstBinding = 0, | ||
| 328 | .dstArrayElement = 0, | ||
| 329 | .descriptorCount = 1, | ||
| 330 | .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, | ||
| 331 | .pImageInfo = nullptr, | ||
| 332 | .pBufferInfo = &buffer_info, | ||
| 333 | .pTexelBufferView = nullptr, | ||
| 334 | }; | ||
| 335 | |||
| 336 | const VkDescriptorImageInfo image_info{ | ||
| 337 | .sampler = *sampler, | ||
| 338 | .imageView = image_view, | ||
| 339 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 340 | }; | ||
| 341 | |||
| 342 | const VkWriteDescriptorSet sampler_write{ | ||
| 343 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 344 | .pNext = nullptr, | ||
| 345 | .dstSet = descriptor_sets[image_index], | ||
| 346 | .dstBinding = 1, | ||
| 347 | .dstArrayElement = 0, | ||
| 348 | .descriptorCount = 1, | ||
| 349 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 350 | .pImageInfo = &image_info, | ||
| 351 | .pBufferInfo = nullptr, | ||
| 352 | .pTexelBufferView = nullptr, | ||
| 353 | }; | ||
| 354 | |||
| 355 | device.GetLogical().UpdateDescriptorSets(std::array{ubo_write, sampler_write}, {}); | ||
| 356 | } | ||
| 357 | |||
| 358 | void WindowAdaptPass::ConfigureLayout(size_t image_index, VkImageView image_view, | ||
| 359 | const Layout::FramebufferLayout& layout, | ||
| 360 | const Common::Rectangle<f32>& crop_rect) { | ||
| 361 | BufferData data; | ||
| 362 | SetUniformData(data, layout); | ||
| 363 | SetVertexData(data, layout, crop_rect); | ||
| 364 | |||
| 365 | const std::span<u8> mapped_span = buffer.Mapped(); | ||
| 366 | std::memcpy(mapped_span.data(), &data, sizeof(data)); | ||
| 367 | |||
| 368 | UpdateDescriptorSet(image_index, image_view); | ||
| 369 | } | ||
| 370 | |||
| 371 | void WindowAdaptPass::CreatePipeline() { | ||
| 372 | const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{ | ||
| 373 | { | ||
| 374 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 375 | .pNext = nullptr, | ||
| 376 | .flags = 0, | ||
| 377 | .stage = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 378 | .module = *vertex_shader, | ||
| 379 | .pName = "main", | ||
| 380 | .pSpecializationInfo = nullptr, | ||
| 381 | }, | ||
| 382 | { | ||
| 383 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 384 | .pNext = nullptr, | ||
| 385 | .flags = 0, | ||
| 386 | .stage = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 387 | .module = *fragment_shader, | ||
| 388 | .pName = "main", | ||
| 389 | .pSpecializationInfo = nullptr, | ||
| 390 | }, | ||
| 391 | }}; | ||
| 392 | |||
| 393 | const auto vertex_binding_description = ScreenRectVertex::GetDescription(); | ||
| 394 | const auto vertex_attrs_description = ScreenRectVertex::GetAttributes(); | ||
| 395 | |||
| 396 | const VkPipelineVertexInputStateCreateInfo vertex_input_ci{ | ||
| 397 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | ||
| 398 | .pNext = nullptr, | ||
| 399 | .flags = 0, | ||
| 400 | .vertexBindingDescriptionCount = 1, | ||
| 401 | .pVertexBindingDescriptions = &vertex_binding_description, | ||
| 402 | .vertexAttributeDescriptionCount = u32{vertex_attrs_description.size()}, | ||
| 403 | .pVertexAttributeDescriptions = vertex_attrs_description.data(), | ||
| 404 | }; | ||
| 405 | |||
| 406 | const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ | ||
| 407 | .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | ||
| 408 | .pNext = nullptr, | ||
| 409 | .flags = 0, | ||
| 410 | .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, | ||
| 411 | .primitiveRestartEnable = VK_FALSE, | ||
| 412 | }; | ||
| 413 | |||
| 414 | const VkPipelineViewportStateCreateInfo viewport_state_ci{ | ||
| 415 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| 416 | .pNext = nullptr, | ||
| 417 | .flags = 0, | ||
| 418 | .viewportCount = 1, | ||
| 419 | .pViewports = nullptr, | ||
| 420 | .scissorCount = 1, | ||
| 421 | .pScissors = nullptr, | ||
| 422 | }; | ||
| 423 | |||
| 424 | const VkPipelineRasterizationStateCreateInfo rasterization_ci{ | ||
| 425 | .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | ||
| 426 | .pNext = nullptr, | ||
| 427 | .flags = 0, | ||
| 428 | .depthClampEnable = VK_FALSE, | ||
| 429 | .rasterizerDiscardEnable = VK_FALSE, | ||
| 430 | .polygonMode = VK_POLYGON_MODE_FILL, | ||
| 431 | .cullMode = VK_CULL_MODE_NONE, | ||
| 432 | .frontFace = VK_FRONT_FACE_CLOCKWISE, | ||
| 433 | .depthBiasEnable = VK_FALSE, | ||
| 434 | .depthBiasConstantFactor = 0.0f, | ||
| 435 | .depthBiasClamp = 0.0f, | ||
| 436 | .depthBiasSlopeFactor = 0.0f, | ||
| 437 | .lineWidth = 1.0f, | ||
| 438 | }; | ||
| 439 | |||
| 440 | const VkPipelineMultisampleStateCreateInfo multisampling_ci{ | ||
| 441 | .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||
| 442 | .pNext = nullptr, | ||
| 443 | .flags = 0, | ||
| 444 | .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, | ||
| 445 | .sampleShadingEnable = VK_FALSE, | ||
| 446 | .minSampleShading = 0.0f, | ||
| 447 | .pSampleMask = nullptr, | ||
| 448 | .alphaToCoverageEnable = VK_FALSE, | ||
| 449 | .alphaToOneEnable = VK_FALSE, | ||
| 450 | }; | ||
| 451 | |||
| 452 | const VkPipelineColorBlendAttachmentState color_blend_attachment{ | ||
| 453 | .blendEnable = VK_FALSE, | ||
| 454 | .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 455 | .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 456 | .colorBlendOp = VK_BLEND_OP_ADD, | ||
| 457 | .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 458 | .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 459 | .alphaBlendOp = VK_BLEND_OP_ADD, | ||
| 460 | .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | | ||
| 461 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, | ||
| 462 | }; | ||
| 463 | |||
| 464 | const VkPipelineColorBlendStateCreateInfo color_blend_ci{ | ||
| 465 | .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | ||
| 466 | .pNext = nullptr, | ||
| 467 | .flags = 0, | ||
| 468 | .logicOpEnable = VK_FALSE, | ||
| 469 | .logicOp = VK_LOGIC_OP_COPY, | ||
| 470 | .attachmentCount = 1, | ||
| 471 | .pAttachments = &color_blend_attachment, | ||
| 472 | .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, | ||
| 473 | }; | ||
| 474 | |||
| 475 | static constexpr std::array dynamic_states{ | ||
| 476 | VK_DYNAMIC_STATE_VIEWPORT, | ||
| 477 | VK_DYNAMIC_STATE_SCISSOR, | ||
| 478 | }; | ||
| 479 | const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ | ||
| 480 | .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||
| 481 | .pNext = nullptr, | ||
| 482 | .flags = 0, | ||
| 483 | .dynamicStateCount = static_cast<u32>(dynamic_states.size()), | ||
| 484 | .pDynamicStates = dynamic_states.data(), | ||
| 485 | }; | ||
| 486 | |||
| 487 | const VkGraphicsPipelineCreateInfo pipeline_ci{ | ||
| 488 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 489 | .pNext = nullptr, | ||
| 490 | .flags = 0, | ||
| 491 | .stageCount = static_cast<u32>(shader_stages.size()), | ||
| 492 | .pStages = shader_stages.data(), | ||
| 493 | .pVertexInputState = &vertex_input_ci, | ||
| 494 | .pInputAssemblyState = &input_assembly_ci, | ||
| 495 | .pTessellationState = nullptr, | ||
| 496 | .pViewportState = &viewport_state_ci, | ||
| 497 | .pRasterizationState = &rasterization_ci, | ||
| 498 | .pMultisampleState = &multisampling_ci, | ||
| 499 | .pDepthStencilState = nullptr, | ||
| 500 | .pColorBlendState = &color_blend_ci, | ||
| 501 | .pDynamicState = &dynamic_state_ci, | ||
| 502 | .layout = *pipeline_layout, | ||
| 503 | .renderPass = *render_pass, | ||
| 504 | .subpass = 0, | ||
| 505 | .basePipelineHandle = 0, | ||
| 506 | .basePipelineIndex = 0, | ||
| 507 | }; | ||
| 508 | |||
| 509 | pipeline = device.GetLogical().CreateGraphicsPipeline(pipeline_ci); | ||
| 510 | } | ||
| 511 | |||
| 512 | } // 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..5309233a2 --- /dev/null +++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.h | |||
| @@ -0,0 +1,71 @@ | |||
| 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/vulkan_common/vulkan_wrapper.h" | ||
| 8 | |||
| 9 | namespace Layout { | ||
| 10 | struct FramebufferLayout; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace Tegra { | ||
| 14 | struct FramebufferConfig; | ||
| 15 | } | ||
| 16 | |||
| 17 | namespace Vulkan { | ||
| 18 | |||
| 19 | class Device; | ||
| 20 | struct Frame; | ||
| 21 | class MemoryAllocator; | ||
| 22 | class Scheduler; | ||
| 23 | |||
| 24 | class WindowAdaptPass final { | ||
| 25 | public: | ||
| 26 | explicit WindowAdaptPass(const Device& device, const MemoryAllocator& memory_allocator, | ||
| 27 | size_t num_images, VkFormat frame_format, vk::Sampler&& sampler, | ||
| 28 | vk::ShaderModule&& fragment_shader); | ||
| 29 | ~WindowAdaptPass(); | ||
| 30 | |||
| 31 | void Draw(Scheduler& scheduler, size_t image_index, VkImageView src_image_view, | ||
| 32 | VkExtent2D src_image_extent, const Common::Rectangle<f32>& crop_rect, | ||
| 33 | const Layout::FramebufferLayout& layout, Frame* dst); | ||
| 34 | |||
| 35 | VkRenderPass GetRenderPass(); | ||
| 36 | |||
| 37 | private: | ||
| 38 | struct BufferData; | ||
| 39 | |||
| 40 | void SetUniformData(BufferData& data, const Layout::FramebufferLayout& layout) const; | ||
| 41 | void SetVertexData(BufferData& data, const Layout::FramebufferLayout& layout, | ||
| 42 | const Common::Rectangle<f32>& crop_rect) const; | ||
| 43 | void UpdateDescriptorSet(size_t image_index, VkImageView image_view); | ||
| 44 | void ConfigureLayout(size_t image_index, VkImageView image_view, | ||
| 45 | const Layout::FramebufferLayout& layout, | ||
| 46 | const Common::Rectangle<f32>& crop_rect); | ||
| 47 | |||
| 48 | void CreateDescriptorPool(size_t num_images); | ||
| 49 | void CreateDescriptorSetLayout(); | ||
| 50 | void CreateDescriptorSets(size_t num_images); | ||
| 51 | void CreatePipelineLayout(); | ||
| 52 | void CreateVertexShader(); | ||
| 53 | void CreateRenderPass(VkFormat frame_format); | ||
| 54 | void CreatePipeline(); | ||
| 55 | void CreateBuffer(const MemoryAllocator& memory_allocator); | ||
| 56 | |||
| 57 | private: | ||
| 58 | const Device& device; | ||
| 59 | vk::DescriptorPool descriptor_pool; | ||
| 60 | vk::DescriptorSetLayout descriptor_set_layout; | ||
| 61 | vk::DescriptorSets descriptor_sets; | ||
| 62 | vk::PipelineLayout pipeline_layout; | ||
| 63 | vk::Sampler sampler; | ||
| 64 | vk::ShaderModule vertex_shader; | ||
| 65 | vk::ShaderModule fragment_shader; | ||
| 66 | vk::RenderPass render_pass; | ||
| 67 | vk::Pipeline pipeline; | ||
| 68 | vk::Buffer buffer; | ||
| 69 | }; | ||
| 70 | |||
| 71 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index e1fe53bbd..2912aaff6 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -97,8 +97,8 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, | |||
| 97 | render_window.GetFramebufferLayout().height), | 97 | render_window.GetFramebufferLayout().height), |
| 98 | present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, | 98 | present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, |
| 99 | surface), | 99 | surface), |
| 100 | blit_screen(device_memory, render_window, device, memory_allocator, swapchain, | 100 | blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler), |
| 101 | present_manager, scheduler), | 101 | blit_screenshot(device_memory, device, memory_allocator, present_manager, scheduler), |
| 102 | rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, | 102 | rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, |
| 103 | scheduler) { | 103 | scheduler) { |
| 104 | if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { | 104 | if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { |
| @@ -127,7 +127,9 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 127 | 127 | ||
| 128 | RenderScreenshot(*framebuffer); | 128 | RenderScreenshot(*framebuffer); |
| 129 | Frame* frame = present_manager.GetRenderFrame(); | 129 | Frame* frame = present_manager.GetRenderFrame(); |
| 130 | blit_screen.DrawToSwapchain(rasterizer, frame, *framebuffer); | 130 | blit_swapchain.DrawToFrame(rasterizer, frame, *framebuffer, |
| 131 | render_window.GetFramebufferLayout(), swapchain.GetImageCount(), | ||
| 132 | swapchain.GetImageViewFormat()); | ||
| 131 | scheduler.Flush(*frame->render_ready); | 133 | scheduler.Flush(*frame->render_ready); |
| 132 | present_manager.Present(frame); | 134 | present_manager.Present(frame); |
| 133 | 135 | ||
| @@ -166,54 +168,65 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 166 | return; | 168 | return; |
| 167 | } | 169 | } |
| 168 | const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; | 170 | const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; |
| 169 | vk::Image staging_image = memory_allocator.CreateImage(VkImageCreateInfo{ | 171 | auto frame = [&]() { |
| 170 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 172 | vk::Image staging_image = memory_allocator.CreateImage(VkImageCreateInfo{ |
| 171 | .pNext = nullptr, | 173 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| 172 | .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, | 174 | .pNext = nullptr, |
| 173 | .imageType = VK_IMAGE_TYPE_2D, | 175 | .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, |
| 174 | .format = VK_FORMAT_B8G8R8A8_UNORM, | 176 | .imageType = VK_IMAGE_TYPE_2D, |
| 175 | .extent = | 177 | .format = VK_FORMAT_B8G8R8A8_UNORM, |
| 176 | { | 178 | .extent = |
| 177 | .width = layout.width, | 179 | { |
| 178 | .height = layout.height, | 180 | .width = layout.width, |
| 179 | .depth = 1, | 181 | .height = layout.height, |
| 182 | .depth = 1, | ||
| 183 | }, | ||
| 184 | .mipLevels = 1, | ||
| 185 | .arrayLayers = 1, | ||
| 186 | .samples = VK_SAMPLE_COUNT_1_BIT, | ||
| 187 | .tiling = VK_IMAGE_TILING_OPTIMAL, | ||
| 188 | .usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | | ||
| 189 | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, | ||
| 190 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 191 | .queueFamilyIndexCount = 0, | ||
| 192 | .pQueueFamilyIndices = nullptr, | ||
| 193 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | ||
| 194 | }); | ||
| 195 | |||
| 196 | vk::ImageView dst_view = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | ||
| 197 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | ||
| 198 | .pNext = nullptr, | ||
| 199 | .flags = 0, | ||
| 200 | .image = *staging_image, | ||
| 201 | .viewType = VK_IMAGE_VIEW_TYPE_2D, | ||
| 202 | .format = VK_FORMAT_B8G8R8A8_UNORM, | ||
| 203 | .components{ | ||
| 204 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 205 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 206 | .b = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 207 | .a = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 180 | }, | 208 | }, |
| 181 | .mipLevels = 1, | 209 | .subresourceRange{ |
| 182 | .arrayLayers = 1, | 210 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, |
| 183 | .samples = VK_SAMPLE_COUNT_1_BIT, | 211 | .baseMipLevel = 0, |
| 184 | .tiling = VK_IMAGE_TILING_OPTIMAL, | 212 | .levelCount = 1, |
| 185 | .usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | | 213 | .baseArrayLayer = 0, |
| 186 | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, | 214 | .layerCount = VK_REMAINING_ARRAY_LAYERS, |
| 187 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 215 | }, |
| 188 | .queueFamilyIndexCount = 0, | 216 | }); |
| 189 | .pQueueFamilyIndices = nullptr, | 217 | vk::Framebuffer screenshot_fb = |
| 190 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 218 | blit_screenshot.CreateFramebuffer(layout, *dst_view, VK_FORMAT_B8G8R8A8_UNORM); |
| 191 | }); | 219 | return Frame{ |
| 220 | .width = layout.width, | ||
| 221 | .height = layout.height, | ||
| 222 | .image = std::move(staging_image), | ||
| 223 | .image_view = std::move(dst_view), | ||
| 224 | .framebuffer = std::move(screenshot_fb), | ||
| 225 | }; | ||
| 226 | }(); | ||
| 192 | 227 | ||
| 193 | const vk::ImageView dst_view = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | 228 | blit_screenshot.DrawToFrame(rasterizer, &frame, framebuffer, layout, 1, |
| 194 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 229 | VK_FORMAT_B8G8R8A8_UNORM); |
| 195 | .pNext = nullptr, | ||
| 196 | .flags = 0, | ||
| 197 | .image = *staging_image, | ||
| 198 | .viewType = VK_IMAGE_VIEW_TYPE_2D, | ||
| 199 | .format = VK_FORMAT_B8G8R8A8_UNORM, | ||
| 200 | .components{ | ||
| 201 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 202 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 203 | .b = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 204 | .a = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 205 | }, | ||
| 206 | .subresourceRange{ | ||
| 207 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 208 | .baseMipLevel = 0, | ||
| 209 | .levelCount = 1, | ||
| 210 | .baseArrayLayer = 0, | ||
| 211 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 212 | }, | ||
| 213 | }); | ||
| 214 | const VkExtent2D render_area{.width = layout.width, .height = layout.height}; | ||
| 215 | const vk::Framebuffer screenshot_fb = blit_screen.CreateFramebuffer(*dst_view, render_area); | ||
| 216 | blit_screen.Draw(rasterizer, framebuffer, *screenshot_fb, layout, render_area); | ||
| 217 | 230 | ||
| 218 | const auto buffer_size = static_cast<VkDeviceSize>(layout.width * layout.height * 4); | 231 | const auto buffer_size = static_cast<VkDeviceSize>(layout.width * layout.height * 4); |
| 219 | const VkBufferCreateInfo dst_buffer_info{ | 232 | const VkBufferCreateInfo dst_buffer_info{ |
| @@ -240,7 +253,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 240 | .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, | 253 | .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| 241 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 254 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 242 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 255 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 243 | .image = *staging_image, | 256 | .image = *frame.image, |
| 244 | .subresourceRange{ | 257 | .subresourceRange{ |
| 245 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | 258 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, |
| 246 | .baseMipLevel = 0, | 259 | .baseMipLevel = 0, |
| @@ -258,7 +271,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 258 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | 271 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, |
| 259 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 272 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 260 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 273 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 261 | .image = *staging_image, | 274 | .image = *frame.image, |
| 262 | .subresourceRange{ | 275 | .subresourceRange{ |
| 263 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | 276 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, |
| 264 | .baseMipLevel = 0, | 277 | .baseMipLevel = 0, |
| @@ -292,7 +305,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 292 | }; | 305 | }; |
| 293 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, | 306 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, |
| 294 | 0, read_barrier); | 307 | 0, read_barrier); |
| 295 | cmdbuf.CopyImageToBuffer(*staging_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *dst_buffer, | 308 | cmdbuf.CopyImageToBuffer(*frame.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *dst_buffer, |
| 296 | copy); | 309 | copy); |
| 297 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | 310 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, |
| 298 | 0, memory_write_barrier, nullptr, image_write_barrier); | 311 | 0, memory_write_barrier, nullptr, image_write_barrier); |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index d7d006b20..5b0560e68 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h | |||
| @@ -78,7 +78,8 @@ private: | |||
| 78 | Scheduler scheduler; | 78 | Scheduler scheduler; |
| 79 | Swapchain swapchain; | 79 | Swapchain swapchain; |
| 80 | PresentManager present_manager; | 80 | PresentManager present_manager; |
| 81 | BlitScreen blit_screen; | 81 | BlitScreen blit_swapchain; |
| 82 | BlitScreen blit_screenshot; | ||
| 82 | RasterizerVulkan rasterizer; | 83 | RasterizerVulkan rasterizer; |
| 83 | std::optional<TurboMode> turbo_mode; | 84 | std::optional<TurboMode> turbo_mode; |
| 84 | }; | 85 | }; |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index fe1a7b0cd..fd7c28779 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -9,19 +9,12 @@ | |||
| 9 | 9 | ||
| 10 | #include "common/assert.h" | 10 | #include "common/assert.h" |
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "common/math_util.h" | ||
| 13 | #include "common/polyfill_ranges.h" | ||
| 14 | #include "common/settings.h" | 12 | #include "common/settings.h" |
| 15 | #include "core/core.h" | 13 | #include "core/core.h" |
| 16 | #include "core/frontend/emu_window.h" | 14 | #include "core/frontend/emu_window.h" |
| 17 | #include "video_core/gpu.h" | 15 | #include "video_core/gpu.h" |
| 18 | #include "video_core/host1x/gpu_device_memory_manager.h" | 16 | #include "video_core/host1x/gpu_device_memory_manager.h" |
| 19 | #include "video_core/host_shaders/present_bicubic_frag_spv.h" | 17 | #include "video_core/renderer_vulkan/present/filters.h" |
| 20 | #include "video_core/host_shaders/present_gaussian_frag_spv.h" | ||
| 21 | #include "video_core/host_shaders/vulkan_present_frag_spv.h" | ||
| 22 | #include "video_core/host_shaders/vulkan_present_scaleforce_fp16_frag_spv.h" | ||
| 23 | #include "video_core/host_shaders/vulkan_present_scaleforce_fp32_frag_spv.h" | ||
| 24 | #include "video_core/host_shaders/vulkan_present_vert_spv.h" | ||
| 25 | #include "video_core/renderer_vulkan/present/fsr.h" | 18 | #include "video_core/renderer_vulkan/present/fsr.h" |
| 26 | #include "video_core/renderer_vulkan/present/fxaa.h" | 19 | #include "video_core/renderer_vulkan/present/fxaa.h" |
| 27 | #include "video_core/renderer_vulkan/present/smaa.h" | 20 | #include "video_core/renderer_vulkan/present/smaa.h" |
| @@ -29,7 +22,6 @@ | |||
| 29 | #include "video_core/renderer_vulkan/vk_blit_screen.h" | 22 | #include "video_core/renderer_vulkan/vk_blit_screen.h" |
| 30 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 23 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 31 | #include "video_core/renderer_vulkan/vk_shader_util.h" | 24 | #include "video_core/renderer_vulkan/vk_shader_util.h" |
| 32 | #include "video_core/renderer_vulkan/vk_swapchain.h" | ||
| 33 | #include "video_core/surface.h" | 25 | #include "video_core/surface.h" |
| 34 | #include "video_core/textures/decoders.h" | 26 | #include "video_core/textures/decoders.h" |
| 35 | #include "video_core/vulkan_common/vulkan_device.h" | 27 | #include "video_core/vulkan_common/vulkan_device.h" |
| @@ -40,48 +32,6 @@ namespace Vulkan { | |||
| 40 | 32 | ||
| 41 | namespace { | 33 | namespace { |
| 42 | 34 | ||
| 43 | struct ScreenRectVertex { | ||
| 44 | ScreenRectVertex() = default; | ||
| 45 | explicit ScreenRectVertex(f32 x, f32 y, f32 u, f32 v) : position{{x, y}}, tex_coord{{u, v}} {} | ||
| 46 | |||
| 47 | std::array<f32, 2> position; | ||
| 48 | std::array<f32, 2> tex_coord; | ||
| 49 | |||
| 50 | static VkVertexInputBindingDescription GetDescription() { | ||
| 51 | return { | ||
| 52 | .binding = 0, | ||
| 53 | .stride = sizeof(ScreenRectVertex), | ||
| 54 | .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, | ||
| 55 | }; | ||
| 56 | } | ||
| 57 | |||
| 58 | static std::array<VkVertexInputAttributeDescription, 2> GetAttributes() { | ||
| 59 | return {{ | ||
| 60 | { | ||
| 61 | .location = 0, | ||
| 62 | .binding = 0, | ||
| 63 | .format = VK_FORMAT_R32G32_SFLOAT, | ||
| 64 | .offset = offsetof(ScreenRectVertex, position), | ||
| 65 | }, | ||
| 66 | { | ||
| 67 | .location = 1, | ||
| 68 | .binding = 0, | ||
| 69 | .format = VK_FORMAT_R32G32_SFLOAT, | ||
| 70 | .offset = offsetof(ScreenRectVertex, tex_coord), | ||
| 71 | }, | ||
| 72 | }}; | ||
| 73 | } | ||
| 74 | }; | ||
| 75 | |||
| 76 | std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) { | ||
| 77 | // clang-format off | ||
| 78 | return { 2.f / width, 0.f, 0.f, 0.f, | ||
| 79 | 0.f, 2.f / height, 0.f, 0.f, | ||
| 80 | 0.f, 0.f, 1.f, 0.f, | ||
| 81 | -1.f, -1.f, 0.f, 1.f}; | ||
| 82 | // clang-format on | ||
| 83 | } | ||
| 84 | |||
| 85 | u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) { | 35 | u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) { |
| 86 | using namespace VideoCore::Surface; | 36 | using namespace VideoCore::Surface; |
| 87 | return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)); | 37 | return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)); |
| @@ -110,43 +60,82 @@ VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) { | |||
| 110 | 60 | ||
| 111 | } // Anonymous namespace | 61 | } // Anonymous namespace |
| 112 | 62 | ||
| 113 | struct BlitScreen::BufferData { | 63 | BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, const Device& device_, |
| 114 | struct { | 64 | MemoryAllocator& memory_allocator_, PresentManager& present_manager_, |
| 115 | std::array<f32, 4 * 4> modelview_matrix; | 65 | Scheduler& scheduler_) |
| 116 | } uniform; | 66 | : device_memory{device_memory_}, device{device_}, memory_allocator{memory_allocator_}, |
| 67 | present_manager{present_manager_}, scheduler{scheduler_}, image_count{1}, | ||
| 68 | swapchain_view_format{VK_FORMAT_B8G8R8A8_UNORM} {} | ||
| 69 | |||
| 70 | BlitScreen::~BlitScreen() = default; | ||
| 71 | |||
| 72 | void BlitScreen::WaitIdle() { | ||
| 73 | present_manager.WaitPresent(); | ||
| 74 | scheduler.Finish(); | ||
| 75 | device.GetLogical().WaitIdle(); | ||
| 76 | } | ||
| 117 | 77 | ||
| 118 | std::array<ScreenRectVertex, 4> vertices; | 78 | void BlitScreen::SetWindowAdaptPass(const Layout::FramebufferLayout& layout) { |
| 79 | scaling_filter = Settings::values.scaling_filter.GetValue(); | ||
| 119 | 80 | ||
| 120 | // Unaligned image data goes here | 81 | const VkExtent2D adapt_size{ |
| 121 | }; | 82 | .width = layout.screen.GetWidth(), |
| 83 | .height = layout.screen.GetHeight(), | ||
| 84 | }; | ||
| 122 | 85 | ||
| 123 | BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, | 86 | fsr.reset(); |
| 124 | Core::Frontend::EmuWindow& render_window_, const Device& device_, | ||
| 125 | MemoryAllocator& memory_allocator_, Swapchain& swapchain_, | ||
| 126 | PresentManager& present_manager_, Scheduler& scheduler_) | ||
| 127 | : device_memory{device_memory_}, render_window{render_window_}, device{device_}, | ||
| 128 | memory_allocator{memory_allocator_}, swapchain{swapchain_}, present_manager{present_manager_}, | ||
| 129 | scheduler{scheduler_}, image_count{swapchain.GetImageCount()} { | ||
| 130 | resource_ticks.resize(image_count); | ||
| 131 | swapchain_view_format = swapchain.GetImageViewFormat(); | ||
| 132 | 87 | ||
| 133 | CreateStaticResources(); | 88 | switch (scaling_filter) { |
| 134 | CreateDynamicResources(); | 89 | case Settings::ScalingFilter::NearestNeighbor: |
| 90 | window_adapt = | ||
| 91 | MakeNearestNeighbor(device, memory_allocator, image_count, swapchain_view_format); | ||
| 92 | break; | ||
| 93 | case Settings::ScalingFilter::Bicubic: | ||
| 94 | window_adapt = MakeBicubic(device, memory_allocator, image_count, swapchain_view_format); | ||
| 95 | break; | ||
| 96 | case Settings::ScalingFilter::Gaussian: | ||
| 97 | window_adapt = MakeGaussian(device, memory_allocator, image_count, swapchain_view_format); | ||
| 98 | break; | ||
| 99 | case Settings::ScalingFilter::ScaleForce: | ||
| 100 | window_adapt = MakeScaleForce(device, memory_allocator, image_count, swapchain_view_format); | ||
| 101 | break; | ||
| 102 | case Settings::ScalingFilter::Fsr: | ||
| 103 | fsr = std::make_unique<FSR>(device, memory_allocator, image_count, adapt_size); | ||
| 104 | [[fallthrough]]; | ||
| 105 | case Settings::ScalingFilter::Bilinear: | ||
| 106 | default: | ||
| 107 | window_adapt = MakeBilinear(device, memory_allocator, image_count, swapchain_view_format); | ||
| 108 | break; | ||
| 109 | } | ||
| 135 | } | 110 | } |
| 136 | 111 | ||
| 137 | BlitScreen::~BlitScreen() = default; | 112 | void BlitScreen::SetAntiAliasPass() { |
| 113 | if (anti_alias && anti_aliasing == Settings::values.anti_aliasing.GetValue()) { | ||
| 114 | return; | ||
| 115 | } | ||
| 138 | 116 | ||
| 139 | void BlitScreen::Recreate() { | 117 | anti_aliasing = Settings::values.anti_aliasing.GetValue(); |
| 140 | present_manager.WaitPresent(); | 118 | |
| 141 | scheduler.Finish(); | 119 | const VkExtent2D render_area{ |
| 142 | device.GetLogical().WaitIdle(); | 120 | .width = Settings::values.resolution_info.ScaleUp(raw_width), |
| 143 | CreateDynamicResources(); | 121 | .height = Settings::values.resolution_info.ScaleUp(raw_height), |
| 122 | }; | ||
| 123 | |||
| 124 | switch (anti_aliasing) { | ||
| 125 | case Settings::AntiAliasing::Fxaa: | ||
| 126 | anti_alias = std::make_unique<FXAA>(device, memory_allocator, image_count, render_area); | ||
| 127 | break; | ||
| 128 | case Settings::AntiAliasing::Smaa: | ||
| 129 | anti_alias = std::make_unique<SMAA>(device, memory_allocator, image_count, render_area); | ||
| 130 | break; | ||
| 131 | default: | ||
| 132 | anti_alias = std::make_unique<NoAA>(); | ||
| 133 | break; | ||
| 134 | } | ||
| 144 | } | 135 | } |
| 145 | 136 | ||
| 146 | void BlitScreen::Draw(RasterizerVulkan& rasterizer, const Tegra::FramebufferConfig& framebuffer, | 137 | void BlitScreen::Draw(RasterizerVulkan& rasterizer, const Tegra::FramebufferConfig& framebuffer, |
| 147 | const VkFramebuffer& host_framebuffer, const Layout::FramebufferLayout layout, | 138 | const Layout::FramebufferLayout& layout, Frame* dst) { |
| 148 | VkExtent2D render_area) { | ||
| 149 | |||
| 150 | const auto texture_info = rasterizer.AccelerateDisplay( | 139 | const auto texture_info = rasterizer.AccelerateDisplay( |
| 151 | framebuffer, framebuffer.address + framebuffer.offset, framebuffer.stride); | 140 | framebuffer, framebuffer.address + framebuffer.offset, framebuffer.stride); |
| 152 | const u32 texture_width = texture_info ? texture_info->width : framebuffer.width; | 141 | const u32 texture_width = texture_info ? texture_info->width : framebuffer.width; |
| @@ -156,23 +145,19 @@ void BlitScreen::Draw(RasterizerVulkan& rasterizer, const Tegra::FramebufferConf | |||
| 156 | const bool use_accelerated = texture_info.has_value(); | 145 | const bool use_accelerated = texture_info.has_value(); |
| 157 | 146 | ||
| 158 | RefreshResources(framebuffer); | 147 | RefreshResources(framebuffer); |
| 148 | SetAntiAliasPass(); | ||
| 159 | 149 | ||
| 160 | // Finish any pending renderpass | 150 | // Finish any pending renderpass |
| 161 | scheduler.RequestOutsideRenderPassOperationContext(); | 151 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 162 | 152 | ||
| 163 | scheduler.Wait(resource_ticks[image_index]); | 153 | scheduler.Wait(resource_ticks[image_index]); |
| 164 | resource_ticks[image_index] = scheduler.CurrentTick(); | 154 | SCOPE_EXIT({ resource_ticks[image_index] = scheduler.CurrentTick(); }); |
| 165 | 155 | ||
| 166 | VkImage source_image = texture_info ? texture_info->image : *raw_images[image_index]; | 156 | VkImage source_image = texture_info ? texture_info->image : *raw_images[image_index]; |
| 167 | VkImageView source_image_view = | 157 | VkImageView source_image_view = |
| 168 | texture_info ? texture_info->image_view : *raw_image_views[image_index]; | 158 | texture_info ? texture_info->image_view : *raw_image_views[image_index]; |
| 169 | 159 | ||
| 170 | BufferData data; | ||
| 171 | SetUniformData(data, layout); | ||
| 172 | SetVertexData(data, framebuffer, layout, texture_width, texture_height); | ||
| 173 | |||
| 174 | const std::span<u8> mapped_span = buffer.Mapped(); | 160 | const std::span<u8> mapped_span = buffer.Mapped(); |
| 175 | std::memcpy(mapped_span.data(), &data, sizeof(data)); | ||
| 176 | 161 | ||
| 177 | if (!use_accelerated) { | 162 | if (!use_accelerated) { |
| 178 | const u64 image_offset = GetRawImageOffset(framebuffer); | 163 | const u64 image_offset = GetRawImageOffset(framebuffer); |
| @@ -249,145 +234,109 @@ void BlitScreen::Draw(RasterizerVulkan& rasterizer, const Tegra::FramebufferConf | |||
| 249 | }); | 234 | }); |
| 250 | } | 235 | } |
| 251 | 236 | ||
| 252 | const auto anti_alias_pass = Settings::values.anti_aliasing.GetValue(); | 237 | source_image_view = anti_alias->Draw(scheduler, image_index, source_image, source_image_view); |
| 253 | if (use_accelerated && anti_alias_pass == Settings::AntiAliasing::Fxaa) { | 238 | |
| 254 | if (!fxaa) { | 239 | const auto crop_rect = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height); |
| 255 | const u32 up_scale = Settings::values.resolution_info.up_scale; | 240 | const VkExtent2D render_extent{ |
| 256 | const u32 down_shift = Settings::values.resolution_info.down_shift; | 241 | .width = scaled_width, |
| 257 | const VkExtent2D fxaa_size{ | 242 | .height = scaled_height, |
| 258 | .width = (up_scale * framebuffer.width) >> down_shift, | 243 | }; |
| 259 | .height = (up_scale * framebuffer.height) >> down_shift, | ||
| 260 | }; | ||
| 261 | fxaa = std::make_unique<FXAA>(device, memory_allocator, image_count, fxaa_size); | ||
| 262 | } | ||
| 263 | 244 | ||
| 264 | source_image_view = fxaa->Draw(scheduler, image_index, source_image, source_image_view); | ||
| 265 | } | ||
| 266 | if (use_accelerated && anti_alias_pass == Settings::AntiAliasing::Smaa) { | ||
| 267 | if (!smaa) { | ||
| 268 | const u32 up_scale = Settings::values.resolution_info.up_scale; | ||
| 269 | const u32 down_shift = Settings::values.resolution_info.down_shift; | ||
| 270 | const VkExtent2D smaa_size{ | ||
| 271 | .width = (up_scale * framebuffer.width) >> down_shift, | ||
| 272 | .height = (up_scale * framebuffer.height) >> down_shift, | ||
| 273 | }; | ||
| 274 | CreateSMAA(smaa_size); | ||
| 275 | } | ||
| 276 | source_image_view = smaa->Draw(scheduler, image_index, source_image, source_image_view); | ||
| 277 | } | ||
| 278 | if (fsr) { | 245 | if (fsr) { |
| 279 | const auto crop_rect = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height); | 246 | const VkExtent2D adapt_size{ |
| 280 | const VkExtent2D fsr_input_size{ | 247 | .width = layout.screen.GetWidth(), |
| 281 | .width = scaled_width, | 248 | .height = layout.screen.GetHeight(), |
| 282 | .height = scaled_height, | ||
| 283 | }; | 249 | }; |
| 284 | VkImageView fsr_image_view = | 250 | |
| 285 | fsr->Draw(scheduler, image_index, source_image_view, fsr_input_size, crop_rect); | 251 | source_image_view = |
| 286 | UpdateDescriptorSet(fsr_image_view, true); | 252 | fsr->Draw(scheduler, image_index, source_image_view, render_extent, crop_rect); |
| 253 | |||
| 254 | const Common::Rectangle<f32> output_crop{0, 0, 1, 1}; | ||
| 255 | window_adapt->Draw(scheduler, image_index, source_image_view, adapt_size, output_crop, | ||
| 256 | layout, dst); | ||
| 287 | } else { | 257 | } else { |
| 288 | const bool is_nn = | 258 | window_adapt->Draw(scheduler, image_index, source_image_view, render_extent, crop_rect, |
| 289 | Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::NearestNeighbor; | 259 | layout, dst); |
| 290 | UpdateDescriptorSet(source_image_view, is_nn); | ||
| 291 | } | 260 | } |
| 261 | } | ||
| 292 | 262 | ||
| 293 | scheduler.Record([this, host_framebuffer, index = image_index, | 263 | void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame, |
| 294 | size = render_area](vk::CommandBuffer cmdbuf) { | 264 | const Tegra::FramebufferConfig& framebuffer, |
| 295 | const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f; | 265 | const Layout::FramebufferLayout& layout, size_t swapchain_images, |
| 296 | const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f; | 266 | VkFormat current_swapchain_view_format) { |
| 297 | const f32 bg_blue = Settings::values.bg_blue.GetValue() / 255.0f; | 267 | bool resource_update_required = false; |
| 298 | const VkClearValue clear_color{ | 268 | bool presentation_recreate_required = false; |
| 299 | .color = {.float32 = {bg_red, bg_green, bg_blue, 1.0f}}, | ||
| 300 | }; | ||
| 301 | const VkRenderPassBeginInfo renderpass_bi{ | ||
| 302 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, | ||
| 303 | .pNext = nullptr, | ||
| 304 | .renderPass = *renderpass, | ||
| 305 | .framebuffer = host_framebuffer, | ||
| 306 | .renderArea = | ||
| 307 | { | ||
| 308 | .offset = {0, 0}, | ||
| 309 | .extent = size, | ||
| 310 | }, | ||
| 311 | .clearValueCount = 1, | ||
| 312 | .pClearValues = &clear_color, | ||
| 313 | }; | ||
| 314 | const VkViewport viewport{ | ||
| 315 | .x = 0.0f, | ||
| 316 | .y = 0.0f, | ||
| 317 | .width = static_cast<float>(size.width), | ||
| 318 | .height = static_cast<float>(size.height), | ||
| 319 | .minDepth = 0.0f, | ||
| 320 | .maxDepth = 1.0f, | ||
| 321 | }; | ||
| 322 | const VkRect2D scissor{ | ||
| 323 | .offset = {0, 0}, | ||
| 324 | .extent = size, | ||
| 325 | }; | ||
| 326 | cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); | ||
| 327 | auto graphics_pipeline = [this]() { | ||
| 328 | switch (Settings::values.scaling_filter.GetValue()) { | ||
| 329 | case Settings::ScalingFilter::NearestNeighbor: | ||
| 330 | case Settings::ScalingFilter::Bilinear: | ||
| 331 | return *bilinear_pipeline; | ||
| 332 | case Settings::ScalingFilter::Bicubic: | ||
| 333 | return *bicubic_pipeline; | ||
| 334 | case Settings::ScalingFilter::Gaussian: | ||
| 335 | return *gaussian_pipeline; | ||
| 336 | case Settings::ScalingFilter::ScaleForce: | ||
| 337 | return *scaleforce_pipeline; | ||
| 338 | default: | ||
| 339 | return *bilinear_pipeline; | ||
| 340 | } | ||
| 341 | }(); | ||
| 342 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline); | ||
| 343 | cmdbuf.SetViewport(0, viewport); | ||
| 344 | cmdbuf.SetScissor(0, scissor); | ||
| 345 | 269 | ||
| 346 | cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices)); | 270 | // Recreate dynamic resources if the adapting filter changed |
| 347 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline_layout, 0, | 271 | if (!window_adapt || scaling_filter != Settings::values.scaling_filter.GetValue()) { |
| 348 | descriptor_sets[index], {}); | 272 | resource_update_required = true; |
| 349 | cmdbuf.Draw(4, 1, 0, 0); | 273 | } |
| 350 | cmdbuf.EndRenderPass(); | ||
| 351 | }); | ||
| 352 | } | ||
| 353 | 274 | ||
| 354 | void BlitScreen::DrawToSwapchain(RasterizerVulkan& rasterizer, Frame* frame, | ||
| 355 | const Tegra::FramebufferConfig& framebuffer) { | ||
| 356 | // Recreate dynamic resources if the the image count or input format changed | 275 | // Recreate dynamic resources if the the image count or input format changed |
| 357 | const VkFormat current_framebuffer_format = | 276 | const VkFormat old_framebuffer_format = |
| 358 | std::exchange(framebuffer_view_format, GetFormat(framebuffer)); | 277 | std::exchange(framebuffer_view_format, GetFormat(framebuffer)); |
| 359 | if (const std::size_t swapchain_images = swapchain.GetImageCount(); | 278 | if (swapchain_images != image_count || old_framebuffer_format != framebuffer_view_format) { |
| 360 | swapchain_images != image_count || current_framebuffer_format != framebuffer_view_format) { | ||
| 361 | image_count = swapchain_images; | 279 | image_count = swapchain_images; |
| 362 | Recreate(); | 280 | resource_update_required = true; |
| 363 | } | 281 | } |
| 364 | 282 | ||
| 365 | // Recreate the presentation frame if the dimensions of the window changed | 283 | // Recreate the presentation frame if the format or dimensions of the window changed |
| 366 | const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); | 284 | const VkFormat old_swapchain_view_format = |
| 367 | if (layout.width != frame->width || layout.height != frame->height) { | 285 | std::exchange(swapchain_view_format, current_swapchain_view_format); |
| 368 | Recreate(); | 286 | if (old_swapchain_view_format != current_swapchain_view_format || |
| 369 | present_manager.RecreateFrame(frame, layout.width, layout.height, swapchain_view_format, | 287 | layout.width != frame->width || layout.height != frame->height) { |
| 370 | *renderpass); | 288 | resource_update_required = true; |
| 289 | presentation_recreate_required = true; | ||
| 371 | } | 290 | } |
| 372 | 291 | ||
| 373 | const VkExtent2D render_area{frame->width, frame->height}; | 292 | // If we have a pending resource update, perform it |
| 374 | Draw(rasterizer, framebuffer, *frame->framebuffer, layout, render_area); | 293 | if (resource_update_required) { |
| 294 | // Wait for idle to ensure no resources are in use | ||
| 295 | WaitIdle(); | ||
| 296 | |||
| 297 | // Set new number of resource ticks | ||
| 298 | resource_ticks.resize(swapchain_images); | ||
| 299 | |||
| 300 | // Update window adapt pass | ||
| 301 | SetWindowAdaptPass(layout); | ||
| 302 | |||
| 303 | // Update frame format if needed | ||
| 304 | if (presentation_recreate_required) { | ||
| 305 | present_manager.RecreateFrame(frame, layout.width, layout.height, swapchain_view_format, | ||
| 306 | window_adapt->GetRenderPass()); | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | Draw(rasterizer, framebuffer, layout, frame); | ||
| 375 | if (++image_index >= image_count) { | 311 | if (++image_index >= image_count) { |
| 376 | image_index = 0; | 312 | image_index = 0; |
| 377 | } | 313 | } |
| 378 | } | 314 | } |
| 379 | 315 | ||
| 380 | vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent) { | 316 | vk::Framebuffer BlitScreen::CreateFramebuffer(const Layout::FramebufferLayout& layout, |
| 381 | return CreateFramebuffer(image_view, extent, renderpass); | 317 | const VkImageView& image_view, |
| 318 | VkFormat current_view_format) { | ||
| 319 | const bool format_updated = | ||
| 320 | std::exchange(swapchain_view_format, current_view_format) != current_view_format; | ||
| 321 | if (!window_adapt || scaling_filter != Settings::values.scaling_filter.GetValue() || | ||
| 322 | format_updated) { | ||
| 323 | WaitIdle(); | ||
| 324 | SetWindowAdaptPass(layout); | ||
| 325 | } | ||
| 326 | const VkExtent2D extent{ | ||
| 327 | .width = layout.width, | ||
| 328 | .height = layout.height, | ||
| 329 | }; | ||
| 330 | return CreateFramebuffer(image_view, extent, window_adapt->GetRenderPass()); | ||
| 382 | } | 331 | } |
| 383 | 332 | ||
| 384 | vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent, | 333 | vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent, |
| 385 | vk::RenderPass& rd) { | 334 | VkRenderPass render_pass) { |
| 386 | return device.GetLogical().CreateFramebuffer(VkFramebufferCreateInfo{ | 335 | return device.GetLogical().CreateFramebuffer(VkFramebufferCreateInfo{ |
| 387 | .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, | 336 | .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, |
| 388 | .pNext = nullptr, | 337 | .pNext = nullptr, |
| 389 | .flags = 0, | 338 | .flags = 0, |
| 390 | .renderPass = *rd, | 339 | .renderPass = render_pass, |
| 391 | .attachmentCount = 1, | 340 | .attachmentCount = 1, |
| 392 | .pAttachments = &image_view, | 341 | .pAttachments = &image_view, |
| 393 | .width = extent.width, | 342 | .width = extent.width, |
| @@ -396,35 +345,7 @@ vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkE | |||
| 396 | }); | 345 | }); |
| 397 | } | 346 | } |
| 398 | 347 | ||
| 399 | void BlitScreen::CreateStaticResources() { | ||
| 400 | CreateShaders(); | ||
| 401 | CreateSampler(); | ||
| 402 | } | ||
| 403 | |||
| 404 | void BlitScreen::CreateDynamicResources() { | ||
| 405 | CreateDescriptorPool(); | ||
| 406 | CreateDescriptorSetLayout(); | ||
| 407 | CreateDescriptorSets(); | ||
| 408 | CreatePipelineLayout(); | ||
| 409 | CreateRenderPass(); | ||
| 410 | CreateGraphicsPipeline(); | ||
| 411 | fsr.reset(); | ||
| 412 | fxaa.reset(); | ||
| 413 | smaa.reset(); | ||
| 414 | if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { | ||
| 415 | CreateFSR(); | ||
| 416 | } | ||
| 417 | } | ||
| 418 | |||
| 419 | void BlitScreen::RefreshResources(const Tegra::FramebufferConfig& framebuffer) { | 348 | void BlitScreen::RefreshResources(const Tegra::FramebufferConfig& framebuffer) { |
| 420 | if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { | ||
| 421 | if (!fsr) { | ||
| 422 | CreateFSR(); | ||
| 423 | } | ||
| 424 | } else { | ||
| 425 | fsr.reset(); | ||
| 426 | } | ||
| 427 | |||
| 428 | if (framebuffer.width == raw_width && framebuffer.height == raw_height && | 349 | if (framebuffer.width == raw_width && framebuffer.height == raw_height && |
| 429 | framebuffer.pixel_format == pixel_format && !raw_images.empty()) { | 350 | framebuffer.pixel_format == pixel_format && !raw_images.empty()) { |
| 430 | return; | 351 | return; |
| @@ -433,486 +354,13 @@ void BlitScreen::RefreshResources(const Tegra::FramebufferConfig& framebuffer) { | |||
| 433 | raw_width = framebuffer.width; | 354 | raw_width = framebuffer.width; |
| 434 | raw_height = framebuffer.height; | 355 | raw_height = framebuffer.height; |
| 435 | pixel_format = framebuffer.pixel_format; | 356 | pixel_format = framebuffer.pixel_format; |
| 357 | anti_alias.reset(); | ||
| 436 | 358 | ||
| 437 | fxaa.reset(); | ||
| 438 | smaa.reset(); | ||
| 439 | ReleaseRawImages(); | 359 | ReleaseRawImages(); |
| 440 | |||
| 441 | CreateStagingBuffer(framebuffer); | 360 | CreateStagingBuffer(framebuffer); |
| 442 | CreateRawImages(framebuffer); | 361 | CreateRawImages(framebuffer); |
| 443 | } | 362 | } |
| 444 | 363 | ||
| 445 | void BlitScreen::CreateShaders() { | ||
| 446 | vertex_shader = BuildShader(device, VULKAN_PRESENT_VERT_SPV); | ||
| 447 | bilinear_fragment_shader = BuildShader(device, VULKAN_PRESENT_FRAG_SPV); | ||
| 448 | bicubic_fragment_shader = BuildShader(device, PRESENT_BICUBIC_FRAG_SPV); | ||
| 449 | gaussian_fragment_shader = BuildShader(device, PRESENT_GAUSSIAN_FRAG_SPV); | ||
| 450 | if (device.IsFloat16Supported()) { | ||
| 451 | scaleforce_fragment_shader = BuildShader(device, VULKAN_PRESENT_SCALEFORCE_FP16_FRAG_SPV); | ||
| 452 | } else { | ||
| 453 | scaleforce_fragment_shader = BuildShader(device, VULKAN_PRESENT_SCALEFORCE_FP32_FRAG_SPV); | ||
| 454 | } | ||
| 455 | } | ||
| 456 | |||
| 457 | void BlitScreen::CreateDescriptorPool() { | ||
| 458 | const std::array<VkDescriptorPoolSize, 2> pool_sizes{{ | ||
| 459 | { | ||
| 460 | .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, | ||
| 461 | .descriptorCount = static_cast<u32>(image_count), | ||
| 462 | }, | ||
| 463 | { | ||
| 464 | .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 465 | .descriptorCount = static_cast<u32>(image_count), | ||
| 466 | }, | ||
| 467 | }}; | ||
| 468 | |||
| 469 | const VkDescriptorPoolCreateInfo ci{ | ||
| 470 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, | ||
| 471 | .pNext = nullptr, | ||
| 472 | .flags = 0, | ||
| 473 | .maxSets = static_cast<u32>(image_count), | ||
| 474 | .poolSizeCount = static_cast<u32>(pool_sizes.size()), | ||
| 475 | .pPoolSizes = pool_sizes.data(), | ||
| 476 | }; | ||
| 477 | descriptor_pool = device.GetLogical().CreateDescriptorPool(ci); | ||
| 478 | } | ||
| 479 | |||
| 480 | void BlitScreen::CreateRenderPass() { | ||
| 481 | renderpass = CreateRenderPassImpl(swapchain_view_format); | ||
| 482 | } | ||
| 483 | |||
| 484 | vk::RenderPass BlitScreen::CreateRenderPassImpl(VkFormat format) { | ||
| 485 | const VkAttachmentDescription color_attachment{ | ||
| 486 | .flags = 0, | ||
| 487 | .format = format, | ||
| 488 | .samples = VK_SAMPLE_COUNT_1_BIT, | ||
| 489 | .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, | ||
| 490 | .storeOp = VK_ATTACHMENT_STORE_OP_STORE, | ||
| 491 | .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, | ||
| 492 | .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, | ||
| 493 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | ||
| 494 | .finalLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 495 | }; | ||
| 496 | |||
| 497 | const VkAttachmentReference color_attachment_ref{ | ||
| 498 | .attachment = 0, | ||
| 499 | .layout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 500 | }; | ||
| 501 | |||
| 502 | const VkSubpassDescription subpass_description{ | ||
| 503 | .flags = 0, | ||
| 504 | .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, | ||
| 505 | .inputAttachmentCount = 0, | ||
| 506 | .pInputAttachments = nullptr, | ||
| 507 | .colorAttachmentCount = 1, | ||
| 508 | .pColorAttachments = &color_attachment_ref, | ||
| 509 | .pResolveAttachments = nullptr, | ||
| 510 | .pDepthStencilAttachment = nullptr, | ||
| 511 | .preserveAttachmentCount = 0, | ||
| 512 | .pPreserveAttachments = nullptr, | ||
| 513 | }; | ||
| 514 | |||
| 515 | const VkSubpassDependency dependency{ | ||
| 516 | .srcSubpass = VK_SUBPASS_EXTERNAL, | ||
| 517 | .dstSubpass = 0, | ||
| 518 | .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | ||
| 519 | .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | ||
| 520 | .srcAccessMask = 0, | ||
| 521 | .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, | ||
| 522 | .dependencyFlags = 0, | ||
| 523 | }; | ||
| 524 | |||
| 525 | const VkRenderPassCreateInfo renderpass_ci{ | ||
| 526 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, | ||
| 527 | .pNext = nullptr, | ||
| 528 | .flags = 0, | ||
| 529 | .attachmentCount = 1, | ||
| 530 | .pAttachments = &color_attachment, | ||
| 531 | .subpassCount = 1, | ||
| 532 | .pSubpasses = &subpass_description, | ||
| 533 | .dependencyCount = 1, | ||
| 534 | .pDependencies = &dependency, | ||
| 535 | }; | ||
| 536 | |||
| 537 | return device.GetLogical().CreateRenderPass(renderpass_ci); | ||
| 538 | } | ||
| 539 | |||
| 540 | void BlitScreen::CreateDescriptorSetLayout() { | ||
| 541 | const std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings{{ | ||
| 542 | { | ||
| 543 | .binding = 0, | ||
| 544 | .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, | ||
| 545 | .descriptorCount = 1, | ||
| 546 | .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 547 | .pImmutableSamplers = nullptr, | ||
| 548 | }, | ||
| 549 | { | ||
| 550 | .binding = 1, | ||
| 551 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 552 | .descriptorCount = 1, | ||
| 553 | .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 554 | .pImmutableSamplers = nullptr, | ||
| 555 | }, | ||
| 556 | }}; | ||
| 557 | |||
| 558 | const VkDescriptorSetLayoutCreateInfo ci{ | ||
| 559 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, | ||
| 560 | .pNext = nullptr, | ||
| 561 | .flags = 0, | ||
| 562 | .bindingCount = static_cast<u32>(layout_bindings.size()), | ||
| 563 | .pBindings = layout_bindings.data(), | ||
| 564 | }; | ||
| 565 | |||
| 566 | descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(ci); | ||
| 567 | } | ||
| 568 | |||
| 569 | void BlitScreen::CreateDescriptorSets() { | ||
| 570 | const std::vector layouts(image_count, *descriptor_set_layout); | ||
| 571 | |||
| 572 | const VkDescriptorSetAllocateInfo ai{ | ||
| 573 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, | ||
| 574 | .pNext = nullptr, | ||
| 575 | .descriptorPool = *descriptor_pool, | ||
| 576 | .descriptorSetCount = static_cast<u32>(image_count), | ||
| 577 | .pSetLayouts = layouts.data(), | ||
| 578 | }; | ||
| 579 | |||
| 580 | descriptor_sets = descriptor_pool.Allocate(ai); | ||
| 581 | } | ||
| 582 | |||
| 583 | void BlitScreen::CreatePipelineLayout() { | ||
| 584 | const VkPipelineLayoutCreateInfo ci{ | ||
| 585 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | ||
| 586 | .pNext = nullptr, | ||
| 587 | .flags = 0, | ||
| 588 | .setLayoutCount = 1, | ||
| 589 | .pSetLayouts = descriptor_set_layout.address(), | ||
| 590 | .pushConstantRangeCount = 0, | ||
| 591 | .pPushConstantRanges = nullptr, | ||
| 592 | }; | ||
| 593 | pipeline_layout = device.GetLogical().CreatePipelineLayout(ci); | ||
| 594 | } | ||
| 595 | |||
| 596 | void BlitScreen::CreateGraphicsPipeline() { | ||
| 597 | const std::array<VkPipelineShaderStageCreateInfo, 2> bilinear_shader_stages{{ | ||
| 598 | { | ||
| 599 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 600 | .pNext = nullptr, | ||
| 601 | .flags = 0, | ||
| 602 | .stage = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 603 | .module = *vertex_shader, | ||
| 604 | .pName = "main", | ||
| 605 | .pSpecializationInfo = nullptr, | ||
| 606 | }, | ||
| 607 | { | ||
| 608 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 609 | .pNext = nullptr, | ||
| 610 | .flags = 0, | ||
| 611 | .stage = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 612 | .module = *bilinear_fragment_shader, | ||
| 613 | .pName = "main", | ||
| 614 | .pSpecializationInfo = nullptr, | ||
| 615 | }, | ||
| 616 | }}; | ||
| 617 | |||
| 618 | const std::array<VkPipelineShaderStageCreateInfo, 2> bicubic_shader_stages{{ | ||
| 619 | { | ||
| 620 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 621 | .pNext = nullptr, | ||
| 622 | .flags = 0, | ||
| 623 | .stage = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 624 | .module = *vertex_shader, | ||
| 625 | .pName = "main", | ||
| 626 | .pSpecializationInfo = nullptr, | ||
| 627 | }, | ||
| 628 | { | ||
| 629 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 630 | .pNext = nullptr, | ||
| 631 | .flags = 0, | ||
| 632 | .stage = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 633 | .module = *bicubic_fragment_shader, | ||
| 634 | .pName = "main", | ||
| 635 | .pSpecializationInfo = nullptr, | ||
| 636 | }, | ||
| 637 | }}; | ||
| 638 | |||
| 639 | const std::array<VkPipelineShaderStageCreateInfo, 2> gaussian_shader_stages{{ | ||
| 640 | { | ||
| 641 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 642 | .pNext = nullptr, | ||
| 643 | .flags = 0, | ||
| 644 | .stage = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 645 | .module = *vertex_shader, | ||
| 646 | .pName = "main", | ||
| 647 | .pSpecializationInfo = nullptr, | ||
| 648 | }, | ||
| 649 | { | ||
| 650 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 651 | .pNext = nullptr, | ||
| 652 | .flags = 0, | ||
| 653 | .stage = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 654 | .module = *gaussian_fragment_shader, | ||
| 655 | .pName = "main", | ||
| 656 | .pSpecializationInfo = nullptr, | ||
| 657 | }, | ||
| 658 | }}; | ||
| 659 | |||
| 660 | const std::array<VkPipelineShaderStageCreateInfo, 2> scaleforce_shader_stages{{ | ||
| 661 | { | ||
| 662 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 663 | .pNext = nullptr, | ||
| 664 | .flags = 0, | ||
| 665 | .stage = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 666 | .module = *vertex_shader, | ||
| 667 | .pName = "main", | ||
| 668 | .pSpecializationInfo = nullptr, | ||
| 669 | }, | ||
| 670 | { | ||
| 671 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 672 | .pNext = nullptr, | ||
| 673 | .flags = 0, | ||
| 674 | .stage = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 675 | .module = *scaleforce_fragment_shader, | ||
| 676 | .pName = "main", | ||
| 677 | .pSpecializationInfo = nullptr, | ||
| 678 | }, | ||
| 679 | }}; | ||
| 680 | |||
| 681 | const auto vertex_binding_description = ScreenRectVertex::GetDescription(); | ||
| 682 | const auto vertex_attrs_description = ScreenRectVertex::GetAttributes(); | ||
| 683 | |||
| 684 | const VkPipelineVertexInputStateCreateInfo vertex_input_ci{ | ||
| 685 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | ||
| 686 | .pNext = nullptr, | ||
| 687 | .flags = 0, | ||
| 688 | .vertexBindingDescriptionCount = 1, | ||
| 689 | .pVertexBindingDescriptions = &vertex_binding_description, | ||
| 690 | .vertexAttributeDescriptionCount = u32{vertex_attrs_description.size()}, | ||
| 691 | .pVertexAttributeDescriptions = vertex_attrs_description.data(), | ||
| 692 | }; | ||
| 693 | |||
| 694 | const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ | ||
| 695 | .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | ||
| 696 | .pNext = nullptr, | ||
| 697 | .flags = 0, | ||
| 698 | .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, | ||
| 699 | .primitiveRestartEnable = VK_FALSE, | ||
| 700 | }; | ||
| 701 | |||
| 702 | const VkPipelineViewportStateCreateInfo viewport_state_ci{ | ||
| 703 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| 704 | .pNext = nullptr, | ||
| 705 | .flags = 0, | ||
| 706 | .viewportCount = 1, | ||
| 707 | .pViewports = nullptr, | ||
| 708 | .scissorCount = 1, | ||
| 709 | .pScissors = nullptr, | ||
| 710 | }; | ||
| 711 | |||
| 712 | const VkPipelineRasterizationStateCreateInfo rasterization_ci{ | ||
| 713 | .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | ||
| 714 | .pNext = nullptr, | ||
| 715 | .flags = 0, | ||
| 716 | .depthClampEnable = VK_FALSE, | ||
| 717 | .rasterizerDiscardEnable = VK_FALSE, | ||
| 718 | .polygonMode = VK_POLYGON_MODE_FILL, | ||
| 719 | .cullMode = VK_CULL_MODE_NONE, | ||
| 720 | .frontFace = VK_FRONT_FACE_CLOCKWISE, | ||
| 721 | .depthBiasEnable = VK_FALSE, | ||
| 722 | .depthBiasConstantFactor = 0.0f, | ||
| 723 | .depthBiasClamp = 0.0f, | ||
| 724 | .depthBiasSlopeFactor = 0.0f, | ||
| 725 | .lineWidth = 1.0f, | ||
| 726 | }; | ||
| 727 | |||
| 728 | const VkPipelineMultisampleStateCreateInfo multisampling_ci{ | ||
| 729 | .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||
| 730 | .pNext = nullptr, | ||
| 731 | .flags = 0, | ||
| 732 | .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, | ||
| 733 | .sampleShadingEnable = VK_FALSE, | ||
| 734 | .minSampleShading = 0.0f, | ||
| 735 | .pSampleMask = nullptr, | ||
| 736 | .alphaToCoverageEnable = VK_FALSE, | ||
| 737 | .alphaToOneEnable = VK_FALSE, | ||
| 738 | }; | ||
| 739 | |||
| 740 | const VkPipelineColorBlendAttachmentState color_blend_attachment{ | ||
| 741 | .blendEnable = VK_FALSE, | ||
| 742 | .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 743 | .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 744 | .colorBlendOp = VK_BLEND_OP_ADD, | ||
| 745 | .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 746 | .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 747 | .alphaBlendOp = VK_BLEND_OP_ADD, | ||
| 748 | .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | | ||
| 749 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, | ||
| 750 | }; | ||
| 751 | |||
| 752 | const VkPipelineColorBlendStateCreateInfo color_blend_ci{ | ||
| 753 | .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | ||
| 754 | .pNext = nullptr, | ||
| 755 | .flags = 0, | ||
| 756 | .logicOpEnable = VK_FALSE, | ||
| 757 | .logicOp = VK_LOGIC_OP_COPY, | ||
| 758 | .attachmentCount = 1, | ||
| 759 | .pAttachments = &color_blend_attachment, | ||
| 760 | .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, | ||
| 761 | }; | ||
| 762 | |||
| 763 | static constexpr std::array dynamic_states{ | ||
| 764 | VK_DYNAMIC_STATE_VIEWPORT, | ||
| 765 | VK_DYNAMIC_STATE_SCISSOR, | ||
| 766 | }; | ||
| 767 | const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ | ||
| 768 | .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||
| 769 | .pNext = nullptr, | ||
| 770 | .flags = 0, | ||
| 771 | .dynamicStateCount = static_cast<u32>(dynamic_states.size()), | ||
| 772 | .pDynamicStates = dynamic_states.data(), | ||
| 773 | }; | ||
| 774 | |||
| 775 | const VkGraphicsPipelineCreateInfo bilinear_pipeline_ci{ | ||
| 776 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 777 | .pNext = nullptr, | ||
| 778 | .flags = 0, | ||
| 779 | .stageCount = static_cast<u32>(bilinear_shader_stages.size()), | ||
| 780 | .pStages = bilinear_shader_stages.data(), | ||
| 781 | .pVertexInputState = &vertex_input_ci, | ||
| 782 | .pInputAssemblyState = &input_assembly_ci, | ||
| 783 | .pTessellationState = nullptr, | ||
| 784 | .pViewportState = &viewport_state_ci, | ||
| 785 | .pRasterizationState = &rasterization_ci, | ||
| 786 | .pMultisampleState = &multisampling_ci, | ||
| 787 | .pDepthStencilState = nullptr, | ||
| 788 | .pColorBlendState = &color_blend_ci, | ||
| 789 | .pDynamicState = &dynamic_state_ci, | ||
| 790 | .layout = *pipeline_layout, | ||
| 791 | .renderPass = *renderpass, | ||
| 792 | .subpass = 0, | ||
| 793 | .basePipelineHandle = 0, | ||
| 794 | .basePipelineIndex = 0, | ||
| 795 | }; | ||
| 796 | |||
| 797 | const VkGraphicsPipelineCreateInfo bicubic_pipeline_ci{ | ||
| 798 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 799 | .pNext = nullptr, | ||
| 800 | .flags = 0, | ||
| 801 | .stageCount = static_cast<u32>(bicubic_shader_stages.size()), | ||
| 802 | .pStages = bicubic_shader_stages.data(), | ||
| 803 | .pVertexInputState = &vertex_input_ci, | ||
| 804 | .pInputAssemblyState = &input_assembly_ci, | ||
| 805 | .pTessellationState = nullptr, | ||
| 806 | .pViewportState = &viewport_state_ci, | ||
| 807 | .pRasterizationState = &rasterization_ci, | ||
| 808 | .pMultisampleState = &multisampling_ci, | ||
| 809 | .pDepthStencilState = nullptr, | ||
| 810 | .pColorBlendState = &color_blend_ci, | ||
| 811 | .pDynamicState = &dynamic_state_ci, | ||
| 812 | .layout = *pipeline_layout, | ||
| 813 | .renderPass = *renderpass, | ||
| 814 | .subpass = 0, | ||
| 815 | .basePipelineHandle = 0, | ||
| 816 | .basePipelineIndex = 0, | ||
| 817 | }; | ||
| 818 | |||
| 819 | const VkGraphicsPipelineCreateInfo gaussian_pipeline_ci{ | ||
| 820 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 821 | .pNext = nullptr, | ||
| 822 | .flags = 0, | ||
| 823 | .stageCount = static_cast<u32>(gaussian_shader_stages.size()), | ||
| 824 | .pStages = gaussian_shader_stages.data(), | ||
| 825 | .pVertexInputState = &vertex_input_ci, | ||
| 826 | .pInputAssemblyState = &input_assembly_ci, | ||
| 827 | .pTessellationState = nullptr, | ||
| 828 | .pViewportState = &viewport_state_ci, | ||
| 829 | .pRasterizationState = &rasterization_ci, | ||
| 830 | .pMultisampleState = &multisampling_ci, | ||
| 831 | .pDepthStencilState = nullptr, | ||
| 832 | .pColorBlendState = &color_blend_ci, | ||
| 833 | .pDynamicState = &dynamic_state_ci, | ||
| 834 | .layout = *pipeline_layout, | ||
| 835 | .renderPass = *renderpass, | ||
| 836 | .subpass = 0, | ||
| 837 | .basePipelineHandle = 0, | ||
| 838 | .basePipelineIndex = 0, | ||
| 839 | }; | ||
| 840 | |||
| 841 | const VkGraphicsPipelineCreateInfo scaleforce_pipeline_ci{ | ||
| 842 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 843 | .pNext = nullptr, | ||
| 844 | .flags = 0, | ||
| 845 | .stageCount = static_cast<u32>(scaleforce_shader_stages.size()), | ||
| 846 | .pStages = scaleforce_shader_stages.data(), | ||
| 847 | .pVertexInputState = &vertex_input_ci, | ||
| 848 | .pInputAssemblyState = &input_assembly_ci, | ||
| 849 | .pTessellationState = nullptr, | ||
| 850 | .pViewportState = &viewport_state_ci, | ||
| 851 | .pRasterizationState = &rasterization_ci, | ||
| 852 | .pMultisampleState = &multisampling_ci, | ||
| 853 | .pDepthStencilState = nullptr, | ||
| 854 | .pColorBlendState = &color_blend_ci, | ||
| 855 | .pDynamicState = &dynamic_state_ci, | ||
| 856 | .layout = *pipeline_layout, | ||
| 857 | .renderPass = *renderpass, | ||
| 858 | .subpass = 0, | ||
| 859 | .basePipelineHandle = 0, | ||
| 860 | .basePipelineIndex = 0, | ||
| 861 | }; | ||
| 862 | |||
| 863 | bilinear_pipeline = device.GetLogical().CreateGraphicsPipeline(bilinear_pipeline_ci); | ||
| 864 | bicubic_pipeline = device.GetLogical().CreateGraphicsPipeline(bicubic_pipeline_ci); | ||
| 865 | gaussian_pipeline = device.GetLogical().CreateGraphicsPipeline(gaussian_pipeline_ci); | ||
| 866 | scaleforce_pipeline = device.GetLogical().CreateGraphicsPipeline(scaleforce_pipeline_ci); | ||
| 867 | } | ||
| 868 | |||
| 869 | void BlitScreen::CreateSampler() { | ||
| 870 | const VkSamplerCreateInfo ci{ | ||
| 871 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, | ||
| 872 | .pNext = nullptr, | ||
| 873 | .flags = 0, | ||
| 874 | .magFilter = VK_FILTER_LINEAR, | ||
| 875 | .minFilter = VK_FILTER_LINEAR, | ||
| 876 | .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, | ||
| 877 | .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 878 | .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 879 | .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 880 | .mipLodBias = 0.0f, | ||
| 881 | .anisotropyEnable = VK_FALSE, | ||
| 882 | .maxAnisotropy = 0.0f, | ||
| 883 | .compareEnable = VK_FALSE, | ||
| 884 | .compareOp = VK_COMPARE_OP_NEVER, | ||
| 885 | .minLod = 0.0f, | ||
| 886 | .maxLod = 0.0f, | ||
| 887 | .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, | ||
| 888 | .unnormalizedCoordinates = VK_FALSE, | ||
| 889 | }; | ||
| 890 | |||
| 891 | const VkSamplerCreateInfo ci_nn{ | ||
| 892 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, | ||
| 893 | .pNext = nullptr, | ||
| 894 | .flags = 0, | ||
| 895 | .magFilter = VK_FILTER_NEAREST, | ||
| 896 | .minFilter = VK_FILTER_NEAREST, | ||
| 897 | .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, | ||
| 898 | .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 899 | .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 900 | .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, | ||
| 901 | .mipLodBias = 0.0f, | ||
| 902 | .anisotropyEnable = VK_FALSE, | ||
| 903 | .maxAnisotropy = 0.0f, | ||
| 904 | .compareEnable = VK_FALSE, | ||
| 905 | .compareOp = VK_COMPARE_OP_NEVER, | ||
| 906 | .minLod = 0.0f, | ||
| 907 | .maxLod = 0.0f, | ||
| 908 | .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, | ||
| 909 | .unnormalizedCoordinates = VK_FALSE, | ||
| 910 | }; | ||
| 911 | |||
| 912 | sampler = device.GetLogical().CreateSampler(ci); | ||
| 913 | nn_sampler = device.GetLogical().CreateSampler(ci_nn); | ||
| 914 | } | ||
| 915 | |||
| 916 | void BlitScreen::ReleaseRawImages() { | 364 | void BlitScreen::ReleaseRawImages() { |
| 917 | for (const u64 tick : resource_ticks) { | 365 | for (const u64 tick : resource_ticks) { |
| 918 | scheduler.Wait(tick); | 366 | scheduler.Wait(tick); |
| @@ -1000,109 +448,12 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | |||
| 1000 | } | 448 | } |
| 1001 | } | 449 | } |
| 1002 | 450 | ||
| 1003 | void BlitScreen::UpdateDescriptorSet(VkImageView image_view, bool nn) const { | ||
| 1004 | const VkDescriptorBufferInfo buffer_info{ | ||
| 1005 | .buffer = *buffer, | ||
| 1006 | .offset = offsetof(BufferData, uniform), | ||
| 1007 | .range = sizeof(BufferData::uniform), | ||
| 1008 | }; | ||
| 1009 | |||
| 1010 | const VkWriteDescriptorSet ubo_write{ | ||
| 1011 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 1012 | .pNext = nullptr, | ||
| 1013 | .dstSet = descriptor_sets[image_index], | ||
| 1014 | .dstBinding = 0, | ||
| 1015 | .dstArrayElement = 0, | ||
| 1016 | .descriptorCount = 1, | ||
| 1017 | .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, | ||
| 1018 | .pImageInfo = nullptr, | ||
| 1019 | .pBufferInfo = &buffer_info, | ||
| 1020 | .pTexelBufferView = nullptr, | ||
| 1021 | }; | ||
| 1022 | |||
| 1023 | const VkDescriptorImageInfo image_info{ | ||
| 1024 | .sampler = nn ? *nn_sampler : *sampler, | ||
| 1025 | .imageView = image_view, | ||
| 1026 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 1027 | }; | ||
| 1028 | |||
| 1029 | const VkWriteDescriptorSet sampler_write{ | ||
| 1030 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 1031 | .pNext = nullptr, | ||
| 1032 | .dstSet = descriptor_sets[image_index], | ||
| 1033 | .dstBinding = 1, | ||
| 1034 | .dstArrayElement = 0, | ||
| 1035 | .descriptorCount = 1, | ||
| 1036 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 1037 | .pImageInfo = &image_info, | ||
| 1038 | .pBufferInfo = nullptr, | ||
| 1039 | .pTexelBufferView = nullptr, | ||
| 1040 | }; | ||
| 1041 | |||
| 1042 | device.GetLogical().UpdateDescriptorSets(std::array{ubo_write, sampler_write}, {}); | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | void BlitScreen::SetUniformData(BufferData& data, const Layout::FramebufferLayout layout) const { | ||
| 1046 | data.uniform.modelview_matrix = | ||
| 1047 | MakeOrthographicMatrix(static_cast<f32>(layout.width), static_cast<f32>(layout.height)); | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | void BlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, | ||
| 1051 | const Layout::FramebufferLayout layout, u32 texture_width, | ||
| 1052 | u32 texture_height) const { | ||
| 1053 | f32 left, top, right, bottom; | ||
| 1054 | |||
| 1055 | if (fsr) { | ||
| 1056 | // FSR has already applied the crop, so we just want to render the image | ||
| 1057 | // it has produced. | ||
| 1058 | left = 0; | ||
| 1059 | top = 0; | ||
| 1060 | right = 1; | ||
| 1061 | bottom = 1; | ||
| 1062 | } else { | ||
| 1063 | // Get the normalized crop rectangle. | ||
| 1064 | const auto crop = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height); | ||
| 1065 | |||
| 1066 | // Apply the crop. | ||
| 1067 | left = crop.left; | ||
| 1068 | top = crop.top; | ||
| 1069 | right = crop.right; | ||
| 1070 | bottom = crop.bottom; | ||
| 1071 | } | ||
| 1072 | |||
| 1073 | // Map the coordinates to the screen. | ||
| 1074 | const auto& screen = layout.screen; | ||
| 1075 | const auto x = static_cast<f32>(screen.left); | ||
| 1076 | const auto y = static_cast<f32>(screen.top); | ||
| 1077 | const auto w = static_cast<f32>(screen.GetWidth()); | ||
| 1078 | const auto h = static_cast<f32>(screen.GetHeight()); | ||
| 1079 | |||
| 1080 | data.vertices[0] = ScreenRectVertex(x, y, left, top); | ||
| 1081 | data.vertices[1] = ScreenRectVertex(x + w, y, right, top); | ||
| 1082 | data.vertices[2] = ScreenRectVertex(x, y + h, left, bottom); | ||
| 1083 | data.vertices[3] = ScreenRectVertex(x + w, y + h, right, bottom); | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | void BlitScreen::CreateSMAA(VkExtent2D smaa_size) { | ||
| 1087 | smaa = std::make_unique<SMAA>(device, memory_allocator, image_count, smaa_size); | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | void BlitScreen::CreateFSR() { | ||
| 1091 | const auto& layout = render_window.GetFramebufferLayout(); | ||
| 1092 | const VkExtent2D fsr_size{ | ||
| 1093 | .width = layout.screen.GetWidth(), | ||
| 1094 | .height = layout.screen.GetHeight(), | ||
| 1095 | }; | ||
| 1096 | fsr = std::make_unique<FSR>(device, memory_allocator, image_count, fsr_size); | ||
| 1097 | } | ||
| 1098 | |||
| 1099 | u64 BlitScreen::CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const { | 451 | u64 BlitScreen::CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const { |
| 1100 | return sizeof(BufferData) + GetSizeInBytes(framebuffer) * image_count; | 452 | return GetSizeInBytes(framebuffer) * image_count; |
| 1101 | } | 453 | } |
| 1102 | 454 | ||
| 1103 | u64 BlitScreen::GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer) const { | 455 | u64 BlitScreen::GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer) const { |
| 1104 | constexpr auto first_image_offset = static_cast<u64>(sizeof(BufferData)); | 456 | return GetSizeInBytes(framebuffer) * image_index; |
| 1105 | return first_image_offset + GetSizeInBytes(framebuffer) * image_index; | ||
| 1106 | } | 457 | } |
| 1107 | 458 | ||
| 1108 | } // namespace Vulkan | 459 | } // 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 d7f8effa2..555b3d82e 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h | |||
| @@ -30,16 +30,20 @@ namespace Service::android { | |||
| 30 | enum class PixelFormat : u32; | 30 | enum class PixelFormat : u32; |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | namespace Settings { | ||
| 34 | enum class AntiAliasing : u32; | ||
| 35 | enum class ScalingFilter : u32; | ||
| 36 | } // namespace Settings | ||
| 37 | |||
| 33 | namespace Vulkan { | 38 | namespace Vulkan { |
| 34 | 39 | ||
| 40 | class AntiAliasPass; | ||
| 35 | class Device; | 41 | class Device; |
| 36 | class FSR; | 42 | class FSR; |
| 37 | class FXAA; | ||
| 38 | class RasterizerVulkan; | 43 | class RasterizerVulkan; |
| 39 | class Scheduler; | 44 | class Scheduler; |
| 40 | class SMAA; | ||
| 41 | class Swapchain; | ||
| 42 | class PresentManager; | 45 | class PresentManager; |
| 46 | class WindowAdaptPass; | ||
| 43 | 47 | ||
| 44 | struct Frame; | 48 | struct Frame; |
| 45 | 49 | ||
| @@ -54,103 +58,66 @@ struct FramebufferTextureInfo { | |||
| 54 | 58 | ||
| 55 | class BlitScreen { | 59 | class BlitScreen { |
| 56 | public: | 60 | public: |
| 57 | explicit BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory, | 61 | explicit BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory, const Device& device, |
| 58 | Core::Frontend::EmuWindow& render_window, const Device& device, | 62 | MemoryAllocator& memory_allocator, PresentManager& present_manager, |
| 59 | MemoryAllocator& memory_manager, Swapchain& swapchain, | 63 | Scheduler& scheduler); |
| 60 | PresentManager& present_manager, Scheduler& scheduler); | ||
| 61 | ~BlitScreen(); | 64 | ~BlitScreen(); |
| 62 | 65 | ||
| 63 | void Recreate(); | 66 | void DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame, |
| 64 | 67 | const Tegra::FramebufferConfig& framebuffer, | |
| 65 | void Draw(RasterizerVulkan& rasterizer, const Tegra::FramebufferConfig& framebuffer, | 68 | const Layout::FramebufferLayout& layout, size_t swapchain_images, |
| 66 | const VkFramebuffer& host_framebuffer, const Layout::FramebufferLayout layout, | 69 | VkFormat current_swapchain_view_format); |
| 67 | VkExtent2D render_area); | ||
| 68 | |||
| 69 | void DrawToSwapchain(RasterizerVulkan& rasterizer, Frame* frame, | ||
| 70 | const Tegra::FramebufferConfig& framebuffer); | ||
| 71 | |||
| 72 | [[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, | ||
| 73 | VkExtent2D extent); | ||
| 74 | 70 | ||
| 75 | [[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, | 71 | [[nodiscard]] vk::Framebuffer CreateFramebuffer(const Layout::FramebufferLayout& layout, |
| 76 | VkExtent2D extent, vk::RenderPass& rd); | 72 | const VkImageView& image_view, |
| 73 | VkFormat current_view_format); | ||
| 77 | 74 | ||
| 78 | private: | 75 | private: |
| 79 | struct BufferData; | 76 | void WaitIdle(); |
| 77 | void SetWindowAdaptPass(const Layout::FramebufferLayout& layout); | ||
| 78 | void SetAntiAliasPass(); | ||
| 80 | 79 | ||
| 81 | void CreateStaticResources(); | 80 | void Draw(RasterizerVulkan& rasterizer, const Tegra::FramebufferConfig& framebuffer, |
| 82 | void CreateShaders(); | 81 | const Layout::FramebufferLayout& layout, Frame* dst); |
| 83 | void CreateDescriptorPool(); | ||
| 84 | void CreateRenderPass(); | ||
| 85 | vk::RenderPass CreateRenderPassImpl(VkFormat format); | ||
| 86 | void CreateDescriptorSetLayout(); | ||
| 87 | void CreateDescriptorSets(); | ||
| 88 | void CreatePipelineLayout(); | ||
| 89 | void CreateGraphicsPipeline(); | ||
| 90 | void CreateSampler(); | ||
| 91 | 82 | ||
| 92 | void CreateDynamicResources(); | 83 | vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent, |
| 84 | VkRenderPass render_pass); | ||
| 93 | 85 | ||
| 94 | void RefreshResources(const Tegra::FramebufferConfig& framebuffer); | 86 | void RefreshResources(const Tegra::FramebufferConfig& framebuffer); |
| 95 | void ReleaseRawImages(); | 87 | void ReleaseRawImages(); |
| 96 | void CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer); | 88 | void CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer); |
| 97 | void CreateRawImages(const Tegra::FramebufferConfig& framebuffer); | 89 | void CreateRawImages(const Tegra::FramebufferConfig& framebuffer); |
| 98 | 90 | ||
| 99 | void UpdateDescriptorSet(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, u32 texture_width, | ||
| 103 | u32 texture_height) const; | ||
| 104 | |||
| 105 | void CreateSMAA(VkExtent2D smaa_size); | ||
| 106 | void CreateFSR(); | ||
| 107 | |||
| 108 | u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const; | 91 | u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const; |
| 109 | u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer) const; | 92 | u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer) const; |
| 110 | 93 | ||
| 111 | Tegra::MaxwellDeviceMemoryManager& device_memory; | 94 | Tegra::MaxwellDeviceMemoryManager& device_memory; |
| 112 | Core::Frontend::EmuWindow& render_window; | ||
| 113 | const Device& device; | 95 | const Device& device; |
| 114 | MemoryAllocator& memory_allocator; | 96 | MemoryAllocator& memory_allocator; |
| 115 | Swapchain& swapchain; | ||
| 116 | PresentManager& present_manager; | 97 | PresentManager& present_manager; |
| 117 | Scheduler& scheduler; | 98 | Scheduler& scheduler; |
| 118 | std::size_t image_count; | 99 | std::size_t image_count; |
| 119 | std::size_t image_index{}; | 100 | std::size_t image_index{}; |
| 120 | 101 | ||
| 121 | vk::ShaderModule vertex_shader; | ||
| 122 | vk::ShaderModule bilinear_fragment_shader; | ||
| 123 | vk::ShaderModule bicubic_fragment_shader; | ||
| 124 | vk::ShaderModule gaussian_fragment_shader; | ||
| 125 | vk::ShaderModule scaleforce_fragment_shader; | ||
| 126 | vk::DescriptorPool descriptor_pool; | ||
| 127 | vk::DescriptorSetLayout descriptor_set_layout; | ||
| 128 | vk::PipelineLayout pipeline_layout; | ||
| 129 | vk::Pipeline bilinear_pipeline; | ||
| 130 | vk::Pipeline bicubic_pipeline; | ||
| 131 | vk::Pipeline gaussian_pipeline; | ||
| 132 | vk::Pipeline scaleforce_pipeline; | ||
| 133 | vk::RenderPass renderpass; | ||
| 134 | vk::DescriptorSets descriptor_sets; | ||
| 135 | vk::Sampler nn_sampler; | ||
| 136 | vk::Sampler sampler; | ||
| 137 | |||
| 138 | vk::Buffer buffer; | 102 | vk::Buffer buffer; |
| 139 | 103 | ||
| 140 | std::vector<u64> resource_ticks; | 104 | std::vector<u64> resource_ticks; |
| 141 | 105 | ||
| 142 | std::vector<vk::Image> raw_images; | 106 | std::vector<vk::Image> raw_images; |
| 143 | std::vector<vk::ImageView> raw_image_views; | 107 | std::vector<vk::ImageView> raw_image_views; |
| 144 | |||
| 145 | u32 raw_width = 0; | 108 | u32 raw_width = 0; |
| 146 | u32 raw_height = 0; | 109 | u32 raw_height = 0; |
| 110 | |||
| 147 | Service::android::PixelFormat pixel_format{}; | 111 | Service::android::PixelFormat pixel_format{}; |
| 148 | VkFormat framebuffer_view_format; | 112 | VkFormat framebuffer_view_format; |
| 149 | VkFormat swapchain_view_format; | 113 | VkFormat swapchain_view_format; |
| 150 | 114 | ||
| 115 | Settings::AntiAliasing anti_aliasing{}; | ||
| 116 | Settings::ScalingFilter scaling_filter{}; | ||
| 117 | |||
| 151 | std::unique_ptr<FSR> fsr; | 118 | std::unique_ptr<FSR> fsr; |
| 152 | std::unique_ptr<SMAA> smaa; | 119 | std::unique_ptr<AntiAliasPass> anti_alias; |
| 153 | std::unique_ptr<FXAA> fxaa; | 120 | std::unique_ptr<WindowAdaptPass> window_adapt; |
| 154 | }; | 121 | }; |
| 155 | 122 | ||
| 156 | } // namespace Vulkan | 123 | } // namespace Vulkan |