summaryrefslogtreecommitdiff
path: root/src/video_core/renderer_vulkan
diff options
context:
space:
mode:
authorGravatar Liam2024-01-18 11:44:13 -0500
committerGravatar Liam2024-01-31 11:27:21 -0500
commit9bdf09bd768f73073e9d1cbc65febfd7f7955db3 (patch)
tree7d29d4c4f61f4c0272056af2370a2c75a769f7d6 /src/video_core/renderer_vulkan
parentrenderer_opengl: split up blit screen resources into antialias and window ada... (diff)
downloadyuzu-9bdf09bd768f73073e9d1cbc65febfd7f7955db3.tar.gz
yuzu-9bdf09bd768f73073e9d1cbc65febfd7f7955db3.tar.xz
yuzu-9bdf09bd768f73073e9d1cbc65febfd7f7955db3.zip
renderer_vulkan: implement layer stack composition
Diffstat (limited to 'src/video_core/renderer_vulkan')
-rw-r--r--src/video_core/renderer_vulkan/present/filters.cpp34
-rw-r--r--src/video_core/renderer_vulkan/present/filters.h24
-rw-r--r--src/video_core/renderer_vulkan/present/layer.cpp336
-rw-r--r--src/video_core/renderer_vulkan/present/layer.h92
-rw-r--r--src/video_core/renderer_vulkan/present/present_push_constants.h34
-rw-r--r--src/video_core/renderer_vulkan/present/util.cpp31
-rw-r--r--src/video_core/renderer_vulkan/present/util.h6
-rw-r--r--src/video_core/renderer_vulkan/present/window_adapt_pass.cpp503
-rw-r--r--src/video_core/renderer_vulkan/present/window_adapt_pass.h29
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp8
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp378
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h59
13 files changed, 624 insertions, 912 deletions
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
30std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device, 30std::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
38std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device, 36std::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
46std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device, 41std::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
54std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device, 46std::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
62std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device, 51std::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
8namespace Vulkan { 8namespace Vulkan {
9 9
10std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device, 10class MemoryAllocator;
11 const MemoryAllocator& memory_allocator,
12 size_t image_count, VkFormat frame_format);
13 11
14std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device, 12std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device, VkFormat frame_format);
15 const MemoryAllocator& memory_allocator, 13std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device, VkFormat frame_format);
16 size_t image_count, VkFormat frame_format); 14std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device, VkFormat frame_format);
17 15std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device, VkFormat frame_format);
18std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device, 16std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device, VkFormat frame_format);
19 const MemoryAllocator& memory_allocator,
20 size_t image_count, VkFormat frame_format);
21
22std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device,
23 const MemoryAllocator& memory_allocator,
24 size_t image_count, VkFormat frame_format);
25
26std::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
17namespace Vulkan {
18
19namespace {
20
21u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) {
22 using namespace VideoCore::Surface;
23 return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format));
24}
25
26std::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
31VkFormat 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
49Layer::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
61Layer::~Layer() {
62 ReleaseRawImages();
63}
64
65void 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
115void Layer::CreateDescriptorPool() {
116 descriptor_pool = CreateWrappedDescriptorPool(device, image_count, image_count);
117}
118
119void Layer::CreateDescriptorSets(VkDescriptorSetLayout layout) {
120 const std::vector layouts(image_count, layout);
121 descriptor_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts);
122}
123
124void 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
140void 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
153void Layer::CreateFSR(VkExtent2D output_size) {
154 fsr = std::make_unique<FSR>(device, memory_allocator, image_count, output_size);
155}
156
157void 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
173void 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
198void Layer::ReleaseRawImages() {
199 for (const u64 tick : resource_ticks) {
200 scheduler.Wait(tick);
201 }
202 raw_images.clear();
203 buffer.reset();
204}
205
206u64 Layer::CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const {
207 return GetSizeInBytes(framebuffer) * image_count;
208}
209
210u64 Layer::GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer,
211 size_t image_index) const {
212 return GetSizeInBytes(framebuffer) * image_index;
213}
214
215void 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
221void 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
236void 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
259void 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
10namespace Layout {
11struct FramebufferLayout;
12}
13
14namespace Tegra {
15struct FramebufferConfig;
16}
17
18namespace Service::android {
19enum class PixelFormat : u32;
20}
21
22namespace Settings {
23enum class AntiAliasing : u32;
24}
25
26namespace Vulkan {
27
28class AntiAliasPass;
29class Device;
30class FSR;
31class MemoryAllocator;
32struct PresentPushConstants;
33class RasterizerVulkan;
34class Scheduler;
35
36class Layer final {
37public:
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
49private:
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
69private:
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
8namespace Vulkan {
9
10struct 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
18static 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
27struct PresentPushConstants {
28 std::array<f32, 4 * 4> modelview_matrix;
29 std::array<ScreenRectVertex, 4> vertices;
30};
31
32static_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
116vk::RenderPass CreateWrappedRenderPass(const Device& device, VkFormat format) { 116vk::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
286vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass, 287vk::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
20void ClearColorImage(vk::CommandBuffer& cmdbuf, VkImage image); 20void ClearColorImage(vk::CommandBuffer& cmdbuf, VkImage image);
21 21
22vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format); 22vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format);
23vk::RenderPass CreateWrappedRenderPass(const Device& device, VkFormat format); 23vk::RenderPass CreateWrappedRenderPass(const Device& device, VkFormat format,
24 VkImageLayout initial_layout = VK_IMAGE_LAYOUT_GENERAL);
24vk::Framebuffer CreateWrappedFramebuffer(const Device& device, vk::RenderPass& render_pass, 25vk::Framebuffer CreateWrappedFramebuffer(const Device& device, vk::RenderPass& render_pass,
25 vk::ImageView& dest_image, VkExtent2D extent); 26 vk::ImageView& dest_image, VkExtent2D extent);
26vk::Sampler CreateWrappedSampler(const Device& device, VkFilter filter = VK_FILTER_LINEAR); 27vk::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);
38vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass, 39vk::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);
41VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images, 43VkWriteDescriptorSet 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
15namespace Vulkan { 16namespace Vulkan {
16 17
17namespace { 18WindowAdaptPass::WindowAdaptPass(const Device& device_, VkFormat frame_format,
18 19 vk::Sampler&& sampler_, vk::ShaderModule&& fragment_shader_)
19struct 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
52std::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
63struct WindowAdaptPass::BufferData {
64 struct {
65 std::array<f32, 4 * 4> modelview_matrix;
66 } uniform;
67
68 std::array<ScreenRectVertex, 4> vertices;
69};
70
71WindowAdaptPass::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
85WindowAdaptPass::~WindowAdaptPass() = default; 28WindowAdaptPass::~WindowAdaptPass() = default;
86 29
87void WindowAdaptPass::Draw(Scheduler& scheduler, size_t image_index, VkImageView src_image_view, 30void 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
147VkRenderPass WindowAdaptPass::GetRenderPass() { 93VkDescriptorSetLayout WindowAdaptPass::GetDescriptorSetLayout() {
148 return *render_pass; 94 return *descriptor_set_layout;
149} 95}
150 96
151void WindowAdaptPass::CreateDescriptorPool(size_t num_images) { 97VkRenderPass 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
174void WindowAdaptPass::CreateDescriptorSetLayout() { 101void 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
203void 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
208void 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
224void WindowAdaptPass::CreateRenderPass(VkFormat frame_format) { 106void 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
280void WindowAdaptPass::CreateVertexShader() {
281 vertex_shader = BuildShader(device, VULKAN_PRESENT_VERT_SPV);
282}
283
284void 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
297void 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
303void 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
318void WindowAdaptPass::UpdateDescriptorSet(size_t image_index, VkImageView image_view) { 124void 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
360void WindowAdaptPass::ConfigureLayout(size_t image_index, VkImageView image_view, 128void 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
373void WindowAdaptPass::CreatePipeline() { 132void 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
19class Device; 21class Device;
20struct Frame; 22struct Frame;
21class MemoryAllocator; 23class Layer;
22class Scheduler; 24class Scheduler;
25class RasterizerVulkan;
23 26
24class WindowAdaptPass final { 27class WindowAdaptPass final {
25public: 28public:
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
37private: 40private:
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
57private: 47private:
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
166void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& framebuffer) { 166void 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:
59private: 59private:
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
31namespace Vulkan { 11namespace Vulkan {
32 12
33namespace {
34
35u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) {
36 using namespace VideoCore::Surface;
37 return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format));
38}
39
40std::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
45VkFormat 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
63BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, const Device& device_, 13BlitScreen::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
78void BlitScreen::SetWindowAdaptPass(const Layout::FramebufferLayout& layout) { 28void 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
112void 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
137void 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
263void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame, 53void 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
348void 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
364void BlitScreen::ReleaseRawImages() {
365 for (const u64 tick : resource_ticks) {
366 scheduler.Wait(tick);
367 }
368 raw_images.clear();
369 buffer.reset();
370}
371
372void 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
388void 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
451u64 BlitScreen::CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const {
452 return GetSizeInBytes(framebuffer) * image_count;
453}
454
455u64 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 {
14class System; 16class System;
15} 17}
16 18
17namespace Core::Frontend {
18class EmuWindow;
19}
20
21namespace Tegra { 19namespace Tegra {
22struct FramebufferConfig; 20struct FramebufferConfig;
23} 21}
24 22
25namespace VideoCore {
26class RasterizerInterface;
27}
28
29namespace Service::android {
30enum class PixelFormat : u32;
31}
32
33namespace Settings { 23namespace Settings {
34enum class AntiAliasing : u32;
35enum class ScalingFilter : u32; 24enum class ScalingFilter : u32;
36} // namespace Settings 25} // namespace Settings
37 26
38namespace Vulkan { 27namespace Vulkan {
39 28
40class AntiAliasPass;
41class Device; 29class Device;
42class FSR;
43class RasterizerVulkan; 30class RasterizerVulkan;
44class Scheduler; 31class Scheduler;
45class PresentManager; 32class 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
75private: 62private:
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