summaryrefslogtreecommitdiff
path: root/src/video_core/renderer_vulkan
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2020-12-30 02:25:23 -0300
committerGravatar ReinUsesLisp2020-12-30 03:38:50 -0300
commit9764c13d6d2977903f407761b27d847c0056e1c4 (patch)
treef6f5d6d6379b0404147969e7d1f548ed3d49ca01 /src/video_core/renderer_vulkan
parentvideo_core: Add a delayed destruction ring abstraction (diff)
downloadyuzu-9764c13d6d2977903f407761b27d847c0056e1c4.tar.gz
yuzu-9764c13d6d2977903f407761b27d847c0056e1c4.tar.xz
yuzu-9764c13d6d2977903f407761b27d847c0056e1c4.zip
video_core: Rewrite the texture cache
The current texture cache has several points that hurt maintainability and performance. It's easy to break unrelated parts of the cache when doing minor changes. The cache can easily forget valuable information about the cached textures by CPU writes or simply by its normal usage.The current texture cache has several points that hurt maintainability and performance. It's easy to break unrelated parts of the cache when doing minor changes. The cache can easily forget valuable information about the cached textures by CPU writes or simply by its normal usage. This commit aims to address those issues.
Diffstat (limited to 'src/video_core/renderer_vulkan')
-rw-r--r--src/video_core/renderer_vulkan/blit_image.cpp624
-rw-r--r--src/video_core/renderer_vulkan/blit_image.h97
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.cpp1
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.h1
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp30
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.h2
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp13
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h3
-rw-r--r--src/video_core/renderer_vulkan/shaders/blit.frag24
-rw-r--r--src/video_core/renderer_vulkan/shaders/blit.vert28
-rw-r--r--src/video_core/renderer_vulkan/shaders/quad_array.comp37
-rw-r--r--src/video_core/renderer_vulkan/shaders/quad_indexed.comp50
-rw-r--r--src/video_core/renderer_vulkan/shaders/uint8.comp33
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp301
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp67
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h10
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.cpp327
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_device.cpp110
-rw-r--r--src/video_core/renderer_vulkan/vk_device.h34
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.cpp7
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.h6
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp64
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.h26
-rw-r--r--src/video_core/renderer_vulkan/vk_image.cpp135
-rw-r--r--src/video_core/renderer_vulkan/vk_image.h84
-rw-r--r--src/video_core/renderer_vulkan/vk_memory_manager.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_memory_manager.h20
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp28
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h16
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp700
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h131
-rw-r--r--src/video_core/renderer_vulkan/vk_renderpass_cache.cpp158
-rw-r--r--src/video_core/renderer_vulkan/vk_renderpass_cache.h70
-rw-r--r--src/video_core/renderer_vulkan/vk_sampler_cache.cpp83
-rw-r--r--src/video_core/renderer_vulkan/vk_sampler_cache.h29
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.cpp79
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.h14
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp6
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.h8
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_util.cpp11
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_util.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_state_tracker.cpp23
-rw-r--r--src/video_core/renderer_vulkan/vk_state_tracker.h8
-rw-r--r--src/video_core/renderer_vulkan/vk_stream_buffer.cpp20
-rw-r--r--src/video_core/renderer_vulkan/vk_stream_buffer.h12
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp1473
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h328
-rw-r--r--src/video_core/renderer_vulkan/vk_update_descriptor.h30
-rw-r--r--src/video_core/renderer_vulkan/wrapper.cpp69
-rw-r--r--src/video_core/renderer_vulkan/wrapper.h117
52 files changed, 2979 insertions, 2582 deletions
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
new file mode 100644
index 000000000..87c8e5693
--- /dev/null
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -0,0 +1,624 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6
7#include "video_core/host_shaders/convert_depth_to_float_frag_spv.h"
8#include "video_core/host_shaders/convert_float_to_depth_frag_spv.h"
9#include "video_core/host_shaders/full_screen_triangle_vert_spv.h"
10#include "video_core/host_shaders/vulkan_blit_color_float_frag_spv.h"
11#include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h"
12#include "video_core/renderer_vulkan/blit_image.h"
13#include "video_core/renderer_vulkan/maxwell_to_vk.h"
14#include "video_core/renderer_vulkan/vk_device.h"
15#include "video_core/renderer_vulkan/vk_scheduler.h"
16#include "video_core/renderer_vulkan/vk_shader_util.h"
17#include "video_core/renderer_vulkan/vk_state_tracker.h"
18#include "video_core/renderer_vulkan/vk_texture_cache.h"
19#include "video_core/renderer_vulkan/vk_update_descriptor.h"
20#include "video_core/renderer_vulkan/wrapper.h"
21#include "video_core/surface.h"
22
23namespace Vulkan {
24
25using VideoCommon::ImageViewType;
26
27namespace {
28struct PushConstants {
29 std::array<float, 2> tex_scale;
30 std::array<float, 2> tex_offset;
31};
32
33template <u32 binding>
34inline constexpr VkDescriptorSetLayoutBinding TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING{
35 .binding = binding,
36 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
37 .descriptorCount = 1,
38 .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
39 .pImmutableSamplers = nullptr,
40};
41constexpr std::array TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS{
42 TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING<0>,
43 TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING<1>,
44};
45constexpr VkDescriptorSetLayoutCreateInfo ONE_TEXTURE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO{
46 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
47 .pNext = nullptr,
48 .flags = 0,
49 .bindingCount = 1,
50 .pBindings = &TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING<0>,
51};
52constexpr VkDescriptorSetLayoutCreateInfo TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_CREATE_INFO{
53 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
54 .pNext = nullptr,
55 .flags = 0,
56 .bindingCount = static_cast<u32>(TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS.size()),
57 .pBindings = TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_BINDINGS.data(),
58};
59constexpr VkPushConstantRange PUSH_CONSTANT_RANGE{
60 .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
61 .offset = 0,
62 .size = sizeof(PushConstants),
63};
64constexpr VkPipelineVertexInputStateCreateInfo PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO{
65 .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
66 .pNext = nullptr,
67 .flags = 0,
68 .vertexBindingDescriptionCount = 0,
69 .pVertexBindingDescriptions = nullptr,
70 .vertexAttributeDescriptionCount = 0,
71 .pVertexAttributeDescriptions = nullptr,
72};
73constexpr VkPipelineInputAssemblyStateCreateInfo PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO{
74 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
75 .pNext = nullptr,
76 .flags = 0,
77 .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
78 .primitiveRestartEnable = VK_FALSE,
79};
80constexpr VkPipelineViewportStateCreateInfo PIPELINE_VIEWPORT_STATE_CREATE_INFO{
81 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
82 .pNext = nullptr,
83 .flags = 0,
84 .viewportCount = 1,
85 .pViewports = nullptr,
86 .scissorCount = 1,
87 .pScissors = nullptr,
88};
89constexpr VkPipelineRasterizationStateCreateInfo PIPELINE_RASTERIZATION_STATE_CREATE_INFO{
90 .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
91 .pNext = nullptr,
92 .flags = 0,
93 .depthClampEnable = VK_FALSE,
94 .rasterizerDiscardEnable = VK_FALSE,
95 .polygonMode = VK_POLYGON_MODE_FILL,
96 .cullMode = VK_CULL_MODE_BACK_BIT,
97 .frontFace = VK_FRONT_FACE_CLOCKWISE,
98 .depthBiasEnable = VK_FALSE,
99 .depthBiasConstantFactor = 0.0f,
100 .depthBiasClamp = 0.0f,
101 .depthBiasSlopeFactor = 0.0f,
102 .lineWidth = 1.0f,
103};
104constexpr VkPipelineMultisampleStateCreateInfo PIPELINE_MULTISAMPLE_STATE_CREATE_INFO{
105 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
106 .pNext = nullptr,
107 .flags = 0,
108 .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
109 .sampleShadingEnable = VK_FALSE,
110 .minSampleShading = 0.0f,
111 .pSampleMask = nullptr,
112 .alphaToCoverageEnable = VK_FALSE,
113 .alphaToOneEnable = VK_FALSE,
114};
115constexpr std::array DYNAMIC_STATES{
116 VK_DYNAMIC_STATE_VIEWPORT,
117 VK_DYNAMIC_STATE_SCISSOR,
118};
119constexpr VkPipelineDynamicStateCreateInfo PIPELINE_DYNAMIC_STATE_CREATE_INFO{
120 .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
121 .pNext = nullptr,
122 .flags = 0,
123 .dynamicStateCount = static_cast<u32>(DYNAMIC_STATES.size()),
124 .pDynamicStates = DYNAMIC_STATES.data(),
125};
126constexpr VkPipelineColorBlendStateCreateInfo PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO{
127 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
128 .pNext = nullptr,
129 .flags = 0,
130 .logicOpEnable = VK_FALSE,
131 .logicOp = VK_LOGIC_OP_CLEAR,
132 .attachmentCount = 0,
133 .pAttachments = nullptr,
134 .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
135};
136constexpr VkPipelineColorBlendAttachmentState PIPELINE_COLOR_BLEND_ATTACHMENT_STATE{
137 .blendEnable = VK_FALSE,
138 .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
139 .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
140 .colorBlendOp = VK_BLEND_OP_ADD,
141 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
142 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
143 .alphaBlendOp = VK_BLEND_OP_ADD,
144 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
145 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
146};
147constexpr VkPipelineColorBlendStateCreateInfo PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO{
148 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
149 .pNext = nullptr,
150 .flags = 0,
151 .logicOpEnable = VK_FALSE,
152 .logicOp = VK_LOGIC_OP_CLEAR,
153 .attachmentCount = 1,
154 .pAttachments = &PIPELINE_COLOR_BLEND_ATTACHMENT_STATE,
155 .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
156};
157constexpr VkPipelineDepthStencilStateCreateInfo PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO{
158 .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
159 .pNext = nullptr,
160 .flags = 0,
161 .depthTestEnable = VK_TRUE,
162 .depthWriteEnable = VK_TRUE,
163 .depthCompareOp = VK_COMPARE_OP_ALWAYS,
164 .depthBoundsTestEnable = VK_FALSE,
165 .stencilTestEnable = VK_FALSE,
166 .front = VkStencilOpState{},
167 .back = VkStencilOpState{},
168 .minDepthBounds = 0.0f,
169 .maxDepthBounds = 0.0f,
170};
171
172template <VkFilter filter>
173inline constexpr VkSamplerCreateInfo SAMPLER_CREATE_INFO{
174 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
175 .pNext = nullptr,
176 .flags = 0,
177 .magFilter = filter,
178 .minFilter = filter,
179 .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
180 .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
181 .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
182 .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
183 .mipLodBias = 0.0f,
184 .anisotropyEnable = VK_FALSE,
185 .maxAnisotropy = 0.0f,
186 .compareEnable = VK_FALSE,
187 .compareOp = VK_COMPARE_OP_NEVER,
188 .minLod = 0.0f,
189 .maxLod = 0.0f,
190 .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
191 .unnormalizedCoordinates = VK_TRUE,
192};
193
194constexpr VkPipelineLayoutCreateInfo PipelineLayoutCreateInfo(
195 const VkDescriptorSetLayout* set_layout) {
196 return VkPipelineLayoutCreateInfo{
197 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
198 .pNext = nullptr,
199 .flags = 0,
200 .setLayoutCount = 1,
201 .pSetLayouts = set_layout,
202 .pushConstantRangeCount = 1,
203 .pPushConstantRanges = &PUSH_CONSTANT_RANGE,
204 };
205}
206
207constexpr VkPipelineShaderStageCreateInfo PipelineShaderStageCreateInfo(VkShaderStageFlagBits stage,
208 VkShaderModule shader) {
209 return VkPipelineShaderStageCreateInfo{
210 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
211 .pNext = nullptr,
212 .flags = 0,
213 .stage = stage,
214 .module = shader,
215 .pName = "main",
216 .pSpecializationInfo = nullptr,
217 };
218}
219
220constexpr std::array<VkPipelineShaderStageCreateInfo, 2> MakeStages(
221 VkShaderModule vertex_shader, VkShaderModule fragment_shader) {
222 return std::array{
223 PipelineShaderStageCreateInfo(VK_SHADER_STAGE_VERTEX_BIT, vertex_shader),
224 PipelineShaderStageCreateInfo(VK_SHADER_STAGE_FRAGMENT_BIT, fragment_shader),
225 };
226}
227
228void UpdateOneTextureDescriptorSet(const VKDevice& device, VkDescriptorSet descriptor_set,
229 VkSampler sampler, VkImageView image_view) {
230 const VkDescriptorImageInfo image_info{
231 .sampler = sampler,
232 .imageView = image_view,
233 .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
234 };
235 const VkWriteDescriptorSet write_descriptor_set{
236 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
237 .pNext = nullptr,
238 .dstSet = descriptor_set,
239 .dstBinding = 0,
240 .dstArrayElement = 0,
241 .descriptorCount = 1,
242 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
243 .pImageInfo = &image_info,
244 .pBufferInfo = nullptr,
245 .pTexelBufferView = nullptr,
246 };
247 device.GetLogical().UpdateDescriptorSets(write_descriptor_set, nullptr);
248}
249
250void UpdateTwoTexturesDescriptorSet(const VKDevice& device, VkDescriptorSet descriptor_set,
251 VkSampler sampler, VkImageView image_view_0,
252 VkImageView image_view_1) {
253 const VkDescriptorImageInfo image_info_0{
254 .sampler = sampler,
255 .imageView = image_view_0,
256 .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
257 };
258 const VkDescriptorImageInfo image_info_1{
259 .sampler = sampler,
260 .imageView = image_view_1,
261 .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
262 };
263 const std::array write_descriptor_sets{
264 VkWriteDescriptorSet{
265 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
266 .pNext = nullptr,
267 .dstSet = descriptor_set,
268 .dstBinding = 0,
269 .dstArrayElement = 0,
270 .descriptorCount = 1,
271 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
272 .pImageInfo = &image_info_0,
273 .pBufferInfo = nullptr,
274 .pTexelBufferView = nullptr,
275 },
276 VkWriteDescriptorSet{
277 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
278 .pNext = nullptr,
279 .dstSet = descriptor_set,
280 .dstBinding = 1,
281 .dstArrayElement = 0,
282 .descriptorCount = 1,
283 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
284 .pImageInfo = &image_info_1,
285 .pBufferInfo = nullptr,
286 .pTexelBufferView = nullptr,
287 },
288 };
289 device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr);
290}
291
292void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout,
293 const std::array<Offset2D, 2>& dst_region,
294 const std::array<Offset2D, 2>& src_region) {
295 const VkOffset2D offset{
296 .x = std::min(dst_region[0].x, dst_region[1].x),
297 .y = std::min(dst_region[0].y, dst_region[1].y),
298 };
299 const VkExtent2D extent{
300 .width = static_cast<u32>(std::abs(dst_region[1].x - dst_region[0].x)),
301 .height = static_cast<u32>(std::abs(dst_region[1].y - dst_region[0].y)),
302 };
303 const VkViewport viewport{
304 .x = static_cast<float>(offset.x),
305 .y = static_cast<float>(offset.y),
306 .width = static_cast<float>(extent.width),
307 .height = static_cast<float>(extent.height),
308 .minDepth = 0.0f,
309 .maxDepth = 1.0f,
310 };
311 // TODO: Support scissored blits
312 const VkRect2D scissor{
313 .offset = offset,
314 .extent = extent,
315 };
316 const float scale_x = static_cast<float>(src_region[1].x - src_region[0].x);
317 const float scale_y = static_cast<float>(src_region[1].y - src_region[0].y);
318 const PushConstants push_constants{
319 .tex_scale = {scale_x, scale_y},
320 .tex_offset = {static_cast<float>(src_region[0].x), static_cast<float>(src_region[0].y)},
321 };
322 cmdbuf.SetViewport(0, viewport);
323 cmdbuf.SetScissor(0, scissor);
324 cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
325}
326
327} // Anonymous namespace
328
329BlitImageHelper::BlitImageHelper(const VKDevice& device_, VKScheduler& scheduler_,
330 StateTracker& state_tracker_, VKDescriptorPool& descriptor_pool)
331 : device{device_}, scheduler{scheduler_}, state_tracker{state_tracker_},
332 one_texture_set_layout(device.GetLogical().CreateDescriptorSetLayout(
333 ONE_TEXTURE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO)),
334 two_textures_set_layout(device.GetLogical().CreateDescriptorSetLayout(
335 TWO_TEXTURES_DESCRIPTOR_SET_LAYOUT_CREATE_INFO)),
336 one_texture_descriptor_allocator(descriptor_pool, *one_texture_set_layout),
337 two_textures_descriptor_allocator(descriptor_pool, *two_textures_set_layout),
338 one_texture_pipeline_layout(device.GetLogical().CreatePipelineLayout(
339 PipelineLayoutCreateInfo(one_texture_set_layout.address()))),
340 two_textures_pipeline_layout(device.GetLogical().CreatePipelineLayout(
341 PipelineLayoutCreateInfo(two_textures_set_layout.address()))),
342 full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)),
343 blit_color_to_color_frag(BuildShader(device, VULKAN_BLIT_COLOR_FLOAT_FRAG_SPV)),
344 convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)),
345 convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
346 linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)),
347 nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) {
348 if (device.IsExtShaderStencilExportSupported()) {
349 blit_depth_stencil_frag = BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV);
350 }
351}
352
353BlitImageHelper::~BlitImageHelper() = default;
354
355void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
356 const std::array<Offset2D, 2>& dst_region,
357 const std::array<Offset2D, 2>& src_region,
358 Tegra::Engines::Fermi2D::Filter filter,
359 Tegra::Engines::Fermi2D::Operation operation) {
360 const bool is_linear = filter == Tegra::Engines::Fermi2D::Filter::Bilinear;
361 const BlitImagePipelineKey key{
362 .renderpass = dst_framebuffer->RenderPass(),
363 .operation = operation,
364 };
365 const VkPipelineLayout layout = *one_texture_pipeline_layout;
366 const VkImageView src_view = src_image_view.Handle(ImageViewType::e2D);
367 const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler;
368 const VkPipeline pipeline = FindOrEmplacePipeline(key);
369 const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
370 scheduler.RequestRenderpass(dst_framebuffer);
371 scheduler.Record([dst_region, src_region, pipeline, layout, sampler, src_view, descriptor_set,
372 &device = device](vk::CommandBuffer cmdbuf) {
373 // TODO: Barriers
374 UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view);
375 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
376 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
377 nullptr);
378 BindBlitState(cmdbuf, layout, dst_region, src_region);
379 cmdbuf.Draw(3, 1, 0, 0);
380 });
381 scheduler.InvalidateState();
382}
383
384void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
385 VkImageView src_depth_view, VkImageView src_stencil_view,
386 const std::array<Offset2D, 2>& dst_region,
387 const std::array<Offset2D, 2>& src_region,
388 Tegra::Engines::Fermi2D::Filter filter,
389 Tegra::Engines::Fermi2D::Operation operation) {
390 ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point);
391 ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy);
392
393 const VkPipelineLayout layout = *two_textures_pipeline_layout;
394 const VkSampler sampler = *nearest_sampler;
395 const VkPipeline pipeline = BlitDepthStencilPipeline(dst_framebuffer->RenderPass());
396 const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit();
397 scheduler.RequestRenderpass(dst_framebuffer);
398 scheduler.Record([dst_region, src_region, pipeline, layout, sampler, src_depth_view,
399 src_stencil_view, descriptor_set,
400 &device = device](vk::CommandBuffer cmdbuf) {
401 // TODO: Barriers
402 UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view,
403 src_stencil_view);
404 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
405 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
406 nullptr);
407 BindBlitState(cmdbuf, layout, dst_region, src_region);
408 cmdbuf.Draw(3, 1, 0, 0);
409 });
410 scheduler.InvalidateState();
411}
412
413void BlitImageHelper::ConvertD32ToR32(const Framebuffer* dst_framebuffer,
414 const ImageView& src_image_view) {
415 ConvertDepthToColorPipeline(convert_d32_to_r32_pipeline, dst_framebuffer->RenderPass());
416 Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view);
417}
418
419void BlitImageHelper::ConvertR32ToD32(const Framebuffer* dst_framebuffer,
420 const ImageView& src_image_view) {
421
422 ConvertColorToDepthPipeline(convert_r32_to_d32_pipeline, dst_framebuffer->RenderPass());
423 Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view);
424}
425
426void BlitImageHelper::ConvertD16ToR16(const Framebuffer* dst_framebuffer,
427 const ImageView& src_image_view) {
428 ConvertDepthToColorPipeline(convert_d16_to_r16_pipeline, dst_framebuffer->RenderPass());
429 Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view);
430}
431
432void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
433 const ImageView& src_image_view) {
434 ConvertColorToDepthPipeline(convert_r16_to_d16_pipeline, dst_framebuffer->RenderPass());
435 Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view);
436}
437
438void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
439 const ImageView& src_image_view) {
440 const VkPipelineLayout layout = *one_texture_pipeline_layout;
441 const VkImageView src_view = src_image_view.Handle(ImageViewType::e2D);
442 const VkSampler sampler = *nearest_sampler;
443 const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
444 const VkExtent2D extent{
445 .width = src_image_view.size.width,
446 .height = src_image_view.size.height,
447 };
448 scheduler.RequestRenderpass(dst_framebuffer);
449 scheduler.Record([pipeline, layout, sampler, src_view, descriptor_set, extent,
450 &device = device](vk::CommandBuffer cmdbuf) {
451 const VkOffset2D offset{
452 .x = 0,
453 .y = 0,
454 };
455 const VkViewport viewport{
456 .x = 0.0f,
457 .y = 0.0f,
458 .width = static_cast<float>(extent.width),
459 .height = static_cast<float>(extent.height),
460 .minDepth = 0.0f,
461 .maxDepth = 0.0f,
462 };
463 const VkRect2D scissor{
464 .offset = offset,
465 .extent = extent,
466 };
467 const PushConstants push_constants{
468 .tex_scale = {viewport.width, viewport.height},
469 .tex_offset = {0.0f, 0.0f},
470 };
471 UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view);
472
473 // TODO: Barriers
474 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
475 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
476 nullptr);
477 cmdbuf.SetViewport(0, viewport);
478 cmdbuf.SetScissor(0, scissor);
479 cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
480 cmdbuf.Draw(3, 1, 0, 0);
481 });
482 scheduler.InvalidateState();
483}
484
485VkPipeline BlitImageHelper::FindOrEmplacePipeline(const BlitImagePipelineKey& key) {
486 const auto it = std::ranges::find(blit_color_keys, key);
487 if (it != blit_color_keys.end()) {
488 return *blit_color_pipelines[std::distance(blit_color_keys.begin(), it)];
489 }
490 blit_color_keys.push_back(key);
491
492 const std::array stages = MakeStages(*full_screen_vert, *blit_color_to_color_frag);
493 const VkPipelineColorBlendAttachmentState blend_attachment{
494 .blendEnable = VK_FALSE,
495 .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
496 .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
497 .colorBlendOp = VK_BLEND_OP_ADD,
498 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
499 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
500 .alphaBlendOp = VK_BLEND_OP_ADD,
501 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
502 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
503 };
504 // TODO: programmable blending
505 const VkPipelineColorBlendStateCreateInfo color_blend_create_info{
506 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
507 .pNext = nullptr,
508 .flags = 0,
509 .logicOpEnable = VK_FALSE,
510 .logicOp = VK_LOGIC_OP_CLEAR,
511 .attachmentCount = 1,
512 .pAttachments = &blend_attachment,
513 .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
514 };
515 blit_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
516 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
517 .pNext = nullptr,
518 .flags = 0,
519 .stageCount = static_cast<u32>(stages.size()),
520 .pStages = stages.data(),
521 .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
522 .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
523 .pTessellationState = nullptr,
524 .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
525 .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
526 .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
527 .pDepthStencilState = nullptr,
528 .pColorBlendState = &color_blend_create_info,
529 .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
530 .layout = *one_texture_pipeline_layout,
531 .renderPass = key.renderpass,
532 .subpass = 0,
533 .basePipelineHandle = VK_NULL_HANDLE,
534 .basePipelineIndex = 0,
535 }));
536 return *blit_color_pipelines.back();
537}
538
539VkPipeline BlitImageHelper::BlitDepthStencilPipeline(VkRenderPass renderpass) {
540 if (blit_depth_stencil_pipeline) {
541 return *blit_depth_stencil_pipeline;
542 }
543 const std::array stages = MakeStages(*full_screen_vert, *blit_depth_stencil_frag);
544 blit_depth_stencil_pipeline = device.GetLogical().CreateGraphicsPipeline({
545 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
546 .pNext = nullptr,
547 .flags = 0,
548 .stageCount = static_cast<u32>(stages.size()),
549 .pStages = stages.data(),
550 .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
551 .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
552 .pTessellationState = nullptr,
553 .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
554 .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
555 .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
556 .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
557 .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO,
558 .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
559 .layout = *two_textures_pipeline_layout,
560 .renderPass = renderpass,
561 .subpass = 0,
562 .basePipelineHandle = VK_NULL_HANDLE,
563 .basePipelineIndex = 0,
564 });
565 return *blit_depth_stencil_pipeline;
566}
567
568void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
569 if (pipeline) {
570 return;
571 }
572 const std::array stages = MakeStages(*full_screen_vert, *convert_depth_to_float_frag);
573 pipeline = device.GetLogical().CreateGraphicsPipeline({
574 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
575 .pNext = nullptr,
576 .flags = 0,
577 .stageCount = static_cast<u32>(stages.size()),
578 .pStages = stages.data(),
579 .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
580 .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
581 .pTessellationState = nullptr,
582 .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
583 .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
584 .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
585 .pDepthStencilState = nullptr,
586 .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
587 .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
588 .layout = *one_texture_pipeline_layout,
589 .renderPass = renderpass,
590 .subpass = 0,
591 .basePipelineHandle = VK_NULL_HANDLE,
592 .basePipelineIndex = 0,
593 });
594}
595
596void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
597 if (pipeline) {
598 return;
599 }
600 const std::array stages = MakeStages(*full_screen_vert, *convert_float_to_depth_frag);
601 pipeline = device.GetLogical().CreateGraphicsPipeline({
602 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
603 .pNext = nullptr,
604 .flags = 0,
605 .stageCount = static_cast<u32>(stages.size()),
606 .pStages = stages.data(),
607 .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
608 .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
609 .pTessellationState = nullptr,
610 .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
611 .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
612 .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
613 .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
614 .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO,
615 .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
616 .layout = *one_texture_pipeline_layout,
617 .renderPass = renderpass,
618 .subpass = 0,
619 .basePipelineHandle = VK_NULL_HANDLE,
620 .basePipelineIndex = 0,
621 });
622}
623
624} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h
new file mode 100644
index 000000000..2c2790bf9
--- /dev/null
+++ b/src/video_core/renderer_vulkan/blit_image.h
@@ -0,0 +1,97 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <compare>
8
9#include "video_core/engines/fermi_2d.h"
10#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
11#include "video_core/renderer_vulkan/wrapper.h"
12#include "video_core/texture_cache/types.h"
13
14namespace Vulkan {
15
16using VideoCommon::Offset2D;
17
18class VKDevice;
19class VKScheduler;
20class StateTracker;
21
22class Framebuffer;
23class ImageView;
24
25struct BlitImagePipelineKey {
26 constexpr auto operator<=>(const BlitImagePipelineKey&) const noexcept = default;
27
28 VkRenderPass renderpass;
29 Tegra::Engines::Fermi2D::Operation operation;
30};
31
32class BlitImageHelper {
33public:
34 explicit BlitImageHelper(const VKDevice& device, VKScheduler& scheduler,
35 StateTracker& state_tracker, VKDescriptorPool& descriptor_pool);
36 ~BlitImageHelper();
37
38 void BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
39 const std::array<Offset2D, 2>& dst_region,
40 const std::array<Offset2D, 2>& src_region,
41 Tegra::Engines::Fermi2D::Filter filter,
42 Tegra::Engines::Fermi2D::Operation operation);
43
44 void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view,
45 VkImageView src_stencil_view, const std::array<Offset2D, 2>& dst_region,
46 const std::array<Offset2D, 2>& src_region,
47 Tegra::Engines::Fermi2D::Filter filter,
48 Tegra::Engines::Fermi2D::Operation operation);
49
50 void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
51
52 void ConvertR32ToD32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
53
54 void ConvertD16ToR16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
55
56 void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
57
58private:
59 void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
60 const ImageView& src_image_view);
61
62 [[nodiscard]] VkPipeline FindOrEmplacePipeline(const BlitImagePipelineKey& key);
63
64 [[nodiscard]] VkPipeline BlitDepthStencilPipeline(VkRenderPass renderpass);
65
66 void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
67
68 void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
69
70 const VKDevice& device;
71 VKScheduler& scheduler;
72 StateTracker& state_tracker;
73
74 vk::DescriptorSetLayout one_texture_set_layout;
75 vk::DescriptorSetLayout two_textures_set_layout;
76 DescriptorAllocator one_texture_descriptor_allocator;
77 DescriptorAllocator two_textures_descriptor_allocator;
78 vk::PipelineLayout one_texture_pipeline_layout;
79 vk::PipelineLayout two_textures_pipeline_layout;
80 vk::ShaderModule full_screen_vert;
81 vk::ShaderModule blit_color_to_color_frag;
82 vk::ShaderModule blit_depth_stencil_frag;
83 vk::ShaderModule convert_depth_to_float_frag;
84 vk::ShaderModule convert_float_to_depth_frag;
85 vk::Sampler linear_sampler;
86 vk::Sampler nearest_sampler;
87
88 std::vector<BlitImagePipelineKey> blit_color_keys;
89 std::vector<vk::Pipeline> blit_color_pipelines;
90 vk::Pipeline blit_depth_stencil_pipeline;
91 vk::Pipeline convert_d32_to_r32_pipeline;
92 vk::Pipeline convert_r32_to_d32_pipeline;
93 vk::Pipeline convert_d16_to_r16_pipeline;
94 vk::Pipeline convert_r16_to_d16_pipeline;
95};
96
97} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
index 5ec43db11..67dd10500 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
@@ -60,6 +60,7 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta
60 logic_op.Assign(PackLogicOp(regs.logic_op.operation)); 60 logic_op.Assign(PackLogicOp(regs.logic_op.operation));
61 rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); 61 rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0);
62 topology.Assign(regs.draw.topology); 62 topology.Assign(regs.draw.topology);
63 msaa_mode.Assign(regs.multisample_mode);
63 64
64 raw2 = 0; 65 raw2 = 0;
65 const auto test_func = 66 const auto test_func =
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h
index c26b77790..7e95e6fce 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h
@@ -186,6 +186,7 @@ struct FixedPipelineState {
186 BitField<19, 4, u32> logic_op; 186 BitField<19, 4, u32> logic_op;
187 BitField<23, 1, u32> rasterize_enable; 187 BitField<23, 1, u32> rasterize_enable;
188 BitField<24, 4, Maxwell::PrimitiveTopology> topology; 188 BitField<24, 4, Maxwell::PrimitiveTopology> topology;
189 BitField<28, 4, Tegra::Texture::MsaaMode> msaa_mode;
189 }; 190 };
190 union { 191 union {
191 u32 raw2; 192 u32 raw2;
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index 58e117eb3..40501e7fa 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -122,7 +122,7 @@ struct FormatTuple {
122 {VK_FORMAT_A8B8G8R8_SINT_PACK32, Attachable | Storage}, // A8B8G8R8_SINT 122 {VK_FORMAT_A8B8G8R8_SINT_PACK32, Attachable | Storage}, // A8B8G8R8_SINT
123 {VK_FORMAT_A8B8G8R8_UINT_PACK32, Attachable | Storage}, // A8B8G8R8_UINT 123 {VK_FORMAT_A8B8G8R8_UINT_PACK32, Attachable | Storage}, // A8B8G8R8_UINT
124 {VK_FORMAT_R5G6B5_UNORM_PACK16, Attachable}, // R5G6B5_UNORM 124 {VK_FORMAT_R5G6B5_UNORM_PACK16, Attachable}, // R5G6B5_UNORM
125 {VK_FORMAT_B5G6R5_UNORM_PACK16, Attachable}, // B5G6R5_UNORM 125 {VK_FORMAT_B5G6R5_UNORM_PACK16}, // B5G6R5_UNORM
126 {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1R5G5B5_UNORM 126 {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1R5G5B5_UNORM
127 {VK_FORMAT_A2B10G10R10_UNORM_PACK32, Attachable | Storage}, // A2B10G10R10_UNORM 127 {VK_FORMAT_A2B10G10R10_UNORM_PACK32, Attachable | Storage}, // A2B10G10R10_UNORM
128 {VK_FORMAT_A2B10G10R10_UINT_PACK32, Attachable | Storage}, // A2B10G10R10_UINT 128 {VK_FORMAT_A2B10G10R10_UINT_PACK32, Attachable | Storage}, // A2B10G10R10_UINT
@@ -163,7 +163,7 @@ struct FormatTuple {
163 {VK_FORMAT_R16G16_UNORM, Attachable | Storage}, // R16G16_UNORM 163 {VK_FORMAT_R16G16_UNORM, Attachable | Storage}, // R16G16_UNORM
164 {VK_FORMAT_R16G16_SFLOAT, Attachable | Storage}, // R16G16_FLOAT 164 {VK_FORMAT_R16G16_SFLOAT, Attachable | Storage}, // R16G16_FLOAT
165 {VK_FORMAT_UNDEFINED}, // R16G16_UINT 165 {VK_FORMAT_UNDEFINED}, // R16G16_UINT
166 {VK_FORMAT_UNDEFINED}, // R16G16_SINT 166 {VK_FORMAT_R16G16_SINT, Attachable | Storage}, // R16G16_SINT
167 {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM 167 {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM
168 {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT 168 {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT
169 {VK_FORMAT_R8G8B8A8_SRGB, Attachable}, // A8B8G8R8_SRGB 169 {VK_FORMAT_R8G8B8A8_SRGB, Attachable}, // A8B8G8R8_SRGB
@@ -233,18 +233,20 @@ FormatInfo SurfaceFormat(const VKDevice& device, FormatType format_type, PixelFo
233 233
234 // Use A8B8G8R8_UNORM on hardware that doesn't support ASTC natively 234 // Use A8B8G8R8_UNORM on hardware that doesn't support ASTC natively
235 if (!device.IsOptimalAstcSupported() && VideoCore::Surface::IsPixelFormatASTC(pixel_format)) { 235 if (!device.IsOptimalAstcSupported() && VideoCore::Surface::IsPixelFormatASTC(pixel_format)) {
236 tuple.format = VideoCore::Surface::IsPixelFormatSRGB(pixel_format) 236 const bool is_srgb = VideoCore::Surface::IsPixelFormatSRGB(pixel_format);
237 ? VK_FORMAT_A8B8G8R8_SRGB_PACK32 237 tuple.format = is_srgb ? VK_FORMAT_A8B8G8R8_SRGB_PACK32 : VK_FORMAT_A8B8G8R8_UNORM_PACK32;
238 : VK_FORMAT_A8B8G8R8_UNORM_PACK32;
239 } 238 }
240 const bool attachable = tuple.usage & Attachable; 239 const bool attachable = tuple.usage & Attachable;
241 const bool storage = tuple.usage & Storage; 240 const bool storage = tuple.usage & Storage;
242 241
243 VkFormatFeatureFlags usage; 242 VkFormatFeatureFlags usage;
244 if (format_type == FormatType::Buffer) { 243 switch (format_type) {
244 case FormatType::Buffer:
245 usage = 245 usage =
246 VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT; 246 VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT;
247 } else { 247 break;
248 case FormatType::Linear:
249 case FormatType::Optimal:
248 usage = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT | 250 usage = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
249 VK_FORMAT_FEATURE_TRANSFER_SRC_BIT; 251 VK_FORMAT_FEATURE_TRANSFER_SRC_BIT;
250 if (attachable) { 252 if (attachable) {
@@ -254,6 +256,7 @@ FormatInfo SurfaceFormat(const VKDevice& device, FormatType format_type, PixelFo
254 if (storage) { 256 if (storage) {
255 usage |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; 257 usage |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
256 } 258 }
259 break;
257 } 260 }
258 return {device.GetSupportedFormat(tuple.format, usage, format_type), attachable, storage}; 261 return {device.GetSupportedFormat(tuple.format, usage, format_type), attachable, storage};
259} 262}
@@ -724,4 +727,17 @@ VkViewportCoordinateSwizzleNV ViewportSwizzle(Maxwell::ViewportSwizzle swizzle)
724 return {}; 727 return {};
725} 728}
726 729
730VkSamplerReductionMode SamplerReduction(Tegra::Texture::SamplerReduction reduction) {
731 switch (reduction) {
732 case Tegra::Texture::SamplerReduction::WeightedAverage:
733 return VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT;
734 case Tegra::Texture::SamplerReduction::Min:
735 return VK_SAMPLER_REDUCTION_MODE_MIN_EXT;
736 case Tegra::Texture::SamplerReduction::Max:
737 return VK_SAMPLER_REDUCTION_MODE_MAX_EXT;
738 }
739 UNREACHABLE_MSG("Invalid sampler mode={}", static_cast<int>(reduction));
740 return VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT;
741}
742
727} // namespace Vulkan::MaxwellToVK 743} // namespace Vulkan::MaxwellToVK
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.h b/src/video_core/renderer_vulkan/maxwell_to_vk.h
index 7e213452f..1a90f192e 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.h
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.h
@@ -61,4 +61,6 @@ VkComponentSwizzle SwizzleSource(Tegra::Texture::SwizzleSource swizzle);
61 61
62VkViewportCoordinateSwizzleNV ViewportSwizzle(Maxwell::ViewportSwizzle swizzle); 62VkViewportCoordinateSwizzleNV ViewportSwizzle(Maxwell::ViewportSwizzle swizzle);
63 63
64VkSamplerReductionMode SamplerReduction(Tegra::Texture::SamplerReduction reduction);
65
64} // namespace Vulkan::MaxwellToVK 66} // namespace Vulkan::MaxwellToVK
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index ea4b7c1e6..7f521cb9b 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -92,9 +92,9 @@ Common::DynamicLibrary OpenVulkanLibrary() {
92 return library; 92 return library;
93} 93}
94 94
95std::pair<vk::Instance, u32> CreateInstance( 95std::pair<vk::Instance, u32> CreateInstance(Common::DynamicLibrary& library,
96 Common::DynamicLibrary& library, vk::InstanceDispatch& dld, 96 vk::InstanceDispatch& dld, WindowSystemType window_type,
97 WindowSystemType window_type = WindowSystemType::Headless, bool enable_layers = false) { 97 bool enable_debug_utils, bool enable_layers) {
98 if (!library.IsOpen()) { 98 if (!library.IsOpen()) {
99 LOG_ERROR(Render_Vulkan, "Vulkan library not available"); 99 LOG_ERROR(Render_Vulkan, "Vulkan library not available");
100 return {}; 100 return {};
@@ -133,7 +133,7 @@ std::pair<vk::Instance, u32> CreateInstance(
133 if (window_type != Core::Frontend::WindowSystemType::Headless) { 133 if (window_type != Core::Frontend::WindowSystemType::Headless) {
134 extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); 134 extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
135 } 135 }
136 if (enable_layers) { 136 if (enable_debug_utils) {
137 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); 137 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
138 } 138 }
139 extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); 139 extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
@@ -287,7 +287,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
287bool RendererVulkan::Init() { 287bool RendererVulkan::Init() {
288 library = OpenVulkanLibrary(); 288 library = OpenVulkanLibrary();
289 std::tie(instance, instance_version) = CreateInstance( 289 std::tie(instance, instance_version) = CreateInstance(
290 library, dld, render_window.GetWindowInfo().type, Settings::values.renderer_debug); 290 library, dld, render_window.GetWindowInfo().type, true, Settings::values.renderer_debug);
291 if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) { 291 if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) {
292 return false; 292 return false;
293 } 293 }
@@ -447,7 +447,8 @@ void RendererVulkan::Report() const {
447std::vector<std::string> RendererVulkan::EnumerateDevices() { 447std::vector<std::string> RendererVulkan::EnumerateDevices() {
448 vk::InstanceDispatch dld; 448 vk::InstanceDispatch dld;
449 Common::DynamicLibrary library = OpenVulkanLibrary(); 449 Common::DynamicLibrary library = OpenVulkanLibrary();
450 vk::Instance instance = CreateInstance(library, dld).first; 450 vk::Instance instance =
451 CreateInstance(library, dld, WindowSystemType::Headless, false, false).first;
451 if (!instance) { 452 if (!instance) {
452 return {}; 453 return {};
453 } 454 }
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index 977b86003..74642fba4 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -33,10 +33,9 @@ class VKDevice;
33class VKMemoryManager; 33class VKMemoryManager;
34class VKSwapchain; 34class VKSwapchain;
35class VKScheduler; 35class VKScheduler;
36class VKImage;
37 36
38struct VKScreenInfo { 37struct VKScreenInfo {
39 VKImage* image{}; 38 VkImageView image_view{};
40 u32 width{}; 39 u32 width{};
41 u32 height{}; 40 u32 height{};
42 bool is_srgb{}; 41 bool is_srgb{};
diff --git a/src/video_core/renderer_vulkan/shaders/blit.frag b/src/video_core/renderer_vulkan/shaders/blit.frag
deleted file mode 100644
index a06ecd24a..000000000
--- a/src/video_core/renderer_vulkan/shaders/blit.frag
+++ /dev/null
@@ -1,24 +0,0 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5/*
6 * Build instructions:
7 * $ glslangValidator -V $THIS_FILE -o output.spv
8 * $ spirv-opt -O --strip-debug output.spv -o optimized.spv
9 * $ xxd -i optimized.spv
10 *
11 * Then copy that bytecode to the C++ file
12 */
13
14#version 460 core
15
16layout (location = 0) in vec2 frag_tex_coord;
17
18layout (location = 0) out vec4 color;
19
20layout (binding = 1) uniform sampler2D color_texture;
21
22void main() {
23 color = texture(color_texture, frag_tex_coord);
24}
diff --git a/src/video_core/renderer_vulkan/shaders/blit.vert b/src/video_core/renderer_vulkan/shaders/blit.vert
deleted file mode 100644
index c64d9235a..000000000
--- a/src/video_core/renderer_vulkan/shaders/blit.vert
+++ /dev/null
@@ -1,28 +0,0 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5/*
6 * Build instructions:
7 * $ glslangValidator -V $THIS_FILE -o output.spv
8 * $ spirv-opt -O --strip-debug output.spv -o optimized.spv
9 * $ xxd -i optimized.spv
10 *
11 * Then copy that bytecode to the C++ file
12 */
13
14#version 460 core
15
16layout (location = 0) in vec2 vert_position;
17layout (location = 1) in vec2 vert_tex_coord;
18
19layout (location = 0) out vec2 frag_tex_coord;
20
21layout (set = 0, binding = 0) uniform MatrixBlock {
22 mat4 modelview_matrix;
23};
24
25void main() {
26 gl_Position = modelview_matrix * vec4(vert_position, 0.0, 1.0);
27 frag_tex_coord = vert_tex_coord;
28}
diff --git a/src/video_core/renderer_vulkan/shaders/quad_array.comp b/src/video_core/renderer_vulkan/shaders/quad_array.comp
deleted file mode 100644
index 5a5703308..000000000
--- a/src/video_core/renderer_vulkan/shaders/quad_array.comp
+++ /dev/null
@@ -1,37 +0,0 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5/*
6 * Build instructions:
7 * $ glslangValidator -V $THIS_FILE -o output.spv
8 * $ spirv-opt -O --strip-debug output.spv -o optimized.spv
9 * $ xxd -i optimized.spv
10 *
11 * Then copy that bytecode to the C++ file
12 */
13
14#version 460 core
15
16layout (local_size_x = 1024) in;
17
18layout (std430, set = 0, binding = 0) buffer OutputBuffer {
19 uint output_indexes[];
20};
21
22layout (push_constant) uniform PushConstants {
23 uint first;
24};
25
26void main() {
27 uint primitive = gl_GlobalInvocationID.x;
28 if (primitive * 6 >= output_indexes.length()) {
29 return;
30 }
31
32 const uint quad_map[6] = uint[](0, 1, 2, 0, 2, 3);
33 for (uint vertex = 0; vertex < 6; ++vertex) {
34 uint index = first + primitive * 4 + quad_map[vertex];
35 output_indexes[primitive * 6 + vertex] = index;
36 }
37}
diff --git a/src/video_core/renderer_vulkan/shaders/quad_indexed.comp b/src/video_core/renderer_vulkan/shaders/quad_indexed.comp
deleted file mode 100644
index 5a472ba9b..000000000
--- a/src/video_core/renderer_vulkan/shaders/quad_indexed.comp
+++ /dev/null
@@ -1,50 +0,0 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5/*
6 * Build instructions:
7 * $ glslangValidator -V quad_indexed.comp -o output.spv
8 * $ spirv-opt -O --strip-debug output.spv -o optimized.spv
9 * $ xxd -i optimized.spv
10 *
11 * Then copy that bytecode to the C++ file
12 */
13
14#version 460 core
15
16layout (local_size_x = 1024) in;
17
18layout (std430, set = 0, binding = 0) readonly buffer InputBuffer {
19 uint input_indexes[];
20};
21
22layout (std430, set = 0, binding = 1) writeonly buffer OutputBuffer {
23 uint output_indexes[];
24};
25
26layout (push_constant) uniform PushConstants {
27 uint base_vertex;
28 int index_shift; // 0: uint8, 1: uint16, 2: uint32
29};
30
31void main() {
32 int primitive = int(gl_GlobalInvocationID.x);
33 if (primitive * 6 >= output_indexes.length()) {
34 return;
35 }
36
37 int index_size = 8 << index_shift;
38 int flipped_shift = 2 - index_shift;
39 int mask = (1 << flipped_shift) - 1;
40
41 const int quad_swizzle[6] = int[](0, 1, 2, 0, 2, 3);
42 for (uint vertex = 0; vertex < 6; ++vertex) {
43 int offset = primitive * 4 + quad_swizzle[vertex];
44 int int_offset = offset >> flipped_shift;
45 int bit_offset = (offset & mask) * index_size;
46 uint packed_input = input_indexes[int_offset];
47 uint index = bitfieldExtract(packed_input, bit_offset, index_size);
48 output_indexes[primitive * 6 + vertex] = index + base_vertex;
49 }
50}
diff --git a/src/video_core/renderer_vulkan/shaders/uint8.comp b/src/video_core/renderer_vulkan/shaders/uint8.comp
deleted file mode 100644
index a320f3ae0..000000000
--- a/src/video_core/renderer_vulkan/shaders/uint8.comp
+++ /dev/null
@@ -1,33 +0,0 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5/*
6 * Build instructions:
7 * $ glslangValidator -V $THIS_FILE -o output.spv
8 * $ spirv-opt -O --strip-debug output.spv -o optimized.spv
9 * $ xxd -i optimized.spv
10 *
11 * Then copy that bytecode to the C++ file
12 */
13
14#version 460 core
15#extension GL_EXT_shader_16bit_storage : require
16#extension GL_EXT_shader_8bit_storage : require
17
18layout (local_size_x = 1024) in;
19
20layout (std430, set = 0, binding = 0) readonly buffer InputBuffer {
21 uint8_t input_indexes[];
22};
23
24layout (std430, set = 0, binding = 1) writeonly buffer OutputBuffer {
25 uint16_t output_indexes[];
26};
27
28void main() {
29 uint id = gl_GlobalInvocationID.x;
30 if (id < input_indexes.length()) {
31 output_indexes[id] = uint16_t(input_indexes[id]);
32 }
33}
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index b5b60309e..d3a83f22f 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -16,12 +16,12 @@
16#include "core/frontend/emu_window.h" 16#include "core/frontend/emu_window.h"
17#include "core/memory.h" 17#include "core/memory.h"
18#include "video_core/gpu.h" 18#include "video_core/gpu.h"
19#include "video_core/morton.h" 19#include "video_core/host_shaders/vulkan_present_frag_spv.h"
20#include "video_core/host_shaders/vulkan_present_vert_spv.h"
20#include "video_core/rasterizer_interface.h" 21#include "video_core/rasterizer_interface.h"
21#include "video_core/renderer_vulkan/renderer_vulkan.h" 22#include "video_core/renderer_vulkan/renderer_vulkan.h"
22#include "video_core/renderer_vulkan/vk_blit_screen.h" 23#include "video_core/renderer_vulkan/vk_blit_screen.h"
23#include "video_core/renderer_vulkan/vk_device.h" 24#include "video_core/renderer_vulkan/vk_device.h"
24#include "video_core/renderer_vulkan/vk_image.h"
25#include "video_core/renderer_vulkan/vk_master_semaphore.h" 25#include "video_core/renderer_vulkan/vk_master_semaphore.h"
26#include "video_core/renderer_vulkan/vk_memory_manager.h" 26#include "video_core/renderer_vulkan/vk_memory_manager.h"
27#include "video_core/renderer_vulkan/vk_scheduler.h" 27#include "video_core/renderer_vulkan/vk_scheduler.h"
@@ -29,108 +29,12 @@
29#include "video_core/renderer_vulkan/vk_swapchain.h" 29#include "video_core/renderer_vulkan/vk_swapchain.h"
30#include "video_core/renderer_vulkan/wrapper.h" 30#include "video_core/renderer_vulkan/wrapper.h"
31#include "video_core/surface.h" 31#include "video_core/surface.h"
32#include "video_core/textures/decoders.h"
32 33
33namespace Vulkan { 34namespace Vulkan {
34 35
35namespace { 36namespace {
36 37
37// Generated from the "shaders/" directory, read the instructions there.
38constexpr u8 blit_vertex_code[] = {
39 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x08, 0x00, 0x27, 0x00, 0x00, 0x00,
40 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00,
41 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
42 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
43 0x0f, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,
44 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
45 0x25, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00,
47 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
48 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
49 0x48, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
50 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
51 0x48, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
52 0x48, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
53 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x11, 0x00, 0x00, 0x00,
55 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
56 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
57 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
58 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
59 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
60 0x01, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00,
61 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00,
62 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
63 0x04, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
64 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
65 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
66 0x09, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
67 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
68 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
69 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
70 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,
71 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00,
72 0x10, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00,
73 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00,
74 0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00,
75 0x13, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,
76 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00,
77 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00,
78 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00,
79 0x19, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
80 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
81 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x20, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00,
82 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00,
83 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00,
84 0x24, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00,
85 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
86 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
87 0x05, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
88 0x13, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
89 0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00,
90 0x1a, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
91 0x1d, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
92 0x06, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
93 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
94 0x1e, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00,
95 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
96 0x41, 0x00, 0x05, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
97 0x0f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x22, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
98 0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
99 0x3e, 0x00, 0x03, 0x00, 0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00,
100 0x38, 0x00, 0x01, 0x00};
101
102constexpr u8 blit_fragment_code[] = {
103 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00,
105 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
106 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
107 0x0f, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,
108 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
109 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,
110 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00,
111 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00,
112 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00,
113 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
114 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00,
115 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
116 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
117 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
118 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x00, 0x00,
119 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00,
121 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00,
122 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00,
123 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00,
124 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
125 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
126 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
127 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
128 0x05, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
129 0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
130 0x11, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
131 0x0e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00,
132 0x13, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00};
133
134struct ScreenRectVertex { 38struct ScreenRectVertex {
135 ScreenRectVertex() = default; 39 ScreenRectVertex() = default;
136 explicit ScreenRectVertex(f32 x, f32 y, f32 u, f32 v) : position{{x, y}}, tex_coord{{u, v}} {} 40 explicit ScreenRectVertex(f32 x, f32 y, f32 u, f32 v) : position{{x, y}}, tex_coord{{u, v}} {}
@@ -173,9 +77,9 @@ constexpr std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) {
173 // clang-format on 77 // clang-format on
174} 78}
175 79
176std::size_t GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) { 80u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) {
177 using namespace VideoCore::Surface; 81 using namespace VideoCore::Surface;
178 return GetBytesPerPixel(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)); 82 return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format));
179} 83}
180 84
181std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) { 85std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) {
@@ -239,34 +143,30 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool
239 scheduler.Wait(resource_ticks[image_index]); 143 scheduler.Wait(resource_ticks[image_index]);
240 resource_ticks[image_index] = scheduler.CurrentTick(); 144 resource_ticks[image_index] = scheduler.CurrentTick();
241 145
242 VKImage* blit_image = use_accelerated ? screen_info.image : raw_images[image_index].get(); 146 UpdateDescriptorSet(image_index,
243 147 use_accelerated ? screen_info.image_view : *raw_image_views[image_index]);
244 UpdateDescriptorSet(image_index, blit_image->GetPresentView());
245 148
246 BufferData data; 149 BufferData data;
247 SetUniformData(data, framebuffer); 150 SetUniformData(data, framebuffer);
248 SetVertexData(data, framebuffer); 151 SetVertexData(data, framebuffer);
249 152
250 auto map = buffer_commit->Map(); 153 auto map = buffer_commit->Map();
251 std::memcpy(map.GetAddress(), &data, sizeof(data)); 154 std::memcpy(map.Address(), &data, sizeof(data));
252 155
253 if (!use_accelerated) { 156 if (!use_accelerated) {
254 const u64 image_offset = GetRawImageOffset(framebuffer, image_index); 157 const u64 image_offset = GetRawImageOffset(framebuffer, image_index);
255 158
256 const auto pixel_format =
257 VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format);
258 const VAddr framebuffer_addr = framebuffer.address + framebuffer.offset; 159 const VAddr framebuffer_addr = framebuffer.address + framebuffer.offset;
259 const auto host_ptr = cpu_memory.GetPointer(framebuffer_addr); 160 const u8* const host_ptr = cpu_memory.GetPointer(framebuffer_addr);
260 rasterizer.FlushRegion(ToCacheAddr(host_ptr), GetSizeInBytes(framebuffer)); 161 const size_t size_bytes = GetSizeInBytes(framebuffer);
162 rasterizer.FlushRegion(ToCacheAddr(host_ptr), size_bytes);
261 163
262 // TODO(Rodrigo): Read this from HLE 164 // TODO(Rodrigo): Read this from HLE
263 constexpr u32 block_height_log2 = 4; 165 constexpr u32 block_height_log2 = 4;
264 VideoCore::MortonSwizzle(VideoCore::MortonSwizzleMode::MortonToLinear, pixel_format, 166 const u32 bytes_per_pixel = GetBytesPerPixel(framebuffer);
265 framebuffer.stride, block_height_log2, framebuffer.height, 0, 1, 1, 167 Tegra::Texture::UnswizzleTexture(
266 map.GetAddress() + image_offset, host_ptr); 168 std::span(map.Address() + image_offset, size_bytes), std::span(host_ptr, size_bytes),
267 169 bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0);
268 blit_image->Transition(0, 1, 0, 1, VK_PIPELINE_STAGE_TRANSFER_BIT,
269 VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
270 170
271 const VkBufferImageCopy copy{ 171 const VkBufferImageCopy copy{
272 .bufferOffset = image_offset, 172 .bufferOffset = image_offset,
@@ -288,15 +188,44 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool
288 }, 188 },
289 }; 189 };
290 scheduler.Record( 190 scheduler.Record(
291 [buffer = *buffer, image = *blit_image->GetHandle(), copy](vk::CommandBuffer cmdbuf) { 191 [buffer = *buffer, image = *raw_images[image_index], copy](vk::CommandBuffer cmdbuf) {
292 cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); 192 const VkImageMemoryBarrier base_barrier{
193 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
194 .pNext = nullptr,
195 .srcAccessMask = 0,
196 .dstAccessMask = 0,
197 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
198 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
199 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
200 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
201 .image = image,
202 .subresourceRange =
203 {
204 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
205 .baseMipLevel = 0,
206 .levelCount = 1,
207 .baseArrayLayer = 0,
208 .layerCount = 1,
209 },
210 };
211 VkImageMemoryBarrier read_barrier = base_barrier;
212 read_barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
213 read_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
214 read_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
215
216 VkImageMemoryBarrier write_barrier = base_barrier;
217 write_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
218 write_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
219
220 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
221 0, read_barrier);
222 cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_GENERAL, copy);
223 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
224 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, write_barrier);
293 }); 225 });
294 } 226 }
295 map.Release(); 227 map.Release();
296 228
297 blit_image->Transition(0, 1, 0, 1, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
298 VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
299
300 scheduler.Record([renderpass = *renderpass, framebuffer = *framebuffers[image_index], 229 scheduler.Record([renderpass = *renderpass, framebuffer = *framebuffers[image_index],
301 descriptor_set = descriptor_sets[image_index], buffer = *buffer, 230 descriptor_set = descriptor_sets[image_index], buffer = *buffer,
302 size = swapchain.GetSize(), pipeline = *pipeline, 231 size = swapchain.GetSize(), pipeline = *pipeline,
@@ -304,31 +233,31 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool
304 const VkClearValue clear_color{ 233 const VkClearValue clear_color{
305 .color = {.float32 = {0.0f, 0.0f, 0.0f, 0.0f}}, 234 .color = {.float32 = {0.0f, 0.0f, 0.0f, 0.0f}},
306 }; 235 };
307 236 const VkRenderPassBeginInfo renderpass_bi{
308 VkRenderPassBeginInfo renderpass_bi; 237 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
309 renderpass_bi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; 238 .pNext = nullptr,
310 renderpass_bi.pNext = nullptr; 239 .renderPass = renderpass,
311 renderpass_bi.renderPass = renderpass; 240 .framebuffer = framebuffer,
312 renderpass_bi.framebuffer = framebuffer; 241 .renderArea =
313 renderpass_bi.renderArea.offset.x = 0; 242 {
314 renderpass_bi.renderArea.offset.y = 0; 243 .offset = {0, 0},
315 renderpass_bi.renderArea.extent = size; 244 .extent = size,
316 renderpass_bi.clearValueCount = 1; 245 },
317 renderpass_bi.pClearValues = &clear_color; 246 .clearValueCount = 1,
318 247 .pClearValues = &clear_color,
319 VkViewport viewport; 248 };
320 viewport.x = 0.0f; 249 const VkViewport viewport{
321 viewport.y = 0.0f; 250 .x = 0.0f,
322 viewport.width = static_cast<float>(size.width); 251 .y = 0.0f,
323 viewport.height = static_cast<float>(size.height); 252 .width = static_cast<float>(size.width),
324 viewport.minDepth = 0.0f; 253 .height = static_cast<float>(size.height),
325 viewport.maxDepth = 1.0f; 254 .minDepth = 0.0f,
326 255 .maxDepth = 1.0f,
327 VkRect2D scissor; 256 };
328 scissor.offset.x = 0; 257 const VkRect2D scissor{
329 scissor.offset.y = 0; 258 .offset = {0, 0},
330 scissor.extent = size; 259 .extent = size,
331 260 };
332 cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); 261 cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
333 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); 262 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
334 cmdbuf.SetViewport(0, viewport); 263 cmdbuf.SetViewport(0, viewport);
@@ -372,8 +301,8 @@ void VKBlitScreen::RefreshResources(const Tegra::FramebufferConfig& framebuffer)
372} 301}
373 302
374void VKBlitScreen::CreateShaders() { 303void VKBlitScreen::CreateShaders() {
375 vertex_shader = BuildShader(device, sizeof(blit_vertex_code), blit_vertex_code); 304 vertex_shader = BuildShader(device, VULKAN_PRESENT_VERT_SPV);
376 fragment_shader = BuildShader(device, sizeof(blit_fragment_code), blit_fragment_code); 305 fragment_shader = BuildShader(device, VULKAN_PRESENT_FRAG_SPV);
377} 306}
378 307
379void VKBlitScreen::CreateSemaphores() { 308void VKBlitScreen::CreateSemaphores() {
@@ -420,7 +349,7 @@ void VKBlitScreen::CreateRenderPass() {
420 349
421 const VkAttachmentReference color_attachment_ref{ 350 const VkAttachmentReference color_attachment_ref{
422 .attachment = 0, 351 .attachment = 0,
423 .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 352 .layout = VK_IMAGE_LAYOUT_GENERAL,
424 }; 353 };
425 354
426 const VkSubpassDescription subpass_description{ 355 const VkSubpassDescription subpass_description{
@@ -735,34 +664,56 @@ void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuff
735 664
736void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { 665void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
737 raw_images.resize(image_count); 666 raw_images.resize(image_count);
667 raw_image_views.resize(image_count);
738 raw_buffer_commits.resize(image_count); 668 raw_buffer_commits.resize(image_count);
739 669
740 const VkImageCreateInfo ci{ 670 for (size_t i = 0; i < image_count; ++i) {
741 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 671 raw_images[i] = device.GetLogical().CreateImage(VkImageCreateInfo{
742 .pNext = nullptr, 672 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
743 .flags = 0, 673 .pNext = nullptr,
744 .imageType = VK_IMAGE_TYPE_2D, 674 .flags = 0,
745 .format = GetFormat(framebuffer), 675 .imageType = VK_IMAGE_TYPE_2D,
746 .extent = 676 .format = GetFormat(framebuffer),
747 { 677 .extent =
748 .width = framebuffer.width, 678 {
749 .height = framebuffer.height, 679 .width = framebuffer.width,
750 .depth = 1, 680 .height = framebuffer.height,
751 }, 681 .depth = 1,
752 .mipLevels = 1, 682 },
753 .arrayLayers = 1, 683 .mipLevels = 1,
754 .samples = VK_SAMPLE_COUNT_1_BIT, 684 .arrayLayers = 1,
755 .tiling = VK_IMAGE_TILING_LINEAR, 685 .samples = VK_SAMPLE_COUNT_1_BIT,
756 .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 686 .tiling = VK_IMAGE_TILING_LINEAR,
757 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 687 .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
758 .queueFamilyIndexCount = 0, 688 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
759 .pQueueFamilyIndices = nullptr, 689 .queueFamilyIndexCount = 0,
760 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 690 .pQueueFamilyIndices = nullptr,
761 }; 691 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
762 692 });
763 for (std::size_t i = 0; i < image_count; ++i) { 693 raw_buffer_commits[i] = memory_manager.Commit(raw_images[i], false);
764 raw_images[i] = std::make_unique<VKImage>(device, scheduler, ci, VK_IMAGE_ASPECT_COLOR_BIT); 694 raw_image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{
765 raw_buffer_commits[i] = memory_manager.Commit(raw_images[i]->GetHandle(), false); 695 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
696 .pNext = nullptr,
697 .flags = 0,
698 .image = *raw_images[i],
699 .viewType = VK_IMAGE_VIEW_TYPE_2D,
700 .format = GetFormat(framebuffer),
701 .components =
702 {
703 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
704 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
705 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
706 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
707 },
708 .subresourceRange =
709 {
710 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
711 .baseMipLevel = 0,
712 .levelCount = 1,
713 .baseArrayLayer = 0,
714 .layerCount = 1,
715 },
716 });
766 } 717 }
767} 718}
768 719
@@ -789,7 +740,7 @@ void VKBlitScreen::UpdateDescriptorSet(std::size_t image_index, VkImageView imag
789 const VkDescriptorImageInfo image_info{ 740 const VkDescriptorImageInfo image_info{
790 .sampler = *sampler, 741 .sampler = *sampler,
791 .imageView = image_view, 742 .imageView = image_view,
792 .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 743 .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
793 }; 744 };
794 745
795 const VkWriteDescriptorSet sampler_write{ 746 const VkWriteDescriptorSet sampler_write{
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h
index 8f2839214..2ee374247 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.h
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.h
@@ -35,7 +35,6 @@ struct ScreenInfo;
35 35
36class RasterizerVulkan; 36class RasterizerVulkan;
37class VKDevice; 37class VKDevice;
38class VKImage;
39class VKScheduler; 38class VKScheduler;
40class VKSwapchain; 39class VKSwapchain;
41 40
@@ -110,7 +109,8 @@ private:
110 std::vector<u64> resource_ticks; 109 std::vector<u64> resource_ticks;
111 110
112 std::vector<vk::Semaphore> semaphores; 111 std::vector<vk::Semaphore> semaphores;
113 std::vector<std::unique_ptr<VKImage>> raw_images; 112 std::vector<vk::Image> raw_images;
113 std::vector<vk::ImageView> raw_image_views;
114 std::vector<VKMemoryCommit> raw_buffer_commits; 114 std::vector<VKMemoryCommit> raw_buffer_commits;
115 u32 raw_width = 0; 115 u32 raw_width = 0;
116 u32 raw_height = 0; 116 u32 raw_height = 0;
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 444d3fb93..10d296c2f 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -31,15 +31,19 @@ constexpr VkAccessFlags UPLOAD_ACCESS_BARRIERS =
31 VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT | 31 VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT |
32 VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDEX_READ_BIT; 32 VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDEX_READ_BIT;
33 33
34constexpr VkAccessFlags TRANSFORM_FEEDBACK_WRITE_ACCESS =
35 VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT;
36
34std::unique_ptr<VKStreamBuffer> CreateStreamBuffer(const VKDevice& device, VKScheduler& scheduler) { 37std::unique_ptr<VKStreamBuffer> CreateStreamBuffer(const VKDevice& device, VKScheduler& scheduler) {
35 return std::make_unique<VKStreamBuffer>(device, scheduler, BUFFER_USAGE); 38 return std::make_unique<VKStreamBuffer>(device, scheduler);
36} 39}
37 40
38} // Anonymous namespace 41} // Anonymous namespace
39 42
40Buffer::Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VKScheduler& scheduler_, 43Buffer::Buffer(const VKDevice& device_, VKMemoryManager& memory_manager, VKScheduler& scheduler_,
41 VKStagingBufferPool& staging_pool_, VAddr cpu_addr_, std::size_t size_) 44 VKStagingBufferPool& staging_pool_, VAddr cpu_addr_, std::size_t size_)
42 : BufferBlock{cpu_addr_, size_}, scheduler{scheduler_}, staging_pool{staging_pool_} { 45 : BufferBlock{cpu_addr_, size_}, device{device_}, scheduler{scheduler_}, staging_pool{
46 staging_pool_} {
43 const VkBufferCreateInfo ci{ 47 const VkBufferCreateInfo ci{
44 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 48 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
45 .pNext = nullptr, 49 .pNext = nullptr,
@@ -64,24 +68,39 @@ void Buffer::Upload(std::size_t offset, std::size_t data_size, const u8* data) {
64 scheduler.RequestOutsideRenderPassOperationContext(); 68 scheduler.RequestOutsideRenderPassOperationContext();
65 69
66 const VkBuffer handle = Handle(); 70 const VkBuffer handle = Handle();
67 scheduler.Record( 71 scheduler.Record([staging = *staging.handle, handle, offset, data_size,
68 [staging = *staging.handle, handle, offset, data_size](vk::CommandBuffer cmdbuf) { 72 &device = device](vk::CommandBuffer cmdbuf) {
69 cmdbuf.CopyBuffer(staging, handle, VkBufferCopy{0, offset, data_size}); 73 const VkBufferMemoryBarrier read_barrier{
70 74 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
71 const VkBufferMemoryBarrier barrier{ 75 .pNext = nullptr,
72 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 76 .srcAccessMask =
73 .pNext = nullptr, 77 VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT |
74 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, 78 VK_ACCESS_HOST_WRITE_BIT |
75 .dstAccessMask = UPLOAD_ACCESS_BARRIERS, 79 (device.IsExtTransformFeedbackSupported() ? TRANSFORM_FEEDBACK_WRITE_ACCESS : 0),
76 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 80 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
77 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 81 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
78 .buffer = handle, 82 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
79 .offset = offset, 83 .buffer = handle,
80 .size = data_size, 84 .offset = offset,
81 }; 85 .size = data_size,
82 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0, {}, 86 };
83 barrier, {}); 87 const VkBufferMemoryBarrier write_barrier{
84 }); 88 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
89 .pNext = nullptr,
90 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
91 .dstAccessMask = UPLOAD_ACCESS_BARRIERS,
92 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
93 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
94 .buffer = handle,
95 .offset = offset,
96 .size = data_size,
97 };
98 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
99 0, read_barrier);
100 cmdbuf.CopyBuffer(staging, handle, VkBufferCopy{0, offset, data_size});
101 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0,
102 write_barrier);
103 });
85} 104}
86 105
87void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) { 106void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) {
@@ -150,8 +169,10 @@ void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst
150VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer_, 169VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer_,
151 Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, 170 Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_,
152 const VKDevice& device_, VKMemoryManager& memory_manager_, 171 const VKDevice& device_, VKMemoryManager& memory_manager_,
153 VKScheduler& scheduler_, VKStagingBufferPool& staging_pool_) 172 VKScheduler& scheduler_, VKStreamBuffer& stream_buffer_,
154 : BufferCache{rasterizer_, gpu_memory_, cpu_memory_, CreateStreamBuffer(device_, scheduler_)}, 173 VKStagingBufferPool& staging_pool_)
174 : VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer_, gpu_memory_,
175 cpu_memory_, stream_buffer_},
155 device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{ 176 device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{
156 staging_pool_} {} 177 staging_pool_} {}
157 178
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index 6008b8373..daf498222 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -41,6 +41,7 @@ public:
41 } 41 }
42 42
43private: 43private:
44 const VKDevice& device;
44 VKScheduler& scheduler; 45 VKScheduler& scheduler;
45 VKStagingBufferPool& staging_pool; 46 VKStagingBufferPool& staging_pool;
46 47
@@ -49,10 +50,11 @@ private:
49 50
50class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer> { 51class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer> {
51public: 52public:
52 explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer_, 53 explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer,
53 Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, 54 Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory,
54 const VKDevice& device_, VKMemoryManager& memory_manager_, 55 const VKDevice& device, VKMemoryManager& memory_manager,
55 VKScheduler& scheduler_, VKStagingBufferPool& staging_pool_); 56 VKScheduler& scheduler, VKStreamBuffer& stream_buffer,
57 VKStagingBufferPool& staging_pool);
56 ~VKBufferCache(); 58 ~VKBufferCache();
57 59
58 BufferInfo GetEmptyBuffer(std::size_t size) override; 60 BufferInfo GetEmptyBuffer(std::size_t size) override;
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
index 1ac7e2a30..2c030e910 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
@@ -10,6 +10,9 @@
10#include "common/alignment.h" 10#include "common/alignment.h"
11#include "common/assert.h" 11#include "common/assert.h"
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "video_core/host_shaders/vulkan_quad_array_comp_spv.h"
14#include "video_core/host_shaders/vulkan_quad_indexed_comp_spv.h"
15#include "video_core/host_shaders/vulkan_uint8_comp_spv.h"
13#include "video_core/renderer_vulkan/vk_compute_pass.h" 16#include "video_core/renderer_vulkan/vk_compute_pass.h"
14#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 17#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
15#include "video_core/renderer_vulkan/vk_device.h" 18#include "video_core/renderer_vulkan/vk_device.h"
@@ -22,99 +25,6 @@ namespace Vulkan {
22 25
23namespace { 26namespace {
24 27
25// Quad array SPIR-V module. Generated from the "shaders/" directory, read the instructions there.
26constexpr u8 quad_array[] = {
27 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x08, 0x00, 0x54, 0x00, 0x00, 0x00,
28 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00,
29 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
30 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
31 0x0f, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,
32 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00,
33 0x11, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
34 0x47, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
35 0x47, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
36 0x48, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
37 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
38 0x47, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
39 0x47, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40 0x48, 0x00, 0x05, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
41 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x29, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
42 0x47, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
43 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
44 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
45 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
46 0x06, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
47 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
48 0x09, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
49 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
50 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
51 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
52 0x06, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x03, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
53 0x1e, 0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
54 0x15, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
55 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
56 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00,
57 0x1b, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x29, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
58 0x20, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,
59 0x3b, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
60 0x2b, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 0x20, 0x00, 0x04, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
62 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
63 0x1c, 0x00, 0x04, 0x00, 0x34, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
64 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
65 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
66 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
67 0x2c, 0x00, 0x09, 0x00, 0x34, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
68 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
69 0x37, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
70 0x34, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
71 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00,
72 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00,
73 0x00, 0x04, 0x00, 0x00, 0x2c, 0x00, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00,
74 0x49, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00,
75 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
76 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x3a, 0x00, 0x00, 0x00,
77 0x3b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x4c, 0x00, 0x00, 0x00,
78 0xf8, 0x00, 0x02, 0x00, 0x4c, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00, 0x4b, 0x00, 0x00, 0x00,
79 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x4d, 0x00, 0x00, 0x00,
80 0xf8, 0x00, 0x02, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00,
81 0x0e, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
82 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x84, 0x00, 0x05, 0x00,
83 0x06, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
84 0x44, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
85 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
86 0x17, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
87 0x19, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
88 0x12, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00,
89 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
90 0x1e, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00,
91 0x4b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00,
92 0x21, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x21, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00,
93 0x06, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
94 0x48, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x05, 0x00, 0x1b, 0x00, 0x00, 0x00,
95 0x27, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00,
96 0x23, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00,
97 0x27, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
98 0x22, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00,
99 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
100 0x2f, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x84, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
101 0x32, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00,
102 0x06, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
103 0x3e, 0x00, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
104 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00,
105 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
106 0x80, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
107 0x3d, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
108 0x12, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x44, 0x00, 0x00, 0x00,
109 0x45, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
110 0x3e, 0x00, 0x03, 0x00, 0x45, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00,
111 0x06, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00,
112 0xf9, 0x00, 0x02, 0x00, 0x21, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x23, 0x00, 0x00, 0x00,
113 0xf9, 0x00, 0x02, 0x00, 0x4b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x4e, 0x00, 0x00, 0x00,
114 0xf9, 0x00, 0x02, 0x00, 0x4c, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x4b, 0x00, 0x00, 0x00,
115 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
116};
117
118VkDescriptorSetLayoutBinding BuildQuadArrayPassDescriptorSetLayoutBinding() { 28VkDescriptorSetLayoutBinding BuildQuadArrayPassDescriptorSetLayoutBinding() {
119 return { 29 return {
120 .binding = 0, 30 .binding = 0,
@@ -144,208 +54,6 @@ VkPushConstantRange BuildComputePushConstantRange(std::size_t size) {
144 }; 54 };
145} 55}
146 56
147// Uint8 SPIR-V module. Generated from the "shaders/" directory.
148constexpr u8 uint8_pass[] = {
149 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x08, 0x00, 0x2f, 0x00, 0x00, 0x00,
150 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
151 0x51, 0x11, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x61, 0x11, 0x00, 0x00, 0x0a, 0x00, 0x07, 0x00,
152 0x53, 0x50, 0x56, 0x5f, 0x4b, 0x48, 0x52, 0x5f, 0x31, 0x36, 0x62, 0x69, 0x74, 0x5f, 0x73, 0x74,
153 0x6f, 0x72, 0x61, 0x67, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x53, 0x50, 0x56, 0x5f,
154 0x4b, 0x48, 0x52, 0x5f, 0x38, 0x62, 0x69, 0x74, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65,
155 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c,
156 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00,
157 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00,
158 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
159 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
160 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
161 0x0b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00,
162 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00,
163 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x13, 0x00, 0x00, 0x00,
164 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
165 0x13, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00,
166 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00,
167 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x00,
168 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,
169 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00,
170 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
171 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00,
172 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00,
173 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2e, 0x00, 0x00, 0x00,
174 0x0b, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
175 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
176 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
177 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
178 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
179 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
180 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,
181 0x06, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
182 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
183 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x03, 0x00,
184 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x13, 0x00, 0x00, 0x00,
185 0x12, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
186 0x13, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
187 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
188 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
189 0x1e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x03, 0x00,
190 0x1f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00,
191 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
192 0x20, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
193 0x02, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
194 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
195 0x11, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
196 0x1e, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
197 0x00, 0x04, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00,
198 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00,
199 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00,
200 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
201 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
202 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00,
203 0x0e, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
204 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
205 0x08, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
206 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x44, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
207 0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00,
208 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00,
209 0x06, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x05, 0x00,
210 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
211 0xf7, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00,
212 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
213 0x1c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
214 0x08, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
215 0x08, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
216 0x15, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
217 0x11, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x71, 0x00, 0x04, 0x00,
218 0x1e, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
219 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
220 0x24, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,
221 0xf9, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00,
222 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
223};
224
225// Quad indexed SPIR-V module. Generated from the "shaders/" directory.
226constexpr u8 QUAD_INDEXED_SPV[] = {
227 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x08, 0x00, 0x7c, 0x00, 0x00, 0x00,
228 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00,
229 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
230 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
231 0x0f, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,
232 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00,
233 0x11, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
234 0x47, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
235 0x47, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
236 0x48, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
237 0x48, 0x00, 0x05, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
238 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
239 0x47, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240 0x47, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
241 0x48, 0x00, 0x05, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
242 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
243 0x23, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x22, 0x00, 0x00, 0x00,
244 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x56, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
245 0x04, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246 0x18, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
247 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x57, 0x00, 0x00, 0x00,
248 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
249 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
250 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
251 0x19, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00,
252 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
253 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
254 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,
255 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00,
256 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
257 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
258 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,
259 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00,
260 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
261 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x03, 0x00, 0x15, 0x00, 0x00, 0x00,
262 0x09, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
263 0x20, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
264 0x3b, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
265 0x14, 0x00, 0x02, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
266 0x21, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00,
267 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00,
268 0x09, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00,
269 0x24, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
270 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00,
271 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
272 0x2b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,
273 0x3b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
274 0x3f, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x41, 0x00, 0x00, 0x00,
275 0x06, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
276 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
277 0x43, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x09, 0x00, 0x41, 0x00, 0x00, 0x00,
278 0x44, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00,
279 0x42, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
280 0x46, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x03, 0x00,
281 0x56, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x57, 0x00, 0x00, 0x00,
282 0x56, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
283 0x57, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00,
284 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
285 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
286 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
287 0x00, 0x04, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00,
288 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00,
289 0x70, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00,
290 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
291 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
292 0x47, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x74, 0x00, 0x00, 0x00,
293 0xf8, 0x00, 0x02, 0x00, 0x74, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00, 0x73, 0x00, 0x00, 0x00,
294 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x75, 0x00, 0x00, 0x00,
295 0xf8, 0x00, 0x02, 0x00, 0x75, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00,
296 0x0f, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
297 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00,
298 0x06, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x84, 0x00, 0x05, 0x00,
299 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
300 0x44, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
301 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
302 0x19, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x05, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
303 0x14, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00,
304 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
305 0x1e, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00,
306 0x73, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
307 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
308 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
309 0xc4, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
310 0x28, 0x00, 0x00, 0x00, 0x82, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00,
311 0x2b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
312 0x31, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x82, 0x00, 0x05, 0x00,
313 0x06, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
314 0xf9, 0x00, 0x02, 0x00, 0x35, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x35, 0x00, 0x00, 0x00,
315 0xf5, 0x00, 0x07, 0x00, 0x09, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
316 0x1e, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x05, 0x00,
317 0x1b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00,
318 0xf6, 0x00, 0x04, 0x00, 0x37, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 0xfa, 0x00, 0x04, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
320 0xf8, 0x00, 0x02, 0x00, 0x36, 0x00, 0x00, 0x00, 0x84, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
321 0x40, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
322 0x47, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00,
323 0x48, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
324 0x06, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00,
325 0x06, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00,
326 0xc3, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00,
327 0x2e, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00,
328 0x4a, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x84, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
329 0x54, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
330 0x5b, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
331 0x4e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00,
332 0x5c, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00,
333 0x5d, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00,
334 0x09, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00,
335 0x09, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00,
336 0x41, 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
337 0x42, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00,
338 0x6a, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
339 0x62, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5b, 0x00, 0x00, 0x00,
340 0x6d, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00,
341 0x3e, 0x00, 0x03, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00,
342 0x09, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
343 0xf9, 0x00, 0x02, 0x00, 0x35, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x37, 0x00, 0x00, 0x00,
344 0xf9, 0x00, 0x02, 0x00, 0x73, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x76, 0x00, 0x00, 0x00,
345 0xf9, 0x00, 0x02, 0x00, 0x74, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x73, 0x00, 0x00, 0x00,
346 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
347};
348
349std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBindings() { 57std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBindings() {
350 return {{ 58 return {{
351 { 59 {
@@ -381,8 +89,8 @@ VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() {
381VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descriptor_pool, 89VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descriptor_pool,
382 vk::Span<VkDescriptorSetLayoutBinding> bindings, 90 vk::Span<VkDescriptorSetLayoutBinding> bindings,
383 vk::Span<VkDescriptorUpdateTemplateEntryKHR> templates, 91 vk::Span<VkDescriptorUpdateTemplateEntryKHR> templates,
384 vk::Span<VkPushConstantRange> push_constants, std::size_t code_size, 92 vk::Span<VkPushConstantRange> push_constants,
385 const u8* code) { 93 std::span<const u32> code) {
386 descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout({ 94 descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout({
387 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 95 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
388 .pNext = nullptr, 96 .pNext = nullptr,
@@ -390,7 +98,6 @@ VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descripto
390 .bindingCount = bindings.size(), 98 .bindingCount = bindings.size(),
391 .pBindings = bindings.data(), 99 .pBindings = bindings.data(),
392 }); 100 });
393
394 layout = device.GetLogical().CreatePipelineLayout({ 101 layout = device.GetLogical().CreatePipelineLayout({
395 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 102 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
396 .pNext = nullptr, 103 .pNext = nullptr,
@@ -400,7 +107,6 @@ VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descripto
400 .pushConstantRangeCount = push_constants.size(), 107 .pushConstantRangeCount = push_constants.size(),
401 .pPushConstantRanges = push_constants.data(), 108 .pPushConstantRanges = push_constants.data(),
402 }); 109 });
403
404 if (!templates.empty()) { 110 if (!templates.empty()) {
405 descriptor_template = device.GetLogical().CreateDescriptorUpdateTemplateKHR({ 111 descriptor_template = device.GetLogical().CreateDescriptorUpdateTemplateKHR({
406 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR, 112 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
@@ -417,18 +123,13 @@ VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descripto
417 123
418 descriptor_allocator.emplace(descriptor_pool, *descriptor_set_layout); 124 descriptor_allocator.emplace(descriptor_pool, *descriptor_set_layout);
419 } 125 }
420
421 auto code_copy = std::make_unique<u32[]>(code_size / sizeof(u32) + 1);
422 std::memcpy(code_copy.get(), code, code_size);
423
424 module = device.GetLogical().CreateShaderModule({ 126 module = device.GetLogical().CreateShaderModule({
425 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 127 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
426 .pNext = nullptr, 128 .pNext = nullptr,
427 .flags = 0, 129 .flags = 0,
428 .codeSize = code_size, 130 .codeSize = static_cast<u32>(code.size_bytes()),
429 .pCode = code_copy.get(), 131 .pCode = code.data(),
430 }); 132 });
431
432 pipeline = device.GetLogical().CreateComputePipeline({ 133 pipeline = device.GetLogical().CreateComputePipeline({
433 .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, 134 .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
434 .pNext = nullptr, 135 .pNext = nullptr,
@@ -467,7 +168,7 @@ QuadArrayPass::QuadArrayPass(const VKDevice& device_, VKScheduler& scheduler_,
467 VKUpdateDescriptorQueue& update_descriptor_queue_) 168 VKUpdateDescriptorQueue& update_descriptor_queue_)
468 : VKComputePass(device_, descriptor_pool_, BuildQuadArrayPassDescriptorSetLayoutBinding(), 169 : VKComputePass(device_, descriptor_pool_, BuildQuadArrayPassDescriptorSetLayoutBinding(),
469 BuildQuadArrayPassDescriptorUpdateTemplateEntry(), 170 BuildQuadArrayPassDescriptorUpdateTemplateEntry(),
470 BuildComputePushConstantRange(sizeof(u32)), std::size(quad_array), quad_array), 171 BuildComputePushConstantRange(sizeof(u32)), VULKAN_QUAD_ARRAY_COMP_SPV),
471 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, 172 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
472 update_descriptor_queue{update_descriptor_queue_} {} 173 update_descriptor_queue{update_descriptor_queue_} {}
473 174
@@ -510,12 +211,11 @@ std::pair<VkBuffer, VkDeviceSize> QuadArrayPass::Assemble(u32 num_vertices, u32
510 return {*buffer.handle, 0}; 211 return {*buffer.handle, 0};
511} 212}
512 213
513Uint8Pass::Uint8Pass(const VKDevice& device_, VKScheduler& scheduler_, 214Uint8Pass::Uint8Pass(const VKDevice& device, VKScheduler& scheduler_,
514 VKDescriptorPool& descriptor_pool_, VKStagingBufferPool& staging_buffer_pool_, 215 VKDescriptorPool& descriptor_pool, VKStagingBufferPool& staging_buffer_pool_,
515 VKUpdateDescriptorQueue& update_descriptor_queue_) 216 VKUpdateDescriptorQueue& update_descriptor_queue_)
516 : VKComputePass(device_, descriptor_pool_, BuildInputOutputDescriptorSetBindings(), 217 : VKComputePass(device, descriptor_pool, BuildInputOutputDescriptorSetBindings(),
517 BuildInputOutputDescriptorUpdateTemplate(), {}, std::size(uint8_pass), 218 BuildInputOutputDescriptorUpdateTemplate(), {}, VULKAN_UINT8_COMP_SPV),
518 uint8_pass),
519 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, 219 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
520 update_descriptor_queue{update_descriptor_queue_} {} 220 update_descriptor_queue{update_descriptor_queue_} {}
521 221
@@ -561,8 +261,7 @@ QuadIndexedPass::QuadIndexedPass(const VKDevice& device_, VKScheduler& scheduler
561 VKUpdateDescriptorQueue& update_descriptor_queue_) 261 VKUpdateDescriptorQueue& update_descriptor_queue_)
562 : VKComputePass(device_, descriptor_pool_, BuildInputOutputDescriptorSetBindings(), 262 : VKComputePass(device_, descriptor_pool_, BuildInputOutputDescriptorSetBindings(),
563 BuildInputOutputDescriptorUpdateTemplate(), 263 BuildInputOutputDescriptorUpdateTemplate(),
564 BuildComputePushConstantRange(sizeof(u32) * 2), std::size(QUAD_INDEXED_SPV), 264 BuildComputePushConstantRange(sizeof(u32) * 2), VULKAN_QUAD_INDEXED_COMP_SPV),
565 QUAD_INDEXED_SPV),
566 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, 265 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
567 update_descriptor_queue{update_descriptor_queue_} {} 266 update_descriptor_queue{update_descriptor_queue_} {}
568 267
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h
index 2dc87902c..abdf61e2c 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <optional> 7#include <optional>
8#include <span>
8#include <utility> 9#include <utility>
9 10
10#include "common/common_types.h" 11#include "common/common_types.h"
@@ -24,8 +25,7 @@ public:
24 explicit VKComputePass(const VKDevice& device, VKDescriptorPool& descriptor_pool, 25 explicit VKComputePass(const VKDevice& device, VKDescriptorPool& descriptor_pool,
25 vk::Span<VkDescriptorSetLayoutBinding> bindings, 26 vk::Span<VkDescriptorSetLayoutBinding> bindings,
26 vk::Span<VkDescriptorUpdateTemplateEntryKHR> templates, 27 vk::Span<VkDescriptorUpdateTemplateEntryKHR> templates,
27 vk::Span<VkPushConstantRange> push_constants, std::size_t code_size, 28 vk::Span<VkPushConstantRange> push_constants, std::span<const u32> code);
28 const u8* code);
29 ~VKComputePass(); 29 ~VKComputePass();
30 30
31protected: 31protected:
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp
index ce3846195..370a63f74 100644
--- a/src/video_core/renderer_vulkan/vk_device.cpp
+++ b/src/video_core/renderer_vulkan/vk_device.cpp
@@ -46,6 +46,7 @@ constexpr std::array REQUIRED_EXTENSIONS{
46 VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, 46 VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
47 VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME, 47 VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME,
48 VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME, 48 VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
49 VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME,
49 VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, 50 VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME,
50 VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME, 51 VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME,
51 VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME, 52 VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME,
@@ -122,6 +123,7 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(
122 VK_FORMAT_R16G16_UNORM, 123 VK_FORMAT_R16G16_UNORM,
123 VK_FORMAT_R16G16_SNORM, 124 VK_FORMAT_R16G16_SNORM,
124 VK_FORMAT_R16G16_SFLOAT, 125 VK_FORMAT_R16G16_SFLOAT,
126 VK_FORMAT_R16G16_SINT,
125 VK_FORMAT_R16_UNORM, 127 VK_FORMAT_R16_UNORM,
126 VK_FORMAT_R16_UINT, 128 VK_FORMAT_R16_UINT,
127 VK_FORMAT_R8G8B8A8_SRGB, 129 VK_FORMAT_R8G8B8A8_SRGB,
@@ -161,18 +163,32 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(
161 VK_FORMAT_BC2_SRGB_BLOCK, 163 VK_FORMAT_BC2_SRGB_BLOCK,
162 VK_FORMAT_BC3_SRGB_BLOCK, 164 VK_FORMAT_BC3_SRGB_BLOCK,
163 VK_FORMAT_BC7_SRGB_BLOCK, 165 VK_FORMAT_BC7_SRGB_BLOCK,
166 VK_FORMAT_ASTC_4x4_UNORM_BLOCK,
164 VK_FORMAT_ASTC_4x4_SRGB_BLOCK, 167 VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
165 VK_FORMAT_ASTC_8x8_SRGB_BLOCK, 168 VK_FORMAT_ASTC_5x4_UNORM_BLOCK,
166 VK_FORMAT_ASTC_8x5_SRGB_BLOCK,
167 VK_FORMAT_ASTC_5x4_SRGB_BLOCK, 169 VK_FORMAT_ASTC_5x4_SRGB_BLOCK,
168 VK_FORMAT_ASTC_5x5_UNORM_BLOCK, 170 VK_FORMAT_ASTC_5x5_UNORM_BLOCK,
169 VK_FORMAT_ASTC_5x5_SRGB_BLOCK, 171 VK_FORMAT_ASTC_5x5_SRGB_BLOCK,
170 VK_FORMAT_ASTC_10x8_UNORM_BLOCK, 172 VK_FORMAT_ASTC_6x5_UNORM_BLOCK,
171 VK_FORMAT_ASTC_10x8_SRGB_BLOCK, 173 VK_FORMAT_ASTC_6x5_SRGB_BLOCK,
172 VK_FORMAT_ASTC_6x6_UNORM_BLOCK, 174 VK_FORMAT_ASTC_6x6_UNORM_BLOCK,
173 VK_FORMAT_ASTC_6x6_SRGB_BLOCK, 175 VK_FORMAT_ASTC_6x6_SRGB_BLOCK,
176 VK_FORMAT_ASTC_8x5_UNORM_BLOCK,
177 VK_FORMAT_ASTC_8x5_SRGB_BLOCK,
178 VK_FORMAT_ASTC_8x6_UNORM_BLOCK,
179 VK_FORMAT_ASTC_8x6_SRGB_BLOCK,
180 VK_FORMAT_ASTC_8x8_UNORM_BLOCK,
181 VK_FORMAT_ASTC_8x8_SRGB_BLOCK,
182 VK_FORMAT_ASTC_10x5_UNORM_BLOCK,
183 VK_FORMAT_ASTC_10x5_SRGB_BLOCK,
184 VK_FORMAT_ASTC_10x6_UNORM_BLOCK,
185 VK_FORMAT_ASTC_10x6_SRGB_BLOCK,
186 VK_FORMAT_ASTC_10x8_UNORM_BLOCK,
187 VK_FORMAT_ASTC_10x8_SRGB_BLOCK,
174 VK_FORMAT_ASTC_10x10_UNORM_BLOCK, 188 VK_FORMAT_ASTC_10x10_UNORM_BLOCK,
175 VK_FORMAT_ASTC_10x10_SRGB_BLOCK, 189 VK_FORMAT_ASTC_10x10_SRGB_BLOCK,
190 VK_FORMAT_ASTC_12x10_UNORM_BLOCK,
191 VK_FORMAT_ASTC_12x10_SRGB_BLOCK,
176 VK_FORMAT_ASTC_12x12_UNORM_BLOCK, 192 VK_FORMAT_ASTC_12x12_UNORM_BLOCK,
177 VK_FORMAT_ASTC_12x12_SRGB_BLOCK, 193 VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
178 VK_FORMAT_ASTC_8x6_UNORM_BLOCK, 194 VK_FORMAT_ASTC_8x6_UNORM_BLOCK,
@@ -192,7 +208,7 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(
192 208
193VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevice physical_, 209VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevice physical_,
194 VkSurfaceKHR surface, const vk::InstanceDispatch& dld_) 210 VkSurfaceKHR surface, const vk::InstanceDispatch& dld_)
195 : dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, 211 : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()},
196 instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} { 212 instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} {
197 SetupFamilies(surface); 213 SetupFamilies(surface);
198 SetupFeatures(); 214 SetupFeatures();
@@ -214,7 +230,7 @@ bool VKDevice::Create() {
214 features2.features = { 230 features2.features = {
215 .robustBufferAccess = false, 231 .robustBufferAccess = false,
216 .fullDrawIndexUint32 = false, 232 .fullDrawIndexUint32 = false,
217 .imageCubeArray = false, 233 .imageCubeArray = true,
218 .independentBlend = true, 234 .independentBlend = true,
219 .geometryShader = true, 235 .geometryShader = true,
220 .tessellationShader = true, 236 .tessellationShader = true,
@@ -242,7 +258,7 @@ bool VKDevice::Create() {
242 .shaderTessellationAndGeometryPointSize = false, 258 .shaderTessellationAndGeometryPointSize = false,
243 .shaderImageGatherExtended = true, 259 .shaderImageGatherExtended = true,
244 .shaderStorageImageExtendedFormats = false, 260 .shaderStorageImageExtendedFormats = false,
245 .shaderStorageImageMultisample = false, 261 .shaderStorageImageMultisample = true,
246 .shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported, 262 .shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported,
247 .shaderStorageImageWriteWithoutFormat = true, 263 .shaderStorageImageWriteWithoutFormat = true,
248 .shaderUniformBufferArrayDynamicIndexing = false, 264 .shaderUniformBufferArrayDynamicIndexing = false,
@@ -268,7 +284,6 @@ bool VKDevice::Create() {
268 .variableMultisampleRate = false, 284 .variableMultisampleRate = false,
269 .inheritedQueries = false, 285 .inheritedQueries = false,
270 }; 286 };
271
272 VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore{ 287 VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore{
273 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR, 288 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR,
274 .pNext = nullptr, 289 .pNext = nullptr,
@@ -380,6 +395,20 @@ bool VKDevice::Create() {
380 LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state"); 395 LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state");
381 } 396 }
382 397
398 VkPhysicalDeviceRobustness2FeaturesEXT robustness2;
399 if (ext_robustness2) {
400 robustness2 = {
401 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT,
402 .pNext = nullptr,
403 .robustBufferAccess2 = false,
404 .robustImageAccess2 = true,
405 .nullDescriptor = true,
406 };
407 SetNext(next, robustness2);
408 } else {
409 LOG_INFO(Render_Vulkan, "Device doesn't support robustness2");
410 }
411
383 if (!ext_depth_range_unrestricted) { 412 if (!ext_depth_range_unrestricted) {
384 LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted"); 413 LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted");
385 } 414 }
@@ -405,7 +434,14 @@ bool VKDevice::Create() {
405 } 434 }
406 435
407 CollectTelemetryParameters(); 436 CollectTelemetryParameters();
437 CollectToolingInfo();
408 438
439 if (ext_extended_dynamic_state && driver_id == VK_DRIVER_ID_MESA_RADV) {
440 LOG_WARNING(
441 Render_Vulkan,
442 "Blacklisting RADV for VK_EXT_extended_dynamic state, likely due to a bug in yuzu");
443 ext_extended_dynamic_state = false;
444 }
409 if (ext_extended_dynamic_state && IsRDNA(properties.deviceName, driver_id)) { 445 if (ext_extended_dynamic_state && IsRDNA(properties.deviceName, driver_id)) {
410 // AMD's proprietary driver supports VK_EXT_extended_dynamic_state but on RDNA devices it 446 // AMD's proprietary driver supports VK_EXT_extended_dynamic_state but on RDNA devices it
411 // seems to cause stability issues 447 // seems to cause stability issues
@@ -458,7 +494,7 @@ void VKDevice::ReportLoss() const {
458 LOG_CRITICAL(Render_Vulkan, "Device loss occured!"); 494 LOG_CRITICAL(Render_Vulkan, "Device loss occured!");
459 495
460 // Wait for the log to flush and for Nsight Aftermath to dump the results 496 // Wait for the log to flush and for Nsight Aftermath to dump the results
461 std::this_thread::sleep_for(std::chrono::seconds{3}); 497 std::this_thread::sleep_for(std::chrono::seconds{15});
462} 498}
463 499
464void VKDevice::SaveShader(const std::vector<u32>& spirv) const { 500void VKDevice::SaveShader(const std::vector<u32>& spirv) const {
@@ -499,6 +535,16 @@ bool VKDevice::IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features)
499 return true; 535 return true;
500} 536}
501 537
538bool VKDevice::TestDepthStencilBlits() const {
539 static constexpr VkFormatFeatureFlags required_features =
540 VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT;
541 const auto test_features = [](VkFormatProperties props) {
542 return (props.optimalTilingFeatures & required_features) == required_features;
543 };
544 return test_features(format_properties.at(VK_FORMAT_D32_SFLOAT_S8_UINT)) &&
545 test_features(format_properties.at(VK_FORMAT_D24_UNORM_S8_UINT));
546}
547
502bool VKDevice::IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, 548bool VKDevice::IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage,
503 FormatType format_type) const { 549 FormatType format_type) const {
504 const auto it = format_properties.find(wanted_format); 550 const auto it = format_properties.find(wanted_format);
@@ -569,6 +615,7 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) {
569 const auto features{physical.GetFeatures()}; 615 const auto features{physical.GetFeatures()};
570 const std::array feature_report = { 616 const std::array feature_report = {
571 std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"), 617 std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),
618 std::make_pair(features.imageCubeArray, "imageCubeArray"),
572 std::make_pair(features.independentBlend, "independentBlend"), 619 std::make_pair(features.independentBlend, "independentBlend"),
573 std::make_pair(features.depthClamp, "depthClamp"), 620 std::make_pair(features.depthClamp, "depthClamp"),
574 std::make_pair(features.samplerAnisotropy, "samplerAnisotropy"), 621 std::make_pair(features.samplerAnisotropy, "samplerAnisotropy"),
@@ -580,6 +627,7 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) {
580 std::make_pair(features.occlusionQueryPrecise, "occlusionQueryPrecise"), 627 std::make_pair(features.occlusionQueryPrecise, "occlusionQueryPrecise"),
581 std::make_pair(features.fragmentStoresAndAtomics, "fragmentStoresAndAtomics"), 628 std::make_pair(features.fragmentStoresAndAtomics, "fragmentStoresAndAtomics"),
582 std::make_pair(features.shaderImageGatherExtended, "shaderImageGatherExtended"), 629 std::make_pair(features.shaderImageGatherExtended, "shaderImageGatherExtended"),
630 std::make_pair(features.shaderStorageImageMultisample, "shaderStorageImageMultisample"),
583 std::make_pair(features.shaderStorageImageWriteWithoutFormat, 631 std::make_pair(features.shaderStorageImageWriteWithoutFormat,
584 "shaderStorageImageWriteWithoutFormat"), 632 "shaderStorageImageWriteWithoutFormat"),
585 }; 633 };
@@ -608,6 +656,7 @@ std::vector<const char*> VKDevice::LoadExtensions() {
608 bool has_ext_transform_feedback{}; 656 bool has_ext_transform_feedback{};
609 bool has_ext_custom_border_color{}; 657 bool has_ext_custom_border_color{};
610 bool has_ext_extended_dynamic_state{}; 658 bool has_ext_extended_dynamic_state{};
659 bool has_ext_robustness2{};
611 for (const VkExtensionProperties& extension : physical.EnumerateDeviceExtensionProperties()) { 660 for (const VkExtensionProperties& extension : physical.EnumerateDeviceExtensionProperties()) {
612 const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name, 661 const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name,
613 bool push) { 662 bool push) {
@@ -627,11 +676,15 @@ std::vector<const char*> VKDevice::LoadExtensions() {
627 test(has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false); 676 test(has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false);
628 test(ext_depth_range_unrestricted, VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true); 677 test(ext_depth_range_unrestricted, VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true);
629 test(ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true); 678 test(ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true);
679 test(ext_sampler_filter_minmax, VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME, true);
630 test(ext_shader_viewport_index_layer, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, 680 test(ext_shader_viewport_index_layer, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME,
631 true); 681 true);
682 test(ext_tooling_info, VK_EXT_TOOLING_INFO_EXTENSION_NAME, true);
683 test(ext_shader_stencil_export, VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, true);
632 test(has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, false); 684 test(has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, false);
633 test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false); 685 test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false);
634 test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false); 686 test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false);
687 test(has_ext_robustness2, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, false);
635 if (instance_version >= VK_API_VERSION_1_1) { 688 if (instance_version >= VK_API_VERSION_1_1) {
636 test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false); 689 test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false);
637 } 690 }
@@ -733,6 +786,18 @@ std::vector<const char*> VKDevice::LoadExtensions() {
733 } 786 }
734 } 787 }
735 788
789 if (has_ext_robustness2) {
790 VkPhysicalDeviceRobustness2FeaturesEXT robustness2;
791 robustness2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT;
792 robustness2.pNext = nullptr;
793 features.pNext = &robustness2;
794 physical.GetFeatures2KHR(features);
795 if (robustness2.nullDescriptor && robustness2.robustImageAccess2) {
796 extensions.push_back(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
797 ext_robustness2 = true;
798 }
799 }
800
736 return extensions; 801 return extensions;
737} 802}
738 803
@@ -764,6 +829,7 @@ void VKDevice::SetupFamilies(VkSurfaceKHR surface) {
764void VKDevice::SetupFeatures() { 829void VKDevice::SetupFeatures() {
765 const auto supported_features{physical.GetFeatures()}; 830 const auto supported_features{physical.GetFeatures()};
766 is_formatless_image_load_supported = supported_features.shaderStorageImageReadWithoutFormat; 831 is_formatless_image_load_supported = supported_features.shaderStorageImageReadWithoutFormat;
832 is_blit_depth_stencil_supported = TestDepthStencilBlits();
767 is_optimal_astc_supported = IsOptimalAstcSupported(supported_features); 833 is_optimal_astc_supported = IsOptimalAstcSupported(supported_features);
768} 834}
769 835
@@ -794,6 +860,32 @@ void VKDevice::CollectTelemetryParameters() {
794 } 860 }
795} 861}
796 862
863void VKDevice::CollectToolingInfo() {
864 if (!ext_tooling_info) {
865 return;
866 }
867 const auto vkGetPhysicalDeviceToolPropertiesEXT =
868 reinterpret_cast<PFN_vkGetPhysicalDeviceToolPropertiesEXT>(
869 dld.vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceToolPropertiesEXT"));
870 if (!vkGetPhysicalDeviceToolPropertiesEXT) {
871 return;
872 }
873 u32 tool_count = 0;
874 if (vkGetPhysicalDeviceToolPropertiesEXT(physical, &tool_count, nullptr) != VK_SUCCESS) {
875 return;
876 }
877 std::vector<VkPhysicalDeviceToolPropertiesEXT> tools(tool_count);
878 if (vkGetPhysicalDeviceToolPropertiesEXT(physical, &tool_count, tools.data()) != VK_SUCCESS) {
879 return;
880 }
881 for (const VkPhysicalDeviceToolPropertiesEXT& tool : tools) {
882 const std::string_view name = tool.name;
883 LOG_INFO(Render_Vulkan, "{}", name);
884 has_renderdoc = has_renderdoc || name == "RenderDoc";
885 has_nsight_graphics = has_nsight_graphics || name == "NVIDIA Nsight Graphics";
886 }
887}
888
797std::vector<VkDeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() const { 889std::vector<VkDeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() const {
798 static constexpr float QUEUE_PRIORITY = 1.0f; 890 static constexpr float QUEUE_PRIORITY = 1.0f;
799 891
diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h
index 4286673d9..995dcfc0f 100644
--- a/src/video_core/renderer_vulkan/vk_device.h
+++ b/src/video_core/renderer_vulkan/vk_device.h
@@ -157,6 +157,11 @@ public:
157 return is_formatless_image_load_supported; 157 return is_formatless_image_load_supported;
158 } 158 }
159 159
160 /// Returns true when blitting from and to depth stencil images is supported.
161 bool IsBlitDepthStencilSupported() const {
162 return is_blit_depth_stencil_supported;
163 }
164
160 /// Returns true if the device supports VK_NV_viewport_swizzle. 165 /// Returns true if the device supports VK_NV_viewport_swizzle.
161 bool IsNvViewportSwizzleSupported() const { 166 bool IsNvViewportSwizzleSupported() const {
162 return nv_viewport_swizzle; 167 return nv_viewport_swizzle;
@@ -172,6 +177,11 @@ public:
172 return ext_index_type_uint8; 177 return ext_index_type_uint8;
173 } 178 }
174 179
180 /// Returns true if the device supports VK_EXT_sampler_filter_minmax.
181 bool IsExtSamplerFilterMinmaxSupported() const {
182 return ext_sampler_filter_minmax;
183 }
184
175 /// Returns true if the device supports VK_EXT_depth_range_unrestricted. 185 /// Returns true if the device supports VK_EXT_depth_range_unrestricted.
176 bool IsExtDepthRangeUnrestrictedSupported() const { 186 bool IsExtDepthRangeUnrestrictedSupported() const {
177 return ext_depth_range_unrestricted; 187 return ext_depth_range_unrestricted;
@@ -197,6 +207,16 @@ public:
197 return ext_extended_dynamic_state; 207 return ext_extended_dynamic_state;
198 } 208 }
199 209
210 /// Returns true if the device supports VK_EXT_shader_stencil_export.
211 bool IsExtShaderStencilExportSupported() const {
212 return ext_shader_stencil_export;
213 }
214
215 /// Returns true when a known debugging tool is attached.
216 bool HasDebuggingToolAttached() const {
217 return has_renderdoc || has_nsight_graphics;
218 }
219
200 /// Returns the vendor name reported from Vulkan. 220 /// Returns the vendor name reported from Vulkan.
201 std::string_view GetVendorName() const { 221 std::string_view GetVendorName() const {
202 return vendor_name; 222 return vendor_name;
@@ -228,16 +248,23 @@ private:
228 /// Collects telemetry information from the device. 248 /// Collects telemetry information from the device.
229 void CollectTelemetryParameters(); 249 void CollectTelemetryParameters();
230 250
251 /// Collects information about attached tools.
252 void CollectToolingInfo();
253
231 /// Returns a list of queue initialization descriptors. 254 /// Returns a list of queue initialization descriptors.
232 std::vector<VkDeviceQueueCreateInfo> GetDeviceQueueCreateInfos() const; 255 std::vector<VkDeviceQueueCreateInfo> GetDeviceQueueCreateInfos() const;
233 256
234 /// Returns true if ASTC textures are natively supported. 257 /// Returns true if ASTC textures are natively supported.
235 bool IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const; 258 bool IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const;
236 259
260 /// Returns true if the device natively supports blitting depth stencil images.
261 bool TestDepthStencilBlits() const;
262
237 /// Returns true if a format is supported. 263 /// Returns true if a format is supported.
238 bool IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, 264 bool IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage,
239 FormatType format_type) const; 265 FormatType format_type) const;
240 266
267 VkInstance instance; ///< Vulkan instance.
241 vk::DeviceDispatch dld; ///< Device function pointers. 268 vk::DeviceDispatch dld; ///< Device function pointers.
242 vk::PhysicalDevice physical; ///< Physical device. 269 vk::PhysicalDevice physical; ///< Physical device.
243 VkPhysicalDeviceProperties properties; ///< Device properties. 270 VkPhysicalDeviceProperties properties; ///< Device properties.
@@ -253,15 +280,22 @@ private:
253 bool is_float16_supported{}; ///< Support for float16 arithmetics. 280 bool is_float16_supported{}; ///< Support for float16 arithmetics.
254 bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest. 281 bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest.
255 bool is_formatless_image_load_supported{}; ///< Support for shader image read without format. 282 bool is_formatless_image_load_supported{}; ///< Support for shader image read without format.
283 bool is_blit_depth_stencil_supported{}; ///< Support for blitting from and to depth stencil.
256 bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle. 284 bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle.
257 bool khr_uniform_buffer_standard_layout{}; ///< Support for std430 on UBOs. 285 bool khr_uniform_buffer_standard_layout{}; ///< Support for std430 on UBOs.
258 bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8. 286 bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8.
287 bool ext_sampler_filter_minmax{}; ///< Support for VK_EXT_sampler_filter_minmax.
259 bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted. 288 bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted.
260 bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer. 289 bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer.
290 bool ext_tooling_info{}; ///< Support for VK_EXT_tooling_info.
261 bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback. 291 bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback.
262 bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color. 292 bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color.
263 bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state. 293 bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state.
294 bool ext_robustness2{}; ///< Support for VK_EXT_robustness2.
295 bool ext_shader_stencil_export{}; ///< Support for VK_EXT_shader_stencil_export.
264 bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config. 296 bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config.
297 bool has_renderdoc{}; ///< Has RenderDoc attached
298 bool has_nsight_graphics{}; ///< Has Nsight Graphics attached
265 299
266 // Asynchronous Graphics Pipeline setting 300 // Asynchronous Graphics Pipeline setting
267 bool use_asynchronous_shaders{}; ///< Setting to use asynchronous shaders/graphics pipeline 301 bool use_asynchronous_shaders{}; ///< Setting to use asynchronous shaders/graphics pipeline
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
index 0bcaee714..774a12a53 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
@@ -73,10 +73,9 @@ bool InnerFence::IsEventSignalled() const {
73} 73}
74 74
75VKFenceManager::VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_, 75VKFenceManager::VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_,
76 Tegra::MemoryManager& memory_manager_, 76 Tegra::MemoryManager& memory_manager_, TextureCache& texture_cache_,
77 VKTextureCache& texture_cache_, VKBufferCache& buffer_cache_, 77 VKBufferCache& buffer_cache_, VKQueryCache& query_cache_,
78 VKQueryCache& query_cache_, const VKDevice& device_, 78 const VKDevice& device_, VKScheduler& scheduler_)
79 VKScheduler& scheduler_)
80 : GenericFenceManager{rasterizer_, gpu_, texture_cache_, buffer_cache_, query_cache_}, 79 : GenericFenceManager{rasterizer_, gpu_, texture_cache_, buffer_cache_, query_cache_},
81 device{device_}, scheduler{scheduler_} {} 80 device{device_}, scheduler{scheduler_} {}
82 81
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.h b/src/video_core/renderer_vulkan/vk_fence_manager.h
index c8547cc24..c2869e8e3 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.h
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.h
@@ -8,6 +8,7 @@
8 8
9#include "video_core/fence_manager.h" 9#include "video_core/fence_manager.h"
10#include "video_core/renderer_vulkan/vk_buffer_cache.h" 10#include "video_core/renderer_vulkan/vk_buffer_cache.h"
11#include "video_core/renderer_vulkan/vk_texture_cache.h"
11#include "video_core/renderer_vulkan/wrapper.h" 12#include "video_core/renderer_vulkan/wrapper.h"
12 13
13namespace Core { 14namespace Core {
@@ -24,7 +25,6 @@ class VKBufferCache;
24class VKDevice; 25class VKDevice;
25class VKQueryCache; 26class VKQueryCache;
26class VKScheduler; 27class VKScheduler;
27class VKTextureCache;
28 28
29class InnerFence : public VideoCommon::FenceBase { 29class InnerFence : public VideoCommon::FenceBase {
30public: 30public:
@@ -51,12 +51,12 @@ private:
51using Fence = std::shared_ptr<InnerFence>; 51using Fence = std::shared_ptr<InnerFence>;
52 52
53using GenericFenceManager = 53using GenericFenceManager =
54 VideoCommon::FenceManager<Fence, VKTextureCache, VKBufferCache, VKQueryCache>; 54 VideoCommon::FenceManager<Fence, TextureCache, VKBufferCache, VKQueryCache>;
55 55
56class VKFenceManager final : public GenericFenceManager { 56class VKFenceManager final : public GenericFenceManager {
57public: 57public:
58 explicit VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_, 58 explicit VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_,
59 Tegra::MemoryManager& memory_manager_, VKTextureCache& texture_cache_, 59 Tegra::MemoryManager& memory_manager_, TextureCache& texture_cache_,
60 VKBufferCache& buffer_cache_, VKQueryCache& query_cache_, 60 VKBufferCache& buffer_cache_, VKQueryCache& query_cache_,
61 const VKDevice& device_, VKScheduler& scheduler_); 61 const VKDevice& device_, VKScheduler& scheduler_);
62 62
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index 970979fa1..7979df3a8 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -15,7 +15,6 @@
15#include "video_core/renderer_vulkan/vk_device.h" 15#include "video_core/renderer_vulkan/vk_device.h"
16#include "video_core/renderer_vulkan/vk_graphics_pipeline.h" 16#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
17#include "video_core/renderer_vulkan/vk_pipeline_cache.h" 17#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
18#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
19#include "video_core/renderer_vulkan/vk_scheduler.h" 18#include "video_core/renderer_vulkan/vk_scheduler.h"
20#include "video_core/renderer_vulkan/vk_update_descriptor.h" 19#include "video_core/renderer_vulkan/vk_update_descriptor.h"
21#include "video_core/renderer_vulkan/wrapper.h" 20#include "video_core/renderer_vulkan/wrapper.h"
@@ -69,23 +68,45 @@ VkViewportSwizzleNV UnpackViewportSwizzle(u16 swizzle) {
69 }; 68 };
70} 69}
71 70
71VkSampleCountFlagBits ConvertMsaaMode(Tegra::Texture::MsaaMode msaa_mode) {
72 switch (msaa_mode) {
73 case Tegra::Texture::MsaaMode::Msaa1x1:
74 return VK_SAMPLE_COUNT_1_BIT;
75 case Tegra::Texture::MsaaMode::Msaa2x1:
76 case Tegra::Texture::MsaaMode::Msaa2x1_D3D:
77 return VK_SAMPLE_COUNT_2_BIT;
78 case Tegra::Texture::MsaaMode::Msaa2x2:
79 case Tegra::Texture::MsaaMode::Msaa2x2_VC4:
80 case Tegra::Texture::MsaaMode::Msaa2x2_VC12:
81 return VK_SAMPLE_COUNT_4_BIT;
82 case Tegra::Texture::MsaaMode::Msaa4x2:
83 case Tegra::Texture::MsaaMode::Msaa4x2_D3D:
84 case Tegra::Texture::MsaaMode::Msaa4x2_VC8:
85 case Tegra::Texture::MsaaMode::Msaa4x2_VC24:
86 return VK_SAMPLE_COUNT_8_BIT;
87 case Tegra::Texture::MsaaMode::Msaa4x4:
88 return VK_SAMPLE_COUNT_16_BIT;
89 default:
90 UNREACHABLE_MSG("Invalid msaa_mode={}", static_cast<int>(msaa_mode));
91 return VK_SAMPLE_COUNT_1_BIT;
92 }
93}
94
72} // Anonymous namespace 95} // Anonymous namespace
73 96
74VKGraphicsPipeline::VKGraphicsPipeline(const VKDevice& device_, VKScheduler& scheduler_, 97VKGraphicsPipeline::VKGraphicsPipeline(const VKDevice& device_, VKScheduler& scheduler_,
75 VKDescriptorPool& descriptor_pool_, 98 VKDescriptorPool& descriptor_pool_,
76 VKUpdateDescriptorQueue& update_descriptor_queue_, 99 VKUpdateDescriptorQueue& update_descriptor_queue_,
77 VKRenderPassCache& renderpass_cache_, 100 const GraphicsPipelineCacheKey& key,
78 const GraphicsPipelineCacheKey& key_, 101 vk::Span<VkDescriptorSetLayoutBinding> bindings,
79 vk::Span<VkDescriptorSetLayoutBinding> bindings_, 102 const SPIRVProgram& program, u32 num_color_buffers)
80 const SPIRVProgram& program_) 103 : device{device_}, scheduler{scheduler_}, cache_key{key}, hash{cache_key.Hash()},
81 : device{device_}, scheduler{scheduler_}, cache_key{key_}, hash{cache_key.Hash()}, 104 descriptor_set_layout{CreateDescriptorSetLayout(bindings)},
82 descriptor_set_layout{CreateDescriptorSetLayout(bindings_)},
83 descriptor_allocator{descriptor_pool_, *descriptor_set_layout}, 105 descriptor_allocator{descriptor_pool_, *descriptor_set_layout},
84 update_descriptor_queue{update_descriptor_queue_}, layout{CreatePipelineLayout()}, 106 update_descriptor_queue{update_descriptor_queue_}, layout{CreatePipelineLayout()},
85 descriptor_template{CreateDescriptorUpdateTemplate(program_)}, modules{CreateShaderModules( 107 descriptor_template{CreateDescriptorUpdateTemplate(program)},
86 program_)}, 108 modules(CreateShaderModules(program)),
87 renderpass{renderpass_cache_.GetRenderPass(cache_key.renderpass_params)}, 109 pipeline(CreatePipeline(program, cache_key.renderpass, num_color_buffers)) {}
88 pipeline{CreatePipeline(cache_key.renderpass_params, program_)} {}
89 110
90VKGraphicsPipeline::~VKGraphicsPipeline() = default; 111VKGraphicsPipeline::~VKGraphicsPipeline() = default;
91 112
@@ -179,8 +200,9 @@ std::vector<vk::ShaderModule> VKGraphicsPipeline::CreateShaderModules(
179 return shader_modules; 200 return shader_modules;
180} 201}
181 202
182vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpass_params, 203vk::Pipeline VKGraphicsPipeline::CreatePipeline(const SPIRVProgram& program,
183 const SPIRVProgram& program) const { 204 VkRenderPass renderpass,
205 u32 num_color_buffers) const {
184 const auto& state = cache_key.fixed_state; 206 const auto& state = cache_key.fixed_state;
185 const auto& viewport_swizzles = state.viewport_swizzles; 207 const auto& viewport_swizzles = state.viewport_swizzles;
186 208
@@ -290,8 +312,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
290 }; 312 };
291 313
292 std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles; 314 std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles;
293 std::transform(viewport_swizzles.begin(), viewport_swizzles.end(), swizzles.begin(), 315 std::ranges::transform(viewport_swizzles, swizzles.begin(), UnpackViewportSwizzle);
294 UnpackViewportSwizzle);
295 VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ 316 VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{
296 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV, 317 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV,
297 .pNext = nullptr, 318 .pNext = nullptr,
@@ -326,7 +347,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
326 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, 347 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
327 .pNext = nullptr, 348 .pNext = nullptr,
328 .flags = 0, 349 .flags = 0,
329 .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, 350 .rasterizationSamples = ConvertMsaaMode(state.msaa_mode),
330 .sampleShadingEnable = VK_FALSE, 351 .sampleShadingEnable = VK_FALSE,
331 .minSampleShading = 0.0f, 352 .minSampleShading = 0.0f,
332 .pSampleMask = nullptr, 353 .pSampleMask = nullptr,
@@ -352,8 +373,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
352 }; 373 };
353 374
354 std::array<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments; 375 std::array<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments;
355 const auto num_attachments = static_cast<std::size_t>(renderpass_params.num_color_attachments); 376 for (std::size_t index = 0; index < num_color_buffers; ++index) {
356 for (std::size_t index = 0; index < num_attachments; ++index) {
357 static constexpr std::array COMPONENT_TABLE{ 377 static constexpr std::array COMPONENT_TABLE{
358 VK_COLOR_COMPONENT_R_BIT, 378 VK_COLOR_COMPONENT_R_BIT,
359 VK_COLOR_COMPONENT_G_BIT, 379 VK_COLOR_COMPONENT_G_BIT,
@@ -387,7 +407,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
387 .flags = 0, 407 .flags = 0,
388 .logicOpEnable = VK_FALSE, 408 .logicOpEnable = VK_FALSE,
389 .logicOp = VK_LOGIC_OP_COPY, 409 .logicOp = VK_LOGIC_OP_COPY,
390 .attachmentCount = static_cast<u32>(num_attachments), 410 .attachmentCount = num_color_buffers,
391 .pAttachments = cb_attachments.data(), 411 .pAttachments = cb_attachments.data(),
392 .blendConstants = {}, 412 .blendConstants = {},
393 }; 413 };
@@ -447,8 +467,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
447 stage_ci.pNext = &subgroup_size_ci; 467 stage_ci.pNext = &subgroup_size_ci;
448 } 468 }
449 } 469 }
450 470 return device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
451 const VkGraphicsPipelineCreateInfo ci{
452 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, 471 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
453 .pNext = nullptr, 472 .pNext = nullptr,
454 .flags = 0, 473 .flags = 0,
@@ -468,8 +487,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
468 .subpass = 0, 487 .subpass = 0,
469 .basePipelineHandle = nullptr, 488 .basePipelineHandle = nullptr,
470 .basePipelineIndex = 0, 489 .basePipelineIndex = 0,
471 }; 490 });
472 return device.GetLogical().CreateGraphicsPipeline(ci);
473} 491}
474 492
475} // namespace Vulkan 493} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
index 3fb31d55a..214d06b4c 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
@@ -8,10 +8,10 @@
8#include <optional> 8#include <optional>
9#include <vector> 9#include <vector>
10 10
11#include "common/common_types.h"
11#include "video_core/engines/maxwell_3d.h" 12#include "video_core/engines/maxwell_3d.h"
12#include "video_core/renderer_vulkan/fixed_pipeline_state.h" 13#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
13#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 14#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
14#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
15#include "video_core/renderer_vulkan/vk_shader_decompiler.h" 15#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
16#include "video_core/renderer_vulkan/wrapper.h" 16#include "video_core/renderer_vulkan/wrapper.h"
17 17
@@ -20,8 +20,7 @@ namespace Vulkan {
20using Maxwell = Tegra::Engines::Maxwell3D::Regs; 20using Maxwell = Tegra::Engines::Maxwell3D::Regs;
21 21
22struct GraphicsPipelineCacheKey { 22struct GraphicsPipelineCacheKey {
23 RenderPassParams renderpass_params; 23 VkRenderPass renderpass;
24 u32 padding;
25 std::array<GPUVAddr, Maxwell::MaxShaderProgram> shaders; 24 std::array<GPUVAddr, Maxwell::MaxShaderProgram> shaders;
26 FixedPipelineState fixed_state; 25 FixedPipelineState fixed_state;
27 26
@@ -34,7 +33,7 @@ struct GraphicsPipelineCacheKey {
34 } 33 }
35 34
36 std::size_t Size() const noexcept { 35 std::size_t Size() const noexcept {
37 return sizeof(renderpass_params) + sizeof(padding) + sizeof(shaders) + fixed_state.Size(); 36 return sizeof(renderpass) + sizeof(shaders) + fixed_state.Size();
38 } 37 }
39}; 38};
40static_assert(std::has_unique_object_representations_v<GraphicsPipelineCacheKey>); 39static_assert(std::has_unique_object_representations_v<GraphicsPipelineCacheKey>);
@@ -43,7 +42,6 @@ static_assert(std::is_trivially_constructible_v<GraphicsPipelineCacheKey>);
43 42
44class VKDescriptorPool; 43class VKDescriptorPool;
45class VKDevice; 44class VKDevice;
46class VKRenderPassCache;
47class VKScheduler; 45class VKScheduler;
48class VKUpdateDescriptorQueue; 46class VKUpdateDescriptorQueue;
49 47
@@ -52,12 +50,11 @@ using SPIRVProgram = std::array<std::optional<SPIRVShader>, Maxwell::MaxShaderSt
52class VKGraphicsPipeline final { 50class VKGraphicsPipeline final {
53public: 51public:
54 explicit VKGraphicsPipeline(const VKDevice& device_, VKScheduler& scheduler_, 52 explicit VKGraphicsPipeline(const VKDevice& device_, VKScheduler& scheduler_,
55 VKDescriptorPool& descriptor_pool_, 53 VKDescriptorPool& descriptor_pool,
56 VKUpdateDescriptorQueue& update_descriptor_queue_, 54 VKUpdateDescriptorQueue& update_descriptor_queue_,
57 VKRenderPassCache& renderpass_cache_, 55 const GraphicsPipelineCacheKey& key,
58 const GraphicsPipelineCacheKey& key_, 56 vk::Span<VkDescriptorSetLayoutBinding> bindings,
59 vk::Span<VkDescriptorSetLayoutBinding> bindings_, 57 const SPIRVProgram& program, u32 num_color_buffers);
60 const SPIRVProgram& program_);
61 ~VKGraphicsPipeline(); 58 ~VKGraphicsPipeline();
62 59
63 VkDescriptorSet CommitDescriptorSet(); 60 VkDescriptorSet CommitDescriptorSet();
@@ -70,10 +67,6 @@ public:
70 return *layout; 67 return *layout;
71 } 68 }
72 69
73 VkRenderPass GetRenderPass() const {
74 return renderpass;
75 }
76
77 GraphicsPipelineCacheKey GetCacheKey() const { 70 GraphicsPipelineCacheKey GetCacheKey() const {
78 return cache_key; 71 return cache_key;
79 } 72 }
@@ -89,8 +82,8 @@ private:
89 82
90 std::vector<vk::ShaderModule> CreateShaderModules(const SPIRVProgram& program) const; 83 std::vector<vk::ShaderModule> CreateShaderModules(const SPIRVProgram& program) const;
91 84
92 vk::Pipeline CreatePipeline(const RenderPassParams& renderpass_params, 85 vk::Pipeline CreatePipeline(const SPIRVProgram& program, VkRenderPass renderpass,
93 const SPIRVProgram& program) const; 86 u32 num_color_buffers) const;
94 87
95 const VKDevice& device; 88 const VKDevice& device;
96 VKScheduler& scheduler; 89 VKScheduler& scheduler;
@@ -104,7 +97,6 @@ private:
104 vk::DescriptorUpdateTemplateKHR descriptor_template; 97 vk::DescriptorUpdateTemplateKHR descriptor_template;
105 std::vector<vk::ShaderModule> modules; 98 std::vector<vk::ShaderModule> modules;
106 99
107 VkRenderPass renderpass;
108 vk::Pipeline pipeline; 100 vk::Pipeline pipeline;
109}; 101};
110 102
diff --git a/src/video_core/renderer_vulkan/vk_image.cpp b/src/video_core/renderer_vulkan/vk_image.cpp
deleted file mode 100644
index 072d14e3b..000000000
--- a/src/video_core/renderer_vulkan/vk_image.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <memory>
6#include <vector>
7
8#include "common/assert.h"
9#include "video_core/renderer_vulkan/vk_device.h"
10#include "video_core/renderer_vulkan/vk_image.h"
11#include "video_core/renderer_vulkan/vk_scheduler.h"
12#include "video_core/renderer_vulkan/wrapper.h"
13
14namespace Vulkan {
15
16VKImage::VKImage(const VKDevice& device_, VKScheduler& scheduler_,
17 const VkImageCreateInfo& image_ci_, VkImageAspectFlags aspect_mask_)
18 : device{device_}, scheduler{scheduler_}, format{image_ci_.format}, aspect_mask{aspect_mask_},
19 image_num_layers{image_ci_.arrayLayers}, image_num_levels{image_ci_.mipLevels} {
20 UNIMPLEMENTED_IF_MSG(image_ci_.queueFamilyIndexCount != 0,
21 "Queue family tracking is not implemented");
22
23 image = device_.GetLogical().CreateImage(image_ci_);
24
25 const u32 num_ranges = image_num_layers * image_num_levels;
26 barriers.resize(num_ranges);
27 subrange_states.resize(num_ranges, {{}, image_ci_.initialLayout});
28}
29
30VKImage::~VKImage() = default;
31
32void VKImage::Transition(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels,
33 VkPipelineStageFlags new_stage_mask, VkAccessFlags new_access,
34 VkImageLayout new_layout) {
35 if (!HasChanged(base_layer, num_layers, base_level, num_levels, new_access, new_layout)) {
36 return;
37 }
38
39 std::size_t cursor = 0;
40 for (u32 layer_it = 0; layer_it < num_layers; ++layer_it) {
41 for (u32 level_it = 0; level_it < num_levels; ++level_it, ++cursor) {
42 const u32 layer = base_layer + layer_it;
43 const u32 level = base_level + level_it;
44 auto& state = GetSubrangeState(layer, level);
45 auto& barrier = barriers[cursor];
46 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
47 barrier.pNext = nullptr;
48 barrier.srcAccessMask = state.access;
49 barrier.dstAccessMask = new_access;
50 barrier.oldLayout = state.layout;
51 barrier.newLayout = new_layout;
52 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
53 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
54 barrier.image = *image;
55 barrier.subresourceRange.aspectMask = aspect_mask;
56 barrier.subresourceRange.baseMipLevel = level;
57 barrier.subresourceRange.levelCount = 1;
58 barrier.subresourceRange.baseArrayLayer = layer;
59 barrier.subresourceRange.layerCount = 1;
60 state.access = new_access;
61 state.layout = new_layout;
62 }
63 }
64
65 scheduler.RequestOutsideRenderPassOperationContext();
66
67 scheduler.Record([barriers = barriers, cursor](vk::CommandBuffer cmdbuf) {
68 // TODO(Rodrigo): Implement a way to use the latest stage across subresources.
69 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
70 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, {}, {},
71 vk::Span(barriers.data(), cursor));
72 });
73}
74
75bool VKImage::HasChanged(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels,
76 VkAccessFlags new_access, VkImageLayout new_layout) noexcept {
77 const bool is_full_range = base_layer == 0 && num_layers == image_num_layers &&
78 base_level == 0 && num_levels == image_num_levels;
79 if (!is_full_range) {
80 state_diverged = true;
81 }
82
83 if (!state_diverged) {
84 auto& state = GetSubrangeState(0, 0);
85 if (state.access != new_access || state.layout != new_layout) {
86 return true;
87 }
88 }
89
90 for (u32 layer_it = 0; layer_it < num_layers; ++layer_it) {
91 for (u32 level_it = 0; level_it < num_levels; ++level_it) {
92 const u32 layer = base_layer + layer_it;
93 const u32 level = base_level + level_it;
94 auto& state = GetSubrangeState(layer, level);
95 if (state.access != new_access || state.layout != new_layout) {
96 return true;
97 }
98 }
99 }
100 return false;
101}
102
103void VKImage::CreatePresentView() {
104 // Image type has to be 2D to be presented.
105 present_view = device.GetLogical().CreateImageView({
106 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
107 .pNext = nullptr,
108 .flags = 0,
109 .image = *image,
110 .viewType = VK_IMAGE_VIEW_TYPE_2D,
111 .format = format,
112 .components =
113 {
114 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
115 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
116 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
117 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
118 },
119 .subresourceRange =
120 {
121 .aspectMask = aspect_mask,
122 .baseMipLevel = 0,
123 .levelCount = 1,
124 .baseArrayLayer = 0,
125 .layerCount = 1,
126 },
127 });
128}
129
130VKImage::SubrangeState& VKImage::GetSubrangeState(u32 layer, u32 level) noexcept {
131 return subrange_states[static_cast<std::size_t>(layer * image_num_levels) +
132 static_cast<std::size_t>(level)];
133}
134
135} // namespace Vulkan \ No newline at end of file
diff --git a/src/video_core/renderer_vulkan/vk_image.h b/src/video_core/renderer_vulkan/vk_image.h
deleted file mode 100644
index 287ab90ca..000000000
--- a/src/video_core/renderer_vulkan/vk_image.h
+++ /dev/null
@@ -1,84 +0,0 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <vector>
9
10#include "common/common_types.h"
11#include "video_core/renderer_vulkan/wrapper.h"
12
13namespace Vulkan {
14
15class VKDevice;
16class VKScheduler;
17
18class VKImage {
19public:
20 explicit VKImage(const VKDevice& device_, VKScheduler& scheduler_,
21 const VkImageCreateInfo& image_ci_, VkImageAspectFlags aspect_mask_);
22 ~VKImage();
23
24 /// Records in the passed command buffer an image transition and updates the state of the image.
25 void Transition(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels,
26 VkPipelineStageFlags new_stage_mask, VkAccessFlags new_access,
27 VkImageLayout new_layout);
28
29 /// Returns a view compatible with presentation, the image has to be 2D.
30 VkImageView GetPresentView() {
31 if (!present_view) {
32 CreatePresentView();
33 }
34 return *present_view;
35 }
36
37 /// Returns the Vulkan image handler.
38 const vk::Image& GetHandle() const {
39 return image;
40 }
41
42 /// Returns the Vulkan format for this image.
43 VkFormat GetFormat() const {
44 return format;
45 }
46
47 /// Returns the Vulkan aspect mask.
48 VkImageAspectFlags GetAspectMask() const {
49 return aspect_mask;
50 }
51
52private:
53 struct SubrangeState final {
54 VkAccessFlags access = 0; ///< Current access bits.
55 VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; ///< Current image layout.
56 };
57
58 bool HasChanged(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels,
59 VkAccessFlags new_access, VkImageLayout new_layout) noexcept;
60
61 /// Creates a presentation view.
62 void CreatePresentView();
63
64 /// Returns the subrange state for a layer and layer.
65 SubrangeState& GetSubrangeState(u32 layer, u32 level) noexcept;
66
67 const VKDevice& device; ///< Device handler.
68 VKScheduler& scheduler; ///< Device scheduler.
69
70 const VkFormat format; ///< Vulkan format.
71 const VkImageAspectFlags aspect_mask; ///< Vulkan aspect mask.
72 const u32 image_num_layers; ///< Number of layers.
73 const u32 image_num_levels; ///< Number of mipmap levels.
74
75 vk::Image image; ///< Image handle.
76 vk::ImageView present_view; ///< Image view compatible with presentation.
77
78 std::vector<VkImageMemoryBarrier> barriers; ///< Pool of barriers.
79 std::vector<SubrangeState> subrange_states; ///< Current subrange state.
80
81 bool state_diverged = false; ///< True when subresources mismatch in layout.
82};
83
84} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.cpp b/src/video_core/renderer_vulkan/vk_memory_manager.cpp
index be53d450f..56b24b70f 100644
--- a/src/video_core/renderer_vulkan/vk_memory_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_memory_manager.cpp
@@ -216,7 +216,7 @@ VKMemoryCommitImpl::~VKMemoryCommitImpl() {
216} 216}
217 217
218MemoryMap VKMemoryCommitImpl::Map(u64 size, u64 offset_) const { 218MemoryMap VKMemoryCommitImpl::Map(u64 size, u64 offset_) const {
219 return MemoryMap{this, memory.Map(interval.first + offset_, size)}; 219 return MemoryMap(this, std::span<u8>(memory.Map(interval.first + offset_, size), size));
220} 220}
221 221
222void VKMemoryCommitImpl::Unmap() const { 222void VKMemoryCommitImpl::Unmap() const {
diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.h b/src/video_core/renderer_vulkan/vk_memory_manager.h
index 39f903ec8..318f8b43e 100644
--- a/src/video_core/renderer_vulkan/vk_memory_manager.h
+++ b/src/video_core/renderer_vulkan/vk_memory_manager.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <span>
8#include <utility> 9#include <utility>
9#include <vector> 10#include <vector>
10#include "common/common_types.h" 11#include "common/common_types.h"
@@ -93,8 +94,8 @@ private:
93/// Holds ownership of a memory map. 94/// Holds ownership of a memory map.
94class MemoryMap final { 95class MemoryMap final {
95public: 96public:
96 explicit MemoryMap(const VKMemoryCommitImpl* commit_, u8* address_) 97 explicit MemoryMap(const VKMemoryCommitImpl* commit_, std::span<u8> span_)
97 : commit{commit_}, address{address_} {} 98 : commit{commit_}, span{span_} {}
98 99
99 ~MemoryMap() { 100 ~MemoryMap() {
100 if (commit) { 101 if (commit) {
@@ -108,19 +109,24 @@ public:
108 commit = nullptr; 109 commit = nullptr;
109 } 110 }
110 111
112 /// Returns a span to the memory map.
113 [[nodiscard]] std::span<u8> Span() const noexcept {
114 return span;
115 }
116
111 /// Returns the address of the memory map. 117 /// Returns the address of the memory map.
112 u8* GetAddress() const { 118 [[nodiscard]] u8* Address() const noexcept {
113 return address; 119 return span.data();
114 } 120 }
115 121
116 /// Returns the address of the memory map; 122 /// Returns the address of the memory map;
117 operator u8*() const { 123 [[nodiscard]] operator u8*() const noexcept {
118 return address; 124 return span.data();
119 } 125 }
120 126
121private: 127private:
122 const VKMemoryCommitImpl* commit{}; ///< Mapped memory commit. 128 const VKMemoryCommitImpl* commit{}; ///< Mapped memory commit.
123 u8* address{}; ///< Address to the mapped memory. 129 std::span<u8> span; ///< Address to the mapped memory.
124}; 130};
125 131
126} // namespace Vulkan 132} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 3fb264d03..083796d05 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -8,6 +8,7 @@
8#include <vector> 8#include <vector>
9 9
10#include "common/bit_cast.h" 10#include "common/bit_cast.h"
11#include "common/cityhash.h"
11#include "common/microprofile.h" 12#include "common/microprofile.h"
12#include "core/core.h" 13#include "core/core.h"
13#include "core/memory.h" 14#include "core/memory.h"
@@ -22,7 +23,6 @@
22#include "video_core/renderer_vulkan/vk_graphics_pipeline.h" 23#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
23#include "video_core/renderer_vulkan/vk_pipeline_cache.h" 24#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
24#include "video_core/renderer_vulkan/vk_rasterizer.h" 25#include "video_core/renderer_vulkan/vk_rasterizer.h"
25#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
26#include "video_core/renderer_vulkan/vk_scheduler.h" 26#include "video_core/renderer_vulkan/vk_scheduler.h"
27#include "video_core/renderer_vulkan/vk_update_descriptor.h" 27#include "video_core/renderer_vulkan/vk_update_descriptor.h"
28#include "video_core/renderer_vulkan/wrapper.h" 28#include "video_core/renderer_vulkan/wrapper.h"
@@ -52,7 +52,9 @@ constexpr VkDescriptorType STORAGE_TEXEL_BUFFER = VK_DESCRIPTOR_TYPE_STORAGE_TEX
52constexpr VkDescriptorType STORAGE_IMAGE = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; 52constexpr VkDescriptorType STORAGE_IMAGE = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
53 53
54constexpr VideoCommon::Shader::CompilerSettings compiler_settings{ 54constexpr VideoCommon::Shader::CompilerSettings compiler_settings{
55 VideoCommon::Shader::CompileDepth::FullDecompile}; 55 .depth = VideoCommon::Shader::CompileDepth::FullDecompile,
56 .disable_else_derivation = true,
57};
56 58
57constexpr std::size_t GetStageFromProgram(std::size_t program) { 59constexpr std::size_t GetStageFromProgram(std::size_t program) {
58 return program == 0 ? 0 : program - 1; 60 return program == 0 ? 0 : program - 1;
@@ -149,12 +151,11 @@ VKPipelineCache::VKPipelineCache(RasterizerVulkan& rasterizer_, Tegra::GPU& gpu_
149 Tegra::Engines::KeplerCompute& kepler_compute_, 151 Tegra::Engines::KeplerCompute& kepler_compute_,
150 Tegra::MemoryManager& gpu_memory_, const VKDevice& device_, 152 Tegra::MemoryManager& gpu_memory_, const VKDevice& device_,
151 VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_, 153 VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_,
152 VKUpdateDescriptorQueue& update_descriptor_queue_, 154 VKUpdateDescriptorQueue& update_descriptor_queue_)
153 VKRenderPassCache& renderpass_cache_) 155 : VideoCommon::ShaderCache<Shader>{rasterizer_}, gpu{gpu_}, maxwell3d{maxwell3d_},
154 : ShaderCache{rasterizer_}, gpu{gpu_}, maxwell3d{maxwell3d_}, kepler_compute{kepler_compute_}, 156 kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, device{device_},
155 gpu_memory{gpu_memory_}, device{device_}, scheduler{scheduler_}, 157 scheduler{scheduler_}, descriptor_pool{descriptor_pool_}, update_descriptor_queue{
156 descriptor_pool{descriptor_pool_}, update_descriptor_queue{update_descriptor_queue_}, 158 update_descriptor_queue_} {}
157 renderpass_cache{renderpass_cache_} {}
158 159
159VKPipelineCache::~VKPipelineCache() = default; 160VKPipelineCache::~VKPipelineCache() = default;
160 161
@@ -199,7 +200,8 @@ std::array<Shader*, Maxwell::MaxShaderProgram> VKPipelineCache::GetShaders() {
199} 200}
200 201
201VKGraphicsPipeline* VKPipelineCache::GetGraphicsPipeline( 202VKGraphicsPipeline* VKPipelineCache::GetGraphicsPipeline(
202 const GraphicsPipelineCacheKey& key, VideoCommon::Shader::AsyncShaders& async_shaders) { 203 const GraphicsPipelineCacheKey& key, u32 num_color_buffers,
204 VideoCommon::Shader::AsyncShaders& async_shaders) {
203 MICROPROFILE_SCOPE(Vulkan_PipelineCache); 205 MICROPROFILE_SCOPE(Vulkan_PipelineCache);
204 206
205 if (last_graphics_pipeline && last_graphics_key == key) { 207 if (last_graphics_pipeline && last_graphics_key == key) {
@@ -215,8 +217,8 @@ VKGraphicsPipeline* VKPipelineCache::GetGraphicsPipeline(
215 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash()); 217 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash());
216 const auto [program, bindings] = DecompileShaders(key.fixed_state); 218 const auto [program, bindings] = DecompileShaders(key.fixed_state);
217 async_shaders.QueueVulkanShader(this, device, scheduler, descriptor_pool, 219 async_shaders.QueueVulkanShader(this, device, scheduler, descriptor_pool,
218 update_descriptor_queue, renderpass_cache, bindings, 220 update_descriptor_queue, bindings, program, key,
219 program, key); 221 num_color_buffers);
220 } 222 }
221 last_graphics_pipeline = pair->second.get(); 223 last_graphics_pipeline = pair->second.get();
222 return last_graphics_pipeline; 224 return last_graphics_pipeline;
@@ -229,8 +231,8 @@ VKGraphicsPipeline* VKPipelineCache::GetGraphicsPipeline(
229 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash()); 231 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash());
230 const auto [program, bindings] = DecompileShaders(key.fixed_state); 232 const auto [program, bindings] = DecompileShaders(key.fixed_state);
231 entry = std::make_unique<VKGraphicsPipeline>(device, scheduler, descriptor_pool, 233 entry = std::make_unique<VKGraphicsPipeline>(device, scheduler, descriptor_pool,
232 update_descriptor_queue, renderpass_cache, key, 234 update_descriptor_queue, key, bindings,
233 bindings, program); 235 program, num_color_buffers);
234 gpu.ShaderNotify().MarkShaderComplete(); 236 gpu.ShaderNotify().MarkShaderComplete();
235 } 237 }
236 last_graphics_pipeline = entry.get(); 238 last_graphics_pipeline = entry.get();
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index 9e1f8fcbb..fbaa8257c 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -19,7 +19,6 @@
19#include "video_core/engines/maxwell_3d.h" 19#include "video_core/engines/maxwell_3d.h"
20#include "video_core/renderer_vulkan/fixed_pipeline_state.h" 20#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
21#include "video_core/renderer_vulkan/vk_graphics_pipeline.h" 21#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
22#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
23#include "video_core/renderer_vulkan/vk_shader_decompiler.h" 22#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
24#include "video_core/renderer_vulkan/wrapper.h" 23#include "video_core/renderer_vulkan/wrapper.h"
25#include "video_core/shader/async_shaders.h" 24#include "video_core/shader/async_shaders.h"
@@ -119,18 +118,18 @@ private:
119 118
120class VKPipelineCache final : public VideoCommon::ShaderCache<Shader> { 119class VKPipelineCache final : public VideoCommon::ShaderCache<Shader> {
121public: 120public:
122 explicit VKPipelineCache(RasterizerVulkan& rasterizer_, Tegra::GPU& gpu_, 121 explicit VKPipelineCache(RasterizerVulkan& rasterizer, Tegra::GPU& gpu,
123 Tegra::Engines::Maxwell3D& maxwell3d_, 122 Tegra::Engines::Maxwell3D& maxwell3d,
124 Tegra::Engines::KeplerCompute& kepler_compute_, 123 Tegra::Engines::KeplerCompute& kepler_compute,
125 Tegra::MemoryManager& gpu_memory_, const VKDevice& device_, 124 Tegra::MemoryManager& gpu_memory, const VKDevice& device,
126 VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_, 125 VKScheduler& scheduler, VKDescriptorPool& descriptor_pool,
127 VKUpdateDescriptorQueue& update_descriptor_queue_, 126 VKUpdateDescriptorQueue& update_descriptor_queue);
128 VKRenderPassCache& renderpass_cache_);
129 ~VKPipelineCache() override; 127 ~VKPipelineCache() override;
130 128
131 std::array<Shader*, Maxwell::MaxShaderProgram> GetShaders(); 129 std::array<Shader*, Maxwell::MaxShaderProgram> GetShaders();
132 130
133 VKGraphicsPipeline* GetGraphicsPipeline(const GraphicsPipelineCacheKey& key, 131 VKGraphicsPipeline* GetGraphicsPipeline(const GraphicsPipelineCacheKey& key,
132 u32 num_color_buffers,
134 VideoCommon::Shader::AsyncShaders& async_shaders); 133 VideoCommon::Shader::AsyncShaders& async_shaders);
135 134
136 VKComputePipeline& GetComputePipeline(const ComputePipelineCacheKey& key); 135 VKComputePipeline& GetComputePipeline(const ComputePipelineCacheKey& key);
@@ -153,7 +152,6 @@ private:
153 VKScheduler& scheduler; 152 VKScheduler& scheduler;
154 VKDescriptorPool& descriptor_pool; 153 VKDescriptorPool& descriptor_pool;
155 VKUpdateDescriptorQueue& update_descriptor_queue; 154 VKUpdateDescriptorQueue& update_descriptor_queue;
156 VKRenderPassCache& renderpass_cache;
157 155
158 std::unique_ptr<Shader> null_shader; 156 std::unique_ptr<Shader> null_shader;
159 std::unique_ptr<Shader> null_kernel; 157 std::unique_ptr<Shader> null_kernel;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index f93986aab..04c5c859c 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -19,6 +19,7 @@
19#include "core/settings.h" 19#include "core/settings.h"
20#include "video_core/engines/kepler_compute.h" 20#include "video_core/engines/kepler_compute.h"
21#include "video_core/engines/maxwell_3d.h" 21#include "video_core/engines/maxwell_3d.h"
22#include "video_core/renderer_vulkan/blit_image.h"
22#include "video_core/renderer_vulkan/fixed_pipeline_state.h" 23#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
23#include "video_core/renderer_vulkan/maxwell_to_vk.h" 24#include "video_core/renderer_vulkan/maxwell_to_vk.h"
24#include "video_core/renderer_vulkan/renderer_vulkan.h" 25#include "video_core/renderer_vulkan/renderer_vulkan.h"
@@ -30,8 +31,6 @@
30#include "video_core/renderer_vulkan/vk_graphics_pipeline.h" 31#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
31#include "video_core/renderer_vulkan/vk_pipeline_cache.h" 32#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
32#include "video_core/renderer_vulkan/vk_rasterizer.h" 33#include "video_core/renderer_vulkan/vk_rasterizer.h"
33#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
34#include "video_core/renderer_vulkan/vk_sampler_cache.h"
35#include "video_core/renderer_vulkan/vk_scheduler.h" 34#include "video_core/renderer_vulkan/vk_scheduler.h"
36#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 35#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
37#include "video_core/renderer_vulkan/vk_state_tracker.h" 36#include "video_core/renderer_vulkan/vk_state_tracker.h"
@@ -39,10 +38,13 @@
39#include "video_core/renderer_vulkan/vk_update_descriptor.h" 38#include "video_core/renderer_vulkan/vk_update_descriptor.h"
40#include "video_core/renderer_vulkan/wrapper.h" 39#include "video_core/renderer_vulkan/wrapper.h"
41#include "video_core/shader_cache.h" 40#include "video_core/shader_cache.h"
41#include "video_core/texture_cache/texture_cache.h"
42 42
43namespace Vulkan { 43namespace Vulkan {
44 44
45using Maxwell = Tegra::Engines::Maxwell3D::Regs; 45using Maxwell = Tegra::Engines::Maxwell3D::Regs;
46using VideoCommon::ImageViewId;
47using VideoCommon::ImageViewType;
46 48
47MICROPROFILE_DEFINE(Vulkan_WaitForWorker, "Vulkan", "Wait for worker", MP_RGB(255, 192, 192)); 49MICROPROFILE_DEFINE(Vulkan_WaitForWorker, "Vulkan", "Wait for worker", MP_RGB(255, 192, 192));
48MICROPROFILE_DEFINE(Vulkan_Drawing, "Vulkan", "Record drawing", MP_RGB(192, 128, 128)); 50MICROPROFILE_DEFINE(Vulkan_Drawing, "Vulkan", "Record drawing", MP_RGB(192, 128, 128));
@@ -58,9 +60,9 @@ MICROPROFILE_DEFINE(Vulkan_PipelineCache, "Vulkan", "Pipeline cache", MP_RGB(192
58 60
59namespace { 61namespace {
60 62
61constexpr auto ComputeShaderIndex = static_cast<std::size_t>(Tegra::Engines::ShaderType::Compute); 63constexpr auto COMPUTE_SHADER_INDEX = static_cast<size_t>(Tegra::Engines::ShaderType::Compute);
62 64
63VkViewport GetViewportState(const VKDevice& device, const Maxwell& regs, std::size_t index) { 65VkViewport GetViewportState(const VKDevice& device, const Maxwell& regs, size_t index) {
64 const auto& src = regs.viewport_transform[index]; 66 const auto& src = regs.viewport_transform[index];
65 const float width = src.scale_x * 2.0f; 67 const float width = src.scale_x * 2.0f;
66 const float height = src.scale_y * 2.0f; 68 const float height = src.scale_y * 2.0f;
@@ -83,7 +85,7 @@ VkViewport GetViewportState(const VKDevice& device, const Maxwell& regs, std::si
83 return viewport; 85 return viewport;
84} 86}
85 87
86VkRect2D GetScissorState(const Maxwell& regs, std::size_t index) { 88VkRect2D GetScissorState(const Maxwell& regs, size_t index) {
87 const auto& src = regs.scissor_test[index]; 89 const auto& src = regs.scissor_test[index];
88 VkRect2D scissor; 90 VkRect2D scissor;
89 if (src.enable) { 91 if (src.enable) {
@@ -103,98 +105,122 @@ VkRect2D GetScissorState(const Maxwell& regs, std::size_t index) {
103std::array<GPUVAddr, Maxwell::MaxShaderProgram> GetShaderAddresses( 105std::array<GPUVAddr, Maxwell::MaxShaderProgram> GetShaderAddresses(
104 const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders) { 106 const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders) {
105 std::array<GPUVAddr, Maxwell::MaxShaderProgram> addresses; 107 std::array<GPUVAddr, Maxwell::MaxShaderProgram> addresses;
106 for (std::size_t i = 0; i < std::size(addresses); ++i) { 108 for (size_t i = 0; i < std::size(addresses); ++i) {
107 addresses[i] = shaders[i] ? shaders[i]->GetGpuAddr() : 0; 109 addresses[i] = shaders[i] ? shaders[i]->GetGpuAddr() : 0;
108 } 110 }
109 return addresses; 111 return addresses;
110} 112}
111 113
112void TransitionImages(const std::vector<ImageView>& views, VkPipelineStageFlags pipeline_stage, 114struct TextureHandle {
113 VkAccessFlags access) { 115 constexpr TextureHandle(u32 data, bool via_header_index) {
114 for (auto& [view, layout] : views) { 116 const Tegra::Texture::TextureHandle handle{data};
115 view->Transition(*layout, pipeline_stage, access); 117 image = handle.tic_id;
118 sampler = via_header_index ? image : handle.tsc_id.Value();
116 } 119 }
117} 120
121 u32 image;
122 u32 sampler;
123};
118 124
119template <typename Engine, typename Entry> 125template <typename Engine, typename Entry>
120Tegra::Texture::FullTextureInfo GetTextureInfo(const Engine& engine, const Entry& entry, 126TextureHandle GetTextureInfo(const Engine& engine, bool via_header_index, const Entry& entry,
121 std::size_t stage, std::size_t index = 0) { 127 size_t stage, size_t index = 0) {
122 const auto stage_type = static_cast<Tegra::Engines::ShaderType>(stage); 128 const auto shader_type = static_cast<Tegra::Engines::ShaderType>(stage);
123 if constexpr (std::is_same_v<Entry, SamplerEntry>) { 129 if constexpr (std::is_same_v<Entry, SamplerEntry>) {
124 if (entry.is_separated) { 130 if (entry.is_separated) {
125 const u32 buffer_1 = entry.buffer; 131 const u32 buffer_1 = entry.buffer;
126 const u32 buffer_2 = entry.secondary_buffer; 132 const u32 buffer_2 = entry.secondary_buffer;
127 const u32 offset_1 = entry.offset; 133 const u32 offset_1 = entry.offset;
128 const u32 offset_2 = entry.secondary_offset; 134 const u32 offset_2 = entry.secondary_offset;
129 const u32 handle_1 = engine.AccessConstBuffer32(stage_type, buffer_1, offset_1); 135 const u32 handle_1 = engine.AccessConstBuffer32(shader_type, buffer_1, offset_1);
130 const u32 handle_2 = engine.AccessConstBuffer32(stage_type, buffer_2, offset_2); 136 const u32 handle_2 = engine.AccessConstBuffer32(shader_type, buffer_2, offset_2);
131 return engine.GetTextureInfo(Tegra::Texture::TextureHandle{handle_1 | handle_2}); 137 return TextureHandle(handle_1 | handle_2, via_header_index);
132 } 138 }
133 } 139 }
134 if (entry.is_bindless) { 140 if (entry.is_bindless) {
135 const auto tex_handle = engine.AccessConstBuffer32(stage_type, entry.buffer, entry.offset); 141 const u32 raw = engine.AccessConstBuffer32(shader_type, entry.buffer, entry.offset);
136 return engine.GetTextureInfo(Tegra::Texture::TextureHandle{tex_handle}); 142 return TextureHandle(raw, via_header_index);
137 }
138 const auto& gpu_profile = engine.AccessGuestDriverProfile();
139 const u32 entry_offset = static_cast<u32>(index * gpu_profile.GetTextureHandlerSize());
140 const u32 offset = entry.offset + entry_offset;
141 if constexpr (std::is_same_v<Engine, Tegra::Engines::Maxwell3D>) {
142 return engine.GetStageTexture(stage_type, offset);
143 } else {
144 return engine.GetTexture(offset);
145 }
146}
147
148/// @brief Determine if an attachment to be updated has to preserve contents
149/// @param is_clear True when a clear is being executed
150/// @param regs 3D registers
151/// @return True when the contents have to be preserved
152bool HasToPreserveColorContents(bool is_clear, const Maxwell& regs) {
153 if (!is_clear) {
154 return true;
155 }
156 // First we have to make sure all clear masks are enabled.
157 if (!regs.clear_buffers.R || !regs.clear_buffers.G || !regs.clear_buffers.B ||
158 !regs.clear_buffers.A) {
159 return true;
160 }
161 // If scissors are disabled, the whole screen is cleared
162 if (!regs.clear_flags.scissor) {
163 return false;
164 } 143 }
165 // Then we have to confirm scissor testing clears the whole image 144 const u32 buffer = engine.GetBoundBuffer();
166 const std::size_t index = regs.clear_buffers.RT; 145 const u64 offset = (entry.offset + index) * sizeof(u32);
167 const auto& scissor = regs.scissor_test[0]; 146 return TextureHandle(engine.AccessConstBuffer32(shader_type, buffer, offset), via_header_index);
168 return scissor.min_x > 0 || scissor.min_y > 0 || scissor.max_x < regs.rt[index].width ||
169 scissor.max_y < regs.rt[index].height;
170} 147}
171 148
172/// @brief Determine if an attachment to be updated has to preserve contents 149template <size_t N>
173/// @param is_clear True when a clear is being executed
174/// @param regs 3D registers
175/// @return True when the contents have to be preserved
176bool HasToPreserveDepthContents(bool is_clear, const Maxwell& regs) {
177 // If we are not clearing, the contents have to be preserved
178 if (!is_clear) {
179 return true;
180 }
181 // For depth stencil clears we only have to confirm scissor test covers the whole image
182 if (!regs.clear_flags.scissor) {
183 return false;
184 }
185 // Make sure the clear cover the whole image
186 const auto& scissor = regs.scissor_test[0];
187 return scissor.min_x > 0 || scissor.min_y > 0 || scissor.max_x < regs.zeta_width ||
188 scissor.max_y < regs.zeta_height;
189}
190
191template <std::size_t N>
192std::array<VkDeviceSize, N> ExpandStrides(const std::array<u16, N>& strides) { 150std::array<VkDeviceSize, N> ExpandStrides(const std::array<u16, N>& strides) {
193 std::array<VkDeviceSize, N> expanded; 151 std::array<VkDeviceSize, N> expanded;
194 std::copy(strides.begin(), strides.end(), expanded.begin()); 152 std::copy(strides.begin(), strides.end(), expanded.begin());
195 return expanded; 153 return expanded;
196} 154}
197 155
156ImageViewType ImageViewTypeFromEntry(const SamplerEntry& entry) {
157 if (entry.is_buffer) {
158 return ImageViewType::e2D;
159 }
160 switch (entry.type) {
161 case Tegra::Shader::TextureType::Texture1D:
162 return entry.is_array ? ImageViewType::e1DArray : ImageViewType::e1D;
163 case Tegra::Shader::TextureType::Texture2D:
164 return entry.is_array ? ImageViewType::e2DArray : ImageViewType::e2D;
165 case Tegra::Shader::TextureType::Texture3D:
166 return ImageViewType::e3D;
167 case Tegra::Shader::TextureType::TextureCube:
168 return entry.is_array ? ImageViewType::CubeArray : ImageViewType::Cube;
169 }
170 UNREACHABLE();
171 return ImageViewType::e2D;
172}
173
174ImageViewType ImageViewTypeFromEntry(const ImageEntry& entry) {
175 switch (entry.type) {
176 case Tegra::Shader::ImageType::Texture1D:
177 return ImageViewType::e1D;
178 case Tegra::Shader::ImageType::Texture1DArray:
179 return ImageViewType::e1DArray;
180 case Tegra::Shader::ImageType::Texture2D:
181 return ImageViewType::e2D;
182 case Tegra::Shader::ImageType::Texture2DArray:
183 return ImageViewType::e2DArray;
184 case Tegra::Shader::ImageType::Texture3D:
185 return ImageViewType::e3D;
186 case Tegra::Shader::ImageType::TextureBuffer:
187 return ImageViewType::Buffer;
188 }
189 UNREACHABLE();
190 return ImageViewType::e2D;
191}
192
193void PushImageDescriptors(const ShaderEntries& entries, TextureCache& texture_cache,
194 VKUpdateDescriptorQueue& update_descriptor_queue,
195 ImageViewId*& image_view_id_ptr, VkSampler*& sampler_ptr) {
196 for ([[maybe_unused]] const auto& entry : entries.uniform_texels) {
197 const ImageViewId image_view_id = *image_view_id_ptr++;
198 const ImageView& image_view = texture_cache.GetImageView(image_view_id);
199 update_descriptor_queue.AddTexelBuffer(image_view.BufferView());
200 }
201 for (const auto& entry : entries.samplers) {
202 for (size_t i = 0; i < entry.size; ++i) {
203 const VkSampler sampler = *sampler_ptr++;
204 const ImageViewId image_view_id = *image_view_id_ptr++;
205 const ImageView& image_view = texture_cache.GetImageView(image_view_id);
206 const VkImageView handle = image_view.Handle(ImageViewTypeFromEntry(entry));
207 update_descriptor_queue.AddSampledImage(handle, sampler);
208 }
209 }
210 for ([[maybe_unused]] const auto& entry : entries.storage_texels) {
211 const ImageViewId image_view_id = *image_view_id_ptr++;
212 const ImageView& image_view = texture_cache.GetImageView(image_view_id);
213 update_descriptor_queue.AddTexelBuffer(image_view.BufferView());
214 }
215 for (const auto& entry : entries.images) {
216 // TODO: Mark as modified
217 const ImageViewId image_view_id = *image_view_id_ptr++;
218 const ImageView& image_view = texture_cache.GetImageView(image_view_id);
219 const VkImageView handle = image_view.Handle(ImageViewTypeFromEntry(entry));
220 update_descriptor_queue.AddImage(handle);
221 }
222}
223
198} // Anonymous namespace 224} // Anonymous namespace
199 225
200class BufferBindings final { 226class BufferBindings final {
@@ -290,7 +316,7 @@ public:
290private: 316private:
291 // Some of these fields are intentionally left uninitialized to avoid initializing them twice. 317 // Some of these fields are intentionally left uninitialized to avoid initializing them twice.
292 struct { 318 struct {
293 std::size_t num_buffers = 0; 319 size_t num_buffers = 0;
294 std::array<VkBuffer, Maxwell::NumVertexArrays> buffers; 320 std::array<VkBuffer, Maxwell::NumVertexArrays> buffers;
295 std::array<VkDeviceSize, Maxwell::NumVertexArrays> offsets; 321 std::array<VkDeviceSize, Maxwell::NumVertexArrays> offsets;
296 std::array<VkDeviceSize, Maxwell::NumVertexArrays> sizes; 322 std::array<VkDeviceSize, Maxwell::NumVertexArrays> sizes;
@@ -303,7 +329,7 @@ private:
303 VkIndexType type; 329 VkIndexType type;
304 } index; 330 } index;
305 331
306 template <std::size_t N> 332 template <size_t N>
307 void BindStatic(const VKDevice& device, VKScheduler& scheduler) const { 333 void BindStatic(const VKDevice& device, VKScheduler& scheduler) const {
308 if (device.IsExtExtendedDynamicStateSupported()) { 334 if (device.IsExtExtendedDynamicStateSupported()) {
309 if (index.buffer) { 335 if (index.buffer) {
@@ -320,7 +346,7 @@ private:
320 } 346 }
321 } 347 }
322 348
323 template <std::size_t N, bool is_indexed, bool has_extended_dynamic_state> 349 template <size_t N, bool is_indexed, bool has_extended_dynamic_state>
324 void BindStatic(VKScheduler& scheduler) const { 350 void BindStatic(VKScheduler& scheduler) const {
325 static_assert(N <= Maxwell::NumVertexArrays); 351 static_assert(N <= Maxwell::NumVertexArrays);
326 if constexpr (N == 0) { 352 if constexpr (N == 0) {
@@ -385,20 +411,23 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
385 Core::Memory::Memory& cpu_memory_, VKScreenInfo& screen_info_, 411 Core::Memory::Memory& cpu_memory_, VKScreenInfo& screen_info_,
386 const VKDevice& device_, VKMemoryManager& memory_manager_, 412 const VKDevice& device_, VKMemoryManager& memory_manager_,
387 StateTracker& state_tracker_, VKScheduler& scheduler_) 413 StateTracker& state_tracker_, VKScheduler& scheduler_)
388 : RasterizerAccelerated(cpu_memory_), gpu(gpu_), gpu_memory(gpu_memory_), 414 : RasterizerAccelerated{cpu_memory_}, gpu{gpu_},
389 maxwell3d(gpu.Maxwell3D()), kepler_compute(gpu.KeplerCompute()), screen_info(screen_info_), 415 gpu_memory{gpu_memory_}, maxwell3d{gpu.Maxwell3D()}, kepler_compute{gpu.KeplerCompute()},
390 device(device_), memory_manager(memory_manager_), state_tracker(state_tracker_), 416 screen_info{screen_info_}, device{device_}, memory_manager{memory_manager_},
391 scheduler(scheduler_), staging_pool(device, memory_manager, scheduler), 417 state_tracker{state_tracker_}, scheduler{scheduler_}, stream_buffer(device, scheduler),
392 descriptor_pool(device, scheduler_), update_descriptor_queue(device, scheduler), 418 staging_pool(device, memory_manager, scheduler), descriptor_pool(device, scheduler),
393 renderpass_cache(device), 419 update_descriptor_queue(device, scheduler),
420 blit_image(device, scheduler, state_tracker, descriptor_pool),
394 quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), 421 quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue),
395 quad_indexed_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), 422 quad_indexed_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue),
396 uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), 423 uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue),
397 texture_cache(*this, maxwell3d, gpu_memory, device, memory_manager, scheduler, staging_pool), 424 texture_cache_runtime{device, scheduler, memory_manager, staging_pool, blit_image},
425 texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory),
398 pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler, 426 pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler,
399 descriptor_pool, update_descriptor_queue, renderpass_cache), 427 descriptor_pool, update_descriptor_queue),
400 buffer_cache(*this, gpu_memory, cpu_memory_, device, memory_manager, scheduler, staging_pool), 428 buffer_cache(*this, gpu_memory, cpu_memory_, device, memory_manager, scheduler, stream_buffer,
401 sampler_cache(device), query_cache(*this, maxwell3d, gpu_memory, device, scheduler), 429 staging_pool),
430 query_cache{*this, maxwell3d, gpu_memory, device, scheduler},
402 fence_manager(*this, gpu, gpu_memory, texture_cache, buffer_cache, query_cache, device, 431 fence_manager(*this, gpu, gpu_memory, texture_cache, buffer_cache, query_cache, device,
403 scheduler), 432 scheduler),
404 wfi_event(device.GetLogical().CreateEvent()), async_shaders(emu_window_) { 433 wfi_event(device.GetLogical().CreateEvent()), async_shaders(emu_window_) {
@@ -427,9 +456,10 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
427 const DrawParameters draw_params = 456 const DrawParameters draw_params =
428 SetupGeometry(key.fixed_state, buffer_bindings, is_indexed, is_instanced); 457 SetupGeometry(key.fixed_state, buffer_bindings, is_indexed, is_instanced);
429 458
430 update_descriptor_queue.Acquire(); 459 auto lock = texture_cache.AcquireLock();
431 sampled_views.clear(); 460 texture_cache.SynchronizeGraphicsDescriptors();
432 image_views.clear(); 461
462 texture_cache.UpdateRenderTargets(false);
433 463
434 const auto shaders = pipeline_cache.GetShaders(); 464 const auto shaders = pipeline_cache.GetShaders();
435 key.shaders = GetShaderAddresses(shaders); 465 key.shaders = GetShaderAddresses(shaders);
@@ -437,30 +467,24 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
437 467
438 buffer_cache.Unmap(); 468 buffer_cache.Unmap();
439 469
440 const Texceptions texceptions = UpdateAttachments(false); 470 const Framebuffer* const framebuffer = texture_cache.GetFramebuffer();
441 SetupImageTransitions(texceptions, color_attachments, zeta_attachment); 471 key.renderpass = framebuffer->RenderPass();
442
443 key.renderpass_params = GetRenderPassParams(texceptions);
444 key.padding = 0;
445 472
446 auto* pipeline = pipeline_cache.GetGraphicsPipeline(key, async_shaders); 473 auto* const pipeline =
474 pipeline_cache.GetGraphicsPipeline(key, framebuffer->NumColorBuffers(), async_shaders);
447 if (pipeline == nullptr || pipeline->GetHandle() == VK_NULL_HANDLE) { 475 if (pipeline == nullptr || pipeline->GetHandle() == VK_NULL_HANDLE) {
448 // Async graphics pipeline was not ready. 476 // Async graphics pipeline was not ready.
449 return; 477 return;
450 } 478 }
451 479
452 scheduler.BindGraphicsPipeline(pipeline->GetHandle());
453
454 const auto renderpass = pipeline->GetRenderPass();
455 const auto [framebuffer, render_area] = ConfigureFramebuffers(renderpass);
456 scheduler.RequestRenderpass(renderpass, framebuffer, render_area);
457
458 UpdateDynamicStates();
459
460 buffer_bindings.Bind(device, scheduler); 480 buffer_bindings.Bind(device, scheduler);
461 481
462 BeginTransformFeedback(); 482 BeginTransformFeedback();
463 483
484 scheduler.RequestRenderpass(framebuffer);
485 scheduler.BindGraphicsPipeline(pipeline->GetHandle());
486 UpdateDynamicStates();
487
464 const auto pipeline_layout = pipeline->GetLayout(); 488 const auto pipeline_layout = pipeline->GetLayout();
465 const auto descriptor_set = pipeline->CommitDescriptorSet(); 489 const auto descriptor_set = pipeline->CommitDescriptorSet();
466 scheduler.Record([pipeline_layout, descriptor_set, draw_params](vk::CommandBuffer cmdbuf) { 490 scheduler.Record([pipeline_layout, descriptor_set, draw_params](vk::CommandBuffer cmdbuf) {
@@ -481,9 +505,6 @@ void RasterizerVulkan::Clear() {
481 return; 505 return;
482 } 506 }
483 507
484 sampled_views.clear();
485 image_views.clear();
486
487 query_cache.UpdateCounters(); 508 query_cache.UpdateCounters();
488 509
489 const auto& regs = maxwell3d.regs; 510 const auto& regs = maxwell3d.regs;
@@ -495,20 +516,24 @@ void RasterizerVulkan::Clear() {
495 return; 516 return;
496 } 517 }
497 518
498 [[maybe_unused]] const auto texceptions = UpdateAttachments(true); 519 auto lock = texture_cache.AcquireLock();
499 DEBUG_ASSERT(texceptions.none()); 520 texture_cache.UpdateRenderTargets(true);
500 SetupImageTransitions(0, color_attachments, zeta_attachment); 521 const Framebuffer* const framebuffer = texture_cache.GetFramebuffer();
522 const VkExtent2D render_area = framebuffer->RenderArea();
523 scheduler.RequestRenderpass(framebuffer);
501 524
502 const VkRenderPass renderpass = renderpass_cache.GetRenderPass(GetRenderPassParams(0)); 525 VkClearRect clear_rect{
503 const auto [framebuffer, render_area] = ConfigureFramebuffers(renderpass); 526 .rect = GetScissorState(regs, 0),
504 scheduler.RequestRenderpass(renderpass, framebuffer, render_area); 527 .baseArrayLayer = regs.clear_buffers.layer,
505 528 .layerCount = 1,
506 VkClearRect clear_rect; 529 };
507 clear_rect.baseArrayLayer = regs.clear_buffers.layer; 530 if (clear_rect.rect.extent.width == 0 || clear_rect.rect.extent.height == 0) {
508 clear_rect.layerCount = 1; 531 return;
509 clear_rect.rect = GetScissorState(regs, 0); 532 }
510 clear_rect.rect.extent.width = std::min(clear_rect.rect.extent.width, render_area.width); 533 clear_rect.rect.extent = VkExtent2D{
511 clear_rect.rect.extent.height = std::min(clear_rect.rect.extent.height, render_area.height); 534 .width = std::min(clear_rect.rect.extent.width, render_area.width),
535 .height = std::min(clear_rect.rect.extent.height, render_area.height),
536 };
512 537
513 if (use_color) { 538 if (use_color) {
514 VkClearValue clear_value; 539 VkClearValue clear_value;
@@ -549,9 +574,6 @@ void RasterizerVulkan::Clear() {
549 574
550void RasterizerVulkan::DispatchCompute(GPUVAddr code_addr) { 575void RasterizerVulkan::DispatchCompute(GPUVAddr code_addr) {
551 MICROPROFILE_SCOPE(Vulkan_Compute); 576 MICROPROFILE_SCOPE(Vulkan_Compute);
552 update_descriptor_queue.Acquire();
553 sampled_views.clear();
554 image_views.clear();
555 577
556 query_cache.UpdateCounters(); 578 query_cache.UpdateCounters();
557 579
@@ -570,29 +592,43 @@ void RasterizerVulkan::DispatchCompute(GPUVAddr code_addr) {
570 // Compute dispatches can't be executed inside a renderpass 592 // Compute dispatches can't be executed inside a renderpass
571 scheduler.RequestOutsideRenderPassOperationContext(); 593 scheduler.RequestOutsideRenderPassOperationContext();
572 594
573 buffer_cache.Map(CalculateComputeStreamBufferSize()); 595 image_view_indices.clear();
596 sampler_handles.clear();
597
598 auto lock = texture_cache.AcquireLock();
599 texture_cache.SynchronizeComputeDescriptors();
574 600
575 const auto& entries = pipeline.GetEntries(); 601 const auto& entries = pipeline.GetEntries();
576 SetupComputeConstBuffers(entries);
577 SetupComputeGlobalBuffers(entries);
578 SetupComputeUniformTexels(entries); 602 SetupComputeUniformTexels(entries);
579 SetupComputeTextures(entries); 603 SetupComputeTextures(entries);
580 SetupComputeStorageTexels(entries); 604 SetupComputeStorageTexels(entries);
581 SetupComputeImages(entries); 605 SetupComputeImages(entries);
582 606
583 buffer_cache.Unmap(); 607 const std::span indices_span(image_view_indices.data(), image_view_indices.size());
608 texture_cache.FillComputeImageViews(indices_span, image_view_ids);
584 609
585 TransitionImages(sampled_views, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 610 buffer_cache.Map(CalculateComputeStreamBufferSize());
586 VK_ACCESS_SHADER_READ_BIT);
587 TransitionImages(image_views, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
588 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT);
589 611
612 update_descriptor_queue.Acquire();
613
614 SetupComputeConstBuffers(entries);
615 SetupComputeGlobalBuffers(entries);
616
617 ImageViewId* image_view_id_ptr = image_view_ids.data();
618 VkSampler* sampler_ptr = sampler_handles.data();
619 PushImageDescriptors(entries, texture_cache, update_descriptor_queue, image_view_id_ptr,
620 sampler_ptr);
621
622 buffer_cache.Unmap();
623
624 const VkPipeline pipeline_handle = pipeline.GetHandle();
625 const VkPipelineLayout pipeline_layout = pipeline.GetLayout();
626 const VkDescriptorSet descriptor_set = pipeline.CommitDescriptorSet();
590 scheduler.Record([grid_x = launch_desc.grid_dim_x, grid_y = launch_desc.grid_dim_y, 627 scheduler.Record([grid_x = launch_desc.grid_dim_x, grid_y = launch_desc.grid_dim_y,
591 grid_z = launch_desc.grid_dim_z, pipeline_handle = pipeline.GetHandle(), 628 grid_z = launch_desc.grid_dim_z, pipeline_handle, pipeline_layout,
592 layout = pipeline.GetLayout(), 629 descriptor_set](vk::CommandBuffer cmdbuf) {
593 descriptor_set = pipeline.CommitDescriptorSet()](vk::CommandBuffer cmdbuf) {
594 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_handle); 630 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_handle);
595 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, layout, DESCRIPTOR_SET, 631 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, DESCRIPTOR_SET,
596 descriptor_set, {}); 632 descriptor_set, {});
597 cmdbuf.Dispatch(grid_x, grid_y, grid_z); 633 cmdbuf.Dispatch(grid_x, grid_y, grid_z);
598 }); 634 });
@@ -613,7 +649,10 @@ void RasterizerVulkan::FlushRegion(VAddr addr, u64 size) {
613 if (addr == 0 || size == 0) { 649 if (addr == 0 || size == 0) {
614 return; 650 return;
615 } 651 }
616 texture_cache.FlushRegion(addr, size); 652 {
653 auto lock = texture_cache.AcquireLock();
654 texture_cache.DownloadMemory(addr, size);
655 }
617 buffer_cache.FlushRegion(addr, size); 656 buffer_cache.FlushRegion(addr, size);
618 query_cache.FlushRegion(addr, size); 657 query_cache.FlushRegion(addr, size);
619} 658}
@@ -622,14 +661,18 @@ bool RasterizerVulkan::MustFlushRegion(VAddr addr, u64 size) {
622 if (!Settings::IsGPULevelHigh()) { 661 if (!Settings::IsGPULevelHigh()) {
623 return buffer_cache.MustFlushRegion(addr, size); 662 return buffer_cache.MustFlushRegion(addr, size);
624 } 663 }
625 return texture_cache.MustFlushRegion(addr, size) || buffer_cache.MustFlushRegion(addr, size); 664 return texture_cache.IsRegionGpuModified(addr, size) ||
665 buffer_cache.MustFlushRegion(addr, size);
626} 666}
627 667
628void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size) { 668void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size) {
629 if (addr == 0 || size == 0) { 669 if (addr == 0 || size == 0) {
630 return; 670 return;
631 } 671 }
632 texture_cache.InvalidateRegion(addr, size); 672 {
673 auto lock = texture_cache.AcquireLock();
674 texture_cache.WriteMemory(addr, size);
675 }
633 pipeline_cache.InvalidateRegion(addr, size); 676 pipeline_cache.InvalidateRegion(addr, size);
634 buffer_cache.InvalidateRegion(addr, size); 677 buffer_cache.InvalidateRegion(addr, size);
635 query_cache.InvalidateRegion(addr, size); 678 query_cache.InvalidateRegion(addr, size);
@@ -639,17 +682,28 @@ void RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) {
639 if (addr == 0 || size == 0) { 682 if (addr == 0 || size == 0) {
640 return; 683 return;
641 } 684 }
642 texture_cache.OnCPUWrite(addr, size); 685 {
686 auto lock = texture_cache.AcquireLock();
687 texture_cache.WriteMemory(addr, size);
688 }
643 pipeline_cache.OnCPUWrite(addr, size); 689 pipeline_cache.OnCPUWrite(addr, size);
644 buffer_cache.OnCPUWrite(addr, size); 690 buffer_cache.OnCPUWrite(addr, size);
645} 691}
646 692
647void RasterizerVulkan::SyncGuestHost() { 693void RasterizerVulkan::SyncGuestHost() {
648 texture_cache.SyncGuestHost();
649 buffer_cache.SyncGuestHost(); 694 buffer_cache.SyncGuestHost();
650 pipeline_cache.SyncGuestHost(); 695 pipeline_cache.SyncGuestHost();
651} 696}
652 697
698void RasterizerVulkan::UnmapMemory(VAddr addr, u64 size) {
699 {
700 auto lock = texture_cache.AcquireLock();
701 texture_cache.UnmapMemory(addr, size);
702 }
703 buffer_cache.OnCPUWrite(addr, size);
704 pipeline_cache.OnCPUWrite(addr, size);
705}
706
653void RasterizerVulkan::SignalSemaphore(GPUVAddr addr, u32 value) { 707void RasterizerVulkan::SignalSemaphore(GPUVAddr addr, u32 value) {
654 if (!gpu.IsAsync()) { 708 if (!gpu.IsAsync()) {
655 gpu_memory.Write<u32>(addr, value); 709 gpu_memory.Write<u32>(addr, value);
@@ -700,6 +754,14 @@ void RasterizerVulkan::WaitForIdle() {
700 }); 754 });
701} 755}
702 756
757void RasterizerVulkan::FragmentBarrier() {
758 // We already put barriers when a render pass finishes
759}
760
761void RasterizerVulkan::TiledCacheBarrier() {
762 // TODO: Implementing tiled barriers requires rewriting a good chunk of the Vulkan backend
763}
764
703void RasterizerVulkan::FlushCommands() { 765void RasterizerVulkan::FlushCommands() {
704 if (draw_counter > 0) { 766 if (draw_counter > 0) {
705 draw_counter = 0; 767 draw_counter = 0;
@@ -710,14 +772,20 @@ void RasterizerVulkan::FlushCommands() {
710void RasterizerVulkan::TickFrame() { 772void RasterizerVulkan::TickFrame() {
711 draw_counter = 0; 773 draw_counter = 0;
712 update_descriptor_queue.TickFrame(); 774 update_descriptor_queue.TickFrame();
775 fence_manager.TickFrame();
713 buffer_cache.TickFrame(); 776 buffer_cache.TickFrame();
714 staging_pool.TickFrame(); 777 staging_pool.TickFrame();
778 {
779 auto lock = texture_cache.AcquireLock();
780 texture_cache.TickFrame();
781 }
715} 782}
716 783
717bool RasterizerVulkan::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, 784bool RasterizerVulkan::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src,
718 const Tegra::Engines::Fermi2D::Regs::Surface& dst, 785 const Tegra::Engines::Fermi2D::Surface& dst,
719 const Tegra::Engines::Fermi2D::Config& copy_config) { 786 const Tegra::Engines::Fermi2D::Config& copy_config) {
720 texture_cache.DoFermiCopy(src, dst, copy_config); 787 auto lock = texture_cache.AcquireLock();
788 texture_cache.BlitImage(dst, src, copy_config);
721 return true; 789 return true;
722} 790}
723 791
@@ -727,20 +795,16 @@ bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config,
727 return false; 795 return false;
728 } 796 }
729 797
730 const auto surface{texture_cache.TryFindFramebufferSurface(framebuffer_addr)}; 798 auto lock = texture_cache.AcquireLock();
731 if (!surface) { 799 ImageView* const image_view = texture_cache.TryFindFramebufferImageView(framebuffer_addr);
800 if (!image_view) {
732 return false; 801 return false;
733 } 802 }
734 803
735 // Verify that the cached surface is the same size and format as the requested framebuffer 804 screen_info.image_view = image_view->Handle(VideoCommon::ImageViewType::e2D);
736 const auto& params{surface->GetSurfaceParams()}; 805 screen_info.width = image_view->size.width;
737 ASSERT_MSG(params.width == config.width, "Framebuffer width is different"); 806 screen_info.height = image_view->size.height;
738 ASSERT_MSG(params.height == config.height, "Framebuffer height is different"); 807 screen_info.is_srgb = VideoCore::Surface::IsPixelFormatSRGB(image_view->format);
739
740 screen_info.image = &surface->GetImage();
741 screen_info.width = params.width;
742 screen_info.height = params.height;
743 screen_info.is_srgb = surface->GetSurfaceParams().srgb_conversion;
744 return true; 808 return true;
745} 809}
746 810
@@ -765,103 +829,6 @@ void RasterizerVulkan::FlushWork() {
765 draw_counter = 0; 829 draw_counter = 0;
766} 830}
767 831
768RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments(bool is_clear) {
769 MICROPROFILE_SCOPE(Vulkan_RenderTargets);
770
771 const auto& regs = maxwell3d.regs;
772 auto& dirty = maxwell3d.dirty.flags;
773 const bool update_rendertargets = dirty[VideoCommon::Dirty::RenderTargets];
774 dirty[VideoCommon::Dirty::RenderTargets] = false;
775
776 texture_cache.GuardRenderTargets(true);
777
778 Texceptions texceptions;
779 for (std::size_t rt = 0; rt < Maxwell::NumRenderTargets; ++rt) {
780 if (update_rendertargets) {
781 const bool preserve_contents = HasToPreserveColorContents(is_clear, regs);
782 color_attachments[rt] = texture_cache.GetColorBufferSurface(rt, preserve_contents);
783 }
784 if (color_attachments[rt] && WalkAttachmentOverlaps(*color_attachments[rt])) {
785 texceptions[rt] = true;
786 }
787 }
788
789 if (update_rendertargets) {
790 const bool preserve_contents = HasToPreserveDepthContents(is_clear, regs);
791 zeta_attachment = texture_cache.GetDepthBufferSurface(preserve_contents);
792 }
793 if (zeta_attachment && WalkAttachmentOverlaps(*zeta_attachment)) {
794 texceptions[ZETA_TEXCEPTION_INDEX] = true;
795 }
796
797 texture_cache.GuardRenderTargets(false);
798
799 return texceptions;
800}
801
802bool RasterizerVulkan::WalkAttachmentOverlaps(const CachedSurfaceView& attachment) {
803 bool overlap = false;
804 for (auto& [view, layout] : sampled_views) {
805 if (!attachment.IsSameSurface(*view)) {
806 continue;
807 }
808 overlap = true;
809 *layout = VK_IMAGE_LAYOUT_GENERAL;
810 }
811 return overlap;
812}
813
814std::tuple<VkFramebuffer, VkExtent2D> RasterizerVulkan::ConfigureFramebuffers(
815 VkRenderPass renderpass) {
816 FramebufferCacheKey key{
817 .renderpass = renderpass,
818 .width = std::numeric_limits<u32>::max(),
819 .height = std::numeric_limits<u32>::max(),
820 .layers = std::numeric_limits<u32>::max(),
821 .views = {},
822 };
823
824 const auto try_push = [&key](const View& view) {
825 if (!view) {
826 return false;
827 }
828 key.views.push_back(view->GetAttachment());
829 key.width = std::min(key.width, view->GetWidth());
830 key.height = std::min(key.height, view->GetHeight());
831 key.layers = std::min(key.layers, view->GetNumLayers());
832 return true;
833 };
834
835 const auto& regs = maxwell3d.regs;
836 const std::size_t num_attachments = static_cast<std::size_t>(regs.rt_control.count);
837 for (std::size_t index = 0; index < num_attachments; ++index) {
838 if (try_push(color_attachments[index])) {
839 texture_cache.MarkColorBufferInUse(index);
840 }
841 }
842 if (try_push(zeta_attachment)) {
843 texture_cache.MarkDepthBufferInUse();
844 }
845
846 const auto [fbentry, is_cache_miss] = framebuffer_cache.try_emplace(key);
847 auto& framebuffer = fbentry->second;
848 if (is_cache_miss) {
849 framebuffer = device.GetLogical().CreateFramebuffer({
850 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
851 .pNext = nullptr,
852 .flags = 0,
853 .renderPass = key.renderpass,
854 .attachmentCount = static_cast<u32>(key.views.size()),
855 .pAttachments = key.views.data(),
856 .width = key.width,
857 .height = key.height,
858 .layers = key.layers,
859 });
860 }
861
862 return {*framebuffer, VkExtent2D{key.width, key.height}};
863}
864
865RasterizerVulkan::DrawParameters RasterizerVulkan::SetupGeometry(FixedPipelineState& fixed_state, 832RasterizerVulkan::DrawParameters RasterizerVulkan::SetupGeometry(FixedPipelineState& fixed_state,
866 BufferBindings& buffer_bindings, 833 BufferBindings& buffer_bindings,
867 bool is_indexed, 834 bool is_indexed,
@@ -885,50 +852,37 @@ RasterizerVulkan::DrawParameters RasterizerVulkan::SetupGeometry(FixedPipelineSt
885 852
886void RasterizerVulkan::SetupShaderDescriptors( 853void RasterizerVulkan::SetupShaderDescriptors(
887 const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders) { 854 const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders) {
888 texture_cache.GuardSamplers(true); 855 image_view_indices.clear();
889 856 sampler_handles.clear();
890 for (std::size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) { 857 for (size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) {
891 // Skip VertexA stage
892 Shader* const shader = shaders[stage + 1]; 858 Shader* const shader = shaders[stage + 1];
893 if (!shader) { 859 if (!shader) {
894 continue; 860 continue;
895 } 861 }
896 const auto& entries = shader->GetEntries(); 862 const auto& entries = shader->GetEntries();
897 SetupGraphicsConstBuffers(entries, stage);
898 SetupGraphicsGlobalBuffers(entries, stage);
899 SetupGraphicsUniformTexels(entries, stage); 863 SetupGraphicsUniformTexels(entries, stage);
900 SetupGraphicsTextures(entries, stage); 864 SetupGraphicsTextures(entries, stage);
901 SetupGraphicsStorageTexels(entries, stage); 865 SetupGraphicsStorageTexels(entries, stage);
902 SetupGraphicsImages(entries, stage); 866 SetupGraphicsImages(entries, stage);
903 } 867 }
904 texture_cache.GuardSamplers(false); 868 const std::span indices_span(image_view_indices.data(), image_view_indices.size());
905} 869 texture_cache.FillGraphicsImageViews(indices_span, image_view_ids);
906 870
907void RasterizerVulkan::SetupImageTransitions(Texceptions texceptions, const ColorAttachments& color, 871 update_descriptor_queue.Acquire();
908 const ZetaAttachment& zeta) {
909 TransitionImages(sampled_views, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_ACCESS_SHADER_READ_BIT);
910 TransitionImages(image_views, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
911 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT);
912 872
913 for (std::size_t rt = 0; rt < color.size(); ++rt) { 873 ImageViewId* image_view_id_ptr = image_view_ids.data();
914 const auto color_attachment = color[rt]; 874 VkSampler* sampler_ptr = sampler_handles.data();
915 if (color_attachment == nullptr) { 875 for (size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) {
876 // Skip VertexA stage
877 Shader* const shader = shaders[stage + 1];
878 if (!shader) {
916 continue; 879 continue;
917 } 880 }
918 const auto image_layout = 881 const auto& entries = shader->GetEntries();
919 texceptions[rt] ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 882 SetupGraphicsConstBuffers(entries, stage);
920 color_attachment->Transition(image_layout, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 883 SetupGraphicsGlobalBuffers(entries, stage);
921 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | 884 PushImageDescriptors(entries, texture_cache, update_descriptor_queue, image_view_id_ptr,
922 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); 885 sampler_ptr);
923 }
924
925 if (zeta != nullptr) {
926 const auto image_layout = texceptions[ZETA_TEXCEPTION_INDEX]
927 ? VK_IMAGE_LAYOUT_GENERAL
928 : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
929 zeta->Transition(image_layout, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
930 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
931 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);
932 } 886 }
933} 887}
934 888
@@ -1000,7 +954,7 @@ void RasterizerVulkan::EndTransformFeedback() {
1000void RasterizerVulkan::SetupVertexArrays(BufferBindings& buffer_bindings) { 954void RasterizerVulkan::SetupVertexArrays(BufferBindings& buffer_bindings) {
1001 const auto& regs = maxwell3d.regs; 955 const auto& regs = maxwell3d.regs;
1002 956
1003 for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { 957 for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) {
1004 const auto& vertex_array = regs.vertex_array[index]; 958 const auto& vertex_array = regs.vertex_array[index];
1005 if (!vertex_array.IsEnabled()) { 959 if (!vertex_array.IsEnabled()) {
1006 continue; 960 continue;
@@ -1009,7 +963,7 @@ void RasterizerVulkan::SetupVertexArrays(BufferBindings& buffer_bindings) {
1009 const GPUVAddr end{regs.vertex_array_limit[index].LimitAddress()}; 963 const GPUVAddr end{regs.vertex_array_limit[index].LimitAddress()};
1010 964
1011 ASSERT(end >= start); 965 ASSERT(end >= start);
1012 const std::size_t size = end - start; 966 const size_t size = end - start;
1013 if (size == 0) { 967 if (size == 0) {
1014 buffer_bindings.AddVertexBinding(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE, 0); 968 buffer_bindings.AddVertexBinding(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE, 0);
1015 continue; 969 continue;
@@ -1070,7 +1024,7 @@ void RasterizerVulkan::SetupIndexBuffer(BufferBindings& buffer_bindings, DrawPar
1070 } 1024 }
1071} 1025}
1072 1026
1073void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, std::size_t stage) { 1027void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, size_t stage) {
1074 MICROPROFILE_SCOPE(Vulkan_ConstBuffers); 1028 MICROPROFILE_SCOPE(Vulkan_ConstBuffers);
1075 const auto& shader_stage = maxwell3d.state.shader_stages[stage]; 1029 const auto& shader_stage = maxwell3d.state.shader_stages[stage];
1076 for (const auto& entry : entries.const_buffers) { 1030 for (const auto& entry : entries.const_buffers) {
@@ -1078,7 +1032,7 @@ void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, s
1078 } 1032 }
1079} 1033}
1080 1034
1081void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries, std::size_t stage) { 1035void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries, size_t stage) {
1082 MICROPROFILE_SCOPE(Vulkan_GlobalBuffers); 1036 MICROPROFILE_SCOPE(Vulkan_GlobalBuffers);
1083 const auto& cbufs{maxwell3d.state.shader_stages[stage]}; 1037 const auto& cbufs{maxwell3d.state.shader_stages[stage]};
1084 1038
@@ -1088,37 +1042,49 @@ void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries,
1088 } 1042 }
1089} 1043}
1090 1044
1091void RasterizerVulkan::SetupGraphicsUniformTexels(const ShaderEntries& entries, std::size_t stage) { 1045void RasterizerVulkan::SetupGraphicsUniformTexels(const ShaderEntries& entries, size_t stage) {
1092 MICROPROFILE_SCOPE(Vulkan_Textures); 1046 MICROPROFILE_SCOPE(Vulkan_Textures);
1047 const auto& regs = maxwell3d.regs;
1048 const bool via_header_index = regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex;
1093 for (const auto& entry : entries.uniform_texels) { 1049 for (const auto& entry : entries.uniform_texels) {
1094 const auto image = GetTextureInfo(maxwell3d, entry, stage).tic; 1050 const TextureHandle handle = GetTextureInfo(maxwell3d, via_header_index, entry, stage);
1095 SetupUniformTexels(image, entry); 1051 image_view_indices.push_back(handle.image);
1096 } 1052 }
1097} 1053}
1098 1054
1099void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, std::size_t stage) { 1055void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, size_t stage) {
1100 MICROPROFILE_SCOPE(Vulkan_Textures); 1056 MICROPROFILE_SCOPE(Vulkan_Textures);
1057 const auto& regs = maxwell3d.regs;
1058 const bool via_header_index = regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex;
1101 for (const auto& entry : entries.samplers) { 1059 for (const auto& entry : entries.samplers) {
1102 for (std::size_t i = 0; i < entry.size; ++i) { 1060 for (size_t index = 0; index < entry.size; ++index) {
1103 const auto texture = GetTextureInfo(maxwell3d, entry, stage, i); 1061 const TextureHandle handle =
1104 SetupTexture(texture, entry); 1062 GetTextureInfo(maxwell3d, via_header_index, entry, stage, index);
1063 image_view_indices.push_back(handle.image);
1064
1065 Sampler* const sampler = texture_cache.GetGraphicsSampler(handle.sampler);
1066 sampler_handles.push_back(sampler->Handle());
1105 } 1067 }
1106 } 1068 }
1107} 1069}
1108 1070
1109void RasterizerVulkan::SetupGraphicsStorageTexels(const ShaderEntries& entries, std::size_t stage) { 1071void RasterizerVulkan::SetupGraphicsStorageTexels(const ShaderEntries& entries, size_t stage) {
1110 MICROPROFILE_SCOPE(Vulkan_Textures); 1072 MICROPROFILE_SCOPE(Vulkan_Textures);
1073 const auto& regs = maxwell3d.regs;
1074 const bool via_header_index = regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex;
1111 for (const auto& entry : entries.storage_texels) { 1075 for (const auto& entry : entries.storage_texels) {
1112 const auto image = GetTextureInfo(maxwell3d, entry, stage).tic; 1076 const TextureHandle handle = GetTextureInfo(maxwell3d, via_header_index, entry, stage);
1113 SetupStorageTexel(image, entry); 1077 image_view_indices.push_back(handle.image);
1114 } 1078 }
1115} 1079}
1116 1080
1117void RasterizerVulkan::SetupGraphicsImages(const ShaderEntries& entries, std::size_t stage) { 1081void RasterizerVulkan::SetupGraphicsImages(const ShaderEntries& entries, size_t stage) {
1118 MICROPROFILE_SCOPE(Vulkan_Images); 1082 MICROPROFILE_SCOPE(Vulkan_Images);
1083 const auto& regs = maxwell3d.regs;
1084 const bool via_header_index = regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex;
1119 for (const auto& entry : entries.images) { 1085 for (const auto& entry : entries.images) {
1120 const auto tic = GetTextureInfo(maxwell3d, entry, stage).tic; 1086 const TextureHandle handle = GetTextureInfo(maxwell3d, via_header_index, entry, stage);
1121 SetupImage(tic, entry); 1087 image_view_indices.push_back(handle.image);
1122 } 1088 }
1123} 1089}
1124 1090
@@ -1128,11 +1094,12 @@ void RasterizerVulkan::SetupComputeConstBuffers(const ShaderEntries& entries) {
1128 for (const auto& entry : entries.const_buffers) { 1094 for (const auto& entry : entries.const_buffers) {
1129 const auto& config = launch_desc.const_buffer_config[entry.GetIndex()]; 1095 const auto& config = launch_desc.const_buffer_config[entry.GetIndex()];
1130 const std::bitset<8> mask = launch_desc.const_buffer_enable_mask.Value(); 1096 const std::bitset<8> mask = launch_desc.const_buffer_enable_mask.Value();
1131 Tegra::Engines::ConstBufferInfo buffer; 1097 const Tegra::Engines::ConstBufferInfo info{
1132 buffer.address = config.Address(); 1098 .address = config.Address(),
1133 buffer.size = config.size; 1099 .size = config.size,
1134 buffer.enabled = mask[entry.GetIndex()]; 1100 .enabled = mask[entry.GetIndex()],
1135 SetupConstBuffer(entry, buffer); 1101 };
1102 SetupConstBuffer(entry, info);
1136 } 1103 }
1137} 1104}
1138 1105
@@ -1147,35 +1114,46 @@ void RasterizerVulkan::SetupComputeGlobalBuffers(const ShaderEntries& entries) {
1147 1114
1148void RasterizerVulkan::SetupComputeUniformTexels(const ShaderEntries& entries) { 1115void RasterizerVulkan::SetupComputeUniformTexels(const ShaderEntries& entries) {
1149 MICROPROFILE_SCOPE(Vulkan_Textures); 1116 MICROPROFILE_SCOPE(Vulkan_Textures);
1117 const bool via_header_index = kepler_compute.launch_description.linked_tsc;
1150 for (const auto& entry : entries.uniform_texels) { 1118 for (const auto& entry : entries.uniform_texels) {
1151 const auto image = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic; 1119 const TextureHandle handle =
1152 SetupUniformTexels(image, entry); 1120 GetTextureInfo(kepler_compute, via_header_index, entry, COMPUTE_SHADER_INDEX);
1121 image_view_indices.push_back(handle.image);
1153 } 1122 }
1154} 1123}
1155 1124
1156void RasterizerVulkan::SetupComputeTextures(const ShaderEntries& entries) { 1125void RasterizerVulkan::SetupComputeTextures(const ShaderEntries& entries) {
1157 MICROPROFILE_SCOPE(Vulkan_Textures); 1126 MICROPROFILE_SCOPE(Vulkan_Textures);
1127 const bool via_header_index = kepler_compute.launch_description.linked_tsc;
1158 for (const auto& entry : entries.samplers) { 1128 for (const auto& entry : entries.samplers) {
1159 for (std::size_t i = 0; i < entry.size; ++i) { 1129 for (size_t index = 0; index < entry.size; ++index) {
1160 const auto texture = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex, i); 1130 const TextureHandle handle = GetTextureInfo(kepler_compute, via_header_index, entry,
1161 SetupTexture(texture, entry); 1131 COMPUTE_SHADER_INDEX, index);
1132 image_view_indices.push_back(handle.image);
1133
1134 Sampler* const sampler = texture_cache.GetComputeSampler(handle.sampler);
1135 sampler_handles.push_back(sampler->Handle());
1162 } 1136 }
1163 } 1137 }
1164} 1138}
1165 1139
1166void RasterizerVulkan::SetupComputeStorageTexels(const ShaderEntries& entries) { 1140void RasterizerVulkan::SetupComputeStorageTexels(const ShaderEntries& entries) {
1167 MICROPROFILE_SCOPE(Vulkan_Textures); 1141 MICROPROFILE_SCOPE(Vulkan_Textures);
1142 const bool via_header_index = kepler_compute.launch_description.linked_tsc;
1168 for (const auto& entry : entries.storage_texels) { 1143 for (const auto& entry : entries.storage_texels) {
1169 const auto image = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic; 1144 const TextureHandle handle =
1170 SetupStorageTexel(image, entry); 1145 GetTextureInfo(kepler_compute, via_header_index, entry, COMPUTE_SHADER_INDEX);
1146 image_view_indices.push_back(handle.image);
1171 } 1147 }
1172} 1148}
1173 1149
1174void RasterizerVulkan::SetupComputeImages(const ShaderEntries& entries) { 1150void RasterizerVulkan::SetupComputeImages(const ShaderEntries& entries) {
1175 MICROPROFILE_SCOPE(Vulkan_Images); 1151 MICROPROFILE_SCOPE(Vulkan_Images);
1152 const bool via_header_index = kepler_compute.launch_description.linked_tsc;
1176 for (const auto& entry : entries.images) { 1153 for (const auto& entry : entries.images) {
1177 const auto tic = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic; 1154 const TextureHandle handle =
1178 SetupImage(tic, entry); 1155 GetTextureInfo(kepler_compute, via_header_index, entry, COMPUTE_SHADER_INDEX);
1156 image_view_indices.push_back(handle.image);
1179 } 1157 }
1180} 1158}
1181 1159
@@ -1186,14 +1164,12 @@ void RasterizerVulkan::SetupConstBuffer(const ConstBufferEntry& entry,
1186 update_descriptor_queue.AddBuffer(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE); 1164 update_descriptor_queue.AddBuffer(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE);
1187 return; 1165 return;
1188 } 1166 }
1189
1190 // Align the size to avoid bad std140 interactions 1167 // Align the size to avoid bad std140 interactions
1191 const std::size_t size = 1168 const size_t size = Common::AlignUp(CalculateConstBufferSize(entry, buffer), 4 * sizeof(float));
1192 Common::AlignUp(CalculateConstBufferSize(entry, buffer), 4 * sizeof(float));
1193 ASSERT(size <= MaxConstbufferSize); 1169 ASSERT(size <= MaxConstbufferSize);
1194 1170
1195 const auto info = 1171 const u64 alignment = device.GetUniformBufferAlignment();
1196 buffer_cache.UploadMemory(buffer.address, size, device.GetUniformBufferAlignment()); 1172 const auto info = buffer_cache.UploadMemory(buffer.address, size, alignment);
1197 update_descriptor_queue.AddBuffer(info.handle, info.offset, size); 1173 update_descriptor_queue.AddBuffer(info.handle, info.offset, size);
1198} 1174}
1199 1175
@@ -1206,7 +1182,7 @@ void RasterizerVulkan::SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAdd
1206 // because Vulkan doesn't like empty buffers. 1182 // because Vulkan doesn't like empty buffers.
1207 // Note: Do *not* use DefaultBuffer() here, storage buffers can be written breaking the 1183 // Note: Do *not* use DefaultBuffer() here, storage buffers can be written breaking the
1208 // default buffer. 1184 // default buffer.
1209 static constexpr std::size_t dummy_size = 4; 1185 static constexpr size_t dummy_size = 4;
1210 const auto info = buffer_cache.GetEmptyBuffer(dummy_size); 1186 const auto info = buffer_cache.GetEmptyBuffer(dummy_size);
1211 update_descriptor_queue.AddBuffer(info.handle, info.offset, dummy_size); 1187 update_descriptor_queue.AddBuffer(info.handle, info.offset, dummy_size);
1212 return; 1188 return;
@@ -1217,55 +1193,6 @@ void RasterizerVulkan::SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAdd
1217 update_descriptor_queue.AddBuffer(info.handle, info.offset, size); 1193 update_descriptor_queue.AddBuffer(info.handle, info.offset, size);
1218} 1194}
1219 1195
1220void RasterizerVulkan::SetupUniformTexels(const Tegra::Texture::TICEntry& tic,
1221 const UniformTexelEntry& entry) {
1222 const auto view = texture_cache.GetTextureSurface(tic, entry);
1223 ASSERT(view->IsBufferView());
1224
1225 update_descriptor_queue.AddTexelBuffer(view->GetBufferView());
1226}
1227
1228void RasterizerVulkan::SetupTexture(const Tegra::Texture::FullTextureInfo& texture,
1229 const SamplerEntry& entry) {
1230 auto view = texture_cache.GetTextureSurface(texture.tic, entry);
1231 ASSERT(!view->IsBufferView());
1232
1233 const VkImageView image_view = view->GetImageView(texture.tic.x_source, texture.tic.y_source,
1234 texture.tic.z_source, texture.tic.w_source);
1235 const auto sampler = sampler_cache.GetSampler(texture.tsc);
1236 update_descriptor_queue.AddSampledImage(sampler, image_view);
1237
1238 VkImageLayout* const image_layout = update_descriptor_queue.LastImageLayout();
1239 *image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1240 sampled_views.push_back(ImageView{std::move(view), image_layout});
1241}
1242
1243void RasterizerVulkan::SetupStorageTexel(const Tegra::Texture::TICEntry& tic,
1244 const StorageTexelEntry& entry) {
1245 const auto view = texture_cache.GetImageSurface(tic, entry);
1246 ASSERT(view->IsBufferView());
1247
1248 update_descriptor_queue.AddTexelBuffer(view->GetBufferView());
1249}
1250
1251void RasterizerVulkan::SetupImage(const Tegra::Texture::TICEntry& tic, const ImageEntry& entry) {
1252 auto view = texture_cache.GetImageSurface(tic, entry);
1253
1254 if (entry.is_written) {
1255 view->MarkAsModified(texture_cache.Tick());
1256 }
1257
1258 UNIMPLEMENTED_IF(tic.IsBuffer());
1259
1260 const VkImageView image_view =
1261 view->GetImageView(tic.x_source, tic.y_source, tic.z_source, tic.w_source);
1262 update_descriptor_queue.AddImage(image_view);
1263
1264 VkImageLayout* const image_layout = update_descriptor_queue.LastImageLayout();
1265 *image_layout = VK_IMAGE_LAYOUT_GENERAL;
1266 image_views.push_back(ImageView{std::move(view), image_layout});
1267}
1268
1269void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs) { 1196void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs) {
1270 if (!state_tracker.TouchViewports()) { 1197 if (!state_tracker.TouchViewports()) {
1271 return; 1198 return;
@@ -1457,8 +1384,8 @@ void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs&
1457 }); 1384 });
1458} 1385}
1459 1386
1460std::size_t RasterizerVulkan::CalculateGraphicsStreamBufferSize(bool is_indexed) const { 1387size_t RasterizerVulkan::CalculateGraphicsStreamBufferSize(bool is_indexed) const {
1461 std::size_t size = CalculateVertexArraysSize(); 1388 size_t size = CalculateVertexArraysSize();
1462 if (is_indexed) { 1389 if (is_indexed) {
1463 size = Common::AlignUp(size, 4) + CalculateIndexBufferSize(); 1390 size = Common::AlignUp(size, 4) + CalculateIndexBufferSize();
1464 } 1391 }
@@ -1466,15 +1393,15 @@ std::size_t RasterizerVulkan::CalculateGraphicsStreamBufferSize(bool is_indexed)
1466 return size; 1393 return size;
1467} 1394}
1468 1395
1469std::size_t RasterizerVulkan::CalculateComputeStreamBufferSize() const { 1396size_t RasterizerVulkan::CalculateComputeStreamBufferSize() const {
1470 return Tegra::Engines::KeplerCompute::NumConstBuffers * 1397 return Tegra::Engines::KeplerCompute::NumConstBuffers *
1471 (Maxwell::MaxConstBufferSize + device.GetUniformBufferAlignment()); 1398 (Maxwell::MaxConstBufferSize + device.GetUniformBufferAlignment());
1472} 1399}
1473 1400
1474std::size_t RasterizerVulkan::CalculateVertexArraysSize() const { 1401size_t RasterizerVulkan::CalculateVertexArraysSize() const {
1475 const auto& regs = maxwell3d.regs; 1402 const auto& regs = maxwell3d.regs;
1476 1403
1477 std::size_t size = 0; 1404 size_t size = 0;
1478 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { 1405 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
1479 // This implementation assumes that all attributes are used in the shader. 1406 // This implementation assumes that all attributes are used in the shader.
1480 const GPUVAddr start{regs.vertex_array[index].StartAddress()}; 1407 const GPUVAddr start{regs.vertex_array[index].StartAddress()};
@@ -1486,12 +1413,12 @@ std::size_t RasterizerVulkan::CalculateVertexArraysSize() const {
1486 return size; 1413 return size;
1487} 1414}
1488 1415
1489std::size_t RasterizerVulkan::CalculateIndexBufferSize() const { 1416size_t RasterizerVulkan::CalculateIndexBufferSize() const {
1490 return static_cast<std::size_t>(maxwell3d.regs.index_array.count) * 1417 return static_cast<size_t>(maxwell3d.regs.index_array.count) *
1491 static_cast<std::size_t>(maxwell3d.regs.index_array.FormatSizeInBytes()); 1418 static_cast<size_t>(maxwell3d.regs.index_array.FormatSizeInBytes());
1492} 1419}
1493 1420
1494std::size_t RasterizerVulkan::CalculateConstBufferSize( 1421size_t RasterizerVulkan::CalculateConstBufferSize(
1495 const ConstBufferEntry& entry, const Tegra::Engines::ConstBufferInfo& buffer) const { 1422 const ConstBufferEntry& entry, const Tegra::Engines::ConstBufferInfo& buffer) const {
1496 if (entry.IsIndirect()) { 1423 if (entry.IsIndirect()) {
1497 // Buffer is accessed indirectly, so upload the entire thing 1424 // Buffer is accessed indirectly, so upload the entire thing
@@ -1502,37 +1429,10 @@ std::size_t RasterizerVulkan::CalculateConstBufferSize(
1502 } 1429 }
1503} 1430}
1504 1431
1505RenderPassParams RasterizerVulkan::GetRenderPassParams(Texceptions texceptions) const {
1506 const auto& regs = maxwell3d.regs;
1507 const std::size_t num_attachments = static_cast<std::size_t>(regs.rt_control.count);
1508
1509 RenderPassParams params;
1510 params.color_formats = {};
1511 std::size_t color_texceptions = 0;
1512
1513 std::size_t index = 0;
1514 for (std::size_t rt = 0; rt < num_attachments; ++rt) {
1515 const auto& rendertarget = regs.rt[rt];
1516 if (rendertarget.Address() == 0 || rendertarget.format == Tegra::RenderTargetFormat::NONE) {
1517 continue;
1518 }
1519 params.color_formats[index] = static_cast<u8>(rendertarget.format);
1520 color_texceptions |= (texceptions[rt] ? 1ULL : 0ULL) << index;
1521 ++index;
1522 }
1523 params.num_color_attachments = static_cast<u8>(index);
1524 params.texceptions = static_cast<u8>(color_texceptions);
1525
1526 params.zeta_format = regs.zeta_enable ? static_cast<u8>(regs.zeta.format) : 0;
1527 params.zeta_texception = texceptions[ZETA_TEXCEPTION_INDEX];
1528 return params;
1529}
1530
1531VkBuffer RasterizerVulkan::DefaultBuffer() { 1432VkBuffer RasterizerVulkan::DefaultBuffer() {
1532 if (default_buffer) { 1433 if (default_buffer) {
1533 return *default_buffer; 1434 return *default_buffer;
1534 } 1435 }
1535
1536 default_buffer = device.GetLogical().CreateBuffer({ 1436 default_buffer = device.GetLogical().CreateBuffer({
1537 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 1437 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1538 .pNext = nullptr, 1438 .pNext = nullptr,
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 30ec58eb4..990f9e031 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -11,11 +11,11 @@
11#include <vector> 11#include <vector>
12 12
13#include <boost/container/static_vector.hpp> 13#include <boost/container/static_vector.hpp>
14#include <boost/functional/hash.hpp>
15 14
16#include "common/common_types.h" 15#include "common/common_types.h"
17#include "video_core/rasterizer_accelerated.h" 16#include "video_core/rasterizer_accelerated.h"
18#include "video_core/rasterizer_interface.h" 17#include "video_core/rasterizer_interface.h"
18#include "video_core/renderer_vulkan/blit_image.h"
19#include "video_core/renderer_vulkan/fixed_pipeline_state.h" 19#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
20#include "video_core/renderer_vulkan/vk_buffer_cache.h" 20#include "video_core/renderer_vulkan/vk_buffer_cache.h"
21#include "video_core/renderer_vulkan/vk_compute_pass.h" 21#include "video_core/renderer_vulkan/vk_compute_pass.h"
@@ -24,10 +24,9 @@
24#include "video_core/renderer_vulkan/vk_memory_manager.h" 24#include "video_core/renderer_vulkan/vk_memory_manager.h"
25#include "video_core/renderer_vulkan/vk_pipeline_cache.h" 25#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
26#include "video_core/renderer_vulkan/vk_query_cache.h" 26#include "video_core/renderer_vulkan/vk_query_cache.h"
27#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
28#include "video_core/renderer_vulkan/vk_sampler_cache.h"
29#include "video_core/renderer_vulkan/vk_scheduler.h" 27#include "video_core/renderer_vulkan/vk_scheduler.h"
30#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 28#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
29#include "video_core/renderer_vulkan/vk_stream_buffer.h"
31#include "video_core/renderer_vulkan/vk_texture_cache.h" 30#include "video_core/renderer_vulkan/vk_texture_cache.h"
32#include "video_core/renderer_vulkan/vk_update_descriptor.h" 31#include "video_core/renderer_vulkan/vk_update_descriptor.h"
33#include "video_core/renderer_vulkan/wrapper.h" 32#include "video_core/renderer_vulkan/wrapper.h"
@@ -49,60 +48,9 @@ namespace Vulkan {
49 48
50struct VKScreenInfo; 49struct VKScreenInfo;
51 50
52using ImageViewsPack = boost::container::static_vector<VkImageView, Maxwell::NumRenderTargets + 1>;
53
54struct FramebufferCacheKey {
55 VkRenderPass renderpass{};
56 u32 width = 0;
57 u32 height = 0;
58 u32 layers = 0;
59 ImageViewsPack views;
60
61 std::size_t Hash() const noexcept {
62 std::size_t hash = 0;
63 boost::hash_combine(hash, static_cast<VkRenderPass>(renderpass));
64 for (const auto& view : views) {
65 boost::hash_combine(hash, static_cast<VkImageView>(view));
66 }
67 boost::hash_combine(hash, width);
68 boost::hash_combine(hash, height);
69 boost::hash_combine(hash, layers);
70 return hash;
71 }
72
73 bool operator==(const FramebufferCacheKey& rhs) const noexcept {
74 return std::tie(renderpass, views, width, height, layers) ==
75 std::tie(rhs.renderpass, rhs.views, rhs.width, rhs.height, rhs.layers);
76 }
77
78 bool operator!=(const FramebufferCacheKey& rhs) const noexcept {
79 return !operator==(rhs);
80 }
81};
82
83} // namespace Vulkan
84
85namespace std {
86
87template <>
88struct hash<Vulkan::FramebufferCacheKey> {
89 std::size_t operator()(const Vulkan::FramebufferCacheKey& k) const noexcept {
90 return k.Hash();
91 }
92};
93
94} // namespace std
95
96namespace Vulkan {
97
98class StateTracker; 51class StateTracker;
99class BufferBindings; 52class BufferBindings;
100 53
101struct ImageView {
102 View view;
103 VkImageLayout* layout = nullptr;
104};
105
106class RasterizerVulkan final : public VideoCore::RasterizerAccelerated { 54class RasterizerVulkan final : public VideoCore::RasterizerAccelerated {
107public: 55public:
108 explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, 56 explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
@@ -123,15 +71,18 @@ public:
123 void InvalidateRegion(VAddr addr, u64 size) override; 71 void InvalidateRegion(VAddr addr, u64 size) override;
124 void OnCPUWrite(VAddr addr, u64 size) override; 72 void OnCPUWrite(VAddr addr, u64 size) override;
125 void SyncGuestHost() override; 73 void SyncGuestHost() override;
74 void UnmapMemory(VAddr addr, u64 size) override;
126 void SignalSemaphore(GPUVAddr addr, u32 value) override; 75 void SignalSemaphore(GPUVAddr addr, u32 value) override;
127 void SignalSyncPoint(u32 value) override; 76 void SignalSyncPoint(u32 value) override;
128 void ReleaseFences() override; 77 void ReleaseFences() override;
129 void FlushAndInvalidateRegion(VAddr addr, u64 size) override; 78 void FlushAndInvalidateRegion(VAddr addr, u64 size) override;
130 void WaitForIdle() override; 79 void WaitForIdle() override;
80 void FragmentBarrier() override;
81 void TiledCacheBarrier() override;
131 void FlushCommands() override; 82 void FlushCommands() override;
132 void TickFrame() override; 83 void TickFrame() override;
133 bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, 84 bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src,
134 const Tegra::Engines::Fermi2D::Regs::Surface& dst, 85 const Tegra::Engines::Fermi2D::Surface& dst,
135 const Tegra::Engines::Fermi2D::Config& copy_config) override; 86 const Tegra::Engines::Fermi2D::Config& copy_config) override;
136 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, 87 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
137 u32 pixel_stride) override; 88 u32 pixel_stride) override;
@@ -145,11 +96,17 @@ public:
145 } 96 }
146 97
147 /// Maximum supported size that a constbuffer can have in bytes. 98 /// Maximum supported size that a constbuffer can have in bytes.
148 static constexpr std::size_t MaxConstbufferSize = 0x10000; 99 static constexpr size_t MaxConstbufferSize = 0x10000;
149 static_assert(MaxConstbufferSize % (4 * sizeof(float)) == 0, 100 static_assert(MaxConstbufferSize % (4 * sizeof(float)) == 0,
150 "The maximum size of a constbuffer must be a multiple of the size of GLvec4"); 101 "The maximum size of a constbuffer must be a multiple of the size of GLvec4");
151 102
152private: 103private:
104 static constexpr size_t MAX_TEXTURES = 192;
105 static constexpr size_t MAX_IMAGES = 48;
106 static constexpr size_t MAX_IMAGE_VIEWS = MAX_TEXTURES + MAX_IMAGES;
107
108 static constexpr VkDeviceSize DEFAULT_BUFFER_SIZE = 4 * sizeof(float);
109
153 struct DrawParameters { 110 struct DrawParameters {
154 void Draw(vk::CommandBuffer cmdbuf) const; 111 void Draw(vk::CommandBuffer cmdbuf) const;
155 112
@@ -160,23 +117,8 @@ private:
160 bool is_indexed = 0; 117 bool is_indexed = 0;
161 }; 118 };
162 119
163 using ColorAttachments = std::array<View, Maxwell::NumRenderTargets>;
164 using ZetaAttachment = View;
165
166 using Texceptions = std::bitset<Maxwell::NumRenderTargets + 1>;
167
168 static constexpr std::size_t ZETA_TEXCEPTION_INDEX = 8;
169 static constexpr VkDeviceSize DEFAULT_BUFFER_SIZE = 4 * sizeof(float);
170
171 void FlushWork(); 120 void FlushWork();
172 121
173 /// @brief Updates the currently bound attachments
174 /// @param is_clear True when the framebuffer is updated as a clear
175 /// @return Bitfield of attachments being used as sampled textures
176 Texceptions UpdateAttachments(bool is_clear);
177
178 std::tuple<VkFramebuffer, VkExtent2D> ConfigureFramebuffers(VkRenderPass renderpass);
179
180 /// Setups geometry buffers and state. 122 /// Setups geometry buffers and state.
181 DrawParameters SetupGeometry(FixedPipelineState& fixed_state, BufferBindings& buffer_bindings, 123 DrawParameters SetupGeometry(FixedPipelineState& fixed_state, BufferBindings& buffer_bindings,
182 bool is_indexed, bool is_instanced); 124 bool is_indexed, bool is_instanced);
@@ -184,17 +126,12 @@ private:
184 /// Setup descriptors in the graphics pipeline. 126 /// Setup descriptors in the graphics pipeline.
185 void SetupShaderDescriptors(const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders); 127 void SetupShaderDescriptors(const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders);
186 128
187 void SetupImageTransitions(Texceptions texceptions, const ColorAttachments& color,
188 const ZetaAttachment& zeta);
189
190 void UpdateDynamicStates(); 129 void UpdateDynamicStates();
191 130
192 void BeginTransformFeedback(); 131 void BeginTransformFeedback();
193 132
194 void EndTransformFeedback(); 133 void EndTransformFeedback();
195 134
196 bool WalkAttachmentOverlaps(const CachedSurfaceView& attachment);
197
198 void SetupVertexArrays(BufferBindings& buffer_bindings); 135 void SetupVertexArrays(BufferBindings& buffer_bindings);
199 136
200 void SetupIndexBuffer(BufferBindings& buffer_bindings, DrawParameters& params, bool is_indexed); 137 void SetupIndexBuffer(BufferBindings& buffer_bindings, DrawParameters& params, bool is_indexed);
@@ -240,14 +177,6 @@ private:
240 177
241 void SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAddr address); 178 void SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAddr address);
242 179
243 void SetupUniformTexels(const Tegra::Texture::TICEntry& image, const UniformTexelEntry& entry);
244
245 void SetupTexture(const Tegra::Texture::FullTextureInfo& texture, const SamplerEntry& entry);
246
247 void SetupStorageTexel(const Tegra::Texture::TICEntry& tic, const StorageTexelEntry& entry);
248
249 void SetupImage(const Tegra::Texture::TICEntry& tic, const ImageEntry& entry);
250
251 void UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs); 180 void UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs);
252 void UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs); 181 void UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs);
253 void UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs); 182 void UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs);
@@ -264,18 +193,16 @@ private:
264 void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs); 193 void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs);
265 void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs); 194 void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
266 195
267 std::size_t CalculateGraphicsStreamBufferSize(bool is_indexed) const; 196 size_t CalculateGraphicsStreamBufferSize(bool is_indexed) const;
268
269 std::size_t CalculateComputeStreamBufferSize() const;
270 197
271 std::size_t CalculateVertexArraysSize() const; 198 size_t CalculateComputeStreamBufferSize() const;
272 199
273 std::size_t CalculateIndexBufferSize() const; 200 size_t CalculateVertexArraysSize() const;
274 201
275 std::size_t CalculateConstBufferSize(const ConstBufferEntry& entry, 202 size_t CalculateIndexBufferSize() const;
276 const Tegra::Engines::ConstBufferInfo& buffer) const;
277 203
278 RenderPassParams GetRenderPassParams(Texceptions texceptions) const; 204 size_t CalculateConstBufferSize(const ConstBufferEntry& entry,
205 const Tegra::Engines::ConstBufferInfo& buffer) const;
279 206
280 VkBuffer DefaultBuffer(); 207 VkBuffer DefaultBuffer();
281 208
@@ -290,18 +217,19 @@ private:
290 StateTracker& state_tracker; 217 StateTracker& state_tracker;
291 VKScheduler& scheduler; 218 VKScheduler& scheduler;
292 219
220 VKStreamBuffer stream_buffer;
293 VKStagingBufferPool staging_pool; 221 VKStagingBufferPool staging_pool;
294 VKDescriptorPool descriptor_pool; 222 VKDescriptorPool descriptor_pool;
295 VKUpdateDescriptorQueue update_descriptor_queue; 223 VKUpdateDescriptorQueue update_descriptor_queue;
296 VKRenderPassCache renderpass_cache; 224 BlitImageHelper blit_image;
297 QuadArrayPass quad_array_pass; 225 QuadArrayPass quad_array_pass;
298 QuadIndexedPass quad_indexed_pass; 226 QuadIndexedPass quad_indexed_pass;
299 Uint8Pass uint8_pass; 227 Uint8Pass uint8_pass;
300 228
301 VKTextureCache texture_cache; 229 TextureCacheRuntime texture_cache_runtime;
230 TextureCache texture_cache;
302 VKPipelineCache pipeline_cache; 231 VKPipelineCache pipeline_cache;
303 VKBufferCache buffer_cache; 232 VKBufferCache buffer_cache;
304 VKSamplerCache sampler_cache;
305 VKQueryCache query_cache; 233 VKQueryCache query_cache;
306 VKFenceManager fence_manager; 234 VKFenceManager fence_manager;
307 235
@@ -310,16 +238,11 @@ private:
310 vk::Event wfi_event; 238 vk::Event wfi_event;
311 VideoCommon::Shader::AsyncShaders async_shaders; 239 VideoCommon::Shader::AsyncShaders async_shaders;
312 240
313 ColorAttachments color_attachments; 241 boost::container::static_vector<u32, MAX_IMAGE_VIEWS> image_view_indices;
314 ZetaAttachment zeta_attachment; 242 std::array<VideoCommon::ImageViewId, MAX_IMAGE_VIEWS> image_view_ids;
315 243 boost::container::static_vector<VkSampler, MAX_TEXTURES> sampler_handles;
316 std::vector<ImageView> sampled_views;
317 std::vector<ImageView> image_views;
318 244
319 u32 draw_counter = 0; 245 u32 draw_counter = 0;
320
321 // TODO(Rodrigo): Invalidate on image destruction
322 std::unordered_map<FramebufferCacheKey, vk::Framebuffer> framebuffer_cache;
323}; 246};
324 247
325} // namespace Vulkan 248} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp b/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp
deleted file mode 100644
index e812c7dd6..000000000
--- a/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp
+++ /dev/null
@@ -1,158 +0,0 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6#include <memory>
7#include <vector>
8
9#include "common/cityhash.h"
10#include "video_core/engines/maxwell_3d.h"
11#include "video_core/renderer_vulkan/maxwell_to_vk.h"
12#include "video_core/renderer_vulkan/vk_device.h"
13#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
14#include "video_core/renderer_vulkan/wrapper.h"
15
16namespace Vulkan {
17
18std::size_t RenderPassParams::Hash() const noexcept {
19 const u64 hash = Common::CityHash64(reinterpret_cast<const char*>(this), sizeof *this);
20 return static_cast<std::size_t>(hash);
21}
22
23bool RenderPassParams::operator==(const RenderPassParams& rhs) const noexcept {
24 return std::memcmp(&rhs, this, sizeof *this) == 0;
25}
26
27VKRenderPassCache::VKRenderPassCache(const VKDevice& device_) : device{device_} {}
28
29VKRenderPassCache::~VKRenderPassCache() = default;
30
31VkRenderPass VKRenderPassCache::GetRenderPass(const RenderPassParams& params) {
32 const auto [pair, is_cache_miss] = cache.try_emplace(params);
33 auto& entry = pair->second;
34 if (is_cache_miss) {
35 entry = CreateRenderPass(params);
36 }
37 return *entry;
38}
39
40vk::RenderPass VKRenderPassCache::CreateRenderPass(const RenderPassParams& params) const {
41 using namespace VideoCore::Surface;
42 const std::size_t num_attachments = static_cast<std::size_t>(params.num_color_attachments);
43
44 std::vector<VkAttachmentDescription> descriptors;
45 descriptors.reserve(num_attachments);
46
47 std::vector<VkAttachmentReference> color_references;
48 color_references.reserve(num_attachments);
49
50 for (std::size_t rt = 0; rt < num_attachments; ++rt) {
51 const auto guest_format = static_cast<Tegra::RenderTargetFormat>(params.color_formats[rt]);
52 const PixelFormat pixel_format = PixelFormatFromRenderTargetFormat(guest_format);
53 const auto format = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, pixel_format);
54 ASSERT_MSG(format.attachable, "Trying to attach a non-attachable format with format={}",
55 static_cast<int>(pixel_format));
56
57 // TODO(Rodrigo): Add MAY_ALIAS_BIT when it's needed.
58 const VkImageLayout color_layout = ((params.texceptions >> rt) & 1) != 0
59 ? VK_IMAGE_LAYOUT_GENERAL
60 : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
61 descriptors.push_back({
62 .flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT,
63 .format = format.format,
64 .samples = VK_SAMPLE_COUNT_1_BIT,
65 .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
66 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
67 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
68 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
69 .initialLayout = color_layout,
70 .finalLayout = color_layout,
71 });
72
73 color_references.push_back({
74 .attachment = static_cast<u32>(rt),
75 .layout = color_layout,
76 });
77 }
78
79 VkAttachmentReference zeta_attachment_ref;
80 const bool has_zeta = params.zeta_format != 0;
81 if (has_zeta) {
82 const auto guest_format = static_cast<Tegra::DepthFormat>(params.zeta_format);
83 const PixelFormat pixel_format = PixelFormatFromDepthFormat(guest_format);
84 const auto format = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, pixel_format);
85 ASSERT_MSG(format.attachable, "Trying to attach a non-attachable format with format={}",
86 static_cast<int>(pixel_format));
87
88 const VkImageLayout zeta_layout = params.zeta_texception != 0
89 ? VK_IMAGE_LAYOUT_GENERAL
90 : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
91 descriptors.push_back({
92 .flags = 0,
93 .format = format.format,
94 .samples = VK_SAMPLE_COUNT_1_BIT,
95 .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
96 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
97 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
98 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE,
99 .initialLayout = zeta_layout,
100 .finalLayout = zeta_layout,
101 });
102
103 zeta_attachment_ref = {
104 .attachment = static_cast<u32>(num_attachments),
105 .layout = zeta_layout,
106 };
107 }
108
109 const VkSubpassDescription subpass_description{
110 .flags = 0,
111 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
112 .inputAttachmentCount = 0,
113 .pInputAttachments = nullptr,
114 .colorAttachmentCount = static_cast<u32>(color_references.size()),
115 .pColorAttachments = color_references.data(),
116 .pResolveAttachments = nullptr,
117 .pDepthStencilAttachment = has_zeta ? &zeta_attachment_ref : nullptr,
118 .preserveAttachmentCount = 0,
119 .pPreserveAttachments = nullptr,
120 };
121
122 VkAccessFlags access = 0;
123 VkPipelineStageFlags stage = 0;
124 if (!color_references.empty()) {
125 access |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
126 stage |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
127 }
128
129 if (has_zeta) {
130 access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
131 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
132 stage |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
133 }
134
135 const VkSubpassDependency subpass_dependency{
136 .srcSubpass = VK_SUBPASS_EXTERNAL,
137 .dstSubpass = 0,
138 .srcStageMask = stage,
139 .dstStageMask = stage,
140 .srcAccessMask = 0,
141 .dstAccessMask = access,
142 .dependencyFlags = 0,
143 };
144
145 return device.GetLogical().CreateRenderPass({
146 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
147 .pNext = nullptr,
148 .flags = 0,
149 .attachmentCount = static_cast<u32>(descriptors.size()),
150 .pAttachments = descriptors.data(),
151 .subpassCount = 1,
152 .pSubpasses = &subpass_description,
153 .dependencyCount = 1,
154 .pDependencies = &subpass_dependency,
155 });
156}
157
158} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_renderpass_cache.h b/src/video_core/renderer_vulkan/vk_renderpass_cache.h
deleted file mode 100644
index 652ecef7b..000000000
--- a/src/video_core/renderer_vulkan/vk_renderpass_cache.h
+++ /dev/null
@@ -1,70 +0,0 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <type_traits>
8#include <unordered_map>
9
10#include <boost/container/static_vector.hpp>
11#include <boost/functional/hash.hpp>
12
13#include "video_core/engines/maxwell_3d.h"
14#include "video_core/renderer_vulkan/wrapper.h"
15#include "video_core/surface.h"
16
17namespace Vulkan {
18
19class VKDevice;
20
21struct RenderPassParams {
22 std::array<u8, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> color_formats;
23 u8 num_color_attachments;
24 u8 texceptions;
25
26 u8 zeta_format;
27 u8 zeta_texception;
28
29 std::size_t Hash() const noexcept;
30
31 bool operator==(const RenderPassParams& rhs) const noexcept;
32
33 bool operator!=(const RenderPassParams& rhs) const noexcept {
34 return !operator==(rhs);
35 }
36};
37static_assert(std::has_unique_object_representations_v<RenderPassParams>);
38static_assert(std::is_trivially_copyable_v<RenderPassParams>);
39static_assert(std::is_trivially_constructible_v<RenderPassParams>);
40
41} // namespace Vulkan
42
43namespace std {
44
45template <>
46struct hash<Vulkan::RenderPassParams> {
47 std::size_t operator()(const Vulkan::RenderPassParams& k) const noexcept {
48 return k.Hash();
49 }
50};
51
52} // namespace std
53
54namespace Vulkan {
55
56class VKRenderPassCache final {
57public:
58 explicit VKRenderPassCache(const VKDevice& device_);
59 ~VKRenderPassCache();
60
61 VkRenderPass GetRenderPass(const RenderPassParams& params);
62
63private:
64 vk::RenderPass CreateRenderPass(const RenderPassParams& params) const;
65
66 const VKDevice& device;
67 std::unordered_map<RenderPassParams, vk::RenderPass> cache;
68};
69
70} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_sampler_cache.cpp b/src/video_core/renderer_vulkan/vk_sampler_cache.cpp
deleted file mode 100644
index b859691fa..000000000
--- a/src/video_core/renderer_vulkan/vk_sampler_cache.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <unordered_map>
6
7#include "video_core/renderer_vulkan/maxwell_to_vk.h"
8#include "video_core/renderer_vulkan/vk_sampler_cache.h"
9#include "video_core/renderer_vulkan/wrapper.h"
10#include "video_core/textures/texture.h"
11
12using Tegra::Texture::TextureMipmapFilter;
13
14namespace Vulkan {
15
16namespace {
17
18VkBorderColor ConvertBorderColor(std::array<float, 4> color) {
19 // TODO(Rodrigo): Manage integer border colors
20 if (color == std::array<float, 4>{0, 0, 0, 0}) {
21 return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
22 } else if (color == std::array<float, 4>{0, 0, 0, 1}) {
23 return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
24 } else if (color == std::array<float, 4>{1, 1, 1, 1}) {
25 return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
26 }
27 if (color[0] + color[1] + color[2] > 1.35f) {
28 // If color elements are brighter than roughly 0.5 average, use white border
29 return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
30 } else if (color[3] > 0.5f) {
31 return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
32 } else {
33 return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
34 }
35}
36
37} // Anonymous namespace
38
39VKSamplerCache::VKSamplerCache(const VKDevice& device_) : device{device_} {}
40
41VKSamplerCache::~VKSamplerCache() = default;
42
43vk::Sampler VKSamplerCache::CreateSampler(const Tegra::Texture::TSCEntry& tsc) const {
44 const bool arbitrary_borders = device.IsExtCustomBorderColorSupported();
45 const std::array color = tsc.GetBorderColor();
46
47 VkSamplerCustomBorderColorCreateInfoEXT border{
48 .sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT,
49 .pNext = nullptr,
50 .customBorderColor = {},
51 .format = VK_FORMAT_UNDEFINED,
52 };
53 std::memcpy(&border.customBorderColor, color.data(), sizeof(color));
54
55 return device.GetLogical().CreateSampler({
56 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
57 .pNext = arbitrary_borders ? &border : nullptr,
58 .flags = 0,
59 .magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter),
60 .minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter),
61 .mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter),
62 .addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter),
63 .addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter),
64 .addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter),
65 .mipLodBias = tsc.GetLodBias(),
66 .anisotropyEnable =
67 static_cast<VkBool32>(tsc.GetMaxAnisotropy() > 1.0f ? VK_TRUE : VK_FALSE),
68 .maxAnisotropy = tsc.GetMaxAnisotropy(),
69 .compareEnable = tsc.depth_compare_enabled,
70 .compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func),
71 .minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.GetMinLod(),
72 .maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.GetMaxLod(),
73 .borderColor =
74 arbitrary_borders ? VK_BORDER_COLOR_INT_CUSTOM_EXT : ConvertBorderColor(color),
75 .unnormalizedCoordinates = VK_FALSE,
76 });
77}
78
79VkSampler VKSamplerCache::ToSamplerType(const vk::Sampler& sampler) const {
80 return *sampler;
81}
82
83} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_sampler_cache.h b/src/video_core/renderer_vulkan/vk_sampler_cache.h
deleted file mode 100644
index 3f22c4610..000000000
--- a/src/video_core/renderer_vulkan/vk_sampler_cache.h
+++ /dev/null
@@ -1,29 +0,0 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "video_core/renderer_vulkan/wrapper.h"
8#include "video_core/sampler_cache.h"
9#include "video_core/textures/texture.h"
10
11namespace Vulkan {
12
13class VKDevice;
14
15class VKSamplerCache final : public VideoCommon::SamplerCache<VkSampler, vk::Sampler> {
16public:
17 explicit VKSamplerCache(const VKDevice& device_);
18 ~VKSamplerCache();
19
20protected:
21 vk::Sampler CreateSampler(const Tegra::Texture::TSCEntry& tsc) const override;
22
23 VkSampler ToSamplerType(const vk::Sampler& sampler) const override;
24
25private:
26 const VKDevice& device;
27};
28
29} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
index 1a483dc71..c104c6fe3 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -16,6 +16,7 @@
16#include "video_core/renderer_vulkan/vk_query_cache.h" 16#include "video_core/renderer_vulkan/vk_query_cache.h"
17#include "video_core/renderer_vulkan/vk_scheduler.h" 17#include "video_core/renderer_vulkan/vk_scheduler.h"
18#include "video_core/renderer_vulkan/vk_state_tracker.h" 18#include "video_core/renderer_vulkan/vk_state_tracker.h"
19#include "video_core/renderer_vulkan/vk_texture_cache.h"
19#include "video_core/renderer_vulkan/wrapper.h" 20#include "video_core/renderer_vulkan/wrapper.h"
20 21
21namespace Vulkan { 22namespace Vulkan {
@@ -96,38 +97,39 @@ void VKScheduler::DispatchWork() {
96 AcquireNewChunk(); 97 AcquireNewChunk();
97} 98}
98 99
99void VKScheduler::RequestRenderpass(VkRenderPass renderpass, VkFramebuffer framebuffer, 100void VKScheduler::RequestRenderpass(const Framebuffer* framebuffer) {
100 VkExtent2D render_area) { 101 const VkRenderPass renderpass = framebuffer->RenderPass();
101 if (renderpass == state.renderpass && framebuffer == state.framebuffer && 102 const VkFramebuffer framebuffer_handle = framebuffer->Handle();
103 const VkExtent2D render_area = framebuffer->RenderArea();
104 if (renderpass == state.renderpass && framebuffer_handle == state.framebuffer &&
102 render_area.width == state.render_area.width && 105 render_area.width == state.render_area.width &&
103 render_area.height == state.render_area.height) { 106 render_area.height == state.render_area.height) {
104 return; 107 return;
105 } 108 }
106 const bool end_renderpass = state.renderpass != nullptr; 109 EndRenderPass();
107 state.renderpass = renderpass; 110 state.renderpass = renderpass;
108 state.framebuffer = framebuffer; 111 state.framebuffer = framebuffer_handle;
109 state.render_area = render_area; 112 state.render_area = render_area;
110 113
111 const VkRenderPassBeginInfo renderpass_bi{ 114 Record([renderpass, framebuffer_handle, render_area](vk::CommandBuffer cmdbuf) {
112 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 115 const VkRenderPassBeginInfo renderpass_bi{
113 .pNext = nullptr, 116 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
114 .renderPass = renderpass, 117 .pNext = nullptr,
115 .framebuffer = framebuffer, 118 .renderPass = renderpass,
116 .renderArea = 119 .framebuffer = framebuffer_handle,
117 { 120 .renderArea =
118 .offset = {.x = 0, .y = 0}, 121 {
119 .extent = render_area, 122 .offset = {.x = 0, .y = 0},
120 }, 123 .extent = render_area,
121 .clearValueCount = 0, 124 },
122 .pClearValues = nullptr, 125 .clearValueCount = 0,
123 }; 126 .pClearValues = nullptr,
124 127 };
125 Record([renderpass_bi, end_renderpass](vk::CommandBuffer cmdbuf) {
126 if (end_renderpass) {
127 cmdbuf.EndRenderPass();
128 }
129 cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); 128 cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
130 }); 129 });
130 num_renderpass_images = framebuffer->NumImages();
131 renderpass_images = framebuffer->Images();
132 renderpass_image_ranges = framebuffer->ImageRanges();
131} 133}
132 134
133void VKScheduler::RequestOutsideRenderPassOperationContext() { 135void VKScheduler::RequestOutsideRenderPassOperationContext() {
@@ -241,8 +243,37 @@ void VKScheduler::EndRenderPass() {
241 if (!state.renderpass) { 243 if (!state.renderpass) {
242 return; 244 return;
243 } 245 }
246 Record([num_images = num_renderpass_images, images = renderpass_images,
247 ranges = renderpass_image_ranges](vk::CommandBuffer cmdbuf) {
248 std::array<VkImageMemoryBarrier, 9> barriers;
249 for (size_t i = 0; i < num_images; ++i) {
250 barriers[i] = VkImageMemoryBarrier{
251 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
252 .pNext = nullptr,
253 .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
254 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
255 .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
256 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
257 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
258 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
259 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
260 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
261 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
262 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
263 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
264 .image = images[i],
265 .subresourceRange = ranges[i],
266 };
267 }
268 cmdbuf.EndRenderPass();
269 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
270 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
271 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
272 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, nullptr, nullptr,
273 vk::Span(barriers.data(), num_images));
274 });
244 state.renderpass = nullptr; 275 state.renderpass = nullptr;
245 Record([](vk::CommandBuffer cmdbuf) { cmdbuf.EndRenderPass(); }); 276 num_renderpass_images = 0;
246} 277}
247 278
248void VKScheduler::AcquireNewChunk() { 279void VKScheduler::AcquireNewChunk() {
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h
index 6d3a5da0b..0a36c8fad 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.h
+++ b/src/video_core/renderer_vulkan/vk_scheduler.h
@@ -17,6 +17,7 @@
17namespace Vulkan { 17namespace Vulkan {
18 18
19class CommandPool; 19class CommandPool;
20class Framebuffer;
20class MasterSemaphore; 21class MasterSemaphore;
21class StateTracker; 22class StateTracker;
22class VKDevice; 23class VKDevice;
@@ -52,8 +53,7 @@ public:
52 void DispatchWork(); 53 void DispatchWork();
53 54
54 /// Requests to begin a renderpass. 55 /// Requests to begin a renderpass.
55 void RequestRenderpass(VkRenderPass renderpass, VkFramebuffer framebuffer, 56 void RequestRenderpass(const Framebuffer* framebuffer);
56 VkExtent2D render_area);
57 57
58 /// Requests the current executino context to be able to execute operations only allowed outside 58 /// Requests the current executino context to be able to execute operations only allowed outside
59 /// of a renderpass. 59 /// of a renderpass.
@@ -62,6 +62,9 @@ public:
62 /// Binds a pipeline to the current execution context. 62 /// Binds a pipeline to the current execution context.
63 void BindGraphicsPipeline(VkPipeline pipeline); 63 void BindGraphicsPipeline(VkPipeline pipeline);
64 64
65 /// Invalidates current command buffer state except for render passes
66 void InvalidateState();
67
65 /// Assigns the query cache. 68 /// Assigns the query cache.
66 void SetQueryCache(VKQueryCache& query_cache_) { 69 void SetQueryCache(VKQueryCache& query_cache_) {
67 query_cache = &query_cache_; 70 query_cache = &query_cache_;
@@ -170,8 +173,6 @@ private:
170 173
171 void AllocateNewContext(); 174 void AllocateNewContext();
172 175
173 void InvalidateState();
174
175 void EndPendingOperations(); 176 void EndPendingOperations();
176 177
177 void EndRenderPass(); 178 void EndRenderPass();
@@ -192,6 +193,11 @@ private:
192 std::thread worker_thread; 193 std::thread worker_thread;
193 194
194 State state; 195 State state;
196
197 u32 num_renderpass_images = 0;
198 std::array<VkImage, 9> renderpass_images{};
199 std::array<VkImageSubresourceRange, 9> renderpass_image_ranges{};
200
195 Common::SPSCQueue<std::unique_ptr<CommandChunk>> chunk_queue; 201 Common::SPSCQueue<std::unique_ptr<CommandChunk>> chunk_queue;
196 Common::SPSCQueue<std::unique_ptr<CommandChunk>> chunk_reserve; 202 Common::SPSCQueue<std::unique_ptr<CommandChunk>> chunk_reserve;
197 std::mutex mutex; 203 std::mutex mutex;
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index 72954d0e3..09d6f9f35 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -102,7 +102,7 @@ struct GenericVaryingDescription {
102 bool is_scalar = false; 102 bool is_scalar = false;
103}; 103};
104 104
105spv::Dim GetSamplerDim(const Sampler& sampler) { 105spv::Dim GetSamplerDim(const SamplerEntry& sampler) {
106 ASSERT(!sampler.is_buffer); 106 ASSERT(!sampler.is_buffer);
107 switch (sampler.type) { 107 switch (sampler.type) {
108 case Tegra::Shader::TextureType::Texture1D: 108 case Tegra::Shader::TextureType::Texture1D:
@@ -119,7 +119,7 @@ spv::Dim GetSamplerDim(const Sampler& sampler) {
119 } 119 }
120} 120}
121 121
122std::pair<spv::Dim, bool> GetImageDim(const Image& image) { 122std::pair<spv::Dim, bool> GetImageDim(const ImageEntry& image) {
123 switch (image.type) { 123 switch (image.type) {
124 case Tegra::Shader::ImageType::Texture1D: 124 case Tegra::Shader::ImageType::Texture1D:
125 return {spv::Dim::Dim1D, false}; 125 return {spv::Dim::Dim1D, false};
@@ -980,7 +980,7 @@ private:
980 return binding; 980 return binding;
981 } 981 }
982 982
983 void DeclareImage(const Image& image, u32& binding) { 983 void DeclareImage(const ImageEntry& image, u32& binding) {
984 const auto [dim, arrayed] = GetImageDim(image); 984 const auto [dim, arrayed] = GetImageDim(image);
985 constexpr int depth = 0; 985 constexpr int depth = 0;
986 constexpr bool ms = false; 986 constexpr bool ms = false;
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.h b/src/video_core/renderer_vulkan/vk_shader_decompiler.h
index df1812514..ad91ad5de 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.h
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.h
@@ -21,10 +21,10 @@ class VKDevice;
21namespace Vulkan { 21namespace Vulkan {
22 22
23using Maxwell = Tegra::Engines::Maxwell3D::Regs; 23using Maxwell = Tegra::Engines::Maxwell3D::Regs;
24using UniformTexelEntry = VideoCommon::Shader::Sampler; 24using UniformTexelEntry = VideoCommon::Shader::SamplerEntry;
25using SamplerEntry = VideoCommon::Shader::Sampler; 25using SamplerEntry = VideoCommon::Shader::SamplerEntry;
26using StorageTexelEntry = VideoCommon::Shader::Image; 26using StorageTexelEntry = VideoCommon::Shader::ImageEntry;
27using ImageEntry = VideoCommon::Shader::Image; 27using ImageEntry = VideoCommon::Shader::ImageEntry;
28 28
29constexpr u32 DESCRIPTOR_SET = 0; 29constexpr u32 DESCRIPTOR_SET = 0;
30 30
diff --git a/src/video_core/renderer_vulkan/vk_shader_util.cpp b/src/video_core/renderer_vulkan/vk_shader_util.cpp
index c1a218d76..38a0be7f2 100644
--- a/src/video_core/renderer_vulkan/vk_shader_util.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_util.cpp
@@ -13,18 +13,13 @@
13 13
14namespace Vulkan { 14namespace Vulkan {
15 15
16vk::ShaderModule BuildShader(const VKDevice& device, std::size_t code_size, const u8* code_data) { 16vk::ShaderModule BuildShader(const VKDevice& device, std::span<const u32> code) {
17 // Avoid undefined behavior by copying to a staging allocation
18 ASSERT(code_size % sizeof(u32) == 0);
19 const auto data = std::make_unique<u32[]>(code_size / sizeof(u32));
20 std::memcpy(data.get(), code_data, code_size);
21
22 return device.GetLogical().CreateShaderModule({ 17 return device.GetLogical().CreateShaderModule({
23 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 18 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
24 .pNext = nullptr, 19 .pNext = nullptr,
25 .flags = 0, 20 .flags = 0,
26 .codeSize = code_size, 21 .codeSize = static_cast<u32>(code.size_bytes()),
27 .pCode = data.get(), 22 .pCode = code.data(),
28 }); 23 });
29} 24}
30 25
diff --git a/src/video_core/renderer_vulkan/vk_shader_util.h b/src/video_core/renderer_vulkan/vk_shader_util.h
index d1d3f3cae..dce34a140 100644
--- a/src/video_core/renderer_vulkan/vk_shader_util.h
+++ b/src/video_core/renderer_vulkan/vk_shader_util.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <span>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8#include "video_core/renderer_vulkan/wrapper.h" 10#include "video_core/renderer_vulkan/wrapper.h"
9 11
@@ -11,6 +13,6 @@ namespace Vulkan {
11 13
12class VKDevice; 14class VKDevice;
13 15
14vk::ShaderModule BuildShader(const VKDevice& device, std::size_t code_size, const u8* code_data); 16vk::ShaderModule BuildShader(const VKDevice& device, std::span<const u32> code);
15 17
16} // namespace Vulkan 18} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp
index 50164cc08..1779a2e30 100644
--- a/src/video_core/renderer_vulkan/vk_state_tracker.cpp
+++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <array>
6#include <cstddef> 7#include <cstddef>
7#include <iterator> 8#include <iterator>
8 9
@@ -29,21 +30,15 @@ using Table = Maxwell3D::DirtyState::Table;
29using Flags = Maxwell3D::DirtyState::Flags; 30using Flags = Maxwell3D::DirtyState::Flags;
30 31
31Flags MakeInvalidationFlags() { 32Flags MakeInvalidationFlags() {
33 static constexpr std::array INVALIDATION_FLAGS{
34 Viewports, Scissors, DepthBias, BlendConstants, DepthBounds,
35 StencilProperties, CullMode, DepthBoundsEnable, DepthTestEnable, DepthWriteEnable,
36 DepthCompareOp, FrontFace, StencilOp, StencilTestEnable,
37 };
32 Flags flags{}; 38 Flags flags{};
33 flags[Viewports] = true; 39 for (const int flag : INVALIDATION_FLAGS) {
34 flags[Scissors] = true; 40 flags[flag] = true;
35 flags[DepthBias] = true; 41 }
36 flags[BlendConstants] = true;
37 flags[DepthBounds] = true;
38 flags[StencilProperties] = true;
39 flags[CullMode] = true;
40 flags[DepthBoundsEnable] = true;
41 flags[DepthTestEnable] = true;
42 flags[DepthWriteEnable] = true;
43 flags[DepthCompareOp] = true;
44 flags[FrontFace] = true;
45 flags[StencilOp] = true;
46 flags[StencilTestEnable] = true;
47 return flags; 42 return flags;
48} 43}
49 44
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.h b/src/video_core/renderer_vulkan/vk_state_tracker.h
index 1de789e57..c335d2bdf 100644
--- a/src/video_core/renderer_vulkan/vk_state_tracker.h
+++ b/src/video_core/renderer_vulkan/vk_state_tracker.h
@@ -52,6 +52,14 @@ public:
52 current_topology = INVALID_TOPOLOGY; 52 current_topology = INVALID_TOPOLOGY;
53 } 53 }
54 54
55 void InvalidateViewports() {
56 flags[Dirty::Viewports] = true;
57 }
58
59 void InvalidateScissors() {
60 flags[Dirty::Scissors] = true;
61 }
62
55 bool TouchViewports() { 63 bool TouchViewports() {
56 return Exchange(Dirty::Viewports, false); 64 return Exchange(Dirty::Viewports, false);
57 } 65 }
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
index 1b59612b9..419cb154d 100644
--- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
+++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
@@ -19,6 +19,10 @@ namespace Vulkan {
19 19
20namespace { 20namespace {
21 21
22constexpr VkBufferUsageFlags BUFFER_USAGE =
23 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
24 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
25
22constexpr u64 WATCHES_INITIAL_RESERVE = 0x4000; 26constexpr u64 WATCHES_INITIAL_RESERVE = 0x4000;
23constexpr u64 WATCHES_RESERVE_CHUNK = 0x1000; 27constexpr u64 WATCHES_RESERVE_CHUNK = 0x1000;
24 28
@@ -56,17 +60,16 @@ u32 GetMemoryType(const VkPhysicalDeviceMemoryProperties& properties,
56 60
57} // Anonymous namespace 61} // Anonymous namespace
58 62
59VKStreamBuffer::VKStreamBuffer(const VKDevice& device_, VKScheduler& scheduler_, 63VKStreamBuffer::VKStreamBuffer(const VKDevice& device_, VKScheduler& scheduler_)
60 VkBufferUsageFlags usage)
61 : device{device_}, scheduler{scheduler_} { 64 : device{device_}, scheduler{scheduler_} {
62 CreateBuffers(usage); 65 CreateBuffers();
63 ReserveWatches(current_watches, WATCHES_INITIAL_RESERVE); 66 ReserveWatches(current_watches, WATCHES_INITIAL_RESERVE);
64 ReserveWatches(previous_watches, WATCHES_INITIAL_RESERVE); 67 ReserveWatches(previous_watches, WATCHES_INITIAL_RESERVE);
65} 68}
66 69
67VKStreamBuffer::~VKStreamBuffer() = default; 70VKStreamBuffer::~VKStreamBuffer() = default;
68 71
69std::tuple<u8*, u64, bool> VKStreamBuffer::Map(u64 size, u64 alignment) { 72std::pair<u8*, u64> VKStreamBuffer::Map(u64 size, u64 alignment) {
70 ASSERT(size <= stream_buffer_size); 73 ASSERT(size <= stream_buffer_size);
71 mapped_size = size; 74 mapped_size = size;
72 75
@@ -76,7 +79,6 @@ std::tuple<u8*, u64, bool> VKStreamBuffer::Map(u64 size, u64 alignment) {
76 79
77 WaitPendingOperations(offset); 80 WaitPendingOperations(offset);
78 81
79 bool invalidated = false;
80 if (offset + size > stream_buffer_size) { 82 if (offset + size > stream_buffer_size) {
81 // The buffer would overflow, save the amount of used watches and reset the state. 83 // The buffer would overflow, save the amount of used watches and reset the state.
82 invalidation_mark = current_watch_cursor; 84 invalidation_mark = current_watch_cursor;
@@ -90,11 +92,9 @@ std::tuple<u8*, u64, bool> VKStreamBuffer::Map(u64 size, u64 alignment) {
90 92
91 // Ensure that we don't wait for uncommitted fences. 93 // Ensure that we don't wait for uncommitted fences.
92 scheduler.Flush(); 94 scheduler.Flush();
93
94 invalidated = true;
95 } 95 }
96 96
97 return {memory.Map(offset, size), offset, invalidated}; 97 return std::make_pair(memory.Map(offset, size), offset);
98} 98}
99 99
100void VKStreamBuffer::Unmap(u64 size) { 100void VKStreamBuffer::Unmap(u64 size) {
@@ -113,7 +113,7 @@ void VKStreamBuffer::Unmap(u64 size) {
113 watch.tick = scheduler.CurrentTick(); 113 watch.tick = scheduler.CurrentTick();
114} 114}
115 115
116void VKStreamBuffer::CreateBuffers(VkBufferUsageFlags usage) { 116void VKStreamBuffer::CreateBuffers() {
117 const auto memory_properties = device.GetPhysical().GetMemoryProperties(); 117 const auto memory_properties = device.GetPhysical().GetMemoryProperties();
118 const u32 preferred_type = GetMemoryType(memory_properties); 118 const u32 preferred_type = GetMemoryType(memory_properties);
119 const u32 preferred_heap = memory_properties.memoryTypes[preferred_type].heapIndex; 119 const u32 preferred_heap = memory_properties.memoryTypes[preferred_type].heapIndex;
@@ -127,7 +127,7 @@ void VKStreamBuffer::CreateBuffers(VkBufferUsageFlags usage) {
127 .pNext = nullptr, 127 .pNext = nullptr,
128 .flags = 0, 128 .flags = 0,
129 .size = std::min(PREFERRED_STREAM_BUFFER_SIZE, allocable_size), 129 .size = std::min(PREFERRED_STREAM_BUFFER_SIZE, allocable_size),
130 .usage = usage, 130 .usage = BUFFER_USAGE,
131 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 131 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
132 .queueFamilyIndexCount = 0, 132 .queueFamilyIndexCount = 0,
133 .pQueueFamilyIndices = nullptr, 133 .pQueueFamilyIndices = nullptr,
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.h b/src/video_core/renderer_vulkan/vk_stream_buffer.h
index 5e15ad78f..1428f77bf 100644
--- a/src/video_core/renderer_vulkan/vk_stream_buffer.h
+++ b/src/video_core/renderer_vulkan/vk_stream_buffer.h
@@ -5,7 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <optional> 7#include <optional>
8#include <tuple> 8#include <utility>
9#include <vector> 9#include <vector>
10 10
11#include "common/common_types.h" 11#include "common/common_types.h"
@@ -19,17 +19,15 @@ class VKScheduler;
19 19
20class VKStreamBuffer final { 20class VKStreamBuffer final {
21public: 21public:
22 explicit VKStreamBuffer(const VKDevice& device, VKScheduler& scheduler, 22 explicit VKStreamBuffer(const VKDevice& device, VKScheduler& scheduler);
23 VkBufferUsageFlags usage);
24 ~VKStreamBuffer(); 23 ~VKStreamBuffer();
25 24
26 /** 25 /**
27 * Reserves a region of memory from the stream buffer. 26 * Reserves a region of memory from the stream buffer.
28 * @param size Size to reserve. 27 * @param size Size to reserve.
29 * @returns A tuple in the following order: Raw memory pointer (with offset added), buffer 28 * @returns A pair of a raw memory pointer (with offset added), and the buffer offset
30 * offset and a boolean that's true when buffer has been invalidated.
31 */ 29 */
32 std::tuple<u8*, u64, bool> Map(u64 size, u64 alignment); 30 std::pair<u8*, u64> Map(u64 size, u64 alignment);
33 31
34 /// Ensures that "size" bytes of memory are available to the GPU, potentially recording a copy. 32 /// Ensures that "size" bytes of memory are available to the GPU, potentially recording a copy.
35 void Unmap(u64 size); 33 void Unmap(u64 size);
@@ -49,7 +47,7 @@ private:
49 }; 47 };
50 48
51 /// Creates Vulkan buffer handles committing the required the required memory. 49 /// Creates Vulkan buffer handles committing the required the required memory.
52 void CreateBuffers(VkBufferUsageFlags usage); 50 void CreateBuffers();
53 51
54 /// Increases the amount of watches available. 52 /// Increases the amount of watches available.
55 void ReserveWatches(std::vector<Watch>& watches, std::size_t grow_size); 53 void ReserveWatches(std::vector<Watch>& watches, std::size_t grow_size);
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index ae2e3322c..261808391 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -4,614 +4,1103 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <array> 6#include <array>
7#include <cstddef> 7#include <span>
8#include <cstring>
9#include <memory>
10#include <variant>
11#include <vector> 8#include <vector>
12 9
13#include "common/assert.h" 10#include "video_core/engines/fermi_2d.h"
14#include "common/common_types.h" 11#include "video_core/renderer_vulkan/blit_image.h"
15#include "core/core.h"
16#include "video_core/engines/maxwell_3d.h"
17#include "video_core/morton.h"
18#include "video_core/renderer_vulkan/maxwell_to_vk.h" 12#include "video_core/renderer_vulkan/maxwell_to_vk.h"
19#include "video_core/renderer_vulkan/vk_device.h" 13#include "video_core/renderer_vulkan/vk_device.h"
20#include "video_core/renderer_vulkan/vk_memory_manager.h"
21#include "video_core/renderer_vulkan/vk_rasterizer.h"
22#include "video_core/renderer_vulkan/vk_scheduler.h" 14#include "video_core/renderer_vulkan/vk_scheduler.h"
23#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 15#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
24#include "video_core/renderer_vulkan/vk_texture_cache.h" 16#include "video_core/renderer_vulkan/vk_texture_cache.h"
25#include "video_core/renderer_vulkan/wrapper.h" 17#include "video_core/renderer_vulkan/wrapper.h"
26#include "video_core/surface.h"
27 18
28namespace Vulkan { 19namespace Vulkan {
29 20
30using VideoCore::MortonSwizzle; 21using Tegra::Engines::Fermi2D;
31using VideoCore::MortonSwizzleMode;
32
33using Tegra::Texture::SwizzleSource; 22using Tegra::Texture::SwizzleSource;
34using VideoCore::Surface::PixelFormat; 23using Tegra::Texture::TextureMipmapFilter;
35using VideoCore::Surface::SurfaceTarget; 24using VideoCommon::BufferImageCopy;
25using VideoCommon::ImageInfo;
26using VideoCommon::ImageType;
27using VideoCommon::SubresourceRange;
28using VideoCore::Surface::IsPixelFormatASTC;
36 29
37namespace { 30namespace {
38 31
39VkImageType SurfaceTargetToImage(SurfaceTarget target) { 32constexpr std::array ATTACHMENT_REFERENCES{
40 switch (target) { 33 VkAttachmentReference{0, VK_IMAGE_LAYOUT_GENERAL},
41 case SurfaceTarget::Texture1D: 34 VkAttachmentReference{1, VK_IMAGE_LAYOUT_GENERAL},
42 case SurfaceTarget::Texture1DArray: 35 VkAttachmentReference{2, VK_IMAGE_LAYOUT_GENERAL},
36 VkAttachmentReference{3, VK_IMAGE_LAYOUT_GENERAL},
37 VkAttachmentReference{4, VK_IMAGE_LAYOUT_GENERAL},
38 VkAttachmentReference{5, VK_IMAGE_LAYOUT_GENERAL},
39 VkAttachmentReference{6, VK_IMAGE_LAYOUT_GENERAL},
40 VkAttachmentReference{7, VK_IMAGE_LAYOUT_GENERAL},
41 VkAttachmentReference{8, VK_IMAGE_LAYOUT_GENERAL},
42};
43
44constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
45 if (color == std::array<float, 4>{0, 0, 0, 0}) {
46 return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
47 } else if (color == std::array<float, 4>{0, 0, 0, 1}) {
48 return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
49 } else if (color == std::array<float, 4>{1, 1, 1, 1}) {
50 return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
51 }
52 if (color[0] + color[1] + color[2] > 1.35f) {
53 // If color elements are brighter than roughly 0.5 average, use white border
54 return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
55 } else if (color[3] > 0.5f) {
56 return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
57 } else {
58 return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
59 }
60}
61
62[[nodiscard]] VkImageType ConvertImageType(const ImageType type) {
63 switch (type) {
64 case ImageType::e1D:
43 return VK_IMAGE_TYPE_1D; 65 return VK_IMAGE_TYPE_1D;
44 case SurfaceTarget::Texture2D: 66 case ImageType::e2D:
45 case SurfaceTarget::Texture2DArray: 67 case ImageType::Linear:
46 case SurfaceTarget::TextureCubemap:
47 case SurfaceTarget::TextureCubeArray:
48 return VK_IMAGE_TYPE_2D; 68 return VK_IMAGE_TYPE_2D;
49 case SurfaceTarget::Texture3D: 69 case ImageType::e3D:
50 return VK_IMAGE_TYPE_3D; 70 return VK_IMAGE_TYPE_3D;
51 case SurfaceTarget::TextureBuffer: 71 case ImageType::Buffer:
52 UNREACHABLE(); 72 break;
53 return {};
54 } 73 }
55 UNREACHABLE_MSG("Unknown texture target={}", target); 74 UNREACHABLE_MSG("Invalid image type={}", type);
56 return {}; 75 return {};
57} 76}
58 77
59VkImageAspectFlags PixelFormatToImageAspect(PixelFormat pixel_format) { 78[[nodiscard]] VkSampleCountFlagBits ConvertSampleCount(u32 num_samples) {
60 if (pixel_format < PixelFormat::MaxColorFormat) { 79 switch (num_samples) {
61 return VK_IMAGE_ASPECT_COLOR_BIT; 80 case 1:
62 } else if (pixel_format < PixelFormat::MaxDepthFormat) { 81 return VK_SAMPLE_COUNT_1_BIT;
63 return VK_IMAGE_ASPECT_DEPTH_BIT; 82 case 2:
64 } else if (pixel_format < PixelFormat::MaxDepthStencilFormat) { 83 return VK_SAMPLE_COUNT_2_BIT;
65 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; 84 case 4:
66 } else { 85 return VK_SAMPLE_COUNT_4_BIT;
67 UNREACHABLE_MSG("Invalid pixel format={}", pixel_format); 86 case 8:
68 return VK_IMAGE_ASPECT_COLOR_BIT; 87 return VK_SAMPLE_COUNT_8_BIT;
88 case 16:
89 return VK_SAMPLE_COUNT_16_BIT;
90 default:
91 UNREACHABLE_MSG("Invalid number of samples={}", num_samples);
92 return VK_SAMPLE_COUNT_1_BIT;
69 } 93 }
70} 94}
71 95
72VkImageViewType GetImageViewType(SurfaceTarget target) { 96[[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const VKDevice& device, const ImageInfo& info) {
73 switch (target) { 97 const auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, info.format);
74 case SurfaceTarget::Texture1D: 98 VkImageCreateFlags flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
75 return VK_IMAGE_VIEW_TYPE_1D; 99 if (info.type == ImageType::e2D && info.resources.layers >= 6 &&
76 case SurfaceTarget::Texture2D: 100 info.size.width == info.size.height) {
77 return VK_IMAGE_VIEW_TYPE_2D; 101 flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
78 case SurfaceTarget::Texture3D:
79 return VK_IMAGE_VIEW_TYPE_3D;
80 case SurfaceTarget::Texture1DArray:
81 return VK_IMAGE_VIEW_TYPE_1D_ARRAY;
82 case SurfaceTarget::Texture2DArray:
83 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
84 case SurfaceTarget::TextureCubemap:
85 return VK_IMAGE_VIEW_TYPE_CUBE;
86 case SurfaceTarget::TextureCubeArray:
87 return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
88 case SurfaceTarget::TextureBuffer:
89 break;
90 } 102 }
91 UNREACHABLE(); 103 if (info.type == ImageType::e3D) {
92 return {}; 104 flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
93} 105 }
94 106 VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
95vk::Buffer CreateBuffer(const VKDevice& device, const SurfaceParams& params, 107 VK_IMAGE_USAGE_SAMPLED_BIT;
96 std::size_t host_memory_size) { 108 if (format_info.attachable) {
97 // TODO(Rodrigo): Move texture buffer creation to the buffer cache 109 switch (VideoCore::Surface::GetFormatType(info.format)) {
98 return device.GetLogical().CreateBuffer({ 110 case VideoCore::Surface::SurfaceType::ColorTexture:
99 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 111 usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
112 break;
113 case VideoCore::Surface::SurfaceType::Depth:
114 case VideoCore::Surface::SurfaceType::DepthStencil:
115 usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
116 break;
117 default:
118 UNREACHABLE_MSG("Invalid surface type");
119 }
120 }
121 if (format_info.storage) {
122 usage |= VK_IMAGE_USAGE_STORAGE_BIT;
123 }
124 const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(info.num_samples);
125 return VkImageCreateInfo{
126 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
100 .pNext = nullptr, 127 .pNext = nullptr,
101 .flags = 0, 128 .flags = flags,
102 .size = static_cast<VkDeviceSize>(host_memory_size), 129 .imageType = ConvertImageType(info.type),
103 .usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | 130 .format = format_info.format,
104 VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | 131 .extent =
105 VK_BUFFER_USAGE_TRANSFER_DST_BIT, 132 {
133 .width = info.size.width >> samples_x,
134 .height = info.size.height >> samples_y,
135 .depth = info.size.depth,
136 },
137 .mipLevels = static_cast<u32>(info.resources.levels),
138 .arrayLayers = static_cast<u32>(info.resources.layers),
139 .samples = ConvertSampleCount(info.num_samples),
140 .tiling = VK_IMAGE_TILING_OPTIMAL,
141 .usage = usage,
106 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 142 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
107 .queueFamilyIndexCount = 0, 143 .queueFamilyIndexCount = 0,
108 .pQueueFamilyIndices = nullptr, 144 .pQueueFamilyIndices = nullptr,
109 }); 145 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
110}
111
112VkBufferViewCreateInfo GenerateBufferViewCreateInfo(const VKDevice& device,
113 const SurfaceParams& params, VkBuffer buffer,
114 std::size_t host_memory_size) {
115 ASSERT(params.IsBuffer());
116
117 return {
118 .sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
119 .pNext = nullptr,
120 .flags = 0,
121 .buffer = buffer,
122 .format =
123 MaxwellToVK::SurfaceFormat(device, FormatType::Buffer, params.pixel_format).format,
124 .offset = 0,
125 .range = static_cast<VkDeviceSize>(host_memory_size),
126 }; 146 };
127} 147}
128 148
129VkImageCreateInfo GenerateImageCreateInfo(const VKDevice& device, const SurfaceParams& params) { 149[[nodiscard]] vk::Image MakeImage(const VKDevice& device, const ImageInfo& info) {
130 ASSERT(!params.IsBuffer()); 150 if (info.type == ImageType::Buffer) {
131 151 return vk::Image{};
132 const auto [format, attachable, storage] = 152 }
133 MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, params.pixel_format); 153 return device.GetLogical().CreateImage(MakeImageCreateInfo(device, info));
154}
134 155
135 VkImageCreateInfo ci{ 156[[nodiscard]] vk::Buffer MakeBuffer(const VKDevice& device, const ImageInfo& info) {
136 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 157 if (info.type != ImageType::Buffer) {
158 return vk::Buffer{};
159 }
160 const size_t bytes_per_block = VideoCore::Surface::BytesPerBlock(info.format);
161 return device.GetLogical().CreateBuffer(VkBufferCreateInfo{
162 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
137 .pNext = nullptr, 163 .pNext = nullptr,
138 .flags = 0, 164 .flags = 0,
139 .imageType = SurfaceTargetToImage(params.target), 165 .size = info.size.width * bytes_per_block,
140 .format = format, 166 .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
141 .extent = {}, 167 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT |
142 .mipLevels = params.num_levels, 168 VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,
143 .arrayLayers = static_cast<u32>(params.GetNumLayers()),
144 .samples = VK_SAMPLE_COUNT_1_BIT,
145 .tiling = VK_IMAGE_TILING_OPTIMAL,
146 .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
147 VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
148 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 169 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
149 .queueFamilyIndexCount = 0, 170 .queueFamilyIndexCount = 0,
150 .pQueueFamilyIndices = nullptr, 171 .pQueueFamilyIndices = nullptr,
151 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 172 });
152 };
153 if (attachable) {
154 ci.usage |= params.IsPixelFormatZeta() ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
155 : VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
156 }
157 if (storage) {
158 ci.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
159 }
160
161 switch (params.target) {
162 case SurfaceTarget::TextureCubemap:
163 case SurfaceTarget::TextureCubeArray:
164 ci.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
165 [[fallthrough]];
166 case SurfaceTarget::Texture1D:
167 case SurfaceTarget::Texture1DArray:
168 case SurfaceTarget::Texture2D:
169 case SurfaceTarget::Texture2DArray:
170 ci.extent = {params.width, params.height, 1};
171 break;
172 case SurfaceTarget::Texture3D:
173 ci.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
174 ci.extent = {params.width, params.height, params.depth};
175 break;
176 case SurfaceTarget::TextureBuffer:
177 UNREACHABLE();
178 }
179
180 return ci;
181} 173}
182 174
183u32 EncodeSwizzle(SwizzleSource x_source, SwizzleSource y_source, SwizzleSource z_source, 175[[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) {
184 SwizzleSource w_source) { 176 switch (VideoCore::Surface::GetFormatType(format)) {
185 return (static_cast<u32>(x_source) << 24) | (static_cast<u32>(y_source) << 16) | 177 case VideoCore::Surface::SurfaceType::ColorTexture:
186 (static_cast<u32>(z_source) << 8) | static_cast<u32>(w_source); 178 return VK_IMAGE_ASPECT_COLOR_BIT;
179 case VideoCore::Surface::SurfaceType::Depth:
180 return VK_IMAGE_ASPECT_DEPTH_BIT;
181 case VideoCore::Surface::SurfaceType::DepthStencil:
182 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
183 default:
184 UNREACHABLE_MSG("Invalid surface type");
185 return VkImageAspectFlags{};
186 }
187} 187}
188 188
189} // Anonymous namespace 189[[nodiscard]] VkImageAspectFlags ImageViewAspectMask(const VideoCommon::ImageViewInfo& info) {
190 190 if (info.IsRenderTarget()) {
191CachedSurface::CachedSurface(const VKDevice& device_, VKMemoryManager& memory_manager_, 191 return ImageAspectMask(info.format);
192 VKScheduler& scheduler_, VKStagingBufferPool& staging_pool_,
193 GPUVAddr gpu_addr_, const SurfaceParams& params_)
194 : SurfaceBase<View>{gpu_addr_, params_, device_.IsOptimalAstcSupported()}, device{device_},
195 memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{staging_pool_} {
196 if (params.IsBuffer()) {
197 buffer = CreateBuffer(device, params, host_memory_size);
198 commit = memory_manager.Commit(buffer, false);
199
200 const auto buffer_view_ci =
201 GenerateBufferViewCreateInfo(device, params, *buffer, host_memory_size);
202 format = buffer_view_ci.format;
203
204 buffer_view = device.GetLogical().CreateBufferView(buffer_view_ci);
205 } else {
206 const auto image_ci = GenerateImageCreateInfo(device, params);
207 format = image_ci.format;
208
209 image.emplace(device, scheduler, image_ci, PixelFormatToImageAspect(params.pixel_format));
210 commit = memory_manager.Commit(image->GetHandle(), false);
211 } 192 }
212 193 const bool is_first = info.Swizzle()[0] == SwizzleSource::R;
213 // TODO(Rodrigo): Move this to a virtual function. 194 switch (info.format) {
214 u32 num_layers = 1; 195 case PixelFormat::D24_UNORM_S8_UINT:
215 if (params.is_layered || params.target == SurfaceTarget::Texture3D) { 196 case PixelFormat::D32_FLOAT_S8_UINT:
216 num_layers = params.depth; 197 return is_first ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT;
198 case PixelFormat::S8_UINT_D24_UNORM:
199 return is_first ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT;
200 case PixelFormat::D16_UNORM:
201 case PixelFormat::D32_FLOAT:
202 return VK_IMAGE_ASPECT_DEPTH_BIT;
203 default:
204 return VK_IMAGE_ASPECT_COLOR_BIT;
217 } 205 }
218 main_view = CreateView(ViewParams(params.target, 0, num_layers, 0, params.num_levels));
219} 206}
220 207
221CachedSurface::~CachedSurface() = default; 208[[nodiscard]] VkAttachmentDescription AttachmentDescription(const VKDevice& device,
222 209 const ImageView* image_view) {
223void CachedSurface::UploadTexture(const std::vector<u8>& staging_buffer) { 210 const auto pixel_format = image_view->format;
224 // To upload data we have to be outside of a renderpass 211 return VkAttachmentDescription{
225 scheduler.RequestOutsideRenderPassOperationContext(); 212 .flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT,
213 .format = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, pixel_format).format,
214 .samples = image_view->Samples(),
215 .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
216 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
217 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
218 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE,
219 .initialLayout = VK_IMAGE_LAYOUT_GENERAL,
220 .finalLayout = VK_IMAGE_LAYOUT_GENERAL,
221 };
222}
226 223
227 if (params.IsBuffer()) { 224[[nodiscard]] VkComponentSwizzle ComponentSwizzle(SwizzleSource swizzle) {
228 UploadBuffer(staging_buffer); 225 switch (swizzle) {
229 } else { 226 case SwizzleSource::Zero:
230 UploadImage(staging_buffer); 227 return VK_COMPONENT_SWIZZLE_ZERO;
228 case SwizzleSource::R:
229 return VK_COMPONENT_SWIZZLE_R;
230 case SwizzleSource::G:
231 return VK_COMPONENT_SWIZZLE_G;
232 case SwizzleSource::B:
233 return VK_COMPONENT_SWIZZLE_B;
234 case SwizzleSource::A:
235 return VK_COMPONENT_SWIZZLE_A;
236 case SwizzleSource::OneFloat:
237 case SwizzleSource::OneInt:
238 return VK_COMPONENT_SWIZZLE_ONE;
231 } 239 }
240 UNREACHABLE_MSG("Invalid swizzle={}", swizzle);
241 return VK_COMPONENT_SWIZZLE_ZERO;
232} 242}
233 243
234void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) { 244[[nodiscard]] VkImageViewType ImageViewType(VideoCommon::ImageViewType type) {
235 UNIMPLEMENTED_IF(params.IsBuffer()); 245 switch (type) {
236 246 case VideoCommon::ImageViewType::e1D:
237 if (params.pixel_format == PixelFormat::A1B5G5R5_UNORM) { 247 return VK_IMAGE_VIEW_TYPE_1D;
238 LOG_WARNING(Render_Vulkan, "A1B5G5R5 flushing is stubbed"); 248 case VideoCommon::ImageViewType::e2D:
249 return VK_IMAGE_VIEW_TYPE_2D;
250 case VideoCommon::ImageViewType::Cube:
251 return VK_IMAGE_VIEW_TYPE_CUBE;
252 case VideoCommon::ImageViewType::e3D:
253 return VK_IMAGE_VIEW_TYPE_3D;
254 case VideoCommon::ImageViewType::e1DArray:
255 return VK_IMAGE_VIEW_TYPE_1D_ARRAY;
256 case VideoCommon::ImageViewType::e2DArray:
257 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
258 case VideoCommon::ImageViewType::CubeArray:
259 return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
260 case VideoCommon::ImageViewType::Rect:
261 LOG_WARNING(Render_Vulkan, "Unnormalized image view type not supported");
262 return VK_IMAGE_VIEW_TYPE_2D;
263 case VideoCommon::ImageViewType::Buffer:
264 UNREACHABLE_MSG("Texture buffers can't be image views");
265 return VK_IMAGE_VIEW_TYPE_1D;
239 } 266 }
267 UNREACHABLE_MSG("Invalid image view type={}", type);
268 return VK_IMAGE_VIEW_TYPE_2D;
269}
240 270
241 // We can't copy images to buffers inside a renderpass 271[[nodiscard]] VkImageSubresourceLayers MakeImageSubresourceLayers(
242 scheduler.RequestOutsideRenderPassOperationContext(); 272 VideoCommon::SubresourceLayers subresource, VkImageAspectFlags aspect_mask) {
273 return VkImageSubresourceLayers{
274 .aspectMask = aspect_mask,
275 .mipLevel = static_cast<u32>(subresource.base_level),
276 .baseArrayLayer = static_cast<u32>(subresource.base_layer),
277 .layerCount = static_cast<u32>(subresource.num_layers),
278 };
279}
243 280
244 FullTransition(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, 281[[nodiscard]] VkOffset3D MakeOffset3D(VideoCommon::Offset3D offset3d) {
245 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); 282 return VkOffset3D{
283 .x = offset3d.x,
284 .y = offset3d.y,
285 .z = offset3d.z,
286 };
287}
246 288
247 const auto& unused_buffer = staging_pool.GetUnusedBuffer(host_memory_size, true); 289[[nodiscard]] VkExtent3D MakeExtent3D(VideoCommon::Extent3D extent3d) {
248 // TODO(Rodrigo): Do this in a single copy 290 return VkExtent3D{
249 for (u32 level = 0; level < params.num_levels; ++level) { 291 .width = static_cast<u32>(extent3d.width),
250 scheduler.Record([image = *image->GetHandle(), buffer = *unused_buffer.handle, 292 .height = static_cast<u32>(extent3d.height),
251 copy = GetBufferImageCopy(level)](vk::CommandBuffer cmdbuf) { 293 .depth = static_cast<u32>(extent3d.depth),
252 cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, copy); 294 };
253 }); 295}
254 }
255 scheduler.Finish();
256 296
257 // TODO(Rodrigo): Use an intern buffer for staging buffers and avoid this unnecessary memcpy. 297[[nodiscard]] VkImageCopy MakeImageCopy(const VideoCommon::ImageCopy& copy,
258 std::memcpy(staging_buffer.data(), unused_buffer.commit->Map(host_memory_size), 298 VkImageAspectFlags aspect_mask) noexcept {
259 host_memory_size); 299 return VkImageCopy{
300 .srcSubresource = MakeImageSubresourceLayers(copy.src_subresource, aspect_mask),
301 .srcOffset = MakeOffset3D(copy.src_offset),
302 .dstSubresource = MakeImageSubresourceLayers(copy.dst_subresource, aspect_mask),
303 .dstOffset = MakeOffset3D(copy.dst_offset),
304 .extent = MakeExtent3D(copy.extent),
305 };
260} 306}
261 307
262void CachedSurface::DecorateSurfaceName() { 308[[nodiscard]] std::vector<VkBufferCopy> TransformBufferCopies(
263 // TODO(Rodrigo): Add name decorations 309 std::span<const VideoCommon::BufferCopy> copies, size_t buffer_offset) {
310 std::vector<VkBufferCopy> result(copies.size());
311 std::ranges::transform(
312 copies, result.begin(), [buffer_offset](const VideoCommon::BufferCopy& copy) {
313 return VkBufferCopy{
314 .srcOffset = static_cast<VkDeviceSize>(copy.src_offset + buffer_offset),
315 .dstOffset = static_cast<VkDeviceSize>(copy.dst_offset),
316 .size = static_cast<VkDeviceSize>(copy.size),
317 };
318 });
319 return result;
264} 320}
265 321
266View CachedSurface::CreateView(const ViewParams& view_params) { 322[[nodiscard]] std::vector<VkBufferImageCopy> TransformBufferImageCopies(
267 // TODO(Rodrigo): Add name decorations 323 std::span<const BufferImageCopy> copies, size_t buffer_offset, VkImageAspectFlags aspect_mask) {
268 return views[view_params] = std::make_shared<CachedSurfaceView>(device, *this, view_params); 324 struct Maker {
325 VkBufferImageCopy operator()(const BufferImageCopy& copy) const {
326 return VkBufferImageCopy{
327 .bufferOffset = copy.buffer_offset + buffer_offset,
328 .bufferRowLength = copy.buffer_row_length,
329 .bufferImageHeight = copy.buffer_image_height,
330 .imageSubresource =
331 {
332 .aspectMask = aspect_mask,
333 .mipLevel = static_cast<u32>(copy.image_subresource.base_level),
334 .baseArrayLayer = static_cast<u32>(copy.image_subresource.base_layer),
335 .layerCount = static_cast<u32>(copy.image_subresource.num_layers),
336 },
337 .imageOffset =
338 {
339 .x = copy.image_offset.x,
340 .y = copy.image_offset.y,
341 .z = copy.image_offset.z,
342 },
343 .imageExtent =
344 {
345 .width = copy.image_extent.width,
346 .height = copy.image_extent.height,
347 .depth = copy.image_extent.depth,
348 },
349 };
350 }
351 size_t buffer_offset;
352 VkImageAspectFlags aspect_mask;
353 };
354 if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
355 std::vector<VkBufferImageCopy> result(copies.size() * 2);
356 std::ranges::transform(copies, result.begin(),
357 Maker{buffer_offset, VK_IMAGE_ASPECT_DEPTH_BIT});
358 std::ranges::transform(copies, result.begin() + copies.size(),
359 Maker{buffer_offset, VK_IMAGE_ASPECT_STENCIL_BIT});
360 return result;
361 } else {
362 std::vector<VkBufferImageCopy> result(copies.size());
363 std::ranges::transform(copies, result.begin(), Maker{buffer_offset, aspect_mask});
364 return result;
365 }
269} 366}
270 367
271void CachedSurface::UploadBuffer(const std::vector<u8>& staging_buffer) { 368[[nodiscard]] VkImageSubresourceRange MakeSubresourceRange(VkImageAspectFlags aspect_mask,
272 const auto& src_buffer = staging_pool.GetUnusedBuffer(host_memory_size, true); 369 const SubresourceRange& range) {
273 std::memcpy(src_buffer.commit->Map(host_memory_size), staging_buffer.data(), host_memory_size); 370 return VkImageSubresourceRange{
371 .aspectMask = aspect_mask,
372 .baseMipLevel = static_cast<u32>(range.base.level),
373 .levelCount = static_cast<u32>(range.extent.levels),
374 .baseArrayLayer = static_cast<u32>(range.base.layer),
375 .layerCount = static_cast<u32>(range.extent.layers),
376 };
377}
274 378
275 scheduler.Record([src_buffer = *src_buffer.handle, dst_buffer = *buffer, 379[[nodiscard]] VkImageSubresourceRange MakeSubresourceRange(const ImageView* image_view) {
276 size = host_memory_size](vk::CommandBuffer cmdbuf) { 380 SubresourceRange range = image_view->range;
277 VkBufferCopy copy; 381 if (True(image_view->flags & VideoCommon::ImageViewFlagBits::Slice)) {
278 copy.srcOffset = 0; 382 // Slice image views always affect a single layer, but their subresource range corresponds
279 copy.dstOffset = 0; 383 // to the slice. Override the value to affect a single layer.
280 copy.size = size; 384 range.base.layer = 0;
281 cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy); 385 range.extent.layers = 1;
386 }
387 return MakeSubresourceRange(ImageAspectMask(image_view->format), range);
388}
282 389
283 VkBufferMemoryBarrier barrier; 390[[nodiscard]] VkImageSubresourceLayers MakeSubresourceLayers(const ImageView* image_view) {
284 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; 391 return VkImageSubresourceLayers{
285 barrier.pNext = nullptr; 392 .aspectMask = ImageAspectMask(image_view->format),
286 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; 393 .mipLevel = static_cast<u32>(image_view->range.base.level),
287 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; 394 .baseArrayLayer = static_cast<u32>(image_view->range.base.layer),
288 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // They'll be ignored anyway 395 .layerCount = static_cast<u32>(image_view->range.extent.layers),
289 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 396 };
290 barrier.buffer = dst_buffer;
291 barrier.offset = 0;
292 barrier.size = size;
293 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
294 0, {}, barrier, {});
295 });
296} 397}
297 398
298void CachedSurface::UploadImage(const std::vector<u8>& staging_buffer) { 399[[nodiscard]] constexpr SwizzleSource ConvertGreenRed(SwizzleSource value) {
299 const auto& src_buffer = staging_pool.GetUnusedBuffer(host_memory_size, true); 400 switch (value) {
300 std::memcpy(src_buffer.commit->Map(host_memory_size), staging_buffer.data(), host_memory_size); 401 case SwizzleSource::G:
301 402 return SwizzleSource::R;
302 FullTransition(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, 403 default:
303 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); 404 return value;
304
305 for (u32 level = 0; level < params.num_levels; ++level) {
306 const VkBufferImageCopy copy = GetBufferImageCopy(level);
307 if (image->GetAspectMask() == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
308 scheduler.Record([buffer = *src_buffer.handle, image = *image->GetHandle(),
309 copy](vk::CommandBuffer cmdbuf) {
310 std::array<VkBufferImageCopy, 2> copies = {copy, copy};
311 copies[0].imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
312 copies[1].imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
313 cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
314 copies);
315 });
316 } else {
317 scheduler.Record([buffer = *src_buffer.handle, image = *image->GetHandle(),
318 copy](vk::CommandBuffer cmdbuf) {
319 cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy);
320 });
321 }
322 } 405 }
323} 406}
324 407
325VkBufferImageCopy CachedSurface::GetBufferImageCopy(u32 level) const { 408void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage image,
326 return { 409 VkImageAspectFlags aspect_mask, bool is_initialized,
327 .bufferOffset = params.GetHostMipmapLevelOffset(level, is_converted), 410 std::span<const VkBufferImageCopy> copies) {
328 .bufferRowLength = 0, 411 static constexpr VkAccessFlags ACCESS_FLAGS = VK_ACCESS_SHADER_WRITE_BIT |
329 .bufferImageHeight = 0, 412 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
330 .imageSubresource = 413 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
414 const VkImageMemoryBarrier read_barrier{
415 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
416 .pNext = nullptr,
417 .srcAccessMask = ACCESS_FLAGS,
418 .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
419 .oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
420 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
421 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
422 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
423 .image = image,
424 .subresourceRange =
331 { 425 {
332 .aspectMask = image->GetAspectMask(), 426 .aspectMask = aspect_mask,
333 .mipLevel = level, 427 .baseMipLevel = 0,
428 .levelCount = VK_REMAINING_MIP_LEVELS,
334 .baseArrayLayer = 0, 429 .baseArrayLayer = 0,
335 .layerCount = static_cast<u32>(params.GetNumLayers()), 430 .layerCount = VK_REMAINING_ARRAY_LAYERS,
336 }, 431 },
337 .imageOffset = {.x = 0, .y = 0, .z = 0}, 432 };
338 .imageExtent = 433 const VkImageMemoryBarrier write_barrier{
434 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
435 .pNext = nullptr,
436 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
437 .dstAccessMask = ACCESS_FLAGS,
438 .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
439 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
440 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
441 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
442 .image = image,
443 .subresourceRange =
339 { 444 {
340 .width = params.GetMipWidth(level), 445 .aspectMask = aspect_mask,
341 .height = params.GetMipHeight(level), 446 .baseMipLevel = 0,
342 .depth = params.target == SurfaceTarget::Texture3D ? params.GetMipDepth(level) : 1U, 447 .levelCount = VK_REMAINING_MIP_LEVELS,
448 .baseArrayLayer = 0,
449 .layerCount = VK_REMAINING_ARRAY_LAYERS,
343 }, 450 },
344 }; 451 };
452 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
453 read_barrier);
454 cmdbuf.CopyBufferToImage(src_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copies);
455 // TODO: Move this to another API
456 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,
457 write_barrier);
345} 458}
346 459
347VkImageSubresourceRange CachedSurface::GetImageSubresourceRange() const { 460[[nodiscard]] VkImageBlit MakeImageBlit(const std::array<Offset2D, 2>& dst_region,
348 return {image->GetAspectMask(), 0, params.num_levels, 0, 461 const std::array<Offset2D, 2>& src_region,
349 static_cast<u32>(params.GetNumLayers())}; 462 const VkImageSubresourceLayers& dst_layers,
463 const VkImageSubresourceLayers& src_layers) {
464 return VkImageBlit{
465 .srcSubresource = src_layers,
466 .srcOffsets =
467 {
468 {
469 .x = src_region[0].x,
470 .y = src_region[0].y,
471 .z = 0,
472 },
473 {
474 .x = src_region[1].x,
475 .y = src_region[1].y,
476 .z = 1,
477 },
478 },
479 .dstSubresource = dst_layers,
480 .dstOffsets =
481 {
482 {
483 .x = dst_region[0].x,
484 .y = dst_region[0].y,
485 .z = 0,
486 },
487 {
488 .x = dst_region[1].x,
489 .y = dst_region[1].y,
490 .z = 1,
491 },
492 },
493 };
350} 494}
351 495
352CachedSurfaceView::CachedSurfaceView(const VKDevice& device_, CachedSurface& surface_, 496[[nodiscard]] VkImageResolve MakeImageResolve(const std::array<Offset2D, 2>& dst_region,
353 const ViewParams& view_params_) 497 const std::array<Offset2D, 2>& src_region,
354 : ViewBase{view_params_}, surface_params{surface_.GetSurfaceParams()}, 498 const VkImageSubresourceLayers& dst_layers,
355 image{surface_.GetImageHandle()}, buffer_view{surface_.GetBufferViewHandle()}, 499 const VkImageSubresourceLayers& src_layers) {
356 aspect_mask{surface_.GetAspectMask()}, device{device_}, surface{surface_}, 500 return VkImageResolve{
357 base_level{view_params_.base_level}, num_levels{view_params_.num_levels}, 501 .srcSubresource = src_layers,
358 image_view_type{image ? GetImageViewType(view_params_.target) : VK_IMAGE_VIEW_TYPE_1D} { 502 .srcOffset =
359 if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) { 503 {
360 base_layer = 0; 504 .x = src_region[0].x,
361 num_layers = 1; 505 .y = src_region[0].y,
362 base_slice = view_params_.base_layer; 506 .z = 0,
363 num_slices = view_params_.num_layers; 507 },
364 } else { 508 .dstSubresource = dst_layers,
365 base_layer = view_params_.base_layer; 509 .dstOffset =
366 num_layers = view_params_.num_layers; 510 {
367 } 511 .x = dst_region[0].x,
512 .y = dst_region[0].y,
513 .z = 0,
514 },
515 .extent =
516 {
517 .width = static_cast<u32>(dst_region[1].x - dst_region[0].x),
518 .height = static_cast<u32>(dst_region[1].y - dst_region[0].y),
519 .depth = 1,
520 },
521 };
368} 522}
369 523
370CachedSurfaceView::~CachedSurfaceView() = default; 524struct RangedBarrierRange {
371 525 u32 min_mip = std::numeric_limits<u32>::max();
372VkImageView CachedSurfaceView::GetImageView(SwizzleSource x_source, SwizzleSource y_source, 526 u32 max_mip = std::numeric_limits<u32>::min();
373 SwizzleSource z_source, SwizzleSource w_source) { 527 u32 min_layer = std::numeric_limits<u32>::max();
374 const u32 new_swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source); 528 u32 max_layer = std::numeric_limits<u32>::min();
375 if (last_image_view && last_swizzle == new_swizzle) { 529
376 return last_image_view; 530 void AddLayers(const VkImageSubresourceLayers& layers) {
531 min_mip = std::min(min_mip, layers.mipLevel);
532 max_mip = std::max(max_mip, layers.mipLevel + 1);
533 min_layer = std::min(min_layer, layers.baseArrayLayer);
534 max_layer = std::max(max_layer, layers.baseArrayLayer + layers.layerCount);
377 } 535 }
378 last_swizzle = new_swizzle;
379 536
380 const auto [entry, is_cache_miss] = view_cache.try_emplace(new_swizzle); 537 VkImageSubresourceRange SubresourceRange(VkImageAspectFlags aspect_mask) const noexcept {
381 auto& image_view = entry->second; 538 return VkImageSubresourceRange{
382 if (!is_cache_miss) { 539 .aspectMask = aspect_mask,
383 return last_image_view = *image_view; 540 .baseMipLevel = min_mip,
541 .levelCount = max_mip - min_mip,
542 .baseArrayLayer = min_layer,
543 .layerCount = max_layer - min_layer,
544 };
384 } 545 }
546};
385 547
386 std::array swizzle{MaxwellToVK::SwizzleSource(x_source), MaxwellToVK::SwizzleSource(y_source), 548} // Anonymous namespace
387 MaxwellToVK::SwizzleSource(z_source), MaxwellToVK::SwizzleSource(w_source)};
388 if (surface_params.pixel_format == PixelFormat::A1B5G5R5_UNORM) {
389 // A1B5G5R5 is implemented as A1R5G5B5, we have to change the swizzle here.
390 std::swap(swizzle[0], swizzle[2]);
391 }
392 549
393 // Games can sample depth or stencil values on textures. This is decided by the swizzle value on 550void TextureCacheRuntime::Finish() {
394 // hardware. To emulate this on Vulkan we specify it in the aspect. 551 scheduler.Finish();
395 VkImageAspectFlags aspect = aspect_mask; 552}
396 if (aspect == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
397 UNIMPLEMENTED_IF(x_source != SwizzleSource::R && x_source != SwizzleSource::G);
398 const bool is_first = x_source == SwizzleSource::R;
399 switch (surface_params.pixel_format) {
400 case PixelFormat::D24_UNORM_S8_UINT:
401 case PixelFormat::D32_FLOAT_S8_UINT:
402 aspect = is_first ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT;
403 break;
404 case PixelFormat::S8_UINT_D24_UNORM:
405 aspect = is_first ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT;
406 break;
407 default:
408 aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
409 UNIMPLEMENTED();
410 }
411 553
412 // Make sure we sample the first component 554ImageBufferMap TextureCacheRuntime::MapUploadBuffer(size_t size) {
413 std::transform( 555 const auto& buffer = staging_buffer_pool.GetUnusedBuffer(size, true);
414 swizzle.begin(), swizzle.end(), swizzle.begin(), [](VkComponentSwizzle component) { 556 return ImageBufferMap{
415 return component == VK_COMPONENT_SWIZZLE_G ? VK_COMPONENT_SWIZZLE_R : component; 557 .handle = *buffer.handle,
416 }); 558 .map = buffer.commit->Map(size),
417 } 559 };
560}
418 561
419 if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) { 562void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src,
420 ASSERT(base_slice == 0); 563 const std::array<Offset2D, 2>& dst_region,
421 ASSERT(num_slices == surface_params.depth); 564 const std::array<Offset2D, 2>& src_region,
565 Tegra::Engines::Fermi2D::Filter filter,
566 Tegra::Engines::Fermi2D::Operation operation) {
567 const VkImageAspectFlags aspect_mask = ImageAspectMask(src.format);
568 const bool is_dst_msaa = dst.Samples() != VK_SAMPLE_COUNT_1_BIT;
569 const bool is_src_msaa = src.Samples() != VK_SAMPLE_COUNT_1_BIT;
570 ASSERT(aspect_mask == ImageAspectMask(dst.format));
571 if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT && !is_src_msaa && !is_dst_msaa) {
572 blit_image_helper.BlitColor(dst_framebuffer, src, dst_region, src_region, filter,
573 operation);
574 return;
422 } 575 }
423 576 if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
424 image_view = device.GetLogical().CreateImageView({ 577 if (!device.IsBlitDepthStencilSupported()) {
425 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 578 UNIMPLEMENTED_IF(is_src_msaa || is_dst_msaa);
426 .pNext = nullptr, 579 blit_image_helper.BlitDepthStencil(dst_framebuffer, src.DepthView(), src.StencilView(),
427 .flags = 0, 580 dst_region, src_region, filter, operation);
428 .image = surface.GetImageHandle(), 581 return;
429 .viewType = image_view_type, 582 }
430 .format = surface.GetImage().GetFormat(), 583 }
431 .components = 584 ASSERT(src.ImageFormat() == dst.ImageFormat());
432 { 585 ASSERT(!(is_dst_msaa && !is_src_msaa));
433 .r = swizzle[0], 586 ASSERT(operation == Fermi2D::Operation::SrcCopy);
434 .g = swizzle[1], 587
435 .b = swizzle[2], 588 const VkImage dst_image = dst.ImageHandle();
436 .a = swizzle[3], 589 const VkImage src_image = src.ImageHandle();
590 const VkImageSubresourceLayers dst_layers = MakeSubresourceLayers(&dst);
591 const VkImageSubresourceLayers src_layers = MakeSubresourceLayers(&src);
592 const bool is_resolve = is_src_msaa && !is_dst_msaa;
593 scheduler.RequestOutsideRenderPassOperationContext();
594 scheduler.Record([filter, dst_region, src_region, dst_image, src_image, dst_layers, src_layers,
595 aspect_mask, is_resolve](vk::CommandBuffer cmdbuf) {
596 const std::array read_barriers{
597 VkImageMemoryBarrier{
598 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
599 .pNext = nullptr,
600 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT |
601 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
602 VK_ACCESS_TRANSFER_WRITE_BIT,
603 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
604 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
605 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
606 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
607 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
608 .image = src_image,
609 .subresourceRange{
610 .aspectMask = aspect_mask,
611 .baseMipLevel = 0,
612 .levelCount = VK_REMAINING_MIP_LEVELS,
613 .baseArrayLayer = 0,
614 .layerCount = VK_REMAINING_ARRAY_LAYERS,
615 },
437 }, 616 },
438 .subresourceRange = 617 VkImageMemoryBarrier{
439 { 618 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
440 .aspectMask = aspect, 619 .pNext = nullptr,
441 .baseMipLevel = base_level, 620 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT |
442 .levelCount = num_levels, 621 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
443 .baseArrayLayer = base_layer, 622 VK_ACCESS_TRANSFER_WRITE_BIT,
444 .layerCount = num_layers, 623 .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
624 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
625 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
626 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
627 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
628 .image = dst_image,
629 .subresourceRange{
630 .aspectMask = aspect_mask,
631 .baseMipLevel = 0,
632 .levelCount = VK_REMAINING_MIP_LEVELS,
633 .baseArrayLayer = 0,
634 .layerCount = VK_REMAINING_ARRAY_LAYERS,
635 },
636 },
637 };
638 VkImageMemoryBarrier write_barrier{
639 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
640 .pNext = nullptr,
641 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
642 .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
643 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
644 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
645 VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
646 .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
647 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
648 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
649 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
650 .image = dst_image,
651 .subresourceRange{
652 .aspectMask = aspect_mask,
653 .baseMipLevel = 0,
654 .levelCount = VK_REMAINING_MIP_LEVELS,
655 .baseArrayLayer = 0,
656 .layerCount = VK_REMAINING_ARRAY_LAYERS,
445 }, 657 },
658 };
659 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
660 0, nullptr, nullptr, read_barriers);
661 if (is_resolve) {
662 cmdbuf.ResolveImage(src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image,
663 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
664 MakeImageResolve(dst_region, src_region, dst_layers, src_layers));
665 } else {
666 const bool is_linear = filter == Fermi2D::Filter::Bilinear;
667 const VkFilter vk_filter = is_linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
668 cmdbuf.BlitImage(
669 src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
670 MakeImageBlit(dst_region, src_region, dst_layers, src_layers), vk_filter);
671 }
672 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
673 0, write_barrier);
446 }); 674 });
447
448 return last_image_view = *image_view;
449} 675}
450 676
451VkImageView CachedSurfaceView::GetAttachment() { 677void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) {
452 if (render_target) { 678 switch (dst_view.format) {
453 return *render_target; 679 case PixelFormat::R16_UNORM:
680 if (src_view.format == PixelFormat::D16_UNORM) {
681 return blit_image_helper.ConvertD16ToR16(dst, src_view);
682 }
683 break;
684 case PixelFormat::R32_FLOAT:
685 if (src_view.format == PixelFormat::D32_FLOAT) {
686 return blit_image_helper.ConvertD32ToR32(dst, src_view);
687 }
688 break;
689 case PixelFormat::D16_UNORM:
690 if (src_view.format == PixelFormat::R16_UNORM) {
691 return blit_image_helper.ConvertR16ToD16(dst, src_view);
692 }
693 break;
694 case PixelFormat::D32_FLOAT:
695 if (src_view.format == PixelFormat::R32_FLOAT) {
696 return blit_image_helper.ConvertR32ToD32(dst, src_view);
697 }
698 break;
699 default:
700 break;
454 } 701 }
702 UNIMPLEMENTED_MSG("Unimplemented format copy from {} to {}", src_view.format, dst_view.format);
703}
455 704
456 VkImageViewCreateInfo ci{ 705void TextureCacheRuntime::CopyImage(Image& dst, Image& src,
457 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 706 std::span<const VideoCommon::ImageCopy> copies) {
458 .pNext = nullptr, 707 std::vector<VkImageCopy> vk_copies(copies.size());
459 .flags = 0, 708 const VkImageAspectFlags aspect_mask = dst.AspectMask();
460 .image = surface.GetImageHandle(), 709 ASSERT(aspect_mask == src.AspectMask());
461 .viewType = VK_IMAGE_VIEW_TYPE_1D, 710
462 .format = surface.GetImage().GetFormat(), 711 std::ranges::transform(copies, vk_copies.begin(), [aspect_mask](const auto& copy) {
463 .components = 712 return MakeImageCopy(copy, aspect_mask);
464 { 713 });
465 .r = VK_COMPONENT_SWIZZLE_IDENTITY, 714 const VkImage dst_image = dst.Handle();
466 .g = VK_COMPONENT_SWIZZLE_IDENTITY, 715 const VkImage src_image = src.Handle();
467 .b = VK_COMPONENT_SWIZZLE_IDENTITY, 716 scheduler.RequestOutsideRenderPassOperationContext();
468 .a = VK_COMPONENT_SWIZZLE_IDENTITY, 717 scheduler.Record([dst_image, src_image, aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) {
718 RangedBarrierRange dst_range;
719 RangedBarrierRange src_range;
720 for (const VkImageCopy& copy : vk_copies) {
721 dst_range.AddLayers(copy.dstSubresource);
722 src_range.AddLayers(copy.srcSubresource);
723 }
724 const std::array read_barriers{
725 VkImageMemoryBarrier{
726 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
727 .pNext = nullptr,
728 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
729 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
730 VK_ACCESS_TRANSFER_WRITE_BIT,
731 .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
732 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
733 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
734 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
735 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
736 .image = src_image,
737 .subresourceRange = src_range.SubresourceRange(aspect_mask),
469 }, 738 },
470 .subresourceRange = 739 VkImageMemoryBarrier{
471 { 740 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
472 .aspectMask = aspect_mask, 741 .pNext = nullptr,
473 .baseMipLevel = base_level, 742 .srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
474 .levelCount = num_levels, 743 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
475 .baseArrayLayer = 0, 744 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
476 .layerCount = 0, 745 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
746 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
747 VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
748 .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
749 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
750 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
751 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
752 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
753 .image = dst_image,
754 .subresourceRange = dst_range.SubresourceRange(aspect_mask),
477 }, 755 },
478 }; 756 };
479 if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) { 757 const VkImageMemoryBarrier write_barrier{
480 ci.viewType = num_slices > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D; 758 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
481 ci.subresourceRange.baseArrayLayer = base_slice; 759 .pNext = nullptr,
482 ci.subresourceRange.layerCount = num_slices; 760 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
761 .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
762 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
763 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
764 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
765 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
766 VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
767 .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
768 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
769 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
770 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
771 .image = dst_image,
772 .subresourceRange = dst_range.SubresourceRange(aspect_mask),
773 };
774 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
775 0, {}, {}, read_barriers);
776 cmdbuf.CopyImage(src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image,
777 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vk_copies);
778 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
779 0, write_barrier);
780 });
781}
782
783Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_addr_,
784 VAddr cpu_addr_)
785 : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime.scheduler},
786 image(MakeImage(runtime.device, info)), buffer(MakeBuffer(runtime.device, info)),
787 aspect_mask(ImageAspectMask(info.format)) {
788 if (image) {
789 commit = runtime.memory_manager.Commit(image, false);
483 } else { 790 } else {
484 ci.viewType = image_view_type; 791 commit = runtime.memory_manager.Commit(buffer, false);
485 ci.subresourceRange.baseArrayLayer = base_layer; 792 }
486 ci.subresourceRange.layerCount = num_layers; 793 if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) {
794 flags |= VideoCommon::ImageFlagBits::Converted;
795 }
796 if (runtime.device.HasDebuggingToolAttached()) {
797 if (image) {
798 image.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
799 } else {
800 buffer.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
801 }
487 } 802 }
488 render_target = device.GetLogical().CreateImageView(ci);
489 return *render_target;
490} 803}
491 804
492VKTextureCache::VKTextureCache(VideoCore::RasterizerInterface& rasterizer_, 805void Image::UploadMemory(const ImageBufferMap& map, size_t buffer_offset,
493 Tegra::Engines::Maxwell3D& maxwell3d_, 806 std::span<const BufferImageCopy> copies) {
494 Tegra::MemoryManager& gpu_memory_, const VKDevice& device_, 807 // TODO: Move this to another API
495 VKMemoryManager& memory_manager_, VKScheduler& scheduler_, 808 scheduler->RequestOutsideRenderPassOperationContext();
496 VKStagingBufferPool& staging_pool_) 809 std::vector vk_copies = TransformBufferImageCopies(copies, buffer_offset, aspect_mask);
497 : TextureCache(rasterizer_, maxwell3d_, gpu_memory_, device_.IsOptimalAstcSupported()), 810 const VkBuffer src_buffer = map.handle;
498 device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{ 811 const VkImage vk_image = *image;
499 staging_pool_} {} 812 const VkImageAspectFlags vk_aspect_mask = aspect_mask;
500 813 const bool is_initialized = std::exchange(initialized, true);
501VKTextureCache::~VKTextureCache() = default; 814 scheduler->Record([src_buffer, vk_image, vk_aspect_mask, is_initialized,
502 815 vk_copies](vk::CommandBuffer cmdbuf) {
503Surface VKTextureCache::CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) { 816 CopyBufferToImage(cmdbuf, src_buffer, vk_image, vk_aspect_mask, is_initialized, vk_copies);
504 return std::make_shared<CachedSurface>(device, memory_manager, scheduler, staging_pool, 817 });
505 gpu_addr, params);
506} 818}
507 819
508void VKTextureCache::ImageCopy(Surface& src_surface, Surface& dst_surface, 820void Image::UploadMemory(const ImageBufferMap& map, size_t buffer_offset,
509 const VideoCommon::CopyParams& copy_params) { 821 std::span<const VideoCommon::BufferCopy> copies) {
510 const bool src_3d = src_surface->GetSurfaceParams().target == SurfaceTarget::Texture3D; 822 // TODO: Move this to another API
511 const bool dst_3d = dst_surface->GetSurfaceParams().target == SurfaceTarget::Texture3D; 823 scheduler->RequestOutsideRenderPassOperationContext();
512 UNIMPLEMENTED_IF(src_3d); 824 std::vector vk_copies = TransformBufferCopies(copies, buffer_offset);
825 const VkBuffer src_buffer = map.handle;
826 const VkBuffer dst_buffer = *buffer;
827 scheduler->Record([src_buffer, dst_buffer, vk_copies](vk::CommandBuffer cmdbuf) {
828 // TODO: Barriers
829 cmdbuf.CopyBuffer(src_buffer, dst_buffer, vk_copies);
830 });
831}
513 832
514 // The texture cache handles depth in OpenGL terms, we have to handle it as subresource and 833void Image::DownloadMemory(const ImageBufferMap& map, size_t buffer_offset,
515 // dimension respectively. 834 std::span<const BufferImageCopy> copies) {
516 const u32 dst_base_layer = dst_3d ? 0 : copy_params.dest_z; 835 std::vector vk_copies = TransformBufferImageCopies(copies, buffer_offset, aspect_mask);
517 const u32 dst_offset_z = dst_3d ? copy_params.dest_z : 0; 836 scheduler->Record([buffer = map.handle, image = *image, aspect_mask = aspect_mask,
837 vk_copies](vk::CommandBuffer cmdbuf) {
838 // TODO: Barriers
839 cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_GENERAL, buffer, vk_copies);
840 });
841}
518 842
519 const u32 extent_z = dst_3d ? copy_params.depth : 1; 843ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
520 const u32 num_layers = dst_3d ? 1 : copy_params.depth; 844 ImageId image_id_, Image& image)
845 : VideoCommon::ImageViewBase{info, image.info, image_id_}, device{&runtime.device},
846 image_handle{image.Handle()}, image_format{image.info.format}, samples{ConvertSampleCount(
847 image.info.num_samples)} {
848 const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info);
849 std::array<SwizzleSource, 4> swizzle{
850 SwizzleSource::R,
851 SwizzleSource::G,
852 SwizzleSource::B,
853 SwizzleSource::A,
854 };
855 if (!info.IsRenderTarget()) {
856 swizzle = info.Swizzle();
857 if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) {
858 std::ranges::transform(swizzle, swizzle.begin(), ConvertGreenRed);
859 }
860 }
861 const VkFormat vk_format =
862 MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, format).format;
863 const VkImageViewCreateInfo create_info{
864 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
865 .pNext = nullptr,
866 .flags = 0,
867 .image = image.Handle(),
868 .viewType = VkImageViewType{},
869 .format = vk_format,
870 .components{
871 .r = ComponentSwizzle(swizzle[0]),
872 .g = ComponentSwizzle(swizzle[1]),
873 .b = ComponentSwizzle(swizzle[2]),
874 .a = ComponentSwizzle(swizzle[3]),
875 },
876 .subresourceRange = MakeSubresourceRange(aspect_mask, info.range),
877 };
878 const auto create = [&](VideoCommon::ImageViewType view_type, std::optional<u32> num_layers) {
879 VkImageViewCreateInfo ci{create_info};
880 ci.viewType = ImageViewType(view_type);
881 if (num_layers) {
882 ci.subresourceRange.layerCount = *num_layers;
883 }
884 vk::ImageView handle = device->GetLogical().CreateImageView(ci);
885 if (device->HasDebuggingToolAttached()) {
886 handle.SetObjectNameEXT(VideoCommon::Name(*this, view_type).c_str());
887 }
888 image_views[static_cast<size_t>(view_type)] = std::move(handle);
889 };
890 switch (info.type) {
891 case VideoCommon::ImageViewType::e1D:
892 case VideoCommon::ImageViewType::e1DArray:
893 create(VideoCommon::ImageViewType::e1D, 1);
894 create(VideoCommon::ImageViewType::e1DArray, std::nullopt);
895 render_target = Handle(VideoCommon::ImageViewType::e1DArray);
896 break;
897 case VideoCommon::ImageViewType::e2D:
898 case VideoCommon::ImageViewType::e2DArray:
899 create(VideoCommon::ImageViewType::e2D, 1);
900 create(VideoCommon::ImageViewType::e2DArray, std::nullopt);
901 render_target = Handle(VideoCommon::ImageViewType::e2DArray);
902 break;
903 case VideoCommon::ImageViewType::e3D:
904 create(VideoCommon::ImageViewType::e3D, std::nullopt);
905 render_target = Handle(VideoCommon::ImageViewType::e3D);
906 break;
907 case VideoCommon::ImageViewType::Cube:
908 case VideoCommon::ImageViewType::CubeArray:
909 create(VideoCommon::ImageViewType::Cube, 6);
910 create(VideoCommon::ImageViewType::CubeArray, std::nullopt);
911 break;
912 case VideoCommon::ImageViewType::Rect:
913 UNIMPLEMENTED();
914 break;
915 case VideoCommon::ImageViewType::Buffer:
916 buffer_view = device->GetLogical().CreateBufferView(VkBufferViewCreateInfo{
917 .sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
918 .pNext = nullptr,
919 .flags = 0,
920 .buffer = image.Buffer(),
921 .format = vk_format,
922 .offset = 0, // TODO: Redesign buffer cache to support this
923 .range = image.guest_size_bytes,
924 });
925 break;
926 }
927}
521 928
522 // We can't copy inside a renderpass 929ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::NullImageParams& params)
523 scheduler.RequestOutsideRenderPassOperationContext(); 930 : VideoCommon::ImageViewBase{params} {}
524 931
525 src_surface->Transition(copy_params.source_z, copy_params.depth, copy_params.source_level, 1, 932VkImageView ImageView::DepthView() {
526 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, 933 if (depth_view) {
527 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); 934 return *depth_view;
528 dst_surface->Transition(dst_base_layer, num_layers, copy_params.dest_level, 1, 935 }
529 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, 936 depth_view = MakeDepthStencilView(VK_IMAGE_ASPECT_DEPTH_BIT);
530 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); 937 return *depth_view;
938}
531 939
532 const VkImageCopy copy{ 940VkImageView ImageView::StencilView() {
533 .srcSubresource = 941 if (stencil_view) {
534 { 942 return *stencil_view;
535 .aspectMask = src_surface->GetAspectMask(), 943 }
536 .mipLevel = copy_params.source_level, 944 stencil_view = MakeDepthStencilView(VK_IMAGE_ASPECT_STENCIL_BIT);
537 .baseArrayLayer = copy_params.source_z, 945 return *stencil_view;
538 .layerCount = num_layers, 946}
539 },
540 .srcOffset =
541 {
542 .x = static_cast<s32>(copy_params.source_x),
543 .y = static_cast<s32>(copy_params.source_y),
544 .z = 0,
545 },
546 .dstSubresource =
547 {
548 .aspectMask = dst_surface->GetAspectMask(),
549 .mipLevel = copy_params.dest_level,
550 .baseArrayLayer = dst_base_layer,
551 .layerCount = num_layers,
552 },
553 .dstOffset =
554 {
555 .x = static_cast<s32>(copy_params.dest_x),
556 .y = static_cast<s32>(copy_params.dest_y),
557 .z = static_cast<s32>(dst_offset_z),
558 },
559 .extent =
560 {
561 .width = copy_params.width,
562 .height = copy_params.height,
563 .depth = extent_z,
564 },
565 };
566 947
567 const VkImage src_image = src_surface->GetImageHandle(); 948vk::ImageView ImageView::MakeDepthStencilView(VkImageAspectFlags aspect_mask) {
568 const VkImage dst_image = dst_surface->GetImageHandle(); 949 return device->GetLogical().CreateImageView({
569 scheduler.Record([src_image, dst_image, copy](vk::CommandBuffer cmdbuf) { 950 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
570 cmdbuf.CopyImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image, 951 .pNext = nullptr,
571 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); 952 .flags = 0,
953 .image = image_handle,
954 .viewType = ImageViewType(type),
955 .format = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, format).format,
956 .components{
957 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
958 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
959 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
960 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
961 },
962 .subresourceRange = MakeSubresourceRange(aspect_mask, range),
572 }); 963 });
573} 964}
574 965
575void VKTextureCache::ImageBlit(View& src_view, View& dst_view, 966Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& tsc) {
576 const Tegra::Engines::Fermi2D::Config& copy_config) { 967 const auto& device = runtime.device;
577 // We can't blit inside a renderpass 968 const bool arbitrary_borders = runtime.device.IsExtCustomBorderColorSupported();
578 scheduler.RequestOutsideRenderPassOperationContext(); 969 const std::array<float, 4> color = tsc.BorderColor();
579 970 // C++20 bit_cast
580 src_view->Transition(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, 971 VkClearColorValue border_color;
581 VK_ACCESS_TRANSFER_READ_BIT); 972 std::memcpy(&border_color, &color, sizeof(color));
582 dst_view->Transition(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, 973 const VkSamplerCustomBorderColorCreateInfoEXT border_ci{
583 VK_ACCESS_TRANSFER_WRITE_BIT); 974 .sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT,
584 975 .pNext = nullptr,
585 VkImageBlit blit; 976 .customBorderColor = border_color,
586 blit.srcSubresource = src_view->GetImageSubresourceLayers(); 977 .format = VK_FORMAT_UNDEFINED,
587 blit.srcOffsets[0].x = copy_config.src_rect.left; 978 };
588 blit.srcOffsets[0].y = copy_config.src_rect.top; 979 const void* pnext = nullptr;
589 blit.srcOffsets[0].z = 0; 980 if (arbitrary_borders) {
590 blit.srcOffsets[1].x = copy_config.src_rect.right; 981 pnext = &border_ci;
591 blit.srcOffsets[1].y = copy_config.src_rect.bottom; 982 }
592 blit.srcOffsets[1].z = 1; 983 const VkSamplerReductionModeCreateInfoEXT reduction_ci{
593 blit.dstSubresource = dst_view->GetImageSubresourceLayers(); 984 .sType = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT,
594 blit.dstOffsets[0].x = copy_config.dst_rect.left; 985 .pNext = pnext,
595 blit.dstOffsets[0].y = copy_config.dst_rect.top; 986 .reductionMode = MaxwellToVK::SamplerReduction(tsc.reduction_filter),
596 blit.dstOffsets[0].z = 0; 987 };
597 blit.dstOffsets[1].x = copy_config.dst_rect.right; 988 if (runtime.device.IsExtSamplerFilterMinmaxSupported()) {
598 blit.dstOffsets[1].y = copy_config.dst_rect.bottom; 989 pnext = &reduction_ci;
599 blit.dstOffsets[1].z = 1; 990 } else if (reduction_ci.reductionMode != VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT) {
600 991 LOG_WARNING(Render_Vulkan, "VK_EXT_sampler_filter_minmax is required");
601 const bool is_linear = copy_config.filter == Tegra::Engines::Fermi2D::Filter::Linear; 992 }
602 993 // Some games have samplers with garbage. Sanitize them here.
603 scheduler.Record([src_image = src_view->GetImage(), dst_image = dst_view->GetImage(), blit, 994 const float max_anisotropy = std::clamp(tsc.MaxAnisotropy(), 1.0f, 16.0f);
604 is_linear](vk::CommandBuffer cmdbuf) { 995 sampler = device.GetLogical().CreateSampler(VkSamplerCreateInfo{
605 cmdbuf.BlitImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image, 996 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
606 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, blit, 997 .pNext = pnext,
607 is_linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST); 998 .flags = 0,
999 .magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter),
1000 .minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter),
1001 .mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter),
1002 .addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter),
1003 .addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter),
1004 .addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter),
1005 .mipLodBias = tsc.LodBias(),
1006 .anisotropyEnable = static_cast<VkBool32>(max_anisotropy > 1.0f ? VK_TRUE : VK_FALSE),
1007 .maxAnisotropy = max_anisotropy,
1008 .compareEnable = tsc.depth_compare_enabled,
1009 .compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func),
1010 .minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(),
1011 .maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(),
1012 .borderColor =
1013 arbitrary_borders ? VK_BORDER_COLOR_INT_CUSTOM_EXT : ConvertBorderColor(color),
1014 .unnormalizedCoordinates = VK_FALSE,
608 }); 1015 });
609} 1016}
610 1017
611void VKTextureCache::BufferCopy(Surface& src_surface, Surface& dst_surface) { 1018Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM_RT> color_buffers,
612 // Currently unimplemented. PBO copies should be dropped and we should use a render pass to 1019 ImageView* depth_buffer, const VideoCommon::RenderTargets& key) {
613 // convert from color to depth and viceversa. 1020 std::vector<VkAttachmentDescription> descriptions;
614 LOG_WARNING(Render_Vulkan, "Unimplemented"); 1021 std::vector<VkImageView> attachments;
1022 RenderPassKey renderpass_key{};
1023 s32 num_layers = 1;
1024
1025 for (size_t index = 0; index < NUM_RT; ++index) {
1026 const ImageView* const color_buffer = color_buffers[index];
1027 if (!color_buffer) {
1028 renderpass_key.color_formats[index] = PixelFormat::Invalid;
1029 continue;
1030 }
1031 descriptions.push_back(AttachmentDescription(runtime.device, color_buffer));
1032 attachments.push_back(color_buffer->RenderTarget());
1033 renderpass_key.color_formats[index] = color_buffer->format;
1034 num_layers = std::max(num_layers, color_buffer->range.extent.layers);
1035 images[num_images] = color_buffer->ImageHandle();
1036 image_ranges[num_images] = MakeSubresourceRange(color_buffer);
1037 samples = color_buffer->Samples();
1038 ++num_images;
1039 }
1040 const size_t num_colors = attachments.size();
1041 const VkAttachmentReference* depth_attachment =
1042 depth_buffer ? &ATTACHMENT_REFERENCES[num_colors] : nullptr;
1043 if (depth_buffer) {
1044 descriptions.push_back(AttachmentDescription(runtime.device, depth_buffer));
1045 attachments.push_back(depth_buffer->RenderTarget());
1046 renderpass_key.depth_format = depth_buffer->format;
1047 num_layers = std::max(num_layers, depth_buffer->range.extent.layers);
1048 images[num_images] = depth_buffer->ImageHandle();
1049 image_ranges[num_images] = MakeSubresourceRange(depth_buffer);
1050 samples = depth_buffer->Samples();
1051 ++num_images;
1052 } else {
1053 renderpass_key.depth_format = PixelFormat::Invalid;
1054 }
1055 renderpass_key.samples = samples;
1056
1057 const auto& device = runtime.device.GetLogical();
1058 const auto [cache_pair, is_new] = runtime.renderpass_cache.try_emplace(renderpass_key);
1059 if (is_new) {
1060 const VkSubpassDescription subpass{
1061 .flags = 0,
1062 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
1063 .inputAttachmentCount = 0,
1064 .pInputAttachments = nullptr,
1065 .colorAttachmentCount = static_cast<u32>(num_colors),
1066 .pColorAttachments = num_colors != 0 ? ATTACHMENT_REFERENCES.data() : nullptr,
1067 .pResolveAttachments = nullptr,
1068 .pDepthStencilAttachment = depth_attachment,
1069 .preserveAttachmentCount = 0,
1070 .pPreserveAttachments = nullptr,
1071 };
1072 cache_pair->second = device.CreateRenderPass(VkRenderPassCreateInfo{
1073 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
1074 .pNext = nullptr,
1075 .flags = 0,
1076 .attachmentCount = static_cast<u32>(descriptions.size()),
1077 .pAttachments = descriptions.data(),
1078 .subpassCount = 1,
1079 .pSubpasses = &subpass,
1080 .dependencyCount = 0,
1081 .pDependencies = nullptr,
1082 });
1083 }
1084 renderpass = *cache_pair->second;
1085 render_area = VkExtent2D{
1086 .width = key.size.width,
1087 .height = key.size.height,
1088 };
1089 num_color_buffers = static_cast<u32>(num_colors);
1090 framebuffer = device.CreateFramebuffer(VkFramebufferCreateInfo{
1091 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
1092 .pNext = nullptr,
1093 .flags = 0,
1094 .renderPass = renderpass,
1095 .attachmentCount = static_cast<u32>(attachments.size()),
1096 .pAttachments = attachments.data(),
1097 .width = key.size.width,
1098 .height = key.size.height,
1099 .layers = static_cast<u32>(num_layers),
1100 });
1101 if (runtime.device.HasDebuggingToolAttached()) {
1102 framebuffer.SetObjectNameEXT(VideoCommon::Name(key).c_str());
1103 }
615} 1104}
616 1105
617} // namespace Vulkan 1106} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index b0be4cb0f..edc3d80c0 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -4,217 +4,265 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <compare>
8#include <unordered_map> 8#include <span>
9 9
10#include "common/common_types.h"
11#include "video_core/renderer_vulkan/vk_image.h"
12#include "video_core/renderer_vulkan/vk_memory_manager.h" 10#include "video_core/renderer_vulkan/vk_memory_manager.h"
13#include "video_core/renderer_vulkan/vk_scheduler.h"
14#include "video_core/renderer_vulkan/wrapper.h" 11#include "video_core/renderer_vulkan/wrapper.h"
15#include "video_core/texture_cache/surface_base.h"
16#include "video_core/texture_cache/texture_cache.h" 12#include "video_core/texture_cache/texture_cache.h"
17 13
18namespace VideoCore {
19class RasterizerInterface;
20}
21
22namespace Vulkan { 14namespace Vulkan {
23 15
24class RasterizerVulkan; 16using VideoCommon::ImageId;
17using VideoCommon::NUM_RT;
18using VideoCommon::Offset2D;
19using VideoCommon::RenderTargets;
20using VideoCore::Surface::PixelFormat;
21
25class VKDevice; 22class VKDevice;
26class VKScheduler; 23class VKScheduler;
27class VKStagingBufferPool; 24class VKStagingBufferPool;
28 25
29class CachedSurfaceView; 26class BlitImageHelper;
30class CachedSurface; 27class Image;
28class ImageView;
29class Framebuffer;
31 30
32using Surface = std::shared_ptr<CachedSurface>; 31struct RenderPassKey {
33using View = std::shared_ptr<CachedSurfaceView>; 32 constexpr auto operator<=>(const RenderPassKey&) const noexcept = default;
34using TextureCacheBase = VideoCommon::TextureCache<Surface, View>;
35 33
36using VideoCommon::SurfaceParams; 34 std::array<PixelFormat, NUM_RT> color_formats;
37using VideoCommon::ViewParams; 35 PixelFormat depth_format;
36 VkSampleCountFlagBits samples;
37};
38 38
39class CachedSurface final : public VideoCommon::SurfaceBase<View> { 39} // namespace Vulkan
40 friend CachedSurfaceView;
41 40
42public: 41namespace std {
43 explicit CachedSurface(const VKDevice& device_, VKMemoryManager& memory_manager_, 42template <>
44 VKScheduler& scheduler_, VKStagingBufferPool& staging_pool_, 43struct hash<Vulkan::RenderPassKey> {
45 GPUVAddr gpu_addr_, const SurfaceParams& params_); 44 [[nodiscard]] constexpr size_t operator()(const Vulkan::RenderPassKey& key) const noexcept {
46 ~CachedSurface(); 45 size_t value = static_cast<size_t>(key.depth_format) << 48;
46 value ^= static_cast<size_t>(key.samples) << 52;
47 for (size_t i = 0; i < key.color_formats.size(); ++i) {
48 value ^= static_cast<size_t>(key.color_formats[i]) << (i * 6);
49 }
50 return value;
51 }
52};
53} // namespace std
47 54
48 void UploadTexture(const std::vector<u8>& staging_buffer) override; 55namespace Vulkan {
49 void DownloadTexture(std::vector<u8>& staging_buffer) override;
50 56
51 void FullTransition(VkPipelineStageFlags new_stage_mask, VkAccessFlags new_access, 57struct ImageBufferMap {
52 VkImageLayout new_layout) { 58 [[nodiscard]] VkBuffer Handle() const noexcept {
53 image->Transition(0, static_cast<u32>(params.GetNumLayers()), 0, params.num_levels, 59 return handle;
54 new_stage_mask, new_access, new_layout);
55 } 60 }
56 61
57 void Transition(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels, 62 [[nodiscard]] std::span<u8> Span() const noexcept {
58 VkPipelineStageFlags new_stage_mask, VkAccessFlags new_access, 63 return map.Span();
59 VkImageLayout new_layout) {
60 image->Transition(base_layer, num_layers, base_level, num_levels, new_stage_mask,
61 new_access, new_layout);
62 } 64 }
63 65
64 VKImage& GetImage() { 66 VkBuffer handle;
65 return *image; 67 MemoryMap map;
66 } 68};
67 69
68 const VKImage& GetImage() const { 70struct TextureCacheRuntime {
69 return *image; 71 const VKDevice& device;
70 } 72 VKScheduler& scheduler;
73 VKMemoryManager& memory_manager;
74 VKStagingBufferPool& staging_buffer_pool;
75 BlitImageHelper& blit_image_helper;
76 std::unordered_map<RenderPassKey, vk::RenderPass> renderpass_cache;
77
78 void Finish();
71 79
72 VkImage GetImageHandle() const { 80 [[nodiscard]] ImageBufferMap MapUploadBuffer(size_t size);
73 return *image->GetHandle(); 81
82 [[nodiscard]] ImageBufferMap MapDownloadBuffer(size_t size) {
83 // TODO: Have a special function for this
84 return MapUploadBuffer(size);
74 } 85 }
75 86
76 VkImageAspectFlags GetAspectMask() const { 87 void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src,
77 return image->GetAspectMask(); 88 const std::array<Offset2D, 2>& dst_region,
89 const std::array<Offset2D, 2>& src_region,
90 Tegra::Engines::Fermi2D::Filter filter,
91 Tegra::Engines::Fermi2D::Operation operation);
92
93 void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
94
95 void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view);
96
97 [[nodiscard]] bool CanAccelerateImageUpload(Image&) const noexcept {
98 return false;
78 } 99 }
79 100
80 VkBufferView GetBufferViewHandle() const { 101 void AccelerateImageUpload(Image&, const ImageBufferMap&, size_t,
81 return *buffer_view; 102 std::span<const VideoCommon::SwizzleParameters>) {
103 UNREACHABLE();
82 } 104 }
83 105
84protected: 106 void InsertUploadMemoryBarrier() {}
85 void DecorateSurfaceName() override; 107};
86 108
87 View CreateView(const ViewParams& view_params) override; 109class Image : public VideoCommon::ImageBase {
110public:
111 explicit Image(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, GPUVAddr gpu_addr,
112 VAddr cpu_addr);
88 113
89private: 114 void UploadMemory(const ImageBufferMap& map, size_t buffer_offset,
90 void UploadBuffer(const std::vector<u8>& staging_buffer); 115 std::span<const VideoCommon::BufferImageCopy> copies);
91 116
92 void UploadImage(const std::vector<u8>& staging_buffer); 117 void UploadMemory(const ImageBufferMap& map, size_t buffer_offset,
118 std::span<const VideoCommon::BufferCopy> copies);
93 119
94 VkBufferImageCopy GetBufferImageCopy(u32 level) const; 120 void DownloadMemory(const ImageBufferMap& map, size_t buffer_offset,
121 std::span<const VideoCommon::BufferImageCopy> copies);
95 122
96 VkImageSubresourceRange GetImageSubresourceRange() const; 123 [[nodiscard]] VkImage Handle() const noexcept {
124 return *image;
125 }
97 126
98 const VKDevice& device; 127 [[nodiscard]] VkBuffer Buffer() const noexcept {
99 VKMemoryManager& memory_manager; 128 return *buffer;
100 VKScheduler& scheduler; 129 }
101 VKStagingBufferPool& staging_pool; 130
131 [[nodiscard]] VkImageCreateFlags AspectMask() const noexcept {
132 return aspect_mask;
133 }
102 134
103 std::optional<VKImage> image; 135private:
136 VKScheduler* scheduler;
137 vk::Image image;
104 vk::Buffer buffer; 138 vk::Buffer buffer;
105 vk::BufferView buffer_view;
106 VKMemoryCommit commit; 139 VKMemoryCommit commit;
107 140 VkImageAspectFlags aspect_mask = 0;
108 VkFormat format = VK_FORMAT_UNDEFINED; 141 bool initialized = false;
109}; 142};
110 143
111class CachedSurfaceView final : public VideoCommon::ViewBase { 144class ImageView : public VideoCommon::ImageViewBase {
112public: 145public:
113 explicit CachedSurfaceView(const VKDevice& device_, CachedSurface& surface_, 146 explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&);
114 const ViewParams& view_params_); 147 explicit ImageView(TextureCacheRuntime&, const VideoCommon::NullImageParams&);
115 ~CachedSurfaceView();
116 148
117 VkImageView GetImageView(Tegra::Texture::SwizzleSource x_source, 149 [[nodiscard]] VkImageView DepthView();
118 Tegra::Texture::SwizzleSource y_source,
119 Tegra::Texture::SwizzleSource z_source,
120 Tegra::Texture::SwizzleSource w_source);
121 150
122 VkImageView GetAttachment(); 151 [[nodiscard]] VkImageView StencilView();
123 152
124 bool IsSameSurface(const CachedSurfaceView& rhs) const { 153 [[nodiscard]] VkImageView Handle(VideoCommon::ImageViewType query_type) const noexcept {
125 return &surface == &rhs.surface; 154 return *image_views[static_cast<size_t>(query_type)];
126 } 155 }
127 156
128 u32 GetWidth() const { 157 [[nodiscard]] VkBufferView BufferView() const noexcept {
129 return surface_params.GetMipWidth(base_level); 158 return *buffer_view;
130 } 159 }
131 160
132 u32 GetHeight() const { 161 [[nodiscard]] VkImage ImageHandle() const noexcept {
133 return surface_params.GetMipHeight(base_level); 162 return image_handle;
134 } 163 }
135 164
136 u32 GetNumLayers() const { 165 [[nodiscard]] VkImageView RenderTarget() const noexcept {
137 return num_layers; 166 return render_target;
138 } 167 }
139 168
140 bool IsBufferView() const { 169 [[nodiscard]] PixelFormat ImageFormat() const noexcept {
141 return buffer_view; 170 return image_format;
142 } 171 }
143 172
144 VkImage GetImage() const { 173 [[nodiscard]] VkSampleCountFlagBits Samples() const noexcept {
145 return image; 174 return samples;
146 } 175 }
147 176
148 VkBufferView GetBufferView() const { 177private:
149 return buffer_view; 178 [[nodiscard]] vk::ImageView MakeDepthStencilView(VkImageAspectFlags aspect_mask);
150 }
151 179
152 VkImageSubresourceRange GetImageSubresourceRange() const { 180 const VKDevice* device = nullptr;
153 return {aspect_mask, base_level, num_levels, base_layer, num_layers}; 181 std::array<vk::ImageView, VideoCommon::NUM_IMAGE_VIEW_TYPES> image_views;
154 } 182 vk::ImageView depth_view;
183 vk::ImageView stencil_view;
184 vk::BufferView buffer_view;
185 VkImage image_handle = VK_NULL_HANDLE;
186 VkImageView render_target = VK_NULL_HANDLE;
187 PixelFormat image_format = PixelFormat::Invalid;
188 VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
189};
155 190
156 VkImageSubresourceLayers GetImageSubresourceLayers() const { 191class ImageAlloc : public VideoCommon::ImageAllocBase {};
157 return {surface.GetAspectMask(), base_level, base_layer, num_layers};
158 }
159 192
160 void Transition(VkImageLayout new_layout, VkPipelineStageFlags new_stage_mask, 193class Sampler {
161 VkAccessFlags new_access) const { 194public:
162 surface.Transition(base_layer, num_layers, base_level, num_levels, new_stage_mask, 195 explicit Sampler(TextureCacheRuntime&, const Tegra::Texture::TSCEntry&);
163 new_access, new_layout);
164 }
165 196
166 void MarkAsModified(u64 tick) { 197 [[nodiscard]] VkSampler Handle() const noexcept {
167 surface.MarkAsModified(true, tick); 198 return *sampler;
168 } 199 }
169 200
170private: 201private:
171 // Store a copy of these values to avoid double dereference when reading them 202 vk::Sampler sampler;
172 const SurfaceParams surface_params;
173 const VkImage image;
174 const VkBufferView buffer_view;
175 const VkImageAspectFlags aspect_mask;
176
177 const VKDevice& device;
178 CachedSurface& surface;
179 const u32 base_level;
180 const u32 num_levels;
181 const VkImageViewType image_view_type;
182 u32 base_layer = 0;
183 u32 num_layers = 0;
184 u32 base_slice = 0;
185 u32 num_slices = 0;
186
187 VkImageView last_image_view = nullptr;
188 u32 last_swizzle = 0;
189
190 vk::ImageView render_target;
191 std::unordered_map<u32, vk::ImageView> view_cache;
192}; 203};
193 204
194class VKTextureCache final : public TextureCacheBase { 205class Framebuffer {
195public: 206public:
196 explicit VKTextureCache(VideoCore::RasterizerInterface& rasterizer_, 207 explicit Framebuffer(TextureCacheRuntime&, std::span<ImageView*, NUM_RT> color_buffers,
197 Tegra::Engines::Maxwell3D& maxwell3d_, 208 ImageView* depth_buffer, const VideoCommon::RenderTargets& key);
198 Tegra::MemoryManager& gpu_memory_, const VKDevice& device_,
199 VKMemoryManager& memory_manager_, VKScheduler& scheduler_,
200 VKStagingBufferPool& staging_pool_);
201 ~VKTextureCache();
202 209
203private: 210 [[nodiscard]] VkFramebuffer Handle() const noexcept {
204 Surface CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) override; 211 return *framebuffer;
212 }
205 213
206 void ImageCopy(Surface& src_surface, Surface& dst_surface, 214 [[nodiscard]] VkRenderPass RenderPass() const noexcept {
207 const VideoCommon::CopyParams& copy_params) override; 215 return renderpass;
216 }
208 217
209 void ImageBlit(View& src_view, View& dst_view, 218 [[nodiscard]] VkExtent2D RenderArea() const noexcept {
210 const Tegra::Engines::Fermi2D::Config& copy_config) override; 219 return render_area;
220 }
211 221
212 void BufferCopy(Surface& src_surface, Surface& dst_surface) override; 222 [[nodiscard]] VkSampleCountFlagBits Samples() const noexcept {
223 return samples;
224 }
213 225
214 const VKDevice& device; 226 [[nodiscard]] u32 NumColorBuffers() const noexcept {
215 VKMemoryManager& memory_manager; 227 return num_color_buffers;
216 VKScheduler& scheduler; 228 }
217 VKStagingBufferPool& staging_pool; 229
230 [[nodiscard]] u32 NumImages() const noexcept {
231 return num_images;
232 }
233
234 [[nodiscard]] const std::array<VkImage, 9>& Images() const noexcept {
235 return images;
236 }
237
238 [[nodiscard]] const std::array<VkImageSubresourceRange, 9>& ImageRanges() const noexcept {
239 return image_ranges;
240 }
241
242private:
243 vk::Framebuffer framebuffer;
244 VkRenderPass renderpass{};
245 VkExtent2D render_area{};
246 VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
247 u32 num_color_buffers = 0;
248 u32 num_images = 0;
249 std::array<VkImage, 9> images{};
250 std::array<VkImageSubresourceRange, 9> image_ranges{};
251};
252
253struct TextureCacheParams {
254 static constexpr bool ENABLE_VALIDATION = true;
255 static constexpr bool FRAMEBUFFER_BLITS = false;
256 static constexpr bool HAS_EMULATED_COPIES = false;
257
258 using Runtime = Vulkan::TextureCacheRuntime;
259 using Image = Vulkan::Image;
260 using ImageAlloc = Vulkan::ImageAlloc;
261 using ImageView = Vulkan::ImageView;
262 using Sampler = Vulkan::Sampler;
263 using Framebuffer = Vulkan::Framebuffer;
218}; 264};
219 265
266using TextureCache = VideoCommon::TextureCache<TextureCacheParams>;
267
220} // namespace Vulkan 268} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.h b/src/video_core/renderer_vulkan/vk_update_descriptor.h
index f7e3c9821..f098a8540 100644
--- a/src/video_core/renderer_vulkan/vk_update_descriptor.h
+++ b/src/video_core/renderer_vulkan/vk_update_descriptor.h
@@ -40,30 +40,34 @@ public:
40 40
41 void Send(VkDescriptorUpdateTemplateKHR update_template, VkDescriptorSet set); 41 void Send(VkDescriptorUpdateTemplateKHR update_template, VkDescriptorSet set);
42 42
43 void AddSampledImage(VkSampler sampler, VkImageView image_view) { 43 void AddSampledImage(VkImageView image_view, VkSampler sampler) {
44 payload.emplace_back(VkDescriptorImageInfo{sampler, image_view, {}}); 44 payload.emplace_back(VkDescriptorImageInfo{
45 .sampler = sampler,
46 .imageView = image_view,
47 .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
48 });
45 } 49 }
46 50
47 void AddImage(VkImageView image_view) { 51 void AddImage(VkImageView image_view) {
48 payload.emplace_back(VkDescriptorImageInfo{{}, image_view, {}}); 52 payload.emplace_back(VkDescriptorImageInfo{
53 .sampler = VK_NULL_HANDLE,
54 .imageView = image_view,
55 .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
56 });
49 } 57 }
50 58
51 void AddBuffer(VkBuffer buffer, u64 offset, std::size_t size) { 59 void AddBuffer(VkBuffer buffer, u64 offset, size_t size) {
52 payload.emplace_back(VkDescriptorBufferInfo{buffer, offset, size}); 60 payload.emplace_back(VkDescriptorBufferInfo{
61 .buffer = buffer,
62 .offset = offset,
63 .range = size,
64 });
53 } 65 }
54 66
55 void AddTexelBuffer(VkBufferView texel_buffer) { 67 void AddTexelBuffer(VkBufferView texel_buffer) {
56 payload.emplace_back(texel_buffer); 68 payload.emplace_back(texel_buffer);
57 } 69 }
58 70
59 VkImageLayout* LastImageLayout() {
60 return &payload.back().image.imageLayout;
61 }
62
63 const VkImageLayout* LastImageLayout() const {
64 return &payload.back().image.imageLayout;
65 }
66
67private: 71private:
68 const VKDevice& device; 72 const VKDevice& device;
69 VKScheduler& scheduler; 73 VKScheduler& scheduler;
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp
index 1eced809e..2a21e850d 100644
--- a/src/video_core/renderer_vulkan/wrapper.cpp
+++ b/src/video_core/renderer_vulkan/wrapper.cpp
@@ -81,6 +81,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
81 X(vkCmdBeginQuery); 81 X(vkCmdBeginQuery);
82 X(vkCmdBeginRenderPass); 82 X(vkCmdBeginRenderPass);
83 X(vkCmdBeginTransformFeedbackEXT); 83 X(vkCmdBeginTransformFeedbackEXT);
84 X(vkCmdBeginDebugUtilsLabelEXT);
84 X(vkCmdBindDescriptorSets); 85 X(vkCmdBindDescriptorSets);
85 X(vkCmdBindIndexBuffer); 86 X(vkCmdBindIndexBuffer);
86 X(vkCmdBindPipeline); 87 X(vkCmdBindPipeline);
@@ -98,6 +99,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
98 X(vkCmdEndQuery); 99 X(vkCmdEndQuery);
99 X(vkCmdEndRenderPass); 100 X(vkCmdEndRenderPass);
100 X(vkCmdEndTransformFeedbackEXT); 101 X(vkCmdEndTransformFeedbackEXT);
102 X(vkCmdEndDebugUtilsLabelEXT);
101 X(vkCmdFillBuffer); 103 X(vkCmdFillBuffer);
102 X(vkCmdPipelineBarrier); 104 X(vkCmdPipelineBarrier);
103 X(vkCmdPushConstants); 105 X(vkCmdPushConstants);
@@ -121,6 +123,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
121 X(vkCmdSetPrimitiveTopologyEXT); 123 X(vkCmdSetPrimitiveTopologyEXT);
122 X(vkCmdSetStencilOpEXT); 124 X(vkCmdSetStencilOpEXT);
123 X(vkCmdSetStencilTestEnableEXT); 125 X(vkCmdSetStencilTestEnableEXT);
126 X(vkCmdResolveImage);
124 X(vkCreateBuffer); 127 X(vkCreateBuffer);
125 X(vkCreateBufferView); 128 X(vkCreateBufferView);
126 X(vkCreateCommandPool); 129 X(vkCreateCommandPool);
@@ -176,6 +179,8 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
176 X(vkQueueSubmit); 179 X(vkQueueSubmit);
177 X(vkResetFences); 180 X(vkResetFences);
178 X(vkResetQueryPoolEXT); 181 X(vkResetQueryPoolEXT);
182 X(vkSetDebugUtilsObjectNameEXT);
183 X(vkSetDebugUtilsObjectTagEXT);
179 X(vkUnmapMemory); 184 X(vkUnmapMemory);
180 X(vkUpdateDescriptorSetWithTemplateKHR); 185 X(vkUpdateDescriptorSetWithTemplateKHR);
181 X(vkUpdateDescriptorSets); 186 X(vkUpdateDescriptorSets);
@@ -184,6 +189,19 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
184#undef X 189#undef X
185} 190}
186 191
192template <typename T>
193void SetObjectName(const DeviceDispatch* dld, VkDevice device, T handle, VkObjectType type,
194 const char* name) {
195 const VkDebugUtilsObjectNameInfoEXT name_info{
196 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
197 .pNext = nullptr,
198 .objectType = VK_OBJECT_TYPE_IMAGE,
199 .objectHandle = reinterpret_cast<u64>(handle),
200 .pObjectName = name,
201 };
202 Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info));
203}
204
187} // Anonymous namespace 205} // Anonymous namespace
188 206
189bool Load(InstanceDispatch& dld) noexcept { 207bool Load(InstanceDispatch& dld) noexcept {
@@ -476,8 +494,7 @@ DebugCallback Instance::TryCreateDebugCallback(
476 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | 494 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
477 VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, 495 VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
478 .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | 496 .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
479 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | 497 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
480 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
481 .pfnUserCallback = callback, 498 .pfnUserCallback = callback,
482 .pUserData = nullptr, 499 .pUserData = nullptr,
483 }; 500 };
@@ -493,10 +510,38 @@ void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const {
493 Check(dld->vkBindBufferMemory(owner, handle, memory, offset)); 510 Check(dld->vkBindBufferMemory(owner, handle, memory, offset));
494} 511}
495 512
513void Buffer::SetObjectNameEXT(const char* name) const {
514 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name);
515}
516
517void BufferView::SetObjectNameEXT(const char* name) const {
518 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name);
519}
520
496void Image::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { 521void Image::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const {
497 Check(dld->vkBindImageMemory(owner, handle, memory, offset)); 522 Check(dld->vkBindImageMemory(owner, handle, memory, offset));
498} 523}
499 524
525void Image::SetObjectNameEXT(const char* name) const {
526 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name);
527}
528
529void ImageView::SetObjectNameEXT(const char* name) const {
530 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE_VIEW, name);
531}
532
533void DeviceMemory::SetObjectNameEXT(const char* name) const {
534 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_DEVICE_MEMORY, name);
535}
536
537void Fence::SetObjectNameEXT(const char* name) const {
538 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_FENCE, name);
539}
540
541void Framebuffer::SetObjectNameEXT(const char* name) const {
542 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_FRAMEBUFFER, name);
543}
544
500DescriptorSets DescriptorPool::Allocate(const VkDescriptorSetAllocateInfo& ai) const { 545DescriptorSets DescriptorPool::Allocate(const VkDescriptorSetAllocateInfo& ai) const {
501 const std::size_t num = ai.descriptorSetCount; 546 const std::size_t num = ai.descriptorSetCount;
502 std::unique_ptr sets = std::make_unique<VkDescriptorSet[]>(num); 547 std::unique_ptr sets = std::make_unique<VkDescriptorSet[]>(num);
@@ -510,6 +555,10 @@ DescriptorSets DescriptorPool::Allocate(const VkDescriptorSetAllocateInfo& ai) c
510 } 555 }
511} 556}
512 557
558void DescriptorPool::SetObjectNameEXT(const char* name) const {
559 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_DESCRIPTOR_POOL, name);
560}
561
513CommandBuffers CommandPool::Allocate(std::size_t num_buffers, VkCommandBufferLevel level) const { 562CommandBuffers CommandPool::Allocate(std::size_t num_buffers, VkCommandBufferLevel level) const {
514 const VkCommandBufferAllocateInfo ai{ 563 const VkCommandBufferAllocateInfo ai{
515 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 564 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
@@ -530,6 +579,10 @@ CommandBuffers CommandPool::Allocate(std::size_t num_buffers, VkCommandBufferLev
530 } 579 }
531} 580}
532 581
582void CommandPool::SetObjectNameEXT(const char* name) const {
583 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_COMMAND_POOL, name);
584}
585
533std::vector<VkImage> SwapchainKHR::GetImages() const { 586std::vector<VkImage> SwapchainKHR::GetImages() const {
534 u32 num; 587 u32 num;
535 Check(dld->vkGetSwapchainImagesKHR(owner, handle, &num, nullptr)); 588 Check(dld->vkGetSwapchainImagesKHR(owner, handle, &num, nullptr));
@@ -538,6 +591,18 @@ std::vector<VkImage> SwapchainKHR::GetImages() const {
538 return images; 591 return images;
539} 592}
540 593
594void Event::SetObjectNameEXT(const char* name) const {
595 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_EVENT, name);
596}
597
598void ShaderModule::SetObjectNameEXT(const char* name) const {
599 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_SHADER_MODULE, name);
600}
601
602void Semaphore::SetObjectNameEXT(const char* name) const {
603 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_SEMAPHORE, name);
604}
605
541Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, 606Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,
542 Span<const char*> enabled_extensions, const void* next, 607 Span<const char*> enabled_extensions, const void* next,
543 DeviceDispatch& dispatch) noexcept { 608 DeviceDispatch& dispatch) noexcept {
diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h
index 76f790eab..f9a184e00 100644
--- a/src/video_core/renderer_vulkan/wrapper.h
+++ b/src/video_core/renderer_vulkan/wrapper.h
@@ -9,6 +9,7 @@
9#include <limits> 9#include <limits>
10#include <memory> 10#include <memory>
11#include <optional> 11#include <optional>
12#include <span>
12#include <type_traits> 13#include <type_traits>
13#include <utility> 14#include <utility>
14#include <vector> 15#include <vector>
@@ -18,6 +19,10 @@
18 19
19#include "common/common_types.h" 20#include "common/common_types.h"
20 21
22#ifdef _MSC_VER
23#pragma warning(disable : 26812) // Disable prefer enum class over enum
24#endif
25
21namespace Vulkan::vk { 26namespace Vulkan::vk {
22 27
23/** 28/**
@@ -41,6 +46,9 @@ public:
41 /// Construct an empty span. 46 /// Construct an empty span.
42 constexpr Span() noexcept = default; 47 constexpr Span() noexcept = default;
43 48
49 /// Construct an empty span
50 constexpr Span(std::nullptr_t) noexcept {}
51
44 /// Construct a span from a single element. 52 /// Construct a span from a single element.
45 constexpr Span(const T& value) noexcept : ptr{&value}, num{1} {} 53 constexpr Span(const T& value) noexcept : ptr{&value}, num{1} {}
46 54
@@ -177,6 +185,7 @@ struct DeviceDispatch : public InstanceDispatch {
177 PFN_vkCmdBeginQuery vkCmdBeginQuery; 185 PFN_vkCmdBeginQuery vkCmdBeginQuery;
178 PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; 186 PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass;
179 PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; 187 PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT;
188 PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT;
180 PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; 189 PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets;
181 PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; 190 PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer;
182 PFN_vkCmdBindPipeline vkCmdBindPipeline; 191 PFN_vkCmdBindPipeline vkCmdBindPipeline;
@@ -194,6 +203,7 @@ struct DeviceDispatch : public InstanceDispatch {
194 PFN_vkCmdEndQuery vkCmdEndQuery; 203 PFN_vkCmdEndQuery vkCmdEndQuery;
195 PFN_vkCmdEndRenderPass vkCmdEndRenderPass; 204 PFN_vkCmdEndRenderPass vkCmdEndRenderPass;
196 PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; 205 PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT;
206 PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT;
197 PFN_vkCmdFillBuffer vkCmdFillBuffer; 207 PFN_vkCmdFillBuffer vkCmdFillBuffer;
198 PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; 208 PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier;
199 PFN_vkCmdPushConstants vkCmdPushConstants; 209 PFN_vkCmdPushConstants vkCmdPushConstants;
@@ -217,6 +227,7 @@ struct DeviceDispatch : public InstanceDispatch {
217 PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; 227 PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT;
218 PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; 228 PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT;
219 PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; 229 PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT;
230 PFN_vkCmdResolveImage vkCmdResolveImage;
220 PFN_vkCreateBuffer vkCreateBuffer; 231 PFN_vkCreateBuffer vkCreateBuffer;
221 PFN_vkCreateBufferView vkCreateBufferView; 232 PFN_vkCreateBufferView vkCreateBufferView;
222 PFN_vkCreateCommandPool vkCreateCommandPool; 233 PFN_vkCreateCommandPool vkCreateCommandPool;
@@ -272,6 +283,8 @@ struct DeviceDispatch : public InstanceDispatch {
272 PFN_vkQueueSubmit vkQueueSubmit; 283 PFN_vkQueueSubmit vkQueueSubmit;
273 PFN_vkResetFences vkResetFences; 284 PFN_vkResetFences vkResetFences;
274 PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; 285 PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT;
286 PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT;
287 PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT;
275 PFN_vkUnmapMemory vkUnmapMemory; 288 PFN_vkUnmapMemory vkUnmapMemory;
276 PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; 289 PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR;
277 PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; 290 PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets;
@@ -542,18 +555,14 @@ private:
542 const DeviceDispatch* dld = nullptr; 555 const DeviceDispatch* dld = nullptr;
543}; 556};
544 557
545using BufferView = Handle<VkBufferView, VkDevice, DeviceDispatch>;
546using DebugCallback = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>; 558using DebugCallback = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>;
547using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>; 559using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>;
548using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>; 560using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>;
549using Framebuffer = Handle<VkFramebuffer, VkDevice, DeviceDispatch>;
550using ImageView = Handle<VkImageView, VkDevice, DeviceDispatch>;
551using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>; 561using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>;
552using PipelineLayout = Handle<VkPipelineLayout, VkDevice, DeviceDispatch>; 562using PipelineLayout = Handle<VkPipelineLayout, VkDevice, DeviceDispatch>;
553using QueryPool = Handle<VkQueryPool, VkDevice, DeviceDispatch>; 563using QueryPool = Handle<VkQueryPool, VkDevice, DeviceDispatch>;
554using RenderPass = Handle<VkRenderPass, VkDevice, DeviceDispatch>; 564using RenderPass = Handle<VkRenderPass, VkDevice, DeviceDispatch>;
555using Sampler = Handle<VkSampler, VkDevice, DeviceDispatch>; 565using Sampler = Handle<VkSampler, VkDevice, DeviceDispatch>;
556using ShaderModule = Handle<VkShaderModule, VkDevice, DeviceDispatch>;
557using SurfaceKHR = Handle<VkSurfaceKHR, VkInstance, InstanceDispatch>; 566using SurfaceKHR = Handle<VkSurfaceKHR, VkInstance, InstanceDispatch>;
558 567
559using DescriptorSets = PoolAllocations<VkDescriptorSet, VkDescriptorPool>; 568using DescriptorSets = PoolAllocations<VkDescriptorSet, VkDescriptorPool>;
@@ -605,6 +614,17 @@ class Buffer : public Handle<VkBuffer, VkDevice, DeviceDispatch> {
605public: 614public:
606 /// Attaches a memory allocation. 615 /// Attaches a memory allocation.
607 void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; 616 void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
617
618 /// Set object name.
619 void SetObjectNameEXT(const char* name) const;
620};
621
622class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> {
623 using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle;
624
625public:
626 /// Set object name.
627 void SetObjectNameEXT(const char* name) const;
608}; 628};
609 629
610class Image : public Handle<VkImage, VkDevice, DeviceDispatch> { 630class Image : public Handle<VkImage, VkDevice, DeviceDispatch> {
@@ -613,12 +633,26 @@ class Image : public Handle<VkImage, VkDevice, DeviceDispatch> {
613public: 633public:
614 /// Attaches a memory allocation. 634 /// Attaches a memory allocation.
615 void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; 635 void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
636
637 /// Set object name.
638 void SetObjectNameEXT(const char* name) const;
639};
640
641class ImageView : public Handle<VkImageView, VkDevice, DeviceDispatch> {
642 using Handle<VkImageView, VkDevice, DeviceDispatch>::Handle;
643
644public:
645 /// Set object name.
646 void SetObjectNameEXT(const char* name) const;
616}; 647};
617 648
618class DeviceMemory : public Handle<VkDeviceMemory, VkDevice, DeviceDispatch> { 649class DeviceMemory : public Handle<VkDeviceMemory, VkDevice, DeviceDispatch> {
619 using Handle<VkDeviceMemory, VkDevice, DeviceDispatch>::Handle; 650 using Handle<VkDeviceMemory, VkDevice, DeviceDispatch>::Handle;
620 651
621public: 652public:
653 /// Set object name.
654 void SetObjectNameEXT(const char* name) const;
655
622 u8* Map(VkDeviceSize offset, VkDeviceSize size) const { 656 u8* Map(VkDeviceSize offset, VkDeviceSize size) const {
623 void* data; 657 void* data;
624 Check(dld->vkMapMemory(owner, handle, offset, size, 0, &data)); 658 Check(dld->vkMapMemory(owner, handle, offset, size, 0, &data));
@@ -634,6 +668,9 @@ class Fence : public Handle<VkFence, VkDevice, DeviceDispatch> {
634 using Handle<VkFence, VkDevice, DeviceDispatch>::Handle; 668 using Handle<VkFence, VkDevice, DeviceDispatch>::Handle;
635 669
636public: 670public:
671 /// Set object name.
672 void SetObjectNameEXT(const char* name) const;
673
637 VkResult Wait(u64 timeout = std::numeric_limits<u64>::max()) const noexcept { 674 VkResult Wait(u64 timeout = std::numeric_limits<u64>::max()) const noexcept {
638 return dld->vkWaitForFences(owner, 1, &handle, true, timeout); 675 return dld->vkWaitForFences(owner, 1, &handle, true, timeout);
639 } 676 }
@@ -647,11 +684,22 @@ public:
647 } 684 }
648}; 685};
649 686
687class Framebuffer : public Handle<VkFramebuffer, VkDevice, DeviceDispatch> {
688 using Handle<VkFramebuffer, VkDevice, DeviceDispatch>::Handle;
689
690public:
691 /// Set object name.
692 void SetObjectNameEXT(const char* name) const;
693};
694
650class DescriptorPool : public Handle<VkDescriptorPool, VkDevice, DeviceDispatch> { 695class DescriptorPool : public Handle<VkDescriptorPool, VkDevice, DeviceDispatch> {
651 using Handle<VkDescriptorPool, VkDevice, DeviceDispatch>::Handle; 696 using Handle<VkDescriptorPool, VkDevice, DeviceDispatch>::Handle;
652 697
653public: 698public:
654 DescriptorSets Allocate(const VkDescriptorSetAllocateInfo& ai) const; 699 DescriptorSets Allocate(const VkDescriptorSetAllocateInfo& ai) const;
700
701 /// Set object name.
702 void SetObjectNameEXT(const char* name) const;
655}; 703};
656 704
657class CommandPool : public Handle<VkCommandPool, VkDevice, DeviceDispatch> { 705class CommandPool : public Handle<VkCommandPool, VkDevice, DeviceDispatch> {
@@ -660,6 +708,9 @@ class CommandPool : public Handle<VkCommandPool, VkDevice, DeviceDispatch> {
660public: 708public:
661 CommandBuffers Allocate(std::size_t num_buffers, 709 CommandBuffers Allocate(std::size_t num_buffers,
662 VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY) const; 710 VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY) const;
711
712 /// Set object name.
713 void SetObjectNameEXT(const char* name) const;
663}; 714};
664 715
665class SwapchainKHR : public Handle<VkSwapchainKHR, VkDevice, DeviceDispatch> { 716class SwapchainKHR : public Handle<VkSwapchainKHR, VkDevice, DeviceDispatch> {
@@ -673,15 +724,29 @@ class Event : public Handle<VkEvent, VkDevice, DeviceDispatch> {
673 using Handle<VkEvent, VkDevice, DeviceDispatch>::Handle; 724 using Handle<VkEvent, VkDevice, DeviceDispatch>::Handle;
674 725
675public: 726public:
727 /// Set object name.
728 void SetObjectNameEXT(const char* name) const;
729
676 VkResult GetStatus() const noexcept { 730 VkResult GetStatus() const noexcept {
677 return dld->vkGetEventStatus(owner, handle); 731 return dld->vkGetEventStatus(owner, handle);
678 } 732 }
679}; 733};
680 734
735class ShaderModule : public Handle<VkShaderModule, VkDevice, DeviceDispatch> {
736 using Handle<VkShaderModule, VkDevice, DeviceDispatch>::Handle;
737
738public:
739 /// Set object name.
740 void SetObjectNameEXT(const char* name) const;
741};
742
681class Semaphore : public Handle<VkSemaphore, VkDevice, DeviceDispatch> { 743class Semaphore : public Handle<VkSemaphore, VkDevice, DeviceDispatch> {
682 using Handle<VkSemaphore, VkDevice, DeviceDispatch>::Handle; 744 using Handle<VkSemaphore, VkDevice, DeviceDispatch>::Handle;
683 745
684public: 746public:
747 /// Set object name.
748 void SetObjectNameEXT(const char* name) const;
749
685 [[nodiscard]] u64 GetCounter() const { 750 [[nodiscard]] u64 GetCounter() const {
686 u64 value; 751 u64 value;
687 Check(dld->vkGetSemaphoreCounterValueKHR(owner, handle, &value)); 752 Check(dld->vkGetSemaphoreCounterValueKHR(owner, handle, &value));
@@ -932,6 +997,12 @@ public:
932 regions.data(), filter); 997 regions.data(), filter);
933 } 998 }
934 999
1000 void ResolveImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image,
1001 VkImageLayout dst_layout, Span<VkImageResolve> regions) {
1002 dld->vkCmdResolveImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(),
1003 regions.data());
1004 }
1005
935 void Dispatch(u32 x, u32 y, u32 z) const noexcept { 1006 void Dispatch(u32 x, u32 y, u32 z) const noexcept {
936 dld->vkCmdDispatch(handle, x, y, z); 1007 dld->vkCmdDispatch(handle, x, y, z);
937 } 1008 }
@@ -946,6 +1017,23 @@ public:
946 image_barriers.size(), image_barriers.data()); 1017 image_barriers.size(), image_barriers.data());
947 } 1018 }
948 1019
1020 void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
1021 VkDependencyFlags dependency_flags = 0) const noexcept {
1022 PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, {}, {});
1023 }
1024
1025 void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
1026 VkDependencyFlags dependency_flags,
1027 const VkBufferMemoryBarrier& buffer_barrier) const noexcept {
1028 PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, buffer_barrier, {});
1029 }
1030
1031 void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
1032 VkDependencyFlags dependency_flags,
1033 const VkImageMemoryBarrier& image_barrier) const noexcept {
1034 PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, {}, image_barrier);
1035 }
1036
949 void CopyBufferToImage(VkBuffer src_buffer, VkImage dst_image, VkImageLayout dst_image_layout, 1037 void CopyBufferToImage(VkBuffer src_buffer, VkImage dst_image, VkImageLayout dst_image_layout,
950 Span<VkBufferImageCopy> regions) const noexcept { 1038 Span<VkBufferImageCopy> regions) const noexcept {
951 dld->vkCmdCopyBufferToImage(handle, src_buffer, dst_image, dst_image_layout, regions.size(), 1039 dld->vkCmdCopyBufferToImage(handle, src_buffer, dst_image, dst_image_layout, regions.size(),
@@ -979,6 +1067,13 @@ public:
979 dld->vkCmdPushConstants(handle, layout, flags, offset, size, values); 1067 dld->vkCmdPushConstants(handle, layout, flags, offset, size, values);
980 } 1068 }
981 1069
1070 template <typename T>
1071 void PushConstants(VkPipelineLayout layout, VkShaderStageFlags flags,
1072 const T& data) const noexcept {
1073 static_assert(std::is_trivially_copyable_v<T>, "<data> is not trivially copyable");
1074 dld->vkCmdPushConstants(handle, layout, flags, 0, static_cast<u32>(sizeof(T)), &data);
1075 }
1076
982 void SetViewport(u32 first, Span<VkViewport> viewports) const noexcept { 1077 void SetViewport(u32 first, Span<VkViewport> viewports) const noexcept {
983 dld->vkCmdSetViewport(handle, first, viewports.size(), viewports.data()); 1078 dld->vkCmdSetViewport(handle, first, viewports.size(), viewports.data());
984 } 1079 }
@@ -1088,6 +1183,20 @@ public:
1088 counter_buffers, counter_buffer_offsets); 1183 counter_buffers, counter_buffer_offsets);
1089 } 1184 }
1090 1185
1186 void BeginDebugUtilsLabelEXT(const char* label, std::span<float, 4> color) const noexcept {
1187 const VkDebugUtilsLabelEXT label_info{
1188 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
1189 .pNext = nullptr,
1190 .pLabelName = label,
1191 .color{color[0], color[1], color[2], color[3]},
1192 };
1193 dld->vkCmdBeginDebugUtilsLabelEXT(handle, &label_info);
1194 }
1195
1196 void EndDebugUtilsLabelEXT() const noexcept {
1197 dld->vkCmdEndDebugUtilsLabelEXT(handle);
1198 }
1199
1091private: 1200private:
1092 VkCommandBuffer handle; 1201 VkCommandBuffer handle;
1093 const DeviceDispatch* dld; 1202 const DeviceDispatch* dld;