summaryrefslogtreecommitdiff
path: root/src/video_core/renderer_vulkan
diff options
context:
space:
mode:
authorGravatar Narr the Reg2024-02-11 20:58:28 -0600
committerGravatar GitHub2024-02-11 20:58:28 -0600
commit2ff45cd0da941dce2564f5c18c580d0283da27bf (patch)
tree81fea8c23f9afa39c167288e03ff57eb25413ee4 /src/video_core/renderer_vulkan
parentMerge pull request #12991 from german77/news2 (diff)
parentam: use applet program loading for tested versions (diff)
downloadyuzu-2ff45cd0da941dce2564f5c18c580d0283da27bf.tar.gz
yuzu-2ff45cd0da941dce2564f5c18c580d0283da27bf.tar.xz
yuzu-2ff45cd0da941dce2564f5c18c580d0283da27bf.zip
Merge pull request #12756 from liamwhite/applet-multiprocess-hwc
general: applet multiprocess
Diffstat (limited to 'src/video_core/renderer_vulkan')
-rw-r--r--src/video_core/renderer_vulkan/present/layer.cpp19
-rw-r--r--src/video_core/renderer_vulkan/present/layer.h6
-rw-r--r--src/video_core/renderer_vulkan/present/util.cpp92
-rw-r--r--src/video_core/renderer_vulkan/present/util.h9
-rw-r--r--src/video_core/renderer_vulkan/present/window_adapt_pass.cpp29
-rw-r--r--src/video_core/renderer_vulkan/present/window_adapt_pass.h6
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp114
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h11
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp14
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h5
10 files changed, 223 insertions, 82 deletions
diff --git a/src/video_core/renderer_vulkan/present/layer.cpp b/src/video_core/renderer_vulkan/present/layer.cpp
index cfc04be44..3847a9a13 100644
--- a/src/video_core/renderer_vulkan/present/layer.cpp
+++ b/src/video_core/renderer_vulkan/present/layer.cpp
@@ -1,6 +1,7 @@
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 "video_core/present.h"
4#include "video_core/renderer_vulkan/vk_rasterizer.h" 5#include "video_core/renderer_vulkan/vk_rasterizer.h"
5 6
6#include "common/settings.h" 7#include "common/settings.h"
@@ -48,12 +49,12 @@ VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) {
48 49
49Layer::Layer(const Device& device_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_, 50Layer::Layer(const Device& device_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_,
50 Tegra::MaxwellDeviceMemoryManager& device_memory_, size_t image_count_, 51 Tegra::MaxwellDeviceMemoryManager& device_memory_, size_t image_count_,
51 VkExtent2D output_size, VkDescriptorSetLayout layout) 52 VkExtent2D output_size, VkDescriptorSetLayout layout, const PresentFilters& filters_)
52 : device(device_), memory_allocator(memory_allocator_), scheduler(scheduler_), 53 : device(device_), memory_allocator(memory_allocator_), scheduler(scheduler_),
53 device_memory(device_memory_), image_count(image_count_) { 54 device_memory(device_memory_), filters(filters_), image_count(image_count_) {
54 CreateDescriptorPool(); 55 CreateDescriptorPool();
55 CreateDescriptorSets(layout); 56 CreateDescriptorSets(layout);
56 if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { 57 if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr) {
57 CreateFSR(output_size); 58 CreateFSR(output_size);
58 } 59 }
59} 60}
@@ -171,11 +172,11 @@ void Layer::RefreshResources(const Tegra::FramebufferConfig& framebuffer) {
171} 172}
172 173
173void Layer::SetAntiAliasPass() { 174void Layer::SetAntiAliasPass() {
174 if (anti_alias && anti_alias_setting == Settings::values.anti_aliasing.GetValue()) { 175 if (anti_alias && anti_alias_setting == filters.get_anti_aliasing()) {
175 return; 176 return;
176 } 177 }
177 178
178 anti_alias_setting = Settings::values.anti_aliasing.GetValue(); 179 anti_alias_setting = filters.get_anti_aliasing();
179 180
180 const VkExtent2D render_area{ 181 const VkExtent2D render_area{
181 .width = Settings::values.resolution_info.ScaleUp(raw_width), 182 .width = Settings::values.resolution_info.ScaleUp(raw_width),
@@ -270,9 +271,11 @@ void Layer::UpdateRawImage(const Tegra::FramebufferConfig& framebuffer, size_t i
270 const u64 linear_size{GetSizeInBytes(framebuffer)}; 271 const u64 linear_size{GetSizeInBytes(framebuffer)};
271 const u64 tiled_size{Tegra::Texture::CalculateSize( 272 const u64 tiled_size{Tegra::Texture::CalculateSize(
272 true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; 273 true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)};
273 Tegra::Texture::UnswizzleTexture( 274 if (host_ptr) {
274 mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size), 275 Tegra::Texture::UnswizzleTexture(
275 bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); 276 mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size),
277 bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0);
278 }
276 279
277 const VkBufferImageCopy copy{ 280 const VkBufferImageCopy copy{
278 .bufferOffset = image_offset, 281 .bufferOffset = image_offset,
diff --git a/src/video_core/renderer_vulkan/present/layer.h b/src/video_core/renderer_vulkan/present/layer.h
index 88d43fc5f..f5effdcd7 100644
--- a/src/video_core/renderer_vulkan/present/layer.h
+++ b/src/video_core/renderer_vulkan/present/layer.h
@@ -11,6 +11,8 @@ namespace Layout {
11struct FramebufferLayout; 11struct FramebufferLayout;
12} 12}
13 13
14struct PresentFilters;
15
14namespace Tegra { 16namespace Tegra {
15struct FramebufferConfig; 17struct FramebufferConfig;
16} 18}
@@ -37,7 +39,8 @@ class Layer final {
37public: 39public:
38 explicit Layer(const Device& device, MemoryAllocator& memory_allocator, Scheduler& scheduler, 40 explicit Layer(const Device& device, MemoryAllocator& memory_allocator, Scheduler& scheduler,
39 Tegra::MaxwellDeviceMemoryManager& device_memory, size_t image_count, 41 Tegra::MaxwellDeviceMemoryManager& device_memory, size_t image_count,
40 VkExtent2D output_size, VkDescriptorSetLayout layout); 42 VkExtent2D output_size, VkDescriptorSetLayout layout,
43 const PresentFilters& filters);
41 ~Layer(); 44 ~Layer();
42 45
43 void ConfigureDraw(PresentPushConstants* out_push_constants, 46 void ConfigureDraw(PresentPushConstants* out_push_constants,
@@ -71,6 +74,7 @@ private:
71 MemoryAllocator& memory_allocator; 74 MemoryAllocator& memory_allocator;
72 Scheduler& scheduler; 75 Scheduler& scheduler;
73 Tegra::MaxwellDeviceMemoryManager& device_memory; 76 Tegra::MaxwellDeviceMemoryManager& device_memory;
77 const PresentFilters& filters;
74 const size_t image_count{}; 78 const size_t image_count{};
75 vk::DescriptorPool descriptor_pool{}; 79 vk::DescriptorPool descriptor_pool{};
76 vk::DescriptorSets descriptor_sets{}; 80 vk::DescriptorSets descriptor_sets{};
diff --git a/src/video_core/renderer_vulkan/present/util.cpp b/src/video_core/renderer_vulkan/present/util.cpp
index 6ee16595d..7f27c7c1b 100644
--- a/src/video_core/renderer_vulkan/present/util.cpp
+++ b/src/video_core/renderer_vulkan/present/util.cpp
@@ -362,10 +362,10 @@ vk::PipelineLayout CreateWrappedPipelineLayout(const Device& device,
362 }); 362 });
363} 363}
364 364
365vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass, 365static vk::Pipeline CreateWrappedPipelineImpl(
366 vk::PipelineLayout& layout, 366 const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
367 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders, 367 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders,
368 bool enable_blending) { 368 VkPipelineColorBlendAttachmentState blending) {
369 const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{ 369 const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{
370 { 370 {
371 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 371 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
@@ -443,30 +443,6 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp
443 .alphaToOneEnable = VK_FALSE, 443 .alphaToOneEnable = VK_FALSE,
444 }; 444 };
445 445
446 constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_disabled{
447 .blendEnable = VK_FALSE,
448 .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
449 .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
450 .colorBlendOp = VK_BLEND_OP_ADD,
451 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
452 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
453 .alphaBlendOp = VK_BLEND_OP_ADD,
454 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
455 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
456 };
457
458 constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_enabled{
459 .blendEnable = VK_TRUE,
460 .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
461 .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
462 .colorBlendOp = VK_BLEND_OP_ADD,
463 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
464 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
465 .alphaBlendOp = VK_BLEND_OP_ADD,
466 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
467 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
468 };
469
470 const VkPipelineColorBlendStateCreateInfo color_blend_ci{ 446 const VkPipelineColorBlendStateCreateInfo color_blend_ci{
471 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, 447 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
472 .pNext = nullptr, 448 .pNext = nullptr,
@@ -474,8 +450,7 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp
474 .logicOpEnable = VK_FALSE, 450 .logicOpEnable = VK_FALSE,
475 .logicOp = VK_LOGIC_OP_COPY, 451 .logicOp = VK_LOGIC_OP_COPY,
476 .attachmentCount = 1, 452 .attachmentCount = 1,
477 .pAttachments = 453 .pAttachments = &blending,
478 enable_blending ? &color_blend_attachment_enabled : &color_blend_attachment_disabled,
479 .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, 454 .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
480 }; 455 };
481 456
@@ -515,6 +490,63 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp
515 }); 490 });
516} 491}
517 492
493vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass,
494 vk::PipelineLayout& layout,
495 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders) {
496 constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_disabled{
497 .blendEnable = VK_FALSE,
498 .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
499 .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
500 .colorBlendOp = VK_BLEND_OP_ADD,
501 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
502 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
503 .alphaBlendOp = VK_BLEND_OP_ADD,
504 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
505 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
506 };
507
508 return CreateWrappedPipelineImpl(device, renderpass, layout, shaders,
509 color_blend_attachment_disabled);
510}
511
512vk::Pipeline CreateWrappedPremultipliedBlendingPipeline(
513 const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
514 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders) {
515 constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_premultiplied{
516 .blendEnable = VK_TRUE,
517 .srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
518 .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
519 .colorBlendOp = VK_BLEND_OP_ADD,
520 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
521 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
522 .alphaBlendOp = VK_BLEND_OP_ADD,
523 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
524 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
525 };
526
527 return CreateWrappedPipelineImpl(device, renderpass, layout, shaders,
528 color_blend_attachment_premultiplied);
529}
530
531vk::Pipeline CreateWrappedCoverageBlendingPipeline(
532 const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
533 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders) {
534 constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_coverage{
535 .blendEnable = VK_TRUE,
536 .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
537 .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
538 .colorBlendOp = VK_BLEND_OP_ADD,
539 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
540 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
541 .alphaBlendOp = VK_BLEND_OP_ADD,
542 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
543 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
544 };
545
546 return CreateWrappedPipelineImpl(device, renderpass, layout, shaders,
547 color_blend_attachment_coverage);
548}
549
518VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images, 550VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images,
519 VkSampler sampler, VkImageView view, 551 VkSampler sampler, VkImageView view,
520 VkDescriptorSet set, u32 binding) { 552 VkDescriptorSet set, u32 binding) {
diff --git a/src/video_core/renderer_vulkan/present/util.h b/src/video_core/renderer_vulkan/present/util.h
index 1104aaa15..5b22f0fa8 100644
--- a/src/video_core/renderer_vulkan/present/util.h
+++ b/src/video_core/renderer_vulkan/present/util.h
@@ -42,8 +42,13 @@ vk::PipelineLayout CreateWrappedPipelineLayout(const Device& device,
42 vk::DescriptorSetLayout& layout); 42 vk::DescriptorSetLayout& layout);
43vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass, 43vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass,
44 vk::PipelineLayout& layout, 44 vk::PipelineLayout& layout,
45 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders, 45 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders);
46 bool enable_blending = false); 46vk::Pipeline CreateWrappedPremultipliedBlendingPipeline(
47 const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
48 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders);
49vk::Pipeline CreateWrappedCoverageBlendingPipeline(
50 const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
51 std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders);
47VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images, 52VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images,
48 VkSampler sampler, VkImageView view, 53 VkSampler sampler, VkImageView view,
49 VkDescriptorSet set, u32 binding); 54 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 c5db0230d..22ffacf11 100644
--- a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp
+++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp
@@ -22,7 +22,7 @@ WindowAdaptPass::WindowAdaptPass(const Device& device_, VkFormat frame_format,
22 CreatePipelineLayout(); 22 CreatePipelineLayout();
23 CreateVertexShader(); 23 CreateVertexShader();
24 CreateRenderPass(frame_format); 24 CreateRenderPass(frame_format);
25 CreatePipeline(); 25 CreatePipelines();
26} 26}
27 27
28WindowAdaptPass::~WindowAdaptPass() = default; 28WindowAdaptPass::~WindowAdaptPass() = default;
@@ -34,7 +34,6 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s
34 34
35 const VkFramebuffer host_framebuffer{*dst->framebuffer}; 35 const VkFramebuffer host_framebuffer{*dst->framebuffer};
36 const VkRenderPass renderpass{*render_pass}; 36 const VkRenderPass renderpass{*render_pass};
37 const VkPipeline graphics_pipeline{*pipeline};
38 const VkPipelineLayout graphics_pipeline_layout{*pipeline_layout}; 37 const VkPipelineLayout graphics_pipeline_layout{*pipeline_layout};
39 const VkExtent2D render_area{ 38 const VkExtent2D render_area{
40 .width = dst->width, 39 .width = dst->width,
@@ -44,9 +43,23 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s
44 const size_t layer_count = configs.size(); 43 const size_t layer_count = configs.size();
45 std::vector<PresentPushConstants> push_constants(layer_count); 44 std::vector<PresentPushConstants> push_constants(layer_count);
46 std::vector<VkDescriptorSet> descriptor_sets(layer_count); 45 std::vector<VkDescriptorSet> descriptor_sets(layer_count);
46 std::vector<VkPipeline> graphics_pipelines(layer_count);
47 47
48 auto layer_it = layers.begin(); 48 auto layer_it = layers.begin();
49 for (size_t i = 0; i < layer_count; i++) { 49 for (size_t i = 0; i < layer_count; i++) {
50 switch (configs[i].blending) {
51 case Tegra::BlendMode::Opaque:
52 default:
53 graphics_pipelines[i] = *opaque_pipeline;
54 break;
55 case Tegra::BlendMode::Premultiplied:
56 graphics_pipelines[i] = *premultiplied_pipeline;
57 break;
58 case Tegra::BlendMode::Coverage:
59 graphics_pipelines[i] = *coverage_pipeline;
60 break;
61 }
62
50 layer_it->ConfigureDraw(&push_constants[i], &descriptor_sets[i], rasterizer, *sampler, 63 layer_it->ConfigureDraw(&push_constants[i], &descriptor_sets[i], rasterizer, *sampler,
51 image_index, configs[i], layout); 64 image_index, configs[i], layout);
52 layer_it++; 65 layer_it++;
@@ -77,8 +90,8 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s
77 BeginRenderPass(cmdbuf, renderpass, host_framebuffer, render_area); 90 BeginRenderPass(cmdbuf, renderpass, host_framebuffer, render_area);
78 cmdbuf.ClearAttachments({clear_attachment}, {clear_rect}); 91 cmdbuf.ClearAttachments({clear_attachment}, {clear_rect});
79 92
80 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline);
81 for (size_t i = 0; i < layer_count; i++) { 93 for (size_t i = 0; i < layer_count; i++) {
94 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipelines[i]);
82 cmdbuf.PushConstants(graphics_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 95 cmdbuf.PushConstants(graphics_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT,
83 push_constants[i]); 96 push_constants[i]);
84 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_layout, 0, 97 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_layout, 0,
@@ -129,9 +142,13 @@ void WindowAdaptPass::CreateRenderPass(VkFormat frame_format) {
129 render_pass = CreateWrappedRenderPass(device, frame_format, VK_IMAGE_LAYOUT_UNDEFINED); 142 render_pass = CreateWrappedRenderPass(device, frame_format, VK_IMAGE_LAYOUT_UNDEFINED);
130} 143}
131 144
132void WindowAdaptPass::CreatePipeline() { 145void WindowAdaptPass::CreatePipelines() {
133 pipeline = CreateWrappedPipeline(device, render_pass, pipeline_layout, 146 opaque_pipeline = CreateWrappedPipeline(device, render_pass, pipeline_layout,
134 std::tie(vertex_shader, fragment_shader), false); 147 std::tie(vertex_shader, fragment_shader));
148 premultiplied_pipeline = CreateWrappedPremultipliedBlendingPipeline(
149 device, render_pass, pipeline_layout, std::tie(vertex_shader, fragment_shader));
150 coverage_pipeline = CreateWrappedCoverageBlendingPipeline(
151 device, render_pass, pipeline_layout, std::tie(vertex_shader, fragment_shader));
135} 152}
136 153
137} // namespace Vulkan 154} // 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 0e2edfc31..cf667a4fc 100644
--- a/src/video_core/renderer_vulkan/present/window_adapt_pass.h
+++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.h
@@ -42,7 +42,7 @@ private:
42 void CreatePipelineLayout(); 42 void CreatePipelineLayout();
43 void CreateVertexShader(); 43 void CreateVertexShader();
44 void CreateRenderPass(VkFormat frame_format); 44 void CreateRenderPass(VkFormat frame_format);
45 void CreatePipeline(); 45 void CreatePipelines();
46 46
47private: 47private:
48 const Device& device; 48 const Device& device;
@@ -52,7 +52,9 @@ private:
52 vk::ShaderModule vertex_shader; 52 vk::ShaderModule vertex_shader;
53 vk::ShaderModule fragment_shader; 53 vk::ShaderModule fragment_shader;
54 vk::RenderPass render_pass; 54 vk::RenderPass render_pass;
55 vk::Pipeline pipeline; 55 vk::Pipeline opaque_pipeline;
56 vk::Pipeline premultiplied_pipeline;
57 vk::Pipeline coverage_pipeline;
56}; 58};
57 59
58} // namespace Vulkan 60} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 48a105327..d50417116 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -19,7 +19,9 @@
19#include "core/core_timing.h" 19#include "core/core_timing.h"
20#include "core/frontend/graphics_context.h" 20#include "core/frontend/graphics_context.h"
21#include "core/telemetry_session.h" 21#include "core/telemetry_session.h"
22#include "video_core/capture.h"
22#include "video_core/gpu.h" 23#include "video_core/gpu.h"
24#include "video_core/present.h"
23#include "video_core/renderer_vulkan/present/util.h" 25#include "video_core/renderer_vulkan/present/util.h"
24#include "video_core/renderer_vulkan/renderer_vulkan.h" 26#include "video_core/renderer_vulkan/renderer_vulkan.h"
25#include "video_core/renderer_vulkan/vk_blit_screen.h" 27#include "video_core/renderer_vulkan/vk_blit_screen.h"
@@ -38,6 +40,20 @@
38 40
39namespace Vulkan { 41namespace Vulkan {
40namespace { 42namespace {
43
44constexpr VkExtent2D CaptureImageSize{
45 .width = VideoCore::Capture::LinearWidth,
46 .height = VideoCore::Capture::LinearHeight,
47};
48
49constexpr VkExtent3D CaptureImageExtent{
50 .width = VideoCore::Capture::LinearWidth,
51 .height = VideoCore::Capture::LinearHeight,
52 .depth = VideoCore::Capture::LinearDepth,
53};
54
55constexpr VkFormat CaptureFormat = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
56
41std::string GetReadableVersion(u32 version) { 57std::string GetReadableVersion(u32 version) {
42 return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), 58 return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version),
43 VK_VERSION_PATCH(version)); 59 VK_VERSION_PATCH(version));
@@ -99,10 +115,15 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
99 render_window.GetFramebufferLayout().height), 115 render_window.GetFramebufferLayout().height),
100 present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, 116 present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain,
101 surface), 117 surface),
102 blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler), 118 blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler,
103 blit_screenshot(device_memory, device, memory_allocator, present_manager, scheduler), 119 PresentFiltersForDisplay),
120 blit_capture(device_memory, device, memory_allocator, present_manager, scheduler,
121 PresentFiltersForDisplay),
122 blit_applet(device_memory, device, memory_allocator, present_manager, scheduler,
123 PresentFiltersForAppletCapture),
104 rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, 124 rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker,
105 scheduler) { 125 scheduler),
126 applet_frame() {
106 if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { 127 if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) {
107 turbo_mode.emplace(instance, dld); 128 turbo_mode.emplace(instance, dld);
108 scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); }); 129 scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); });
@@ -125,6 +146,8 @@ void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebu
125 146
126 SCOPE_EXIT({ render_window.OnFrameDisplayed(); }); 147 SCOPE_EXIT({ render_window.OnFrameDisplayed(); });
127 148
149 RenderAppletCaptureLayer(framebuffers);
150
128 if (!render_window.IsShown()) { 151 if (!render_window.IsShown()) {
129 return; 152 return;
130 } 153 }
@@ -167,30 +190,20 @@ void RendererVulkan::Report() const {
167 telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); 190 telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions);
168} 191}
169 192
170void Vulkan::RendererVulkan::RenderScreenshot( 193vk::Buffer RendererVulkan::RenderToBuffer(std::span<const Tegra::FramebufferConfig> framebuffers,
171 std::span<const Tegra::FramebufferConfig> framebuffers) { 194 const Layout::FramebufferLayout& layout, VkFormat format,
172 if (!renderer_settings.screenshot_requested) { 195 VkDeviceSize buffer_size) {
173 return;
174 }
175
176 constexpr VkFormat ScreenshotFormat{VK_FORMAT_B8G8R8A8_UNORM};
177 const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout};
178
179 auto frame = [&]() { 196 auto frame = [&]() {
180 Frame f{}; 197 Frame f{};
181 f.image = CreateWrappedImage(memory_allocator, VkExtent2D{layout.width, layout.height}, 198 f.image =
182 ScreenshotFormat); 199 CreateWrappedImage(memory_allocator, VkExtent2D{layout.width, layout.height}, format);
183 f.image_view = CreateWrappedImageView(device, f.image, ScreenshotFormat); 200 f.image_view = CreateWrappedImageView(device, f.image, format);
184 f.framebuffer = blit_screenshot.CreateFramebuffer(layout, *f.image_view, ScreenshotFormat); 201 f.framebuffer = blit_capture.CreateFramebuffer(layout, *f.image_view, format);
185 return f; 202 return f;
186 }(); 203 }();
187 204
188 blit_screenshot.DrawToFrame(rasterizer, &frame, framebuffers, layout, 1, 205 auto dst_buffer = CreateWrappedBuffer(memory_allocator, buffer_size, MemoryUsage::Download);
189 VK_FORMAT_B8G8R8A8_UNORM); 206 blit_capture.DrawToFrame(rasterizer, &frame, framebuffers, layout, 1, format);
190
191 const auto dst_buffer = CreateWrappedBuffer(
192 memory_allocator, static_cast<VkDeviceSize>(layout.width * layout.height * 4),
193 MemoryUsage::Download);
194 207
195 scheduler.RequestOutsideRenderPassOperationContext(); 208 scheduler.RequestOutsideRenderPassOperationContext();
196 scheduler.Record([&](vk::CommandBuffer cmdbuf) { 209 scheduler.Record([&](vk::CommandBuffer cmdbuf) {
@@ -198,15 +211,68 @@ void Vulkan::RendererVulkan::RenderScreenshot(
198 VkExtent3D{layout.width, layout.height, 1}); 211 VkExtent3D{layout.width, layout.height, 1});
199 }); 212 });
200 213
201 // Ensure the copy is fully completed before saving the screenshot 214 // Ensure the copy is fully completed before saving the capture
202 scheduler.Finish(); 215 scheduler.Finish();
203 216
204 // Copy backing image data to the QImage screenshot buffer 217 // Copy backing image data to the capture buffer
205 dst_buffer.Invalidate(); 218 dst_buffer.Invalidate();
219 return dst_buffer;
220}
221
222void RendererVulkan::RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers) {
223 if (!renderer_settings.screenshot_requested) {
224 return;
225 }
226
227 const auto& layout{renderer_settings.screenshot_framebuffer_layout};
228 const auto dst_buffer = RenderToBuffer(framebuffers, layout, VK_FORMAT_B8G8R8A8_UNORM,
229 layout.width * layout.height * 4);
230
206 std::memcpy(renderer_settings.screenshot_bits, dst_buffer.Mapped().data(), 231 std::memcpy(renderer_settings.screenshot_bits, dst_buffer.Mapped().data(),
207 dst_buffer.Mapped().size()); 232 dst_buffer.Mapped().size());
208 renderer_settings.screenshot_complete_callback(false); 233 renderer_settings.screenshot_complete_callback(false);
209 renderer_settings.screenshot_requested = false; 234 renderer_settings.screenshot_requested = false;
210} 235}
211 236
237std::vector<u8> RendererVulkan::GetAppletCaptureBuffer() {
238 using namespace VideoCore::Capture;
239
240 std::vector<u8> out(VideoCore::Capture::TiledSize);
241
242 if (!applet_frame.image) {
243 return out;
244 }
245
246 const auto dst_buffer =
247 CreateWrappedBuffer(memory_allocator, VideoCore::Capture::TiledSize, MemoryUsage::Download);
248
249 scheduler.RequestOutsideRenderPassOperationContext();
250 scheduler.Record([&](vk::CommandBuffer cmdbuf) {
251 DownloadColorImage(cmdbuf, *applet_frame.image, *dst_buffer, CaptureImageExtent);
252 });
253
254 // Ensure the copy is fully completed before writing the capture
255 scheduler.Finish();
256
257 // Swizzle image data to the capture buffer
258 dst_buffer.Invalidate();
259 Tegra::Texture::SwizzleTexture(out, dst_buffer.Mapped(), BytesPerPixel, LinearWidth,
260 LinearHeight, LinearDepth, BlockHeight, BlockDepth);
261
262 return out;
263}
264
265void RendererVulkan::RenderAppletCaptureLayer(
266 std::span<const Tegra::FramebufferConfig> framebuffers) {
267 if (!applet_frame.image) {
268 applet_frame.image = CreateWrappedImage(memory_allocator, CaptureImageSize, CaptureFormat);
269 applet_frame.image_view = CreateWrappedImageView(device, applet_frame.image, CaptureFormat);
270 applet_frame.framebuffer = blit_applet.CreateFramebuffer(
271 VideoCore::Capture::Layout, *applet_frame.image_view, CaptureFormat);
272 }
273
274 blit_applet.DrawToFrame(rasterizer, &applet_frame, framebuffers, VideoCore::Capture::Layout, 1,
275 CaptureFormat);
276}
277
212} // namespace Vulkan 278} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index c6d8a0f21..fb9d83412 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -48,6 +48,8 @@ public:
48 48
49 void Composite(std::span<const Tegra::FramebufferConfig> framebuffers) override; 49 void Composite(std::span<const Tegra::FramebufferConfig> framebuffers) override;
50 50
51 std::vector<u8> GetAppletCaptureBuffer() override;
52
51 VideoCore::RasterizerInterface* ReadRasterizer() override { 53 VideoCore::RasterizerInterface* ReadRasterizer() override {
52 return &rasterizer; 54 return &rasterizer;
53 } 55 }
@@ -59,7 +61,11 @@ public:
59private: 61private:
60 void Report() const; 62 void Report() const;
61 63
64 vk::Buffer RenderToBuffer(std::span<const Tegra::FramebufferConfig> framebuffers,
65 const Layout::FramebufferLayout& layout, VkFormat format,
66 VkDeviceSize buffer_size);
62 void RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers); 67 void RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers);
68 void RenderAppletCaptureLayer(std::span<const Tegra::FramebufferConfig> framebuffers);
63 69
64 Core::TelemetrySession& telemetry_session; 70 Core::TelemetrySession& telemetry_session;
65 Tegra::MaxwellDeviceMemoryManager& device_memory; 71 Tegra::MaxwellDeviceMemoryManager& device_memory;
@@ -79,9 +85,12 @@ private:
79 Swapchain swapchain; 85 Swapchain swapchain;
80 PresentManager present_manager; 86 PresentManager present_manager;
81 BlitScreen blit_swapchain; 87 BlitScreen blit_swapchain;
82 BlitScreen blit_screenshot; 88 BlitScreen blit_capture;
89 BlitScreen blit_applet;
83 RasterizerVulkan rasterizer; 90 RasterizerVulkan rasterizer;
84 std::optional<TurboMode> turbo_mode; 91 std::optional<TurboMode> turbo_mode;
92
93 Frame applet_frame;
85}; 94};
86 95
87} // namespace Vulkan 96} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index 2275fcc46..b7797f833 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -2,6 +2,7 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "video_core/framebuffer_config.h" 4#include "video_core/framebuffer_config.h"
5#include "video_core/present.h"
5#include "video_core/renderer_vulkan/present/filters.h" 6#include "video_core/renderer_vulkan/present/filters.h"
6#include "video_core/renderer_vulkan/present/layer.h" 7#include "video_core/renderer_vulkan/present/layer.h"
7#include "video_core/renderer_vulkan/vk_blit_screen.h" 8#include "video_core/renderer_vulkan/vk_blit_screen.h"
@@ -12,9 +13,9 @@ namespace Vulkan {
12 13
13BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, const Device& device_, 14BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, const Device& device_,
14 MemoryAllocator& memory_allocator_, PresentManager& present_manager_, 15 MemoryAllocator& memory_allocator_, PresentManager& present_manager_,
15 Scheduler& scheduler_) 16 Scheduler& scheduler_, const PresentFilters& filters_)
16 : device_memory{device_memory_}, device{device_}, memory_allocator{memory_allocator_}, 17 : device_memory{device_memory_}, device{device_}, memory_allocator{memory_allocator_},
17 present_manager{present_manager_}, scheduler{scheduler_}, image_count{1}, 18 present_manager{present_manager_}, scheduler{scheduler_}, filters{filters_}, image_count{1},
18 swapchain_view_format{VK_FORMAT_B8G8R8A8_UNORM} {} 19 swapchain_view_format{VK_FORMAT_B8G8R8A8_UNORM} {}
19 20
20BlitScreen::~BlitScreen() = default; 21BlitScreen::~BlitScreen() = default;
@@ -27,7 +28,7 @@ void BlitScreen::WaitIdle() {
27 28
28void BlitScreen::SetWindowAdaptPass() { 29void BlitScreen::SetWindowAdaptPass() {
29 layers.clear(); 30 layers.clear();
30 scaling_filter = Settings::values.scaling_filter.GetValue(); 31 scaling_filter = filters.get_scaling_filter();
31 32
32 switch (scaling_filter) { 33 switch (scaling_filter) {
33 case Settings::ScalingFilter::NearestNeighbor: 34 case Settings::ScalingFilter::NearestNeighbor:
@@ -59,7 +60,7 @@ void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame,
59 bool presentation_recreate_required = false; 60 bool presentation_recreate_required = false;
60 61
61 // Recreate dynamic resources if the adapting filter changed 62 // Recreate dynamic resources if the adapting filter changed
62 if (!window_adapt || scaling_filter != Settings::values.scaling_filter.GetValue()) { 63 if (!window_adapt || scaling_filter != filters.get_scaling_filter()) {
63 resource_update_required = true; 64 resource_update_required = true;
64 } 65 }
65 66
@@ -102,7 +103,7 @@ void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame,
102 103
103 while (layers.size() < framebuffers.size()) { 104 while (layers.size() < framebuffers.size()) {
104 layers.emplace_back(device, memory_allocator, scheduler, device_memory, image_count, 105 layers.emplace_back(device, memory_allocator, scheduler, device_memory, image_count,
105 window_size, window_adapt->GetDescriptorSetLayout()); 106 window_size, window_adapt->GetDescriptorSetLayout(), filters);
106 } 107 }
107 108
108 // Perform the draw 109 // Perform the draw
@@ -119,8 +120,7 @@ vk::Framebuffer BlitScreen::CreateFramebuffer(const Layout::FramebufferLayout& l
119 VkFormat current_view_format) { 120 VkFormat current_view_format) {
120 const bool format_updated = 121 const bool format_updated =
121 std::exchange(swapchain_view_format, current_view_format) != current_view_format; 122 std::exchange(swapchain_view_format, current_view_format) != current_view_format;
122 if (!window_adapt || scaling_filter != Settings::values.scaling_filter.GetValue() || 123 if (!window_adapt || scaling_filter != filters.get_scaling_filter() || format_updated) {
123 format_updated) {
124 WaitIdle(); 124 WaitIdle();
125 SetWindowAdaptPass(); 125 SetWindowAdaptPass();
126 } 126 }
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h
index cbdf2d5d0..531c57fc5 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.h
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.h
@@ -16,6 +16,8 @@ namespace Core {
16class System; 16class System;
17} 17}
18 18
19struct PresentFilters;
20
19namespace Tegra { 21namespace Tegra {
20struct FramebufferConfig; 22struct FramebufferConfig;
21} 23}
@@ -47,7 +49,7 @@ class BlitScreen {
47public: 49public:
48 explicit BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory, const Device& device, 50 explicit BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory, const Device& device,
49 MemoryAllocator& memory_allocator, PresentManager& present_manager, 51 MemoryAllocator& memory_allocator, PresentManager& present_manager,
50 Scheduler& scheduler); 52 Scheduler& scheduler, const PresentFilters& filters);
51 ~BlitScreen(); 53 ~BlitScreen();
52 54
53 void DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame, 55 void DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame,
@@ -70,6 +72,7 @@ private:
70 MemoryAllocator& memory_allocator; 72 MemoryAllocator& memory_allocator;
71 PresentManager& present_manager; 73 PresentManager& present_manager;
72 Scheduler& scheduler; 74 Scheduler& scheduler;
75 const PresentFilters& filters;
73 std::size_t image_count{}; 76 std::size_t image_count{};
74 std::size_t image_index{}; 77 std::size_t image_index{};
75 VkFormat swapchain_view_format{}; 78 VkFormat swapchain_view_format{};