diff options
Diffstat (limited to 'src')
22 files changed, 662 insertions, 952 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index c6b0d628d..7526de699 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -174,6 +174,9 @@ add_library(video_core STATIC | |||
| 174 | renderer_vulkan/present/fsr.h | 174 | renderer_vulkan/present/fsr.h |
| 175 | renderer_vulkan/present/fxaa.cpp | 175 | renderer_vulkan/present/fxaa.cpp |
| 176 | renderer_vulkan/present/fxaa.h | 176 | renderer_vulkan/present/fxaa.h |
| 177 | renderer_vulkan/present/layer.cpp | ||
| 178 | renderer_vulkan/present/layer.h | ||
| 179 | renderer_vulkan/present/present_push_constants.h | ||
| 177 | renderer_vulkan/present/smaa.cpp | 180 | renderer_vulkan/present/smaa.cpp |
| 178 | renderer_vulkan/present/smaa.h | 181 | renderer_vulkan/present/smaa.h |
| 179 | renderer_vulkan/present/util.cpp | 182 | renderer_vulkan/present/util.cpp |
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h index 1a43e24b6..99341e431 100644 --- a/src/video_core/engines/maxwell_dma.h +++ b/src/video_core/engines/maxwell_dma.h | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | 9 | ||
| 10 | #include "common/bit_field.h" | 10 | #include "common/bit_field.h" |
| 11 | #include "common/common_funcs.h" | ||
| 11 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 12 | #include "common/scratch_buffer.h" | 13 | #include "common/scratch_buffer.h" |
| 13 | #include "video_core/engines/engine_interface.h" | 14 | #include "video_core/engines/engine_interface.h" |
diff --git a/src/video_core/host_shaders/opengl_present_scaleforce.frag b/src/video_core/host_shaders/opengl_present_scaleforce.frag index a780373e3..1598575a1 100644 --- a/src/video_core/host_shaders/opengl_present_scaleforce.frag +++ b/src/video_core/host_shaders/opengl_present_scaleforce.frag | |||
| @@ -26,21 +26,11 @@ | |||
| 26 | 26 | ||
| 27 | #endif | 27 | #endif |
| 28 | 28 | ||
| 29 | #ifdef VULKAN | ||
| 30 | |||
| 31 | #define BINDING_COLOR_TEXTURE 1 | ||
| 32 | |||
| 33 | #else // ^^^ Vulkan ^^^ // vvv OpenGL vvv | ||
| 34 | |||
| 35 | #define BINDING_COLOR_TEXTURE 0 | ||
| 36 | |||
| 37 | #endif | ||
| 38 | |||
| 39 | layout (location = 0) in vec2 tex_coord; | 29 | layout (location = 0) in vec2 tex_coord; |
| 40 | 30 | ||
| 41 | layout (location = 0) out vec4 frag_color; | 31 | layout (location = 0) out vec4 frag_color; |
| 42 | 32 | ||
| 43 | layout (binding = BINDING_COLOR_TEXTURE) uniform sampler2D input_texture; | 33 | layout (binding = 0) uniform sampler2D input_texture; |
| 44 | 34 | ||
| 45 | const bool ignore_alpha = true; | 35 | const bool ignore_alpha = true; |
| 46 | 36 | ||
diff --git a/src/video_core/host_shaders/present_bicubic.frag b/src/video_core/host_shaders/present_bicubic.frag index c57dd2851..c814629cf 100644 --- a/src/video_core/host_shaders/present_bicubic.frag +++ b/src/video_core/host_shaders/present_bicubic.frag | |||
| @@ -3,22 +3,12 @@ | |||
| 3 | 3 | ||
| 4 | #version 460 core | 4 | #version 460 core |
| 5 | 5 | ||
| 6 | #ifdef VULKAN | ||
| 7 | |||
| 8 | #define BINDING_COLOR_TEXTURE 1 | ||
| 9 | |||
| 10 | #else // ^^^ Vulkan ^^^ // vvv OpenGL vvv | ||
| 11 | |||
| 12 | #define BINDING_COLOR_TEXTURE 0 | ||
| 13 | |||
| 14 | #endif | ||
| 15 | |||
| 16 | 6 | ||
| 17 | layout (location = 0) in vec2 frag_tex_coord; | 7 | layout (location = 0) in vec2 frag_tex_coord; |
| 18 | 8 | ||
| 19 | layout (location = 0) out vec4 color; | 9 | layout (location = 0) out vec4 color; |
| 20 | 10 | ||
| 21 | layout (binding = BINDING_COLOR_TEXTURE) uniform sampler2D color_texture; | 11 | layout (binding = 0) uniform sampler2D color_texture; |
| 22 | 12 | ||
| 23 | vec4 cubic(float v) { | 13 | vec4 cubic(float v) { |
| 24 | vec4 n = vec4(1.0, 2.0, 3.0, 4.0) - v; | 14 | vec4 n = vec4(1.0, 2.0, 3.0, 4.0) - v; |
diff --git a/src/video_core/host_shaders/present_gaussian.frag b/src/video_core/host_shaders/present_gaussian.frag index 5f54b71b6..ad9bb76a4 100644 --- a/src/video_core/host_shaders/present_gaussian.frag +++ b/src/video_core/host_shaders/present_gaussian.frag | |||
| @@ -7,21 +7,11 @@ | |||
| 7 | 7 | ||
| 8 | #version 460 core | 8 | #version 460 core |
| 9 | 9 | ||
| 10 | #ifdef VULKAN | ||
| 11 | |||
| 12 | #define BINDING_COLOR_TEXTURE 1 | ||
| 13 | |||
| 14 | #else // ^^^ Vulkan ^^^ // vvv OpenGL vvv | ||
| 15 | |||
| 16 | #define BINDING_COLOR_TEXTURE 0 | ||
| 17 | |||
| 18 | #endif | ||
| 19 | |||
| 20 | layout(location = 0) in vec2 frag_tex_coord; | 10 | layout(location = 0) in vec2 frag_tex_coord; |
| 21 | 11 | ||
| 22 | layout(location = 0) out vec4 color; | 12 | layout(location = 0) out vec4 color; |
| 23 | 13 | ||
| 24 | layout(binding = BINDING_COLOR_TEXTURE) uniform sampler2D color_texture; | 14 | layout(binding = 0) uniform sampler2D color_texture; |
| 25 | 15 | ||
| 26 | const float offset[3] = float[](0.0, 1.3846153846, 3.2307692308); | 16 | const float offset[3] = float[](0.0, 1.3846153846, 3.2307692308); |
| 27 | const float weight[3] = float[](0.2270270270, 0.3162162162, 0.0702702703); | 17 | const float weight[3] = float[](0.2270270270, 0.3162162162, 0.0702702703); |
diff --git a/src/video_core/host_shaders/vulkan_present.frag b/src/video_core/host_shaders/vulkan_present.frag index 97e098ced..adada9411 100644 --- a/src/video_core/host_shaders/vulkan_present.frag +++ b/src/video_core/host_shaders/vulkan_present.frag | |||
| @@ -7,7 +7,7 @@ layout (location = 0) in vec2 frag_tex_coord; | |||
| 7 | 7 | ||
| 8 | layout (location = 0) out vec4 color; | 8 | layout (location = 0) out vec4 color; |
| 9 | 9 | ||
| 10 | layout (binding = 1) uniform sampler2D color_texture; | 10 | layout (binding = 0) uniform sampler2D color_texture; |
| 11 | 11 | ||
| 12 | void main() { | 12 | void main() { |
| 13 | color = texture(color_texture, frag_tex_coord); | 13 | color = texture(color_texture, frag_tex_coord); |
diff --git a/src/video_core/host_shaders/vulkan_present.vert b/src/video_core/host_shaders/vulkan_present.vert index 89dc80468..249c9675a 100644 --- a/src/video_core/host_shaders/vulkan_present.vert +++ b/src/video_core/host_shaders/vulkan_present.vert | |||
| @@ -3,16 +3,37 @@ | |||
| 3 | 3 | ||
| 4 | #version 460 core | 4 | #version 460 core |
| 5 | 5 | ||
| 6 | layout (location = 0) in vec2 vert_position; | ||
| 7 | layout (location = 1) in vec2 vert_tex_coord; | ||
| 8 | |||
| 9 | layout (location = 0) out vec2 frag_tex_coord; | 6 | layout (location = 0) out vec2 frag_tex_coord; |
| 10 | 7 | ||
| 11 | layout (set = 0, binding = 0) uniform MatrixBlock { | 8 | struct ScreenRectVertex { |
| 9 | vec2 position; | ||
| 10 | vec2 tex_coord; | ||
| 11 | }; | ||
| 12 | |||
| 13 | layout (push_constant) uniform PushConstants { | ||
| 12 | mat4 modelview_matrix; | 14 | mat4 modelview_matrix; |
| 15 | ScreenRectVertex vertices[4]; | ||
| 13 | }; | 16 | }; |
| 14 | 17 | ||
| 18 | // Vulkan spec 15.8.1: | ||
| 19 | // Any member of a push constant block that is declared as an | ||
| 20 | // array must only be accessed with dynamically uniform indices. | ||
| 21 | ScreenRectVertex GetVertex(int index) { | ||
| 22 | switch (index) { | ||
| 23 | case 0: | ||
| 24 | default: | ||
| 25 | return vertices[0]; | ||
| 26 | case 1: | ||
| 27 | return vertices[1]; | ||
| 28 | case 2: | ||
| 29 | return vertices[2]; | ||
| 30 | case 3: | ||
| 31 | return vertices[3]; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 15 | void main() { | 35 | void main() { |
| 16 | gl_Position = modelview_matrix * vec4(vert_position, 0.0, 1.0); | 36 | ScreenRectVertex vertex = GetVertex(gl_VertexIndex); |
| 17 | frag_tex_coord = vert_tex_coord; | 37 | gl_Position = modelview_matrix * vec4(vertex.position, 0.0, 1.0); |
| 38 | frag_tex_coord = vertex.tex_coord; | ||
| 18 | } | 39 | } |
diff --git a/src/video_core/host_shaders/vulkan_present_scaleforce_fp16.frag b/src/video_core/host_shaders/vulkan_present_scaleforce_fp16.frag index 3dc9c0df5..79ea817c2 100644 --- a/src/video_core/host_shaders/vulkan_present_scaleforce_fp16.frag +++ b/src/video_core/host_shaders/vulkan_present_scaleforce_fp16.frag | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #extension GL_GOOGLE_include_directive : enable | 6 | #extension GL_GOOGLE_include_directive : enable |
| 7 | 7 | ||
| 8 | #define VERSION 1 | ||
| 8 | #define YUZU_USE_FP16 | 9 | #define YUZU_USE_FP16 |
| 9 | 10 | ||
| 10 | #include "opengl_present_scaleforce.frag" | 11 | #include "opengl_present_scaleforce.frag" |
diff --git a/src/video_core/host_shaders/vulkan_present_scaleforce_fp32.frag b/src/video_core/host_shaders/vulkan_present_scaleforce_fp32.frag index 77ed07552..9605bb58b 100644 --- a/src/video_core/host_shaders/vulkan_present_scaleforce_fp32.frag +++ b/src/video_core/host_shaders/vulkan_present_scaleforce_fp32.frag | |||
| @@ -5,4 +5,6 @@ | |||
| 5 | 5 | ||
| 6 | #extension GL_GOOGLE_include_directive : enable | 6 | #extension GL_GOOGLE_include_directive : enable |
| 7 | 7 | ||
| 8 | #define VERSION 1 | ||
| 9 | |||
| 8 | #include "opengl_present_scaleforce.frag" | 10 | #include "opengl_present_scaleforce.frag" |
diff --git a/src/video_core/renderer_vulkan/present/filters.cpp b/src/video_core/renderer_vulkan/present/filters.cpp index ee6239cc4..b5e08938e 100644 --- a/src/video_core/renderer_vulkan/present/filters.cpp +++ b/src/video_core/renderer_vulkan/present/filters.cpp | |||
| @@ -27,43 +27,29 @@ vk::ShaderModule SelectScaleForceShader(const Device& device) { | |||
| 27 | 27 | ||
| 28 | } // Anonymous namespace | 28 | } // Anonymous namespace |
| 29 | 29 | ||
| 30 | std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device, | 30 | std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device, VkFormat frame_format) { |
| 31 | const MemoryAllocator& memory_allocator, | 31 | return std::make_unique<WindowAdaptPass>(device, frame_format, |
| 32 | size_t image_count, VkFormat frame_format) { | ||
| 33 | return std::make_unique<WindowAdaptPass>(device, memory_allocator, image_count, frame_format, | ||
| 34 | CreateNearestNeighborSampler(device), | 32 | CreateNearestNeighborSampler(device), |
| 35 | BuildShader(device, VULKAN_PRESENT_FRAG_SPV)); | 33 | BuildShader(device, VULKAN_PRESENT_FRAG_SPV)); |
| 36 | } | 34 | } |
| 37 | 35 | ||
| 38 | std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device, | 36 | std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device, VkFormat frame_format) { |
| 39 | const MemoryAllocator& memory_allocator, | 37 | return std::make_unique<WindowAdaptPass>(device, frame_format, CreateBilinearSampler(device), |
| 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)); | 38 | BuildShader(device, VULKAN_PRESENT_FRAG_SPV)); |
| 44 | } | 39 | } |
| 45 | 40 | ||
| 46 | std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device, | 41 | std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device, VkFormat frame_format) { |
| 47 | const MemoryAllocator& memory_allocator, | 42 | return std::make_unique<WindowAdaptPass>(device, frame_format, CreateBilinearSampler(device), |
| 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)); | 43 | BuildShader(device, PRESENT_BICUBIC_FRAG_SPV)); |
| 52 | } | 44 | } |
| 53 | 45 | ||
| 54 | std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device, | 46 | std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device, VkFormat frame_format) { |
| 55 | const MemoryAllocator& memory_allocator, | 47 | return std::make_unique<WindowAdaptPass>(device, frame_format, CreateBilinearSampler(device), |
| 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)); | 48 | BuildShader(device, PRESENT_GAUSSIAN_FRAG_SPV)); |
| 60 | } | 49 | } |
| 61 | 50 | ||
| 62 | std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device, | 51 | std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device, VkFormat frame_format) { |
| 63 | const MemoryAllocator& memory_allocator, | 52 | return std::make_unique<WindowAdaptPass>(device, frame_format, CreateBilinearSampler(device), |
| 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)); | 53 | SelectScaleForceShader(device)); |
| 68 | } | 54 | } |
| 69 | 55 | ||
diff --git a/src/video_core/renderer_vulkan/present/filters.h b/src/video_core/renderer_vulkan/present/filters.h index 42d7052da..6c83726dd 100644 --- a/src/video_core/renderer_vulkan/present/filters.h +++ b/src/video_core/renderer_vulkan/present/filters.h | |||
| @@ -7,24 +7,12 @@ | |||
| 7 | 7 | ||
| 8 | namespace Vulkan { | 8 | namespace Vulkan { |
| 9 | 9 | ||
| 10 | std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device, | 10 | class MemoryAllocator; |
| 11 | const MemoryAllocator& memory_allocator, | ||
| 12 | size_t image_count, VkFormat frame_format); | ||
| 13 | 11 | ||
| 14 | std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device, | 12 | std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device, VkFormat frame_format); |
| 15 | const MemoryAllocator& memory_allocator, | 13 | std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device, VkFormat frame_format); |
| 16 | size_t image_count, VkFormat frame_format); | 14 | std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device, VkFormat frame_format); |
| 17 | 15 | std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device, VkFormat frame_format); | |
| 18 | std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device, | 16 | std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device, VkFormat frame_format); |
| 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 | 17 | ||
| 30 | } // namespace Vulkan | 18 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/present/layer.cpp b/src/video_core/renderer_vulkan/present/layer.cpp new file mode 100644 index 000000000..cfc04be44 --- /dev/null +++ b/src/video_core/renderer_vulkan/present/layer.cpp | |||
| @@ -0,0 +1,336 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | ||
| 5 | |||
| 6 | #include "common/settings.h" | ||
| 7 | #include "video_core/framebuffer_config.h" | ||
| 8 | #include "video_core/renderer_vulkan/present/fsr.h" | ||
| 9 | #include "video_core/renderer_vulkan/present/fxaa.h" | ||
| 10 | #include "video_core/renderer_vulkan/present/layer.h" | ||
| 11 | #include "video_core/renderer_vulkan/present/present_push_constants.h" | ||
| 12 | #include "video_core/renderer_vulkan/present/smaa.h" | ||
| 13 | #include "video_core/renderer_vulkan/present/util.h" | ||
| 14 | #include "video_core/renderer_vulkan/vk_blit_screen.h" | ||
| 15 | #include "video_core/textures/decoders.h" | ||
| 16 | |||
| 17 | namespace Vulkan { | ||
| 18 | |||
| 19 | namespace { | ||
| 20 | |||
| 21 | u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) { | ||
| 22 | using namespace VideoCore::Surface; | ||
| 23 | return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)); | ||
| 24 | } | ||
| 25 | |||
| 26 | std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) { | ||
| 27 | return static_cast<std::size_t>(framebuffer.stride) * | ||
| 28 | static_cast<std::size_t>(framebuffer.height) * GetBytesPerPixel(framebuffer); | ||
| 29 | } | ||
| 30 | |||
| 31 | VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) { | ||
| 32 | switch (framebuffer.pixel_format) { | ||
| 33 | case Service::android::PixelFormat::Rgba8888: | ||
| 34 | case Service::android::PixelFormat::Rgbx8888: | ||
| 35 | return VK_FORMAT_A8B8G8R8_UNORM_PACK32; | ||
| 36 | case Service::android::PixelFormat::Rgb565: | ||
| 37 | return VK_FORMAT_R5G6B5_UNORM_PACK16; | ||
| 38 | case Service::android::PixelFormat::Bgra8888: | ||
| 39 | return VK_FORMAT_B8G8R8A8_UNORM; | ||
| 40 | default: | ||
| 41 | UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", | ||
| 42 | static_cast<u32>(framebuffer.pixel_format)); | ||
| 43 | return VK_FORMAT_A8B8G8R8_UNORM_PACK32; | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | } // Anonymous namespace | ||
| 48 | |||
| 49 | Layer::Layer(const Device& device_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_, | ||
| 50 | Tegra::MaxwellDeviceMemoryManager& device_memory_, size_t image_count_, | ||
| 51 | VkExtent2D output_size, VkDescriptorSetLayout layout) | ||
| 52 | : device(device_), memory_allocator(memory_allocator_), scheduler(scheduler_), | ||
| 53 | device_memory(device_memory_), image_count(image_count_) { | ||
| 54 | CreateDescriptorPool(); | ||
| 55 | CreateDescriptorSets(layout); | ||
| 56 | if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { | ||
| 57 | CreateFSR(output_size); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | Layer::~Layer() { | ||
| 62 | ReleaseRawImages(); | ||
| 63 | } | ||
| 64 | |||
| 65 | void Layer::ConfigureDraw(PresentPushConstants* out_push_constants, | ||
| 66 | VkDescriptorSet* out_descriptor_set, RasterizerVulkan& rasterizer, | ||
| 67 | VkSampler sampler, size_t image_index, | ||
| 68 | const Tegra::FramebufferConfig& framebuffer, | ||
| 69 | const Layout::FramebufferLayout& layout) { | ||
| 70 | const auto texture_info = rasterizer.AccelerateDisplay( | ||
| 71 | framebuffer, framebuffer.address + framebuffer.offset, framebuffer.stride); | ||
| 72 | const u32 texture_width = texture_info ? texture_info->width : framebuffer.width; | ||
| 73 | const u32 texture_height = texture_info ? texture_info->height : framebuffer.height; | ||
| 74 | const u32 scaled_width = texture_info ? texture_info->scaled_width : texture_width; | ||
| 75 | const u32 scaled_height = texture_info ? texture_info->scaled_height : texture_height; | ||
| 76 | const bool use_accelerated = texture_info.has_value(); | ||
| 77 | |||
| 78 | RefreshResources(framebuffer); | ||
| 79 | SetAntiAliasPass(); | ||
| 80 | |||
| 81 | // Finish any pending renderpass | ||
| 82 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 83 | scheduler.Wait(resource_ticks[image_index]); | ||
| 84 | SCOPE_EXIT({ resource_ticks[image_index] = scheduler.CurrentTick(); }); | ||
| 85 | |||
| 86 | if (!use_accelerated) { | ||
| 87 | UpdateRawImage(framebuffer, image_index); | ||
| 88 | } | ||
| 89 | |||
| 90 | VkImage source_image = texture_info ? texture_info->image : *raw_images[image_index]; | ||
| 91 | VkImageView source_image_view = | ||
| 92 | texture_info ? texture_info->image_view : *raw_image_views[image_index]; | ||
| 93 | |||
| 94 | anti_alias->Draw(scheduler, image_index, &source_image, &source_image_view); | ||
| 95 | |||
| 96 | auto crop_rect = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height); | ||
| 97 | const VkExtent2D render_extent{ | ||
| 98 | .width = scaled_width, | ||
| 99 | .height = scaled_height, | ||
| 100 | }; | ||
| 101 | |||
| 102 | if (fsr) { | ||
| 103 | source_image_view = fsr->Draw(scheduler, image_index, source_image, source_image_view, | ||
| 104 | render_extent, crop_rect); | ||
| 105 | crop_rect = {0, 0, 1, 1}; | ||
| 106 | } | ||
| 107 | |||
| 108 | SetMatrixData(*out_push_constants, layout); | ||
| 109 | SetVertexData(*out_push_constants, layout, crop_rect); | ||
| 110 | |||
| 111 | UpdateDescriptorSet(source_image_view, sampler, image_index); | ||
| 112 | *out_descriptor_set = descriptor_sets[image_index]; | ||
| 113 | } | ||
| 114 | |||
| 115 | void Layer::CreateDescriptorPool() { | ||
| 116 | descriptor_pool = CreateWrappedDescriptorPool(device, image_count, image_count); | ||
| 117 | } | ||
| 118 | |||
| 119 | void Layer::CreateDescriptorSets(VkDescriptorSetLayout layout) { | ||
| 120 | const std::vector layouts(image_count, layout); | ||
| 121 | descriptor_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts); | ||
| 122 | } | ||
| 123 | |||
| 124 | void Layer::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { | ||
| 125 | const VkBufferCreateInfo ci{ | ||
| 126 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | ||
| 127 | .pNext = nullptr, | ||
| 128 | .flags = 0, | ||
| 129 | .size = CalculateBufferSize(framebuffer), | ||
| 130 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | | ||
| 131 | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, | ||
| 132 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 133 | .queueFamilyIndexCount = 0, | ||
| 134 | .pQueueFamilyIndices = nullptr, | ||
| 135 | }; | ||
| 136 | |||
| 137 | buffer = memory_allocator.CreateBuffer(ci, MemoryUsage::Upload); | ||
| 138 | } | ||
| 139 | |||
| 140 | void Layer::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | ||
| 141 | const auto format = GetFormat(framebuffer); | ||
| 142 | resource_ticks.resize(image_count); | ||
| 143 | raw_images.resize(image_count); | ||
| 144 | raw_image_views.resize(image_count); | ||
| 145 | |||
| 146 | for (size_t i = 0; i < image_count; ++i) { | ||
| 147 | raw_images[i] = | ||
| 148 | CreateWrappedImage(memory_allocator, {framebuffer.width, framebuffer.height}, format); | ||
| 149 | raw_image_views[i] = CreateWrappedImageView(device, raw_images[i], format); | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | void Layer::CreateFSR(VkExtent2D output_size) { | ||
| 154 | fsr = std::make_unique<FSR>(device, memory_allocator, image_count, output_size); | ||
| 155 | } | ||
| 156 | |||
| 157 | void Layer::RefreshResources(const Tegra::FramebufferConfig& framebuffer) { | ||
| 158 | if (framebuffer.width == raw_width && framebuffer.height == raw_height && | ||
| 159 | framebuffer.pixel_format == pixel_format && !raw_images.empty()) { | ||
| 160 | return; | ||
| 161 | } | ||
| 162 | |||
| 163 | raw_width = framebuffer.width; | ||
| 164 | raw_height = framebuffer.height; | ||
| 165 | pixel_format = framebuffer.pixel_format; | ||
| 166 | anti_alias.reset(); | ||
| 167 | |||
| 168 | ReleaseRawImages(); | ||
| 169 | CreateStagingBuffer(framebuffer); | ||
| 170 | CreateRawImages(framebuffer); | ||
| 171 | } | ||
| 172 | |||
| 173 | void Layer::SetAntiAliasPass() { | ||
| 174 | if (anti_alias && anti_alias_setting == Settings::values.anti_aliasing.GetValue()) { | ||
| 175 | return; | ||
| 176 | } | ||
| 177 | |||
| 178 | anti_alias_setting = Settings::values.anti_aliasing.GetValue(); | ||
| 179 | |||
| 180 | const VkExtent2D render_area{ | ||
| 181 | .width = Settings::values.resolution_info.ScaleUp(raw_width), | ||
| 182 | .height = Settings::values.resolution_info.ScaleUp(raw_height), | ||
| 183 | }; | ||
| 184 | |||
| 185 | switch (anti_alias_setting) { | ||
| 186 | case Settings::AntiAliasing::Fxaa: | ||
| 187 | anti_alias = std::make_unique<FXAA>(device, memory_allocator, image_count, render_area); | ||
| 188 | break; | ||
| 189 | case Settings::AntiAliasing::Smaa: | ||
| 190 | anti_alias = std::make_unique<SMAA>(device, memory_allocator, image_count, render_area); | ||
| 191 | break; | ||
| 192 | default: | ||
| 193 | anti_alias = std::make_unique<NoAA>(); | ||
| 194 | break; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | void Layer::ReleaseRawImages() { | ||
| 199 | for (const u64 tick : resource_ticks) { | ||
| 200 | scheduler.Wait(tick); | ||
| 201 | } | ||
| 202 | raw_images.clear(); | ||
| 203 | buffer.reset(); | ||
| 204 | } | ||
| 205 | |||
| 206 | u64 Layer::CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const { | ||
| 207 | return GetSizeInBytes(framebuffer) * image_count; | ||
| 208 | } | ||
| 209 | |||
| 210 | u64 Layer::GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer, | ||
| 211 | size_t image_index) const { | ||
| 212 | return GetSizeInBytes(framebuffer) * image_index; | ||
| 213 | } | ||
| 214 | |||
| 215 | void Layer::SetMatrixData(PresentPushConstants& data, | ||
| 216 | const Layout::FramebufferLayout& layout) const { | ||
| 217 | data.modelview_matrix = | ||
| 218 | MakeOrthographicMatrix(static_cast<f32>(layout.width), static_cast<f32>(layout.height)); | ||
| 219 | } | ||
| 220 | |||
| 221 | void Layer::SetVertexData(PresentPushConstants& data, const Layout::FramebufferLayout& layout, | ||
| 222 | const Common::Rectangle<f32>& crop) const { | ||
| 223 | // Map the coordinates to the screen. | ||
| 224 | const auto& screen = layout.screen; | ||
| 225 | const auto x = static_cast<f32>(screen.left); | ||
| 226 | const auto y = static_cast<f32>(screen.top); | ||
| 227 | const auto w = static_cast<f32>(screen.GetWidth()); | ||
| 228 | const auto h = static_cast<f32>(screen.GetHeight()); | ||
| 229 | |||
| 230 | data.vertices[0] = ScreenRectVertex(x, y, crop.left, crop.top); | ||
| 231 | data.vertices[1] = ScreenRectVertex(x + w, y, crop.right, crop.top); | ||
| 232 | data.vertices[2] = ScreenRectVertex(x, y + h, crop.left, crop.bottom); | ||
| 233 | data.vertices[3] = ScreenRectVertex(x + w, y + h, crop.right, crop.bottom); | ||
| 234 | } | ||
| 235 | |||
| 236 | void Layer::UpdateDescriptorSet(VkImageView image_view, VkSampler sampler, size_t image_index) { | ||
| 237 | const VkDescriptorImageInfo image_info{ | ||
| 238 | .sampler = sampler, | ||
| 239 | .imageView = image_view, | ||
| 240 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 241 | }; | ||
| 242 | |||
| 243 | const VkWriteDescriptorSet sampler_write{ | ||
| 244 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 245 | .pNext = nullptr, | ||
| 246 | .dstSet = descriptor_sets[image_index], | ||
| 247 | .dstBinding = 0, | ||
| 248 | .dstArrayElement = 0, | ||
| 249 | .descriptorCount = 1, | ||
| 250 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 251 | .pImageInfo = &image_info, | ||
| 252 | .pBufferInfo = nullptr, | ||
| 253 | .pTexelBufferView = nullptr, | ||
| 254 | }; | ||
| 255 | |||
| 256 | device.GetLogical().UpdateDescriptorSets(std::array{sampler_write}, {}); | ||
| 257 | } | ||
| 258 | |||
| 259 | void Layer::UpdateRawImage(const Tegra::FramebufferConfig& framebuffer, size_t image_index) { | ||
| 260 | const std::span<u8> mapped_span = buffer.Mapped(); | ||
| 261 | |||
| 262 | const u64 image_offset = GetRawImageOffset(framebuffer, image_index); | ||
| 263 | |||
| 264 | const DAddr framebuffer_addr = framebuffer.address + framebuffer.offset; | ||
| 265 | const u8* const host_ptr = device_memory.GetPointer<u8>(framebuffer_addr); | ||
| 266 | |||
| 267 | // TODO(Rodrigo): Read this from HLE | ||
| 268 | constexpr u32 block_height_log2 = 4; | ||
| 269 | const u32 bytes_per_pixel = GetBytesPerPixel(framebuffer); | ||
| 270 | const u64 linear_size{GetSizeInBytes(framebuffer)}; | ||
| 271 | const u64 tiled_size{Tegra::Texture::CalculateSize( | ||
| 272 | true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; | ||
| 273 | Tegra::Texture::UnswizzleTexture( | ||
| 274 | mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size), | ||
| 275 | bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); | ||
| 276 | |||
| 277 | const VkBufferImageCopy copy{ | ||
| 278 | .bufferOffset = image_offset, | ||
| 279 | .bufferRowLength = 0, | ||
| 280 | .bufferImageHeight = 0, | ||
| 281 | .imageSubresource = | ||
| 282 | { | ||
| 283 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 284 | .mipLevel = 0, | ||
| 285 | .baseArrayLayer = 0, | ||
| 286 | .layerCount = 1, | ||
| 287 | }, | ||
| 288 | .imageOffset = {.x = 0, .y = 0, .z = 0}, | ||
| 289 | .imageExtent = | ||
| 290 | { | ||
| 291 | .width = framebuffer.width, | ||
| 292 | .height = framebuffer.height, | ||
| 293 | .depth = 1, | ||
| 294 | }, | ||
| 295 | }; | ||
| 296 | scheduler.Record([this, copy, index = image_index](vk::CommandBuffer cmdbuf) { | ||
| 297 | const VkImage image = *raw_images[index]; | ||
| 298 | const VkImageMemoryBarrier base_barrier{ | ||
| 299 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 300 | .pNext = nullptr, | ||
| 301 | .srcAccessMask = 0, | ||
| 302 | .dstAccessMask = 0, | ||
| 303 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 304 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 305 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 306 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 307 | .image = image, | ||
| 308 | .subresourceRange{ | ||
| 309 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 310 | .baseMipLevel = 0, | ||
| 311 | .levelCount = 1, | ||
| 312 | .baseArrayLayer = 0, | ||
| 313 | .layerCount = 1, | ||
| 314 | }, | ||
| 315 | }; | ||
| 316 | VkImageMemoryBarrier read_barrier = base_barrier; | ||
| 317 | read_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | ||
| 318 | read_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||
| 319 | read_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; | ||
| 320 | |||
| 321 | VkImageMemoryBarrier write_barrier = base_barrier; | ||
| 322 | write_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | ||
| 323 | write_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; | ||
| 324 | write_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; | ||
| 325 | |||
| 326 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, | ||
| 327 | read_barrier); | ||
| 328 | cmdbuf.CopyBufferToImage(*buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); | ||
| 329 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 330 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | | ||
| 331 | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | ||
| 332 | 0, write_barrier); | ||
| 333 | }); | ||
| 334 | } | ||
| 335 | |||
| 336 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/present/layer.h b/src/video_core/renderer_vulkan/present/layer.h new file mode 100644 index 000000000..88d43fc5f --- /dev/null +++ b/src/video_core/renderer_vulkan/present/layer.h | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/math_util.h" | ||
| 7 | #include "video_core/host1x/gpu_device_memory_manager.h" | ||
| 8 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 9 | |||
| 10 | namespace Layout { | ||
| 11 | struct FramebufferLayout; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace Tegra { | ||
| 15 | struct FramebufferConfig; | ||
| 16 | } | ||
| 17 | |||
| 18 | namespace Service::android { | ||
| 19 | enum class PixelFormat : u32; | ||
| 20 | } | ||
| 21 | |||
| 22 | namespace Settings { | ||
| 23 | enum class AntiAliasing : u32; | ||
| 24 | } | ||
| 25 | |||
| 26 | namespace Vulkan { | ||
| 27 | |||
| 28 | class AntiAliasPass; | ||
| 29 | class Device; | ||
| 30 | class FSR; | ||
| 31 | class MemoryAllocator; | ||
| 32 | struct PresentPushConstants; | ||
| 33 | class RasterizerVulkan; | ||
| 34 | class Scheduler; | ||
| 35 | |||
| 36 | class Layer final { | ||
| 37 | public: | ||
| 38 | explicit Layer(const Device& device, MemoryAllocator& memory_allocator, Scheduler& scheduler, | ||
| 39 | Tegra::MaxwellDeviceMemoryManager& device_memory, size_t image_count, | ||
| 40 | VkExtent2D output_size, VkDescriptorSetLayout layout); | ||
| 41 | ~Layer(); | ||
| 42 | |||
| 43 | void ConfigureDraw(PresentPushConstants* out_push_constants, | ||
| 44 | VkDescriptorSet* out_descriptor_set, RasterizerVulkan& rasterizer, | ||
| 45 | VkSampler sampler, size_t image_index, | ||
| 46 | const Tegra::FramebufferConfig& framebuffer, | ||
| 47 | const Layout::FramebufferLayout& layout); | ||
| 48 | |||
| 49 | private: | ||
| 50 | void CreateDescriptorPool(); | ||
| 51 | void CreateDescriptorSets(VkDescriptorSetLayout layout); | ||
| 52 | void CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer); | ||
| 53 | void CreateRawImages(const Tegra::FramebufferConfig& framebuffer); | ||
| 54 | void CreateFSR(VkExtent2D output_size); | ||
| 55 | |||
| 56 | void RefreshResources(const Tegra::FramebufferConfig& framebuffer); | ||
| 57 | void SetAntiAliasPass(); | ||
| 58 | void ReleaseRawImages(); | ||
| 59 | |||
| 60 | u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const; | ||
| 61 | u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer, size_t image_index) const; | ||
| 62 | |||
| 63 | void SetMatrixData(PresentPushConstants& data, const Layout::FramebufferLayout& layout) const; | ||
| 64 | void SetVertexData(PresentPushConstants& data, const Layout::FramebufferLayout& layout, | ||
| 65 | const Common::Rectangle<f32>& crop) const; | ||
| 66 | void UpdateDescriptorSet(VkImageView image_view, VkSampler sampler, size_t image_index); | ||
| 67 | void UpdateRawImage(const Tegra::FramebufferConfig& framebuffer, size_t image_index); | ||
| 68 | |||
| 69 | private: | ||
| 70 | const Device& device; | ||
| 71 | MemoryAllocator& memory_allocator; | ||
| 72 | Scheduler& scheduler; | ||
| 73 | Tegra::MaxwellDeviceMemoryManager& device_memory; | ||
| 74 | const size_t image_count{}; | ||
| 75 | vk::DescriptorPool descriptor_pool{}; | ||
| 76 | vk::DescriptorSets descriptor_sets{}; | ||
| 77 | |||
| 78 | vk::Buffer buffer{}; | ||
| 79 | std::vector<vk::Image> raw_images{}; | ||
| 80 | std::vector<vk::ImageView> raw_image_views{}; | ||
| 81 | u32 raw_width{}; | ||
| 82 | u32 raw_height{}; | ||
| 83 | Service::android::PixelFormat pixel_format{}; | ||
| 84 | |||
| 85 | Settings::AntiAliasing anti_alias_setting{}; | ||
| 86 | std::unique_ptr<AntiAliasPass> anti_alias{}; | ||
| 87 | |||
| 88 | std::unique_ptr<FSR> fsr{}; | ||
| 89 | std::vector<u64> resource_ticks{}; | ||
| 90 | }; | ||
| 91 | |||
| 92 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/present/present_push_constants.h b/src/video_core/renderer_vulkan/present/present_push_constants.h new file mode 100644 index 000000000..f1949e7aa --- /dev/null +++ b/src/video_core/renderer_vulkan/present/present_push_constants.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | |||
| 8 | namespace Vulkan { | ||
| 9 | |||
| 10 | struct ScreenRectVertex { | ||
| 11 | ScreenRectVertex() = default; | ||
| 12 | explicit ScreenRectVertex(f32 x, f32 y, f32 u, f32 v) : position{{x, y}}, tex_coord{{u, v}} {} | ||
| 13 | |||
| 14 | std::array<f32, 2> position; | ||
| 15 | std::array<f32, 2> tex_coord; | ||
| 16 | }; | ||
| 17 | |||
| 18 | static inline std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) { | ||
| 19 | // clang-format off | ||
| 20 | return { 2.f / width, 0.f, 0.f, 0.f, | ||
| 21 | 0.f, 2.f / height, 0.f, 0.f, | ||
| 22 | 0.f, 0.f, 1.f, 0.f, | ||
| 23 | -1.f, -1.f, 0.f, 1.f}; | ||
| 24 | // clang-format on | ||
| 25 | } | ||
| 26 | |||
| 27 | struct PresentPushConstants { | ||
| 28 | std::array<f32, 4 * 4> modelview_matrix; | ||
| 29 | std::array<ScreenRectVertex, 4> vertices; | ||
| 30 | }; | ||
| 31 | |||
| 32 | static_assert(sizeof(PresentPushConstants) <= 128, "Push constants are too large"); | ||
| 33 | |||
| 34 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/present/util.cpp b/src/video_core/renderer_vulkan/present/util.cpp index 9c08ac613..7bff1c436 100644 --- a/src/video_core/renderer_vulkan/present/util.cpp +++ b/src/video_core/renderer_vulkan/present/util.cpp | |||
| @@ -113,16 +113,18 @@ vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkF | |||
| 113 | }); | 113 | }); |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | vk::RenderPass CreateWrappedRenderPass(const Device& device, VkFormat format) { | 116 | vk::RenderPass CreateWrappedRenderPass(const Device& device, VkFormat format, |
| 117 | VkImageLayout initial_layout) { | ||
| 117 | const VkAttachmentDescription attachment{ | 118 | const VkAttachmentDescription attachment{ |
| 118 | .flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, | 119 | .flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, |
| 119 | .format = format, | 120 | .format = format, |
| 120 | .samples = VK_SAMPLE_COUNT_1_BIT, | 121 | .samples = VK_SAMPLE_COUNT_1_BIT, |
| 121 | .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, | 122 | .loadOp = initial_layout == VK_IMAGE_LAYOUT_UNDEFINED ? VK_ATTACHMENT_LOAD_OP_DONT_CARE |
| 123 | : VK_ATTACHMENT_LOAD_OP_LOAD, | ||
| 122 | .storeOp = VK_ATTACHMENT_STORE_OP_STORE, | 124 | .storeOp = VK_ATTACHMENT_STORE_OP_STORE, |
| 123 | .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD, | 125 | .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD, |
| 124 | .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, | 126 | .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, |
| 125 | .initialLayout = VK_IMAGE_LAYOUT_GENERAL, | 127 | .initialLayout = initial_layout, |
| 126 | .finalLayout = VK_IMAGE_LAYOUT_GENERAL, | 128 | .finalLayout = VK_IMAGE_LAYOUT_GENERAL, |
| 127 | }; | 129 | }; |
| 128 | 130 | ||
| @@ -244,8 +246,7 @@ vk::DescriptorSetLayout CreateWrappedDescriptorSetLayout( | |||
| 244 | .binding = static_cast<u32>(i), | 246 | .binding = static_cast<u32>(i), |
| 245 | .descriptorType = std::data(types)[i], | 247 | .descriptorType = std::data(types)[i], |
| 246 | .descriptorCount = 1, | 248 | .descriptorCount = 1, |
| 247 | .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | | 249 | .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, |
| 248 | VK_SHADER_STAGE_COMPUTE_BIT, | ||
| 249 | .pImmutableSamplers = nullptr, | 250 | .pImmutableSamplers = nullptr, |
| 250 | }; | 251 | }; |
| 251 | } | 252 | } |
| @@ -285,7 +286,8 @@ vk::PipelineLayout CreateWrappedPipelineLayout(const Device& device, | |||
| 285 | 286 | ||
| 286 | vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass, | 287 | vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass, |
| 287 | vk::PipelineLayout& layout, | 288 | vk::PipelineLayout& layout, |
| 288 | std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders) { | 289 | std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders, |
| 290 | bool enable_blending) { | ||
| 289 | const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{ | 291 | const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{ |
| 290 | { | 292 | { |
| 291 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | 293 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, |
| @@ -363,7 +365,7 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp | |||
| 363 | .alphaToOneEnable = VK_FALSE, | 365 | .alphaToOneEnable = VK_FALSE, |
| 364 | }; | 366 | }; |
| 365 | 367 | ||
| 366 | constexpr VkPipelineColorBlendAttachmentState color_blend_attachment{ | 368 | constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_disabled{ |
| 367 | .blendEnable = VK_FALSE, | 369 | .blendEnable = VK_FALSE, |
| 368 | .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO, | 370 | .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO, |
| 369 | .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, | 371 | .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, |
| @@ -375,6 +377,18 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp | |||
| 375 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, | 377 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, |
| 376 | }; | 378 | }; |
| 377 | 379 | ||
| 380 | constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_enabled{ | ||
| 381 | .blendEnable = VK_TRUE, | ||
| 382 | .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, | ||
| 383 | .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, | ||
| 384 | .colorBlendOp = VK_BLEND_OP_ADD, | ||
| 385 | .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, | ||
| 386 | .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 387 | .alphaBlendOp = VK_BLEND_OP_ADD, | ||
| 388 | .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | | ||
| 389 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, | ||
| 390 | }; | ||
| 391 | |||
| 378 | const VkPipelineColorBlendStateCreateInfo color_blend_ci{ | 392 | const VkPipelineColorBlendStateCreateInfo color_blend_ci{ |
| 379 | .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | 393 | .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, |
| 380 | .pNext = nullptr, | 394 | .pNext = nullptr, |
| @@ -382,7 +396,8 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp | |||
| 382 | .logicOpEnable = VK_FALSE, | 396 | .logicOpEnable = VK_FALSE, |
| 383 | .logicOp = VK_LOGIC_OP_COPY, | 397 | .logicOp = VK_LOGIC_OP_COPY, |
| 384 | .attachmentCount = 1, | 398 | .attachmentCount = 1, |
| 385 | .pAttachments = &color_blend_attachment, | 399 | .pAttachments = |
| 400 | enable_blending ? &color_blend_attachment_enabled : &color_blend_attachment_disabled, | ||
| 386 | .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, | 401 | .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, |
| 387 | }; | 402 | }; |
| 388 | 403 | ||
diff --git a/src/video_core/renderer_vulkan/present/util.h b/src/video_core/renderer_vulkan/present/util.h index 2f3a538fa..fb4e4a8e4 100644 --- a/src/video_core/renderer_vulkan/present/util.h +++ b/src/video_core/renderer_vulkan/present/util.h | |||
| @@ -20,7 +20,8 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc | |||
| 20 | void ClearColorImage(vk::CommandBuffer& cmdbuf, VkImage image); | 20 | void ClearColorImage(vk::CommandBuffer& cmdbuf, VkImage image); |
| 21 | 21 | ||
| 22 | vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format); | 22 | vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format); |
| 23 | vk::RenderPass CreateWrappedRenderPass(const Device& device, VkFormat format); | 23 | vk::RenderPass CreateWrappedRenderPass(const Device& device, VkFormat format, |
| 24 | VkImageLayout initial_layout = VK_IMAGE_LAYOUT_GENERAL); | ||
| 24 | vk::Framebuffer CreateWrappedFramebuffer(const Device& device, vk::RenderPass& render_pass, | 25 | vk::Framebuffer CreateWrappedFramebuffer(const Device& device, vk::RenderPass& render_pass, |
| 25 | vk::ImageView& dest_image, VkExtent2D extent); | 26 | vk::ImageView& dest_image, VkExtent2D extent); |
| 26 | vk::Sampler CreateWrappedSampler(const Device& device, VkFilter filter = VK_FILTER_LINEAR); | 27 | vk::Sampler CreateWrappedSampler(const Device& device, VkFilter filter = VK_FILTER_LINEAR); |
| @@ -37,7 +38,8 @@ vk::PipelineLayout CreateWrappedPipelineLayout(const Device& device, | |||
| 37 | vk::DescriptorSetLayout& layout); | 38 | vk::DescriptorSetLayout& layout); |
| 38 | vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass, | 39 | vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass, |
| 39 | vk::PipelineLayout& layout, | 40 | vk::PipelineLayout& layout, |
| 40 | std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders); | 41 | std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders, |
| 42 | bool enable_blending = false); | ||
| 41 | VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images, | 43 | VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images, |
| 42 | VkSampler sampler, VkImageView view, | 44 | VkSampler sampler, VkImageView view, |
| 43 | VkDescriptorSet set, u32 binding); | 45 | VkDescriptorSet set, u32 binding); |
diff --git a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp index 1d1828a4c..c5db0230d 100644 --- a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp +++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp | |||
| @@ -1,10 +1,11 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <cstring> | ||
| 5 | |||
| 6 | #include "core/frontend/framebuffer_layout.h" | 4 | #include "core/frontend/framebuffer_layout.h" |
| 5 | #include "video_core/framebuffer_config.h" | ||
| 7 | #include "video_core/host_shaders/vulkan_present_vert_spv.h" | 6 | #include "video_core/host_shaders/vulkan_present_vert_spv.h" |
| 7 | #include "video_core/renderer_vulkan/present/layer.h" | ||
| 8 | #include "video_core/renderer_vulkan/present/present_push_constants.h" | ||
| 8 | #include "video_core/renderer_vulkan/present/util.h" | 9 | #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/present/window_adapt_pass.h" |
| 10 | #include "video_core/renderer_vulkan/vk_present_manager.h" | 11 | #include "video_core/renderer_vulkan/vk_present_manager.h" |
| @@ -14,501 +15,123 @@ | |||
| 14 | 15 | ||
| 15 | namespace Vulkan { | 16 | namespace Vulkan { |
| 16 | 17 | ||
| 17 | namespace { | 18 | WindowAdaptPass::WindowAdaptPass(const Device& device_, VkFormat frame_format, |
| 18 | 19 | vk::Sampler&& sampler_, vk::ShaderModule&& fragment_shader_) | |
| 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_)) { | 20 | : device(device_), sampler(std::move(sampler_)), fragment_shader(std::move(fragment_shader_)) { |
| 75 | CreateDescriptorPool(num_images); | ||
| 76 | CreateDescriptorSetLayout(); | 21 | CreateDescriptorSetLayout(); |
| 77 | CreateDescriptorSets(num_images); | ||
| 78 | CreatePipelineLayout(); | 22 | CreatePipelineLayout(); |
| 79 | CreateVertexShader(); | 23 | CreateVertexShader(); |
| 80 | CreateRenderPass(frame_format); | 24 | CreateRenderPass(frame_format); |
| 81 | CreatePipeline(); | 25 | CreatePipeline(); |
| 82 | CreateBuffer(memory_allocator); | ||
| 83 | } | 26 | } |
| 84 | 27 | ||
| 85 | WindowAdaptPass::~WindowAdaptPass() = default; | 28 | WindowAdaptPass::~WindowAdaptPass() = default; |
| 86 | 29 | ||
| 87 | void WindowAdaptPass::Draw(Scheduler& scheduler, size_t image_index, VkImageView src_image_view, | 30 | void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, size_t image_index, |
| 88 | VkExtent2D src_image_extent, const Common::Rectangle<f32>& crop_rect, | 31 | std::list<Layer>& layers, |
| 32 | std::span<const Tegra::FramebufferConfig> configs, | ||
| 89 | const Layout::FramebufferLayout& layout, Frame* dst) { | 33 | const Layout::FramebufferLayout& layout, Frame* dst) { |
| 90 | ConfigureLayout(image_index, src_image_view, layout, crop_rect); | ||
| 91 | 34 | ||
| 92 | const VkFramebuffer host_framebuffer{*dst->framebuffer}; | 35 | const VkFramebuffer host_framebuffer{*dst->framebuffer}; |
| 93 | const VkRenderPass renderpass{*render_pass}; | 36 | const VkRenderPass renderpass{*render_pass}; |
| 94 | const VkPipeline graphics_pipeline{*pipeline}; | 37 | const VkPipeline graphics_pipeline{*pipeline}; |
| 95 | const VkPipelineLayout graphics_pipeline_layout{*pipeline_layout}; | 38 | const VkPipelineLayout graphics_pipeline_layout{*pipeline_layout}; |
| 96 | const VkDescriptorSet descriptor_set{descriptor_sets[image_index]}; | ||
| 97 | const VkBuffer vertex_buffer{*buffer}; | ||
| 98 | const VkExtent2D render_area{ | 39 | const VkExtent2D render_area{ |
| 99 | .width = dst->width, | 40 | .width = dst->width, |
| 100 | .height = dst->height, | 41 | .height = dst->height, |
| 101 | }; | 42 | }; |
| 102 | 43 | ||
| 44 | const size_t layer_count = configs.size(); | ||
| 45 | std::vector<PresentPushConstants> push_constants(layer_count); | ||
| 46 | std::vector<VkDescriptorSet> descriptor_sets(layer_count); | ||
| 47 | |||
| 48 | auto layer_it = layers.begin(); | ||
| 49 | for (size_t i = 0; i < layer_count; i++) { | ||
| 50 | layer_it->ConfigureDraw(&push_constants[i], &descriptor_sets[i], rasterizer, *sampler, | ||
| 51 | image_index, configs[i], layout); | ||
| 52 | layer_it++; | ||
| 53 | } | ||
| 54 | |||
| 103 | scheduler.Record([=](vk::CommandBuffer cmdbuf) { | 55 | scheduler.Record([=](vk::CommandBuffer cmdbuf) { |
| 104 | const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f; | 56 | const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f; |
| 105 | const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f; | 57 | const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f; |
| 106 | const f32 bg_blue = Settings::values.bg_blue.GetValue() / 255.0f; | 58 | const f32 bg_blue = Settings::values.bg_blue.GetValue() / 255.0f; |
| 107 | const VkClearValue clear_color{ | 59 | const VkClearAttachment clear_attachment{ |
| 108 | .color = {.float32 = {bg_red, bg_green, bg_blue, 1.0f}}, | 60 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, |
| 61 | .colorAttachment = 0, | ||
| 62 | .clearValue = | ||
| 63 | { | ||
| 64 | .color = {.float32 = {bg_red, bg_green, bg_blue, 1.0f}}, | ||
| 65 | }, | ||
| 109 | }; | 66 | }; |
| 110 | const VkRenderPassBeginInfo renderpass_bi{ | 67 | const VkClearRect clear_rect{ |
| 111 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, | 68 | .rect = |
| 112 | .pNext = nullptr, | ||
| 113 | .renderPass = renderpass, | ||
| 114 | .framebuffer = host_framebuffer, | ||
| 115 | .renderArea = | ||
| 116 | { | 69 | { |
| 117 | .offset = {0, 0}, | 70 | .offset = {0, 0}, |
| 118 | .extent = render_area, | 71 | .extent = render_area, |
| 119 | }, | 72 | }, |
| 120 | .clearValueCount = 1, | 73 | .baseArrayLayer = 0, |
| 121 | .pClearValues = &clear_color, | 74 | .layerCount = 1, |
| 122 | }; | ||
| 123 | const VkViewport viewport{ | ||
| 124 | .x = 0.0f, | ||
| 125 | .y = 0.0f, | ||
| 126 | .width = static_cast<float>(render_area.width), | ||
| 127 | .height = static_cast<float>(render_area.height), | ||
| 128 | .minDepth = 0.0f, | ||
| 129 | .maxDepth = 1.0f, | ||
| 130 | }; | 75 | }; |
| 131 | const VkRect2D scissor{ | 76 | |
| 132 | .offset = {0, 0}, | 77 | BeginRenderPass(cmdbuf, renderpass, host_framebuffer, render_area); |
| 133 | .extent = render_area, | 78 | cmdbuf.ClearAttachments({clear_attachment}, {clear_rect}); |
| 134 | }; | 79 | |
| 135 | cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); | ||
| 136 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline); | 80 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline); |
| 137 | cmdbuf.SetViewport(0, viewport); | 81 | for (size_t i = 0; i < layer_count; i++) { |
| 138 | cmdbuf.SetScissor(0, scissor); | 82 | cmdbuf.PushConstants(graphics_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, |
| 139 | cmdbuf.BindVertexBuffer(0, vertex_buffer, offsetof(BufferData, vertices)); | 83 | push_constants[i]); |
| 140 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_layout, 0, | 84 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_layout, 0, |
| 141 | descriptor_set, {}); | 85 | descriptor_sets[i], {}); |
| 142 | cmdbuf.Draw(4, 1, 0, 0); | 86 | cmdbuf.Draw(4, 1, 0, 0); |
| 87 | } | ||
| 88 | |||
| 143 | cmdbuf.EndRenderPass(); | 89 | cmdbuf.EndRenderPass(); |
| 144 | }); | 90 | }); |
| 145 | } | 91 | } |
| 146 | 92 | ||
| 147 | VkRenderPass WindowAdaptPass::GetRenderPass() { | 93 | VkDescriptorSetLayout WindowAdaptPass::GetDescriptorSetLayout() { |
| 148 | return *render_pass; | 94 | return *descriptor_set_layout; |
| 149 | } | 95 | } |
| 150 | 96 | ||
| 151 | void WindowAdaptPass::CreateDescriptorPool(size_t num_images) { | 97 | VkRenderPass WindowAdaptPass::GetRenderPass() { |
| 152 | const std::array<VkDescriptorPoolSize, 2> pool_sizes{{ | 98 | return *render_pass; |
| 153 | { | ||
| 154 | .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, | ||
| 155 | .descriptorCount = static_cast<u32>(num_images), | ||
| 156 | }, | ||
| 157 | { | ||
| 158 | .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 159 | .descriptorCount = static_cast<u32>(num_images), | ||
| 160 | }, | ||
| 161 | }}; | ||
| 162 | |||
| 163 | const VkDescriptorPoolCreateInfo ci{ | ||
| 164 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, | ||
| 165 | .pNext = nullptr, | ||
| 166 | .flags = 0, | ||
| 167 | .maxSets = static_cast<u32>(num_images), | ||
| 168 | .poolSizeCount = static_cast<u32>(pool_sizes.size()), | ||
| 169 | .pPoolSizes = pool_sizes.data(), | ||
| 170 | }; | ||
| 171 | descriptor_pool = device.GetLogical().CreateDescriptorPool(ci); | ||
| 172 | } | 99 | } |
| 173 | 100 | ||
| 174 | void WindowAdaptPass::CreateDescriptorSetLayout() { | 101 | void WindowAdaptPass::CreateDescriptorSetLayout() { |
| 175 | const std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings{{ | 102 | descriptor_set_layout = |
| 176 | { | 103 | CreateWrappedDescriptorSetLayout(device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER}); |
| 177 | .binding = 0, | ||
| 178 | .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, | ||
| 179 | .descriptorCount = 1, | ||
| 180 | .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 181 | .pImmutableSamplers = nullptr, | ||
| 182 | }, | ||
| 183 | { | ||
| 184 | .binding = 1, | ||
| 185 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 186 | .descriptorCount = 1, | ||
| 187 | .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 188 | .pImmutableSamplers = nullptr, | ||
| 189 | }, | ||
| 190 | }}; | ||
| 191 | |||
| 192 | const VkDescriptorSetLayoutCreateInfo ci{ | ||
| 193 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, | ||
| 194 | .pNext = nullptr, | ||
| 195 | .flags = 0, | ||
| 196 | .bindingCount = static_cast<u32>(layout_bindings.size()), | ||
| 197 | .pBindings = layout_bindings.data(), | ||
| 198 | }; | ||
| 199 | |||
| 200 | descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(ci); | ||
| 201 | } | ||
| 202 | |||
| 203 | void WindowAdaptPass::CreateDescriptorSets(size_t num_images) { | ||
| 204 | const std::vector layouts(num_images, *descriptor_set_layout); | ||
| 205 | descriptor_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts); | ||
| 206 | } | ||
| 207 | |||
| 208 | void WindowAdaptPass::CreateBuffer(const MemoryAllocator& memory_allocator) { | ||
| 209 | const VkBufferCreateInfo ci{ | ||
| 210 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | ||
| 211 | .pNext = nullptr, | ||
| 212 | .flags = 0, | ||
| 213 | .size = sizeof(BufferData), | ||
| 214 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | | ||
| 215 | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, | ||
| 216 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 217 | .queueFamilyIndexCount = 0, | ||
| 218 | .pQueueFamilyIndices = nullptr, | ||
| 219 | }; | ||
| 220 | |||
| 221 | buffer = memory_allocator.CreateBuffer(ci, MemoryUsage::Upload); | ||
| 222 | } | 104 | } |
| 223 | 105 | ||
| 224 | void WindowAdaptPass::CreateRenderPass(VkFormat frame_format) { | 106 | void WindowAdaptPass::CreatePipelineLayout() { |
| 225 | const VkAttachmentDescription color_attachment{ | 107 | const VkPushConstantRange range{ |
| 226 | .flags = 0, | 108 | .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, |
| 227 | .format = frame_format, | 109 | .offset = 0, |
| 228 | .samples = VK_SAMPLE_COUNT_1_BIT, | 110 | .size = sizeof(PresentPushConstants), |
| 229 | .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, | ||
| 230 | .storeOp = VK_ATTACHMENT_STORE_OP_STORE, | ||
| 231 | .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, | ||
| 232 | .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, | ||
| 233 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | ||
| 234 | .finalLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 235 | }; | ||
| 236 | |||
| 237 | const VkAttachmentReference color_attachment_ref{ | ||
| 238 | .attachment = 0, | ||
| 239 | .layout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 240 | }; | ||
| 241 | |||
| 242 | const VkSubpassDescription subpass_description{ | ||
| 243 | .flags = 0, | ||
| 244 | .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, | ||
| 245 | .inputAttachmentCount = 0, | ||
| 246 | .pInputAttachments = nullptr, | ||
| 247 | .colorAttachmentCount = 1, | ||
| 248 | .pColorAttachments = &color_attachment_ref, | ||
| 249 | .pResolveAttachments = nullptr, | ||
| 250 | .pDepthStencilAttachment = nullptr, | ||
| 251 | .preserveAttachmentCount = 0, | ||
| 252 | .pPreserveAttachments = nullptr, | ||
| 253 | }; | ||
| 254 | |||
| 255 | const VkSubpassDependency dependency{ | ||
| 256 | .srcSubpass = VK_SUBPASS_EXTERNAL, | ||
| 257 | .dstSubpass = 0, | ||
| 258 | .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | ||
| 259 | .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | ||
| 260 | .srcAccessMask = 0, | ||
| 261 | .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, | ||
| 262 | .dependencyFlags = 0, | ||
| 263 | }; | ||
| 264 | |||
| 265 | const VkRenderPassCreateInfo renderpass_ci{ | ||
| 266 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, | ||
| 267 | .pNext = nullptr, | ||
| 268 | .flags = 0, | ||
| 269 | .attachmentCount = 1, | ||
| 270 | .pAttachments = &color_attachment, | ||
| 271 | .subpassCount = 1, | ||
| 272 | .pSubpasses = &subpass_description, | ||
| 273 | .dependencyCount = 1, | ||
| 274 | .pDependencies = &dependency, | ||
| 275 | }; | 111 | }; |
| 276 | 112 | ||
| 277 | render_pass = device.GetLogical().CreateRenderPass(renderpass_ci); | 113 | pipeline_layout = device.GetLogical().CreatePipelineLayout(VkPipelineLayoutCreateInfo{ |
| 278 | } | ||
| 279 | |||
| 280 | void WindowAdaptPass::CreateVertexShader() { | ||
| 281 | vertex_shader = BuildShader(device, VULKAN_PRESENT_VERT_SPV); | ||
| 282 | } | ||
| 283 | |||
| 284 | void WindowAdaptPass::CreatePipelineLayout() { | ||
| 285 | const VkPipelineLayoutCreateInfo ci{ | ||
| 286 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | 114 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, |
| 287 | .pNext = nullptr, | 115 | .pNext = nullptr, |
| 288 | .flags = 0, | 116 | .flags = 0, |
| 289 | .setLayoutCount = 1, | 117 | .setLayoutCount = 1, |
| 290 | .pSetLayouts = descriptor_set_layout.address(), | 118 | .pSetLayouts = descriptor_set_layout.address(), |
| 291 | .pushConstantRangeCount = 0, | 119 | .pushConstantRangeCount = 1, |
| 292 | .pPushConstantRanges = nullptr, | 120 | .pPushConstantRanges = &range, |
| 293 | }; | 121 | }); |
| 294 | pipeline_layout = device.GetLogical().CreatePipelineLayout(ci); | ||
| 295 | } | ||
| 296 | |||
| 297 | void WindowAdaptPass::SetUniformData(BufferData& data, | ||
| 298 | const Layout::FramebufferLayout& layout) const { | ||
| 299 | data.uniform.modelview_matrix = | ||
| 300 | MakeOrthographicMatrix(static_cast<f32>(layout.width), static_cast<f32>(layout.height)); | ||
| 301 | } | ||
| 302 | |||
| 303 | void WindowAdaptPass::SetVertexData(BufferData& data, const Layout::FramebufferLayout& layout, | ||
| 304 | const Common::Rectangle<f32>& crop) const { | ||
| 305 | // Map the coordinates to the screen. | ||
| 306 | const auto& screen = layout.screen; | ||
| 307 | const auto x = static_cast<f32>(screen.left); | ||
| 308 | const auto y = static_cast<f32>(screen.top); | ||
| 309 | const auto w = static_cast<f32>(screen.GetWidth()); | ||
| 310 | const auto h = static_cast<f32>(screen.GetHeight()); | ||
| 311 | |||
| 312 | data.vertices[0] = ScreenRectVertex(x, y, crop.left, crop.top); | ||
| 313 | data.vertices[1] = ScreenRectVertex(x + w, y, crop.right, crop.top); | ||
| 314 | data.vertices[2] = ScreenRectVertex(x, y + h, crop.left, crop.bottom); | ||
| 315 | data.vertices[3] = ScreenRectVertex(x + w, y + h, crop.right, crop.bottom); | ||
| 316 | } | 122 | } |
| 317 | 123 | ||
| 318 | void WindowAdaptPass::UpdateDescriptorSet(size_t image_index, VkImageView image_view) { | 124 | void WindowAdaptPass::CreateVertexShader() { |
| 319 | const VkDescriptorBufferInfo buffer_info{ | 125 | vertex_shader = BuildShader(device, VULKAN_PRESENT_VERT_SPV); |
| 320 | .buffer = *buffer, | ||
| 321 | .offset = offsetof(BufferData, uniform), | ||
| 322 | .range = sizeof(BufferData::uniform), | ||
| 323 | }; | ||
| 324 | |||
| 325 | const VkWriteDescriptorSet ubo_write{ | ||
| 326 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 327 | .pNext = nullptr, | ||
| 328 | .dstSet = descriptor_sets[image_index], | ||
| 329 | .dstBinding = 0, | ||
| 330 | .dstArrayElement = 0, | ||
| 331 | .descriptorCount = 1, | ||
| 332 | .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, | ||
| 333 | .pImageInfo = nullptr, | ||
| 334 | .pBufferInfo = &buffer_info, | ||
| 335 | .pTexelBufferView = nullptr, | ||
| 336 | }; | ||
| 337 | |||
| 338 | const VkDescriptorImageInfo image_info{ | ||
| 339 | .sampler = *sampler, | ||
| 340 | .imageView = image_view, | ||
| 341 | .imageLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 342 | }; | ||
| 343 | |||
| 344 | const VkWriteDescriptorSet sampler_write{ | ||
| 345 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | ||
| 346 | .pNext = nullptr, | ||
| 347 | .dstSet = descriptor_sets[image_index], | ||
| 348 | .dstBinding = 1, | ||
| 349 | .dstArrayElement = 0, | ||
| 350 | .descriptorCount = 1, | ||
| 351 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, | ||
| 352 | .pImageInfo = &image_info, | ||
| 353 | .pBufferInfo = nullptr, | ||
| 354 | .pTexelBufferView = nullptr, | ||
| 355 | }; | ||
| 356 | |||
| 357 | device.GetLogical().UpdateDescriptorSets(std::array{ubo_write, sampler_write}, {}); | ||
| 358 | } | 126 | } |
| 359 | 127 | ||
| 360 | void WindowAdaptPass::ConfigureLayout(size_t image_index, VkImageView image_view, | 128 | void WindowAdaptPass::CreateRenderPass(VkFormat frame_format) { |
| 361 | const Layout::FramebufferLayout& layout, | 129 | render_pass = CreateWrappedRenderPass(device, frame_format, VK_IMAGE_LAYOUT_UNDEFINED); |
| 362 | const Common::Rectangle<f32>& crop_rect) { | ||
| 363 | BufferData data; | ||
| 364 | SetUniformData(data, layout); | ||
| 365 | SetVertexData(data, layout, crop_rect); | ||
| 366 | |||
| 367 | const std::span<u8> mapped_span = buffer.Mapped(); | ||
| 368 | std::memcpy(mapped_span.data(), &data, sizeof(data)); | ||
| 369 | |||
| 370 | UpdateDescriptorSet(image_index, image_view); | ||
| 371 | } | 130 | } |
| 372 | 131 | ||
| 373 | void WindowAdaptPass::CreatePipeline() { | 132 | void WindowAdaptPass::CreatePipeline() { |
| 374 | const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{ | 133 | pipeline = CreateWrappedPipeline(device, render_pass, pipeline_layout, |
| 375 | { | 134 | std::tie(vertex_shader, fragment_shader), false); |
| 376 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 377 | .pNext = nullptr, | ||
| 378 | .flags = 0, | ||
| 379 | .stage = VK_SHADER_STAGE_VERTEX_BIT, | ||
| 380 | .module = *vertex_shader, | ||
| 381 | .pName = "main", | ||
| 382 | .pSpecializationInfo = nullptr, | ||
| 383 | }, | ||
| 384 | { | ||
| 385 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | ||
| 386 | .pNext = nullptr, | ||
| 387 | .flags = 0, | ||
| 388 | .stage = VK_SHADER_STAGE_FRAGMENT_BIT, | ||
| 389 | .module = *fragment_shader, | ||
| 390 | .pName = "main", | ||
| 391 | .pSpecializationInfo = nullptr, | ||
| 392 | }, | ||
| 393 | }}; | ||
| 394 | |||
| 395 | const auto vertex_binding_description = ScreenRectVertex::GetDescription(); | ||
| 396 | const auto vertex_attrs_description = ScreenRectVertex::GetAttributes(); | ||
| 397 | |||
| 398 | const VkPipelineVertexInputStateCreateInfo vertex_input_ci{ | ||
| 399 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | ||
| 400 | .pNext = nullptr, | ||
| 401 | .flags = 0, | ||
| 402 | .vertexBindingDescriptionCount = 1, | ||
| 403 | .pVertexBindingDescriptions = &vertex_binding_description, | ||
| 404 | .vertexAttributeDescriptionCount = u32{vertex_attrs_description.size()}, | ||
| 405 | .pVertexAttributeDescriptions = vertex_attrs_description.data(), | ||
| 406 | }; | ||
| 407 | |||
| 408 | const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ | ||
| 409 | .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | ||
| 410 | .pNext = nullptr, | ||
| 411 | .flags = 0, | ||
| 412 | .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, | ||
| 413 | .primitiveRestartEnable = VK_FALSE, | ||
| 414 | }; | ||
| 415 | |||
| 416 | const VkPipelineViewportStateCreateInfo viewport_state_ci{ | ||
| 417 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| 418 | .pNext = nullptr, | ||
| 419 | .flags = 0, | ||
| 420 | .viewportCount = 1, | ||
| 421 | .pViewports = nullptr, | ||
| 422 | .scissorCount = 1, | ||
| 423 | .pScissors = nullptr, | ||
| 424 | }; | ||
| 425 | |||
| 426 | const VkPipelineRasterizationStateCreateInfo rasterization_ci{ | ||
| 427 | .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | ||
| 428 | .pNext = nullptr, | ||
| 429 | .flags = 0, | ||
| 430 | .depthClampEnable = VK_FALSE, | ||
| 431 | .rasterizerDiscardEnable = VK_FALSE, | ||
| 432 | .polygonMode = VK_POLYGON_MODE_FILL, | ||
| 433 | .cullMode = VK_CULL_MODE_NONE, | ||
| 434 | .frontFace = VK_FRONT_FACE_CLOCKWISE, | ||
| 435 | .depthBiasEnable = VK_FALSE, | ||
| 436 | .depthBiasConstantFactor = 0.0f, | ||
| 437 | .depthBiasClamp = 0.0f, | ||
| 438 | .depthBiasSlopeFactor = 0.0f, | ||
| 439 | .lineWidth = 1.0f, | ||
| 440 | }; | ||
| 441 | |||
| 442 | const VkPipelineMultisampleStateCreateInfo multisampling_ci{ | ||
| 443 | .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||
| 444 | .pNext = nullptr, | ||
| 445 | .flags = 0, | ||
| 446 | .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, | ||
| 447 | .sampleShadingEnable = VK_FALSE, | ||
| 448 | .minSampleShading = 0.0f, | ||
| 449 | .pSampleMask = nullptr, | ||
| 450 | .alphaToCoverageEnable = VK_FALSE, | ||
| 451 | .alphaToOneEnable = VK_FALSE, | ||
| 452 | }; | ||
| 453 | |||
| 454 | const VkPipelineColorBlendAttachmentState color_blend_attachment{ | ||
| 455 | .blendEnable = VK_FALSE, | ||
| 456 | .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 457 | .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 458 | .colorBlendOp = VK_BLEND_OP_ADD, | ||
| 459 | .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 460 | .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | ||
| 461 | .alphaBlendOp = VK_BLEND_OP_ADD, | ||
| 462 | .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | | ||
| 463 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, | ||
| 464 | }; | ||
| 465 | |||
| 466 | const VkPipelineColorBlendStateCreateInfo color_blend_ci{ | ||
| 467 | .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | ||
| 468 | .pNext = nullptr, | ||
| 469 | .flags = 0, | ||
| 470 | .logicOpEnable = VK_FALSE, | ||
| 471 | .logicOp = VK_LOGIC_OP_COPY, | ||
| 472 | .attachmentCount = 1, | ||
| 473 | .pAttachments = &color_blend_attachment, | ||
| 474 | .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, | ||
| 475 | }; | ||
| 476 | |||
| 477 | static constexpr std::array dynamic_states{ | ||
| 478 | VK_DYNAMIC_STATE_VIEWPORT, | ||
| 479 | VK_DYNAMIC_STATE_SCISSOR, | ||
| 480 | }; | ||
| 481 | const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ | ||
| 482 | .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||
| 483 | .pNext = nullptr, | ||
| 484 | .flags = 0, | ||
| 485 | .dynamicStateCount = static_cast<u32>(dynamic_states.size()), | ||
| 486 | .pDynamicStates = dynamic_states.data(), | ||
| 487 | }; | ||
| 488 | |||
| 489 | const VkGraphicsPipelineCreateInfo pipeline_ci{ | ||
| 490 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 491 | .pNext = nullptr, | ||
| 492 | .flags = 0, | ||
| 493 | .stageCount = static_cast<u32>(shader_stages.size()), | ||
| 494 | .pStages = shader_stages.data(), | ||
| 495 | .pVertexInputState = &vertex_input_ci, | ||
| 496 | .pInputAssemblyState = &input_assembly_ci, | ||
| 497 | .pTessellationState = nullptr, | ||
| 498 | .pViewportState = &viewport_state_ci, | ||
| 499 | .pRasterizationState = &rasterization_ci, | ||
| 500 | .pMultisampleState = &multisampling_ci, | ||
| 501 | .pDepthStencilState = nullptr, | ||
| 502 | .pColorBlendState = &color_blend_ci, | ||
| 503 | .pDynamicState = &dynamic_state_ci, | ||
| 504 | .layout = *pipeline_layout, | ||
| 505 | .renderPass = *render_pass, | ||
| 506 | .subpass = 0, | ||
| 507 | .basePipelineHandle = 0, | ||
| 508 | .basePipelineIndex = 0, | ||
| 509 | }; | ||
| 510 | |||
| 511 | pipeline = device.GetLogical().CreateGraphicsPipeline(pipeline_ci); | ||
| 512 | } | 135 | } |
| 513 | 136 | ||
| 514 | } // namespace Vulkan | 137 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/present/window_adapt_pass.h b/src/video_core/renderer_vulkan/present/window_adapt_pass.h index 5309233a2..0e2edfc31 100644 --- a/src/video_core/renderer_vulkan/present/window_adapt_pass.h +++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.h | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <list> | ||
| 7 | |||
| 6 | #include "common/math_util.h" | 8 | #include "common/math_util.h" |
| 7 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 9 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 8 | 10 | ||
| @@ -18,54 +20,39 @@ namespace Vulkan { | |||
| 18 | 20 | ||
| 19 | class Device; | 21 | class Device; |
| 20 | struct Frame; | 22 | struct Frame; |
| 21 | class MemoryAllocator; | 23 | class Layer; |
| 22 | class Scheduler; | 24 | class Scheduler; |
| 25 | class RasterizerVulkan; | ||
| 23 | 26 | ||
| 24 | class WindowAdaptPass final { | 27 | class WindowAdaptPass final { |
| 25 | public: | 28 | public: |
| 26 | explicit WindowAdaptPass(const Device& device, const MemoryAllocator& memory_allocator, | 29 | explicit WindowAdaptPass(const Device& device, VkFormat frame_format, vk::Sampler&& sampler, |
| 27 | size_t num_images, VkFormat frame_format, vk::Sampler&& sampler, | ||
| 28 | vk::ShaderModule&& fragment_shader); | 30 | vk::ShaderModule&& fragment_shader); |
| 29 | ~WindowAdaptPass(); | 31 | ~WindowAdaptPass(); |
| 30 | 32 | ||
| 31 | void Draw(Scheduler& scheduler, size_t image_index, VkImageView src_image_view, | 33 | void Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, size_t image_index, |
| 32 | VkExtent2D src_image_extent, const Common::Rectangle<f32>& crop_rect, | 34 | std::list<Layer>& layers, std::span<const Tegra::FramebufferConfig> configs, |
| 33 | const Layout::FramebufferLayout& layout, Frame* dst); | 35 | const Layout::FramebufferLayout& layout, Frame* dst); |
| 34 | 36 | ||
| 37 | VkDescriptorSetLayout GetDescriptorSetLayout(); | ||
| 35 | VkRenderPass GetRenderPass(); | 38 | VkRenderPass GetRenderPass(); |
| 36 | 39 | ||
| 37 | private: | 40 | 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(); | 41 | void CreateDescriptorSetLayout(); |
| 50 | void CreateDescriptorSets(size_t num_images); | ||
| 51 | void CreatePipelineLayout(); | 42 | void CreatePipelineLayout(); |
| 52 | void CreateVertexShader(); | 43 | void CreateVertexShader(); |
| 53 | void CreateRenderPass(VkFormat frame_format); | 44 | void CreateRenderPass(VkFormat frame_format); |
| 54 | void CreatePipeline(); | 45 | void CreatePipeline(); |
| 55 | void CreateBuffer(const MemoryAllocator& memory_allocator); | ||
| 56 | 46 | ||
| 57 | private: | 47 | private: |
| 58 | const Device& device; | 48 | const Device& device; |
| 59 | vk::DescriptorPool descriptor_pool; | ||
| 60 | vk::DescriptorSetLayout descriptor_set_layout; | 49 | vk::DescriptorSetLayout descriptor_set_layout; |
| 61 | vk::DescriptorSets descriptor_sets; | ||
| 62 | vk::PipelineLayout pipeline_layout; | 50 | vk::PipelineLayout pipeline_layout; |
| 63 | vk::Sampler sampler; | 51 | vk::Sampler sampler; |
| 64 | vk::ShaderModule vertex_shader; | 52 | vk::ShaderModule vertex_shader; |
| 65 | vk::ShaderModule fragment_shader; | 53 | vk::ShaderModule fragment_shader; |
| 66 | vk::RenderPass render_pass; | 54 | vk::RenderPass render_pass; |
| 67 | vk::Pipeline pipeline; | 55 | vk::Pipeline pipeline; |
| 68 | vk::Buffer buffer; | ||
| 69 | }; | 56 | }; |
| 70 | 57 | ||
| 71 | } // namespace Vulkan | 58 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index a99ef08a5..77837adde 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -125,9 +125,9 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 125 | return; | 125 | return; |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | RenderScreenshot(*framebuffer); | 128 | RenderScreenshot(framebuffer); |
| 129 | Frame* frame = present_manager.GetRenderFrame(); | 129 | Frame* frame = present_manager.GetRenderFrame(); |
| 130 | blit_swapchain.DrawToFrame(rasterizer, frame, *framebuffer, | 130 | blit_swapchain.DrawToFrame(rasterizer, frame, std::span(framebuffer, 1), |
| 131 | render_window.GetFramebufferLayout(), swapchain.GetImageCount(), | 131 | render_window.GetFramebufferLayout(), swapchain.GetImageCount(), |
| 132 | swapchain.GetImageViewFormat()); | 132 | swapchain.GetImageViewFormat()); |
| 133 | scheduler.Flush(*frame->render_ready); | 133 | scheduler.Flush(*frame->render_ready); |
| @@ -163,7 +163,7 @@ void RendererVulkan::Report() const { | |||
| 163 | telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); | 163 | telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& framebuffer) { | 166 | void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig* framebuffer) { |
| 167 | if (!renderer_settings.screenshot_requested) { | 167 | if (!renderer_settings.screenshot_requested) { |
| 168 | return; | 168 | return; |
| 169 | } | 169 | } |
| @@ -228,7 +228,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 228 | }; | 228 | }; |
| 229 | }(); | 229 | }(); |
| 230 | 230 | ||
| 231 | blit_screenshot.DrawToFrame(rasterizer, &frame, framebuffer, layout, 1, | 231 | blit_screenshot.DrawToFrame(rasterizer, &frame, std::span(framebuffer, 1), layout, 1, |
| 232 | VK_FORMAT_B8G8R8A8_UNORM); | 232 | VK_FORMAT_B8G8R8A8_UNORM); |
| 233 | 233 | ||
| 234 | const auto buffer_size = static_cast<VkDeviceSize>(layout.width * layout.height * 4); | 234 | const auto buffer_size = static_cast<VkDeviceSize>(layout.width * layout.height * 4); |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 5b0560e68..bdeb43a54 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h | |||
| @@ -59,7 +59,7 @@ public: | |||
| 59 | private: | 59 | private: |
| 60 | void Report() const; | 60 | void Report() const; |
| 61 | 61 | ||
| 62 | void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer); | 62 | void RenderScreenshot(const Tegra::FramebufferConfig* framebuffer); |
| 63 | 63 | ||
| 64 | Core::TelemetrySession& telemetry_session; | 64 | Core::TelemetrySession& telemetry_session; |
| 65 | Tegra::MaxwellDeviceMemoryManager& device_memory; | 65 | Tegra::MaxwellDeviceMemoryManager& device_memory; |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 8d01ec9fc..b2dcbf80b 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -1,65 +1,15 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <algorithm> | 4 | #include "video_core/framebuffer_config.h" |
| 5 | #include <array> | ||
| 6 | #include <cstring> | ||
| 7 | #include <memory> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/assert.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "common/settings.h" | ||
| 13 | #include "core/core.h" | ||
| 14 | #include "core/frontend/emu_window.h" | ||
| 15 | #include "video_core/gpu.h" | ||
| 16 | #include "video_core/host1x/gpu_device_memory_manager.h" | ||
| 17 | #include "video_core/renderer_vulkan/present/filters.h" | 5 | #include "video_core/renderer_vulkan/present/filters.h" |
| 18 | #include "video_core/renderer_vulkan/present/fsr.h" | 6 | #include "video_core/renderer_vulkan/present/layer.h" |
| 19 | #include "video_core/renderer_vulkan/present/fxaa.h" | ||
| 20 | #include "video_core/renderer_vulkan/present/smaa.h" | ||
| 21 | #include "video_core/renderer_vulkan/renderer_vulkan.h" | ||
| 22 | #include "video_core/renderer_vulkan/vk_blit_screen.h" | 7 | #include "video_core/renderer_vulkan/vk_blit_screen.h" |
| 8 | #include "video_core/renderer_vulkan/vk_present_manager.h" | ||
| 23 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 9 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 24 | #include "video_core/renderer_vulkan/vk_shader_util.h" | ||
| 25 | #include "video_core/surface.h" | ||
| 26 | #include "video_core/textures/decoders.h" | ||
| 27 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 28 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | ||
| 29 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 30 | 10 | ||
| 31 | namespace Vulkan { | 11 | namespace Vulkan { |
| 32 | 12 | ||
| 33 | namespace { | ||
| 34 | |||
| 35 | u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) { | ||
| 36 | using namespace VideoCore::Surface; | ||
| 37 | return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)); | ||
| 38 | } | ||
| 39 | |||
| 40 | std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) { | ||
| 41 | return static_cast<std::size_t>(framebuffer.stride) * | ||
| 42 | static_cast<std::size_t>(framebuffer.height) * GetBytesPerPixel(framebuffer); | ||
| 43 | } | ||
| 44 | |||
| 45 | VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) { | ||
| 46 | switch (framebuffer.pixel_format) { | ||
| 47 | case Service::android::PixelFormat::Rgba8888: | ||
| 48 | case Service::android::PixelFormat::Rgbx8888: | ||
| 49 | return VK_FORMAT_A8B8G8R8_UNORM_PACK32; | ||
| 50 | case Service::android::PixelFormat::Rgb565: | ||
| 51 | return VK_FORMAT_R5G6B5_UNORM_PACK16; | ||
| 52 | case Service::android::PixelFormat::Bgra8888: | ||
| 53 | return VK_FORMAT_B8G8R8A8_UNORM; | ||
| 54 | default: | ||
| 55 | UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", | ||
| 56 | static_cast<u32>(framebuffer.pixel_format)); | ||
| 57 | return VK_FORMAT_A8B8G8R8_UNORM_PACK32; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | } // Anonymous namespace | ||
| 62 | |||
| 63 | BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, const Device& device_, | 13 | BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, const Device& device_, |
| 64 | MemoryAllocator& memory_allocator_, PresentManager& present_manager_, | 14 | MemoryAllocator& memory_allocator_, PresentManager& present_manager_, |
| 65 | Scheduler& scheduler_) | 15 | Scheduler& scheduler_) |
| @@ -75,194 +25,35 @@ void BlitScreen::WaitIdle() { | |||
| 75 | device.GetLogical().WaitIdle(); | 25 | device.GetLogical().WaitIdle(); |
| 76 | } | 26 | } |
| 77 | 27 | ||
| 78 | void BlitScreen::SetWindowAdaptPass(const Layout::FramebufferLayout& layout) { | 28 | void BlitScreen::SetWindowAdaptPass() { |
| 29 | layers.clear(); | ||
| 79 | scaling_filter = Settings::values.scaling_filter.GetValue(); | 30 | scaling_filter = Settings::values.scaling_filter.GetValue(); |
| 80 | 31 | ||
| 81 | const VkExtent2D adapt_size{ | ||
| 82 | .width = layout.screen.GetWidth(), | ||
| 83 | .height = layout.screen.GetHeight(), | ||
| 84 | }; | ||
| 85 | |||
| 86 | fsr.reset(); | ||
| 87 | |||
| 88 | switch (scaling_filter) { | 32 | switch (scaling_filter) { |
| 89 | case Settings::ScalingFilter::NearestNeighbor: | 33 | case Settings::ScalingFilter::NearestNeighbor: |
| 90 | window_adapt = | 34 | window_adapt = MakeNearestNeighbor(device, swapchain_view_format); |
| 91 | MakeNearestNeighbor(device, memory_allocator, image_count, swapchain_view_format); | ||
| 92 | break; | 35 | break; |
| 93 | case Settings::ScalingFilter::Bicubic: | 36 | case Settings::ScalingFilter::Bicubic: |
| 94 | window_adapt = MakeBicubic(device, memory_allocator, image_count, swapchain_view_format); | 37 | window_adapt = MakeBicubic(device, swapchain_view_format); |
| 95 | break; | 38 | break; |
| 96 | case Settings::ScalingFilter::Gaussian: | 39 | case Settings::ScalingFilter::Gaussian: |
| 97 | window_adapt = MakeGaussian(device, memory_allocator, image_count, swapchain_view_format); | 40 | window_adapt = MakeGaussian(device, swapchain_view_format); |
| 98 | break; | 41 | break; |
| 99 | case Settings::ScalingFilter::ScaleForce: | 42 | case Settings::ScalingFilter::ScaleForce: |
| 100 | window_adapt = MakeScaleForce(device, memory_allocator, image_count, swapchain_view_format); | 43 | window_adapt = MakeScaleForce(device, swapchain_view_format); |
| 101 | break; | 44 | break; |
| 102 | case Settings::ScalingFilter::Fsr: | 45 | case Settings::ScalingFilter::Fsr: |
| 103 | fsr = std::make_unique<FSR>(device, memory_allocator, image_count, adapt_size); | ||
| 104 | [[fallthrough]]; | ||
| 105 | case Settings::ScalingFilter::Bilinear: | 46 | case Settings::ScalingFilter::Bilinear: |
| 106 | default: | 47 | default: |
| 107 | window_adapt = MakeBilinear(device, memory_allocator, image_count, swapchain_view_format); | 48 | window_adapt = MakeBilinear(device, swapchain_view_format); |
| 108 | break; | 49 | break; |
| 109 | } | 50 | } |
| 110 | } | 51 | } |
| 111 | 52 | ||
| 112 | void BlitScreen::SetAntiAliasPass() { | ||
| 113 | if (anti_alias && anti_aliasing == Settings::values.anti_aliasing.GetValue()) { | ||
| 114 | return; | ||
| 115 | } | ||
| 116 | |||
| 117 | anti_aliasing = Settings::values.anti_aliasing.GetValue(); | ||
| 118 | |||
| 119 | const VkExtent2D render_area{ | ||
| 120 | .width = Settings::values.resolution_info.ScaleUp(raw_width), | ||
| 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 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | void BlitScreen::Draw(RasterizerVulkan& rasterizer, const Tegra::FramebufferConfig& framebuffer, | ||
| 138 | const Layout::FramebufferLayout& layout, Frame* dst) { | ||
| 139 | const auto texture_info = rasterizer.AccelerateDisplay( | ||
| 140 | framebuffer, framebuffer.address + framebuffer.offset, framebuffer.stride); | ||
| 141 | const u32 texture_width = texture_info ? texture_info->width : framebuffer.width; | ||
| 142 | const u32 texture_height = texture_info ? texture_info->height : framebuffer.height; | ||
| 143 | const u32 scaled_width = texture_info ? texture_info->scaled_width : texture_width; | ||
| 144 | const u32 scaled_height = texture_info ? texture_info->scaled_height : texture_height; | ||
| 145 | const bool use_accelerated = texture_info.has_value(); | ||
| 146 | |||
| 147 | RefreshResources(framebuffer); | ||
| 148 | SetAntiAliasPass(); | ||
| 149 | |||
| 150 | // Finish any pending renderpass | ||
| 151 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 152 | |||
| 153 | scheduler.Wait(resource_ticks[image_index]); | ||
| 154 | SCOPE_EXIT({ resource_ticks[image_index] = scheduler.CurrentTick(); }); | ||
| 155 | |||
| 156 | VkImage source_image = texture_info ? texture_info->image : *raw_images[image_index]; | ||
| 157 | VkImageView source_image_view = | ||
| 158 | texture_info ? texture_info->image_view : *raw_image_views[image_index]; | ||
| 159 | |||
| 160 | const std::span<u8> mapped_span = buffer.Mapped(); | ||
| 161 | |||
| 162 | if (!use_accelerated) { | ||
| 163 | const u64 image_offset = GetRawImageOffset(framebuffer); | ||
| 164 | |||
| 165 | const DAddr framebuffer_addr = framebuffer.address + framebuffer.offset; | ||
| 166 | const u8* const host_ptr = device_memory.GetPointer<u8>(framebuffer_addr); | ||
| 167 | |||
| 168 | // TODO(Rodrigo): Read this from HLE | ||
| 169 | constexpr u32 block_height_log2 = 4; | ||
| 170 | const u32 bytes_per_pixel = GetBytesPerPixel(framebuffer); | ||
| 171 | const u64 linear_size{GetSizeInBytes(framebuffer)}; | ||
| 172 | const u64 tiled_size{Tegra::Texture::CalculateSize(true, bytes_per_pixel, | ||
| 173 | framebuffer.stride, framebuffer.height, | ||
| 174 | 1, block_height_log2, 0)}; | ||
| 175 | Tegra::Texture::UnswizzleTexture( | ||
| 176 | mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size), | ||
| 177 | bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); | ||
| 178 | |||
| 179 | const VkBufferImageCopy copy{ | ||
| 180 | .bufferOffset = image_offset, | ||
| 181 | .bufferRowLength = 0, | ||
| 182 | .bufferImageHeight = 0, | ||
| 183 | .imageSubresource = | ||
| 184 | { | ||
| 185 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 186 | .mipLevel = 0, | ||
| 187 | .baseArrayLayer = 0, | ||
| 188 | .layerCount = 1, | ||
| 189 | }, | ||
| 190 | .imageOffset = {.x = 0, .y = 0, .z = 0}, | ||
| 191 | .imageExtent = | ||
| 192 | { | ||
| 193 | .width = framebuffer.width, | ||
| 194 | .height = framebuffer.height, | ||
| 195 | .depth = 1, | ||
| 196 | }, | ||
| 197 | }; | ||
| 198 | scheduler.Record([this, copy, index = image_index](vk::CommandBuffer cmdbuf) { | ||
| 199 | const VkImage image = *raw_images[index]; | ||
| 200 | const VkImageMemoryBarrier base_barrier{ | ||
| 201 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 202 | .pNext = nullptr, | ||
| 203 | .srcAccessMask = 0, | ||
| 204 | .dstAccessMask = 0, | ||
| 205 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 206 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 207 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 208 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 209 | .image = image, | ||
| 210 | .subresourceRange{ | ||
| 211 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 212 | .baseMipLevel = 0, | ||
| 213 | .levelCount = 1, | ||
| 214 | .baseArrayLayer = 0, | ||
| 215 | .layerCount = 1, | ||
| 216 | }, | ||
| 217 | }; | ||
| 218 | VkImageMemoryBarrier read_barrier = base_barrier; | ||
| 219 | read_barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; | ||
| 220 | read_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | ||
| 221 | read_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||
| 222 | |||
| 223 | VkImageMemoryBarrier write_barrier = base_barrier; | ||
| 224 | write_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | ||
| 225 | write_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; | ||
| 226 | |||
| 227 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, | ||
| 228 | read_barrier); | ||
| 229 | cmdbuf.CopyBufferToImage(*buffer, image, VK_IMAGE_LAYOUT_GENERAL, copy); | ||
| 230 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 231 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | | ||
| 232 | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | ||
| 233 | 0, write_barrier); | ||
| 234 | }); | ||
| 235 | } | ||
| 236 | |||
| 237 | anti_alias->Draw(scheduler, image_index, &source_image, &source_image_view); | ||
| 238 | |||
| 239 | const auto crop_rect = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height); | ||
| 240 | const VkExtent2D render_extent{ | ||
| 241 | .width = scaled_width, | ||
| 242 | .height = scaled_height, | ||
| 243 | }; | ||
| 244 | |||
| 245 | if (fsr) { | ||
| 246 | const VkExtent2D adapt_size{ | ||
| 247 | .width = layout.screen.GetWidth(), | ||
| 248 | .height = layout.screen.GetHeight(), | ||
| 249 | }; | ||
| 250 | |||
| 251 | source_image_view = fsr->Draw(scheduler, image_index, source_image, source_image_view, | ||
| 252 | 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); | ||
| 257 | } else { | ||
| 258 | window_adapt->Draw(scheduler, image_index, source_image_view, render_extent, crop_rect, | ||
| 259 | layout, dst); | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame, | 53 | void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame, |
| 264 | const Tegra::FramebufferConfig& framebuffer, | 54 | std::span<const Tegra::FramebufferConfig> framebuffers, |
| 265 | const Layout::FramebufferLayout& layout, size_t swapchain_images, | 55 | const Layout::FramebufferLayout& layout, |
| 56 | size_t current_swapchain_image_count, | ||
| 266 | VkFormat current_swapchain_view_format) { | 57 | VkFormat current_swapchain_view_format) { |
| 267 | bool resource_update_required = false; | 58 | bool resource_update_required = false; |
| 268 | bool presentation_recreate_required = false; | 59 | bool presentation_recreate_required = false; |
| @@ -272,11 +63,10 @@ void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame, | |||
| 272 | resource_update_required = true; | 63 | resource_update_required = true; |
| 273 | } | 64 | } |
| 274 | 65 | ||
| 275 | // Recreate dynamic resources if the the image count or input format changed | 66 | // Recreate dynamic resources if the image count changed |
| 276 | const VkFormat old_framebuffer_format = | 67 | const size_t old_swapchain_image_count = |
| 277 | std::exchange(framebuffer_view_format, GetFormat(framebuffer)); | 68 | std::exchange(image_count, current_swapchain_image_count); |
| 278 | if (swapchain_images != image_count || old_framebuffer_format != framebuffer_view_format) { | 69 | if (old_swapchain_image_count != current_swapchain_image_count) { |
| 279 | image_count = swapchain_images; | ||
| 280 | resource_update_required = true; | 70 | resource_update_required = true; |
| 281 | } | 71 | } |
| 282 | 72 | ||
| @@ -294,11 +84,8 @@ void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame, | |||
| 294 | // Wait for idle to ensure no resources are in use | 84 | // Wait for idle to ensure no resources are in use |
| 295 | WaitIdle(); | 85 | WaitIdle(); |
| 296 | 86 | ||
| 297 | // Set new number of resource ticks | ||
| 298 | resource_ticks.resize(swapchain_images); | ||
| 299 | |||
| 300 | // Update window adapt pass | 87 | // Update window adapt pass |
| 301 | SetWindowAdaptPass(layout); | 88 | SetWindowAdaptPass(); |
| 302 | 89 | ||
| 303 | // Update frame format if needed | 90 | // Update frame format if needed |
| 304 | if (presentation_recreate_required) { | 91 | if (presentation_recreate_required) { |
| @@ -307,7 +94,21 @@ void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame, | |||
| 307 | } | 94 | } |
| 308 | } | 95 | } |
| 309 | 96 | ||
| 310 | Draw(rasterizer, framebuffer, layout, frame); | 97 | // Add additional layers if needed |
| 98 | const VkExtent2D window_size{ | ||
| 99 | .width = layout.screen.GetWidth(), | ||
| 100 | .height = layout.screen.GetHeight(), | ||
| 101 | }; | ||
| 102 | |||
| 103 | while (layers.size() < framebuffers.size()) { | ||
| 104 | layers.emplace_back(device, memory_allocator, scheduler, device_memory, image_count, | ||
| 105 | window_size, window_adapt->GetDescriptorSetLayout()); | ||
| 106 | } | ||
| 107 | |||
| 108 | // Perform the draw | ||
| 109 | window_adapt->Draw(rasterizer, scheduler, image_index, layers, framebuffers, layout, frame); | ||
| 110 | |||
| 111 | // Advance to next image | ||
| 311 | if (++image_index >= image_count) { | 112 | if (++image_index >= image_count) { |
| 312 | image_index = 0; | 113 | image_index = 0; |
| 313 | } | 114 | } |
| @@ -321,7 +122,7 @@ vk::Framebuffer BlitScreen::CreateFramebuffer(const Layout::FramebufferLayout& l | |||
| 321 | if (!window_adapt || scaling_filter != Settings::values.scaling_filter.GetValue() || | 122 | if (!window_adapt || scaling_filter != Settings::values.scaling_filter.GetValue() || |
| 322 | format_updated) { | 123 | format_updated) { |
| 323 | WaitIdle(); | 124 | WaitIdle(); |
| 324 | SetWindowAdaptPass(layout); | 125 | SetWindowAdaptPass(); |
| 325 | } | 126 | } |
| 326 | const VkExtent2D extent{ | 127 | const VkExtent2D extent{ |
| 327 | .width = layout.width, | 128 | .width = layout.width, |
| @@ -345,115 +146,4 @@ vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkE | |||
| 345 | }); | 146 | }); |
| 346 | } | 147 | } |
| 347 | 148 | ||
| 348 | void BlitScreen::RefreshResources(const Tegra::FramebufferConfig& framebuffer) { | ||
| 349 | if (framebuffer.width == raw_width && framebuffer.height == raw_height && | ||
| 350 | framebuffer.pixel_format == pixel_format && !raw_images.empty()) { | ||
| 351 | return; | ||
| 352 | } | ||
| 353 | |||
| 354 | raw_width = framebuffer.width; | ||
| 355 | raw_height = framebuffer.height; | ||
| 356 | pixel_format = framebuffer.pixel_format; | ||
| 357 | anti_alias.reset(); | ||
| 358 | |||
| 359 | ReleaseRawImages(); | ||
| 360 | CreateStagingBuffer(framebuffer); | ||
| 361 | CreateRawImages(framebuffer); | ||
| 362 | } | ||
| 363 | |||
| 364 | void BlitScreen::ReleaseRawImages() { | ||
| 365 | for (const u64 tick : resource_ticks) { | ||
| 366 | scheduler.Wait(tick); | ||
| 367 | } | ||
| 368 | raw_images.clear(); | ||
| 369 | buffer.reset(); | ||
| 370 | } | ||
| 371 | |||
| 372 | void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { | ||
| 373 | const VkBufferCreateInfo ci{ | ||
| 374 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | ||
| 375 | .pNext = nullptr, | ||
| 376 | .flags = 0, | ||
| 377 | .size = CalculateBufferSize(framebuffer), | ||
| 378 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | | ||
| 379 | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, | ||
| 380 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 381 | .queueFamilyIndexCount = 0, | ||
| 382 | .pQueueFamilyIndices = nullptr, | ||
| 383 | }; | ||
| 384 | |||
| 385 | buffer = memory_allocator.CreateBuffer(ci, MemoryUsage::Upload); | ||
| 386 | } | ||
| 387 | |||
| 388 | void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | ||
| 389 | raw_images.resize(image_count); | ||
| 390 | raw_image_views.resize(image_count); | ||
| 391 | |||
| 392 | const auto create_image = [&](bool used_on_framebuffer = false, u32 up_scale = 1, | ||
| 393 | u32 down_shift = 0) { | ||
| 394 | u32 extra_usages = used_on_framebuffer ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | ||
| 395 | : VK_IMAGE_USAGE_TRANSFER_DST_BIT; | ||
| 396 | return memory_allocator.CreateImage(VkImageCreateInfo{ | ||
| 397 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | ||
| 398 | .pNext = nullptr, | ||
| 399 | .flags = 0, | ||
| 400 | .imageType = VK_IMAGE_TYPE_2D, | ||
| 401 | .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : framebuffer_view_format, | ||
| 402 | .extent = | ||
| 403 | { | ||
| 404 | .width = (up_scale * framebuffer.width) >> down_shift, | ||
| 405 | .height = (up_scale * framebuffer.height) >> down_shift, | ||
| 406 | .depth = 1, | ||
| 407 | }, | ||
| 408 | .mipLevels = 1, | ||
| 409 | .arrayLayers = 1, | ||
| 410 | .samples = VK_SAMPLE_COUNT_1_BIT, | ||
| 411 | .tiling = used_on_framebuffer ? VK_IMAGE_TILING_OPTIMAL : VK_IMAGE_TILING_LINEAR, | ||
| 412 | .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | extra_usages, | ||
| 413 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 414 | .queueFamilyIndexCount = 0, | ||
| 415 | .pQueueFamilyIndices = nullptr, | ||
| 416 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | ||
| 417 | }); | ||
| 418 | }; | ||
| 419 | const auto create_image_view = [&](vk::Image& image, bool used_on_framebuffer = false) { | ||
| 420 | return device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | ||
| 421 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | ||
| 422 | .pNext = nullptr, | ||
| 423 | .flags = 0, | ||
| 424 | .image = *image, | ||
| 425 | .viewType = VK_IMAGE_VIEW_TYPE_2D, | ||
| 426 | .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : framebuffer_view_format, | ||
| 427 | .components = | ||
| 428 | { | ||
| 429 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 430 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 431 | .b = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 432 | .a = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 433 | }, | ||
| 434 | .subresourceRange = | ||
| 435 | { | ||
| 436 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 437 | .baseMipLevel = 0, | ||
| 438 | .levelCount = 1, | ||
| 439 | .baseArrayLayer = 0, | ||
| 440 | .layerCount = 1, | ||
| 441 | }, | ||
| 442 | }); | ||
| 443 | }; | ||
| 444 | |||
| 445 | for (size_t i = 0; i < image_count; ++i) { | ||
| 446 | raw_images[i] = create_image(); | ||
| 447 | raw_image_views[i] = create_image_view(raw_images[i]); | ||
| 448 | } | ||
| 449 | } | ||
| 450 | |||
| 451 | u64 BlitScreen::CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const { | ||
| 452 | return GetSizeInBytes(framebuffer) * image_count; | ||
| 453 | } | ||
| 454 | |||
| 455 | u64 BlitScreen::GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer) const { | ||
| 456 | return GetSizeInBytes(framebuffer) * image_index; | ||
| 457 | } | ||
| 458 | |||
| 459 | } // namespace Vulkan | 149 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 555b3d82e..9a3476c77 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h | |||
| @@ -3,10 +3,12 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <list> | ||
| 6 | #include <memory> | 7 | #include <memory> |
| 7 | 8 | ||
| 8 | #include "core/frontend/framebuffer_layout.h" | 9 | #include "core/frontend/framebuffer_layout.h" |
| 9 | #include "video_core/host1x/gpu_device_memory_manager.h" | 10 | #include "video_core/host1x/gpu_device_memory_manager.h" |
| 11 | #include "video_core/renderer_vulkan/present/layer.h" | ||
| 10 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | 12 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" |
| 11 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 12 | 14 | ||
| @@ -14,32 +16,17 @@ namespace Core { | |||
| 14 | class System; | 16 | class System; |
| 15 | } | 17 | } |
| 16 | 18 | ||
| 17 | namespace Core::Frontend { | ||
| 18 | class EmuWindow; | ||
| 19 | } | ||
| 20 | |||
| 21 | namespace Tegra { | 19 | namespace Tegra { |
| 22 | struct FramebufferConfig; | 20 | struct FramebufferConfig; |
| 23 | } | 21 | } |
| 24 | 22 | ||
| 25 | namespace VideoCore { | ||
| 26 | class RasterizerInterface; | ||
| 27 | } | ||
| 28 | |||
| 29 | namespace Service::android { | ||
| 30 | enum class PixelFormat : u32; | ||
| 31 | } | ||
| 32 | |||
| 33 | namespace Settings { | 23 | namespace Settings { |
| 34 | enum class AntiAliasing : u32; | ||
| 35 | enum class ScalingFilter : u32; | 24 | enum class ScalingFilter : u32; |
| 36 | } // namespace Settings | 25 | } // namespace Settings |
| 37 | 26 | ||
| 38 | namespace Vulkan { | 27 | namespace Vulkan { |
| 39 | 28 | ||
| 40 | class AntiAliasPass; | ||
| 41 | class Device; | 29 | class Device; |
| 42 | class FSR; | ||
| 43 | class RasterizerVulkan; | 30 | class RasterizerVulkan; |
| 44 | class Scheduler; | 31 | class Scheduler; |
| 45 | class PresentManager; | 32 | class PresentManager; |
| @@ -64,8 +51,8 @@ public: | |||
| 64 | ~BlitScreen(); | 51 | ~BlitScreen(); |
| 65 | 52 | ||
| 66 | void DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame, | 53 | void DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame, |
| 67 | const Tegra::FramebufferConfig& framebuffer, | 54 | std::span<const Tegra::FramebufferConfig> framebuffers, |
| 68 | const Layout::FramebufferLayout& layout, size_t swapchain_images, | 55 | const Layout::FramebufferLayout& layout, size_t current_swapchain_image_count, |
| 69 | VkFormat current_swapchain_view_format); | 56 | VkFormat current_swapchain_view_format); |
| 70 | 57 | ||
| 71 | [[nodiscard]] vk::Framebuffer CreateFramebuffer(const Layout::FramebufferLayout& layout, | 58 | [[nodiscard]] vk::Framebuffer CreateFramebuffer(const Layout::FramebufferLayout& layout, |
| @@ -74,50 +61,22 @@ public: | |||
| 74 | 61 | ||
| 75 | private: | 62 | private: |
| 76 | void WaitIdle(); | 63 | void WaitIdle(); |
| 77 | void SetWindowAdaptPass(const Layout::FramebufferLayout& layout); | 64 | void SetWindowAdaptPass(); |
| 78 | void SetAntiAliasPass(); | ||
| 79 | |||
| 80 | void Draw(RasterizerVulkan& rasterizer, const Tegra::FramebufferConfig& framebuffer, | ||
| 81 | const Layout::FramebufferLayout& layout, Frame* dst); | ||
| 82 | |||
| 83 | vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent, | 65 | vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent, |
| 84 | VkRenderPass render_pass); | 66 | VkRenderPass render_pass); |
| 85 | 67 | ||
| 86 | void RefreshResources(const Tegra::FramebufferConfig& framebuffer); | ||
| 87 | void ReleaseRawImages(); | ||
| 88 | void CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer); | ||
| 89 | void CreateRawImages(const Tegra::FramebufferConfig& framebuffer); | ||
| 90 | |||
| 91 | u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const; | ||
| 92 | u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer) const; | ||
| 93 | |||
| 94 | Tegra::MaxwellDeviceMemoryManager& device_memory; | 68 | Tegra::MaxwellDeviceMemoryManager& device_memory; |
| 95 | const Device& device; | 69 | const Device& device; |
| 96 | MemoryAllocator& memory_allocator; | 70 | MemoryAllocator& memory_allocator; |
| 97 | PresentManager& present_manager; | 71 | PresentManager& present_manager; |
| 98 | Scheduler& scheduler; | 72 | Scheduler& scheduler; |
| 99 | std::size_t image_count; | 73 | std::size_t image_count{}; |
| 100 | std::size_t image_index{}; | 74 | std::size_t image_index{}; |
| 75 | VkFormat swapchain_view_format{}; | ||
| 101 | 76 | ||
| 102 | vk::Buffer buffer; | ||
| 103 | |||
| 104 | std::vector<u64> resource_ticks; | ||
| 105 | |||
| 106 | std::vector<vk::Image> raw_images; | ||
| 107 | std::vector<vk::ImageView> raw_image_views; | ||
| 108 | u32 raw_width = 0; | ||
| 109 | u32 raw_height = 0; | ||
| 110 | |||
| 111 | Service::android::PixelFormat pixel_format{}; | ||
| 112 | VkFormat framebuffer_view_format; | ||
| 113 | VkFormat swapchain_view_format; | ||
| 114 | |||
| 115 | Settings::AntiAliasing anti_aliasing{}; | ||
| 116 | Settings::ScalingFilter scaling_filter{}; | 77 | Settings::ScalingFilter scaling_filter{}; |
| 117 | 78 | std::unique_ptr<WindowAdaptPass> window_adapt{}; | |
| 118 | std::unique_ptr<FSR> fsr; | 79 | std::list<Layer> layers{}; |
| 119 | std::unique_ptr<AntiAliasPass> anti_alias; | ||
| 120 | std::unique_ptr<WindowAdaptPass> window_adapt; | ||
| 121 | }; | 80 | }; |
| 122 | 81 | ||
| 123 | } // namespace Vulkan | 82 | } // namespace Vulkan |