summaryrefslogtreecommitdiff
path: root/src/video_core/renderer_vulkan
diff options
context:
space:
mode:
authorGravatar Levi2021-01-10 22:09:56 -0700
committerGravatar Levi2021-01-10 22:09:56 -0700
commit7a3c884e39fccfbb498b855080bffabc9ce2e7f1 (patch)
tree5056f9406dec188439cb0deb87603498243a9412 /src/video_core/renderer_vulkan
parentMore forgetting... duh (diff)
parentMerge pull request #5229 from Morph1984/fullscreen-opt (diff)
downloadyuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.tar.gz
yuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.tar.xz
yuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.zip
Merge remote-tracking branch 'upstream/master' into int-flags
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.h96
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.cpp30
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.h31
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp81
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.h14
-rw-r--r--src/video_core/renderer_vulkan/nsight_aftermath_tracker.cpp220
-rw-r--r--src/video_core/renderer_vulkan/nsight_aftermath_tracker.h87
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp315
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h24
-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.cpp307
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h12
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp125
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h22
-rw-r--r--src/video_core/renderer_vulkan/vk_command_pool.cpp13
-rw-r--r--src/video_core/renderer_vulkan/vk_command_pool.h17
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.cpp365
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.h33
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp20
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.h14
-rw-r--r--src/video_core/renderer_vulkan/vk_descriptor_pool.cpp6
-rw-r--r--src/video_core/renderer_vulkan/vk_descriptor_pool.h8
-rw-r--r--src/video_core/renderer_vulkan/vk_device.cpp801
-rw-r--r--src/video_core/renderer_vulkan/vk_device.h274
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.cpp25
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.h28
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp102
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.h30
-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_master_semaphore.cpp6
-rw-r--r--src/video_core/renderer_vulkan/vk_master_semaphore.h6
-rw-r--r--src/video_core/renderer_vulkan/vk_memory_manager.cpp26
-rw-r--r--src/video_core/renderer_vulkan/vk_memory_manager.h34
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp55
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h20
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.cpp50
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.h28
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp732
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h144
-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.cpp85
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.h24
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp103
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.h25
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_util.cpp15
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_util.h8
-rw-r--r--src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp6
-rw-r--r--src/video_core/renderer_vulkan/vk_staging_buffer_pool.h8
-rw-r--r--src/video_core/renderer_vulkan/vk_state_tracker.cpp25
-rw-r--r--src/video_core/renderer_vulkan/vk_state_tracker.h8
-rw-r--r--src/video_core/renderer_vulkan/vk_stream_buffer.cpp27
-rw-r--r--src/video_core/renderer_vulkan/vk_stream_buffer.h18
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp6
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.h8
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp1474
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h334
-rw-r--r--src/video_core/renderer_vulkan/vk_update_descriptor.cpp8
-rw-r--r--src/video_core/renderer_vulkan/vk_update_descriptor.h38
-rw-r--r--src/video_core/renderer_vulkan/wrapper.cpp826
-rw-r--r--src/video_core/renderer_vulkan/wrapper.h1099
69 files changed, 3149 insertions, 6552 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..1f6a169ae
--- /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_scheduler.h"
15#include "video_core/renderer_vulkan/vk_shader_util.h"
16#include "video_core/renderer_vulkan/vk_state_tracker.h"
17#include "video_core/renderer_vulkan/vk_texture_cache.h"
18#include "video_core/renderer_vulkan/vk_update_descriptor.h"
19#include "video_core/surface.h"
20#include "video_core/vulkan_common/vulkan_device.h"
21#include "video_core/vulkan_common/vulkan_wrapper.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 Device& 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 Device& 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 Device& 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..43fd3d737
--- /dev/null
+++ b/src/video_core/renderer_vulkan/blit_image.h
@@ -0,0 +1,96 @@
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/texture_cache/types.h"
12#include "video_core/vulkan_common/vulkan_wrapper.h"
13
14namespace Vulkan {
15
16using VideoCommon::Offset2D;
17
18class Device;
19class Framebuffer;
20class ImageView;
21class StateTracker;
22class VKScheduler;
23
24struct BlitImagePipelineKey {
25 constexpr auto operator<=>(const BlitImagePipelineKey&) const noexcept = default;
26
27 VkRenderPass renderpass;
28 Tegra::Engines::Fermi2D::Operation operation;
29};
30
31class BlitImageHelper {
32public:
33 explicit BlitImageHelper(const Device& device, VKScheduler& scheduler,
34 StateTracker& state_tracker, VKDescriptorPool& descriptor_pool);
35 ~BlitImageHelper();
36
37 void BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
38 const std::array<Offset2D, 2>& dst_region,
39 const std::array<Offset2D, 2>& src_region,
40 Tegra::Engines::Fermi2D::Filter filter,
41 Tegra::Engines::Fermi2D::Operation operation);
42
43 void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view,
44 VkImageView src_stencil_view, const std::array<Offset2D, 2>& dst_region,
45 const std::array<Offset2D, 2>& src_region,
46 Tegra::Engines::Fermi2D::Filter filter,
47 Tegra::Engines::Fermi2D::Operation operation);
48
49 void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
50
51 void ConvertR32ToD32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
52
53 void ConvertD16ToR16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
54
55 void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
56
57private:
58 void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
59 const ImageView& src_image_view);
60
61 [[nodiscard]] VkPipeline FindOrEmplacePipeline(const BlitImagePipelineKey& key);
62
63 [[nodiscard]] VkPipeline BlitDepthStencilPipeline(VkRenderPass renderpass);
64
65 void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
66
67 void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
68
69 const Device& device;
70 VKScheduler& scheduler;
71 StateTracker& state_tracker;
72
73 vk::DescriptorSetLayout one_texture_set_layout;
74 vk::DescriptorSetLayout two_textures_set_layout;
75 DescriptorAllocator one_texture_descriptor_allocator;
76 DescriptorAllocator two_textures_descriptor_allocator;
77 vk::PipelineLayout one_texture_pipeline_layout;
78 vk::PipelineLayout two_textures_pipeline_layout;
79 vk::ShaderModule full_screen_vert;
80 vk::ShaderModule blit_color_to_color_frag;
81 vk::ShaderModule blit_depth_stencil_frag;
82 vk::ShaderModule convert_depth_to_float_frag;
83 vk::ShaderModule convert_float_to_depth_frag;
84 vk::Sampler linear_sampler;
85 vk::Sampler nearest_sampler;
86
87 std::vector<BlitImagePipelineKey> blit_color_keys;
88 std::vector<vk::Pipeline> blit_color_pipelines;
89 vk::Pipeline blit_depth_stencil_pipeline;
90 vk::Pipeline convert_d32_to_r32_pipeline;
91 vk::Pipeline convert_r32_to_d32_pipeline;
92 vk::Pipeline convert_d16_to_r16_pipeline;
93 vk::Pipeline convert_r16_to_d16_pipeline;
94};
95
96} // 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 81a39a3b8..5be6dabd9 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
@@ -8,6 +8,7 @@
8 8
9#include <boost/functional/hash.hpp> 9#include <boost/functional/hash.hpp>
10 10
11#include "common/bit_cast.h"
11#include "common/cityhash.h" 12#include "common/cityhash.h"
12#include "common/common_types.h" 13#include "common/common_types.h"
13#include "video_core/renderer_vulkan/fixed_pipeline_state.h" 14#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
@@ -45,7 +46,7 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta
45 regs.polygon_offset_fill_enable}; 46 regs.polygon_offset_fill_enable};
46 const u32 topology_index = static_cast<u32>(regs.draw.topology.Value()); 47 const u32 topology_index = static_cast<u32>(regs.draw.topology.Value());
47 48
48 raw = 0; 49 raw1 = 0;
49 primitive_restart_enable.Assign(regs.primitive_restart.enabled != 0 ? 1 : 0); 50 primitive_restart_enable.Assign(regs.primitive_restart.enabled != 0 ? 1 : 0);
50 depth_bias_enable.Assign(enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]] != 0 ? 1 : 0); 51 depth_bias_enable.Assign(enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]] != 0 ? 1 : 0);
51 depth_clamp_disabled.Assign(regs.view_volume_clip_control.depth_clamp_disabled.Value()); 52 depth_clamp_disabled.Assign(regs.view_volume_clip_control.depth_clamp_disabled.Value());
@@ -58,15 +59,24 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta
58 logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); 59 logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0);
59 logic_op.Assign(PackLogicOp(regs.logic_op.operation)); 60 logic_op.Assign(PackLogicOp(regs.logic_op.operation));
60 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);
63 msaa_mode.Assign(regs.multisample_mode);
64
65 raw2 = 0;
66 const auto test_func =
67 regs.alpha_test_enabled == 1 ? regs.alpha_test_func : Maxwell::ComparisonOp::Always;
68 alpha_test_func.Assign(PackComparisonOp(test_func));
69 early_z.Assign(regs.force_early_fragment_tests != 0 ? 1 : 0);
61 70
62 std::memcpy(&point_size, &regs.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast 71 alpha_test_ref = Common::BitCast<u32>(regs.alpha_test_ref);
72 point_size = Common::BitCast<u32>(regs.point_size);
63 73
64 for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { 74 for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) {
65 binding_divisors[index] = 75 binding_divisors[index] =
66 regs.instanced_arrays.IsInstancingEnabled(index) ? regs.vertex_array[index].divisor : 0; 76 regs.instanced_arrays.IsInstancingEnabled(index) ? regs.vertex_array[index].divisor : 0;
67 } 77 }
68 78
69 for (std::size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) { 79 for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
70 const auto& input = regs.vertex_attrib_format[index]; 80 const auto& input = regs.vertex_attrib_format[index];
71 auto& attribute = attributes[index]; 81 auto& attribute = attributes[index];
72 attribute.raw = 0; 82 attribute.raw = 0;
@@ -75,6 +85,7 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta
75 attribute.offset.Assign(input.offset); 85 attribute.offset.Assign(input.offset);
76 attribute.type.Assign(static_cast<u32>(input.type.Value())); 86 attribute.type.Assign(static_cast<u32>(input.type.Value()));
77 attribute.size.Assign(static_cast<u32>(input.size.Value())); 87 attribute.size.Assign(static_cast<u32>(input.size.Value()));
88 attribute.binding_index_enabled.Assign(regs.vertex_array[index].IsEnabled() ? 1 : 0);
78 } 89 }
79 90
80 for (std::size_t index = 0; index < std::size(attachments); ++index) { 91 for (std::size_t index = 0; index < std::size(attachments); ++index) {
@@ -131,7 +142,6 @@ void FixedPipelineState::BlendingAttachment::Fill(const Maxwell& regs, std::size
131} 142}
132 143
133void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) { 144void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) {
134 const u32 topology_index = static_cast<u32>(regs.draw.topology.Value());
135 u32 packed_front_face = PackFrontFace(regs.front_face); 145 u32 packed_front_face = PackFrontFace(regs.front_face);
136 if (regs.screen_y_control.triangle_rast_flip != 0) { 146 if (regs.screen_y_control.triangle_rast_flip != 0) {
137 // Flip front face 147 // Flip front face
@@ -161,17 +171,11 @@ void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) {
161 depth_test_enable.Assign(regs.depth_test_enable); 171 depth_test_enable.Assign(regs.depth_test_enable);
162 front_face.Assign(packed_front_face); 172 front_face.Assign(packed_front_face);
163 depth_test_func.Assign(PackComparisonOp(regs.depth_test_func)); 173 depth_test_func.Assign(PackComparisonOp(regs.depth_test_func));
164 topology.Assign(topology_index);
165 cull_face.Assign(PackCullFace(regs.cull_face)); 174 cull_face.Assign(PackCullFace(regs.cull_face));
166 cull_enable.Assign(regs.cull_test_enabled != 0 ? 1 : 0); 175 cull_enable.Assign(regs.cull_test_enabled != 0 ? 1 : 0);
167 176 std::ranges::transform(regs.vertex_array, vertex_strides.begin(), [](const auto& array) {
168 for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { 177 return static_cast<u16>(array.stride.Value());
169 const auto& input = regs.vertex_array[index]; 178 });
170 VertexBinding& binding = vertex_bindings[index];
171 binding.raw = 0;
172 binding.enabled.Assign(input.IsEnabled() ? 1 : 0);
173 binding.stride.Assign(static_cast<u16>(input.stride.Value()));
174 }
175} 179}
176 180
177std::size_t FixedPipelineState::Hash() const noexcept { 181std::size_t FixedPipelineState::Hash() const noexcept {
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h
index cdcbb65f5..465a55fdb 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h
@@ -96,6 +96,8 @@ struct FixedPipelineState {
96 BitField<6, 14, u32> offset; 96 BitField<6, 14, u32> offset;
97 BitField<20, 3, u32> type; 97 BitField<20, 3, u32> type;
98 BitField<23, 6, u32> size; 98 BitField<23, 6, u32> size;
99 // Not really an element of a vertex attribute, but it can be packed here
100 BitField<29, 1, u32> binding_index_enabled;
99 101
100 constexpr Maxwell::VertexAttribute::Type Type() const noexcept { 102 constexpr Maxwell::VertexAttribute::Type Type() const noexcept {
101 return static_cast<Maxwell::VertexAttribute::Type>(type.Value()); 103 return static_cast<Maxwell::VertexAttribute::Type>(type.Value());
@@ -130,12 +132,6 @@ struct FixedPipelineState {
130 } 132 }
131 }; 133 };
132 134
133 union VertexBinding {
134 u16 raw;
135 BitField<0, 12, u16> stride;
136 BitField<12, 1, u16> enabled;
137 };
138
139 struct DynamicState { 135 struct DynamicState {
140 union { 136 union {
141 u32 raw1; 137 u32 raw1;
@@ -150,11 +146,11 @@ struct FixedPipelineState {
150 }; 146 };
151 union { 147 union {
152 u32 raw2; 148 u32 raw2;
153 BitField<0, 4, u32> topology; 149 BitField<0, 2, u32> cull_face;
154 BitField<4, 2, u32> cull_face; 150 BitField<2, 1, u32> cull_enable;
155 BitField<6, 1, u32> cull_enable;
156 }; 151 };
157 std::array<VertexBinding, Maxwell::NumVertexArrays> vertex_bindings; 152 // Vertex stride is a 12 bits value, we have 4 bits to spare per element
153 std::array<u16, Maxwell::NumVertexArrays> vertex_strides;
158 154
159 void Fill(const Maxwell& regs); 155 void Fill(const Maxwell& regs);
160 156
@@ -169,14 +165,10 @@ struct FixedPipelineState {
169 Maxwell::FrontFace FrontFace() const noexcept { 165 Maxwell::FrontFace FrontFace() const noexcept {
170 return UnpackFrontFace(front_face.Value()); 166 return UnpackFrontFace(front_face.Value());
171 } 167 }
172
173 constexpr Maxwell::PrimitiveTopology Topology() const noexcept {
174 return static_cast<Maxwell::PrimitiveTopology>(topology.Value());
175 }
176 }; 168 };
177 169
178 union { 170 union {
179 u32 raw; 171 u32 raw1;
180 BitField<0, 1, u32> no_extended_dynamic_state; 172 BitField<0, 1, u32> no_extended_dynamic_state;
181 BitField<2, 1, u32> primitive_restart_enable; 173 BitField<2, 1, u32> primitive_restart_enable;
182 BitField<3, 1, u32> depth_bias_enable; 174 BitField<3, 1, u32> depth_bias_enable;
@@ -190,7 +182,16 @@ struct FixedPipelineState {
190 BitField<18, 1, u32> logic_op_enable; 182 BitField<18, 1, u32> logic_op_enable;
191 BitField<19, 4, u32> logic_op; 183 BitField<19, 4, u32> logic_op;
192 BitField<23, 1, u32> rasterize_enable; 184 BitField<23, 1, u32> rasterize_enable;
185 BitField<24, 4, Maxwell::PrimitiveTopology> topology;
186 BitField<28, 4, Tegra::Texture::MsaaMode> msaa_mode;
187 };
188 union {
189 u32 raw2;
190 BitField<0, 3, u32> alpha_test_func;
191 BitField<3, 1, u32> early_z;
193 }; 192 };
193
194 u32 alpha_test_ref;
194 u32 point_size; 195 u32 point_size;
195 std::array<u32, Maxwell::NumVertexArrays> binding_divisors; 196 std::array<u32, Maxwell::NumVertexArrays> binding_divisors;
196 std::array<VertexAttribute, Maxwell::NumVertexAttributes> attributes; 197 std::array<VertexAttribute, Maxwell::NumVertexAttributes> attributes;
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index d22de1d81..ca7c2c579 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -9,9 +9,9 @@
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "video_core/engines/maxwell_3d.h" 10#include "video_core/engines/maxwell_3d.h"
11#include "video_core/renderer_vulkan/maxwell_to_vk.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/wrapper.h"
14#include "video_core/surface.h" 12#include "video_core/surface.h"
13#include "video_core/vulkan_common/vulkan_device.h"
14#include "video_core/vulkan_common/vulkan_wrapper.h"
15 15
16namespace Vulkan::MaxwellToVK { 16namespace Vulkan::MaxwellToVK {
17 17
@@ -26,7 +26,7 @@ VkFilter Filter(Tegra::Texture::TextureFilter filter) {
26 case Tegra::Texture::TextureFilter::Linear: 26 case Tegra::Texture::TextureFilter::Linear:
27 return VK_FILTER_LINEAR; 27 return VK_FILTER_LINEAR;
28 } 28 }
29 UNREACHABLE_MSG("Invalid sampler filter={}", static_cast<u32>(filter)); 29 UNREACHABLE_MSG("Invalid sampler filter={}", filter);
30 return {}; 30 return {};
31} 31}
32 32
@@ -43,11 +43,11 @@ VkSamplerMipmapMode MipmapMode(Tegra::Texture::TextureMipmapFilter mipmap_filter
43 case Tegra::Texture::TextureMipmapFilter::Linear: 43 case Tegra::Texture::TextureMipmapFilter::Linear:
44 return VK_SAMPLER_MIPMAP_MODE_LINEAR; 44 return VK_SAMPLER_MIPMAP_MODE_LINEAR;
45 } 45 }
46 UNREACHABLE_MSG("Invalid sampler mipmap mode={}", static_cast<u32>(mipmap_filter)); 46 UNREACHABLE_MSG("Invalid sampler mipmap mode={}", mipmap_filter);
47 return {}; 47 return {};
48} 48}
49 49
50VkSamplerAddressMode WrapMode(const VKDevice& device, Tegra::Texture::WrapMode wrap_mode, 50VkSamplerAddressMode WrapMode(const Device& device, Tegra::Texture::WrapMode wrap_mode,
51 Tegra::Texture::TextureFilter filter) { 51 Tegra::Texture::TextureFilter filter) {
52 switch (wrap_mode) { 52 switch (wrap_mode) {
53 case Tegra::Texture::WrapMode::Wrap: 53 case Tegra::Texture::WrapMode::Wrap:
@@ -79,7 +79,7 @@ VkSamplerAddressMode WrapMode(const VKDevice& device, Tegra::Texture::WrapMode w
79 UNIMPLEMENTED(); 79 UNIMPLEMENTED();
80 return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; 80 return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
81 default: 81 default:
82 UNIMPLEMENTED_MSG("Unimplemented wrap mode={}", static_cast<u32>(wrap_mode)); 82 UNIMPLEMENTED_MSG("Unimplemented wrap mode={}", wrap_mode);
83 return {}; 83 return {};
84 } 84 }
85} 85}
@@ -103,8 +103,7 @@ VkCompareOp DepthCompareFunction(Tegra::Texture::DepthCompareFunc depth_compare_
103 case Tegra::Texture::DepthCompareFunc::Always: 103 case Tegra::Texture::DepthCompareFunc::Always:
104 return VK_COMPARE_OP_ALWAYS; 104 return VK_COMPARE_OP_ALWAYS;
105 } 105 }
106 UNIMPLEMENTED_MSG("Unimplemented sampler depth compare function={}", 106 UNIMPLEMENTED_MSG("Unimplemented sampler depth compare function={}", depth_compare_func);
107 static_cast<u32>(depth_compare_func));
108 return {}; 107 return {};
109} 108}
110 109
@@ -123,7 +122,7 @@ struct FormatTuple {
123 {VK_FORMAT_A8B8G8R8_SINT_PACK32, Attachable | Storage}, // A8B8G8R8_SINT 122 {VK_FORMAT_A8B8G8R8_SINT_PACK32, Attachable | Storage}, // A8B8G8R8_SINT
124 {VK_FORMAT_A8B8G8R8_UINT_PACK32, Attachable | Storage}, // A8B8G8R8_UINT 123 {VK_FORMAT_A8B8G8R8_UINT_PACK32, Attachable | Storage}, // A8B8G8R8_UINT
125 {VK_FORMAT_R5G6B5_UNORM_PACK16, Attachable}, // R5G6B5_UNORM 124 {VK_FORMAT_R5G6B5_UNORM_PACK16, Attachable}, // R5G6B5_UNORM
126 {VK_FORMAT_B5G6R5_UNORM_PACK16, Attachable}, // B5G6R5_UNORM 125 {VK_FORMAT_B5G6R5_UNORM_PACK16}, // B5G6R5_UNORM
127 {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1R5G5B5_UNORM 126 {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1R5G5B5_UNORM
128 {VK_FORMAT_A2B10G10R10_UNORM_PACK32, Attachable | Storage}, // A2B10G10R10_UNORM 127 {VK_FORMAT_A2B10G10R10_UNORM_PACK32, Attachable | Storage}, // A2B10G10R10_UNORM
129 {VK_FORMAT_A2B10G10R10_UINT_PACK32, Attachable | Storage}, // A2B10G10R10_UINT 128 {VK_FORMAT_A2B10G10R10_UINT_PACK32, Attachable | Storage}, // A2B10G10R10_UINT
@@ -164,7 +163,7 @@ struct FormatTuple {
164 {VK_FORMAT_R16G16_UNORM, Attachable | Storage}, // R16G16_UNORM 163 {VK_FORMAT_R16G16_UNORM, Attachable | Storage}, // R16G16_UNORM
165 {VK_FORMAT_R16G16_SFLOAT, Attachable | Storage}, // R16G16_FLOAT 164 {VK_FORMAT_R16G16_SFLOAT, Attachable | Storage}, // R16G16_FLOAT
166 {VK_FORMAT_UNDEFINED}, // R16G16_UINT 165 {VK_FORMAT_UNDEFINED}, // R16G16_UINT
167 {VK_FORMAT_UNDEFINED}, // R16G16_SINT 166 {VK_FORMAT_R16G16_SINT, Attachable | Storage}, // R16G16_SINT
168 {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM 167 {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM
169 {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT 168 {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT
170 {VK_FORMAT_R8G8B8A8_SRGB, Attachable}, // A8B8G8R8_SRGB 169 {VK_FORMAT_R8G8B8A8_SRGB, Attachable}, // A8B8G8R8_SRGB
@@ -223,30 +222,31 @@ constexpr bool IsZetaFormat(PixelFormat pixel_format) {
223 222
224} // Anonymous namespace 223} // Anonymous namespace
225 224
226FormatInfo SurfaceFormat(const VKDevice& device, FormatType format_type, PixelFormat pixel_format) { 225FormatInfo SurfaceFormat(const Device& device, FormatType format_type, PixelFormat pixel_format) {
227 ASSERT(static_cast<std::size_t>(pixel_format) < std::size(tex_format_tuples)); 226 ASSERT(static_cast<std::size_t>(pixel_format) < std::size(tex_format_tuples));
228 227
229 auto tuple = tex_format_tuples[static_cast<std::size_t>(pixel_format)]; 228 auto tuple = tex_format_tuples[static_cast<std::size_t>(pixel_format)];
230 if (tuple.format == VK_FORMAT_UNDEFINED) { 229 if (tuple.format == VK_FORMAT_UNDEFINED) {
231 UNIMPLEMENTED_MSG("Unimplemented texture format with pixel format={}", 230 UNIMPLEMENTED_MSG("Unimplemented texture format with pixel format={}", pixel_format);
232 static_cast<u32>(pixel_format));
233 return {VK_FORMAT_A8B8G8R8_UNORM_PACK32, true, true}; 231 return {VK_FORMAT_A8B8G8R8_UNORM_PACK32, true, true};
234 } 232 }
235 233
236 // Use A8B8G8R8_UNORM on hardware that doesn't support ASTC natively 234 // Use A8B8G8R8_UNORM on hardware that doesn't support ASTC natively
237 if (!device.IsOptimalAstcSupported() && VideoCore::Surface::IsPixelFormatASTC(pixel_format)) { 235 if (!device.IsOptimalAstcSupported() && VideoCore::Surface::IsPixelFormatASTC(pixel_format)) {
238 tuple.format = VideoCore::Surface::IsPixelFormatSRGB(pixel_format) 236 const bool is_srgb = VideoCore::Surface::IsPixelFormatSRGB(pixel_format);
239 ? VK_FORMAT_A8B8G8R8_SRGB_PACK32 237 tuple.format = is_srgb ? VK_FORMAT_A8B8G8R8_SRGB_PACK32 : VK_FORMAT_A8B8G8R8_UNORM_PACK32;
240 : VK_FORMAT_A8B8G8R8_UNORM_PACK32;
241 } 238 }
242 const bool attachable = tuple.usage & Attachable; 239 const bool attachable = tuple.usage & Attachable;
243 const bool storage = tuple.usage & Storage; 240 const bool storage = tuple.usage & Storage;
244 241
245 VkFormatFeatureFlags usage; 242 VkFormatFeatureFlags usage{};
246 if (format_type == FormatType::Buffer) { 243 switch (format_type) {
244 case FormatType::Buffer:
247 usage = 245 usage =
248 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;
249 } else { 247 break;
248 case FormatType::Linear:
249 case FormatType::Optimal:
250 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 |
251 VK_FORMAT_FEATURE_TRANSFER_SRC_BIT; 251 VK_FORMAT_FEATURE_TRANSFER_SRC_BIT;
252 if (attachable) { 252 if (attachable) {
@@ -256,6 +256,7 @@ FormatInfo SurfaceFormat(const VKDevice& device, FormatType format_type, PixelFo
256 if (storage) { 256 if (storage) {
257 usage |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; 257 usage |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
258 } 258 }
259 break;
259 } 260 }
260 return {device.GetSupportedFormat(tuple.format, usage, format_type), attachable, storage}; 261 return {device.GetSupportedFormat(tuple.format, usage, format_type), attachable, storage};
261} 262}
@@ -275,11 +276,11 @@ VkShaderStageFlagBits ShaderStage(Tegra::Engines::ShaderType stage) {
275 case Tegra::Engines::ShaderType::Compute: 276 case Tegra::Engines::ShaderType::Compute:
276 return VK_SHADER_STAGE_COMPUTE_BIT; 277 return VK_SHADER_STAGE_COMPUTE_BIT;
277 } 278 }
278 UNIMPLEMENTED_MSG("Unimplemented shader stage={}", static_cast<u32>(stage)); 279 UNIMPLEMENTED_MSG("Unimplemented shader stage={}", stage);
279 return {}; 280 return {};
280} 281}
281 282
282VkPrimitiveTopology PrimitiveTopology([[maybe_unused]] const VKDevice& device, 283VkPrimitiveTopology PrimitiveTopology([[maybe_unused]] const Device& device,
283 Maxwell::PrimitiveTopology topology) { 284 Maxwell::PrimitiveTopology topology) {
284 switch (topology) { 285 switch (topology) {
285 case Maxwell::PrimitiveTopology::Points: 286 case Maxwell::PrimitiveTopology::Points:
@@ -300,7 +301,7 @@ VkPrimitiveTopology PrimitiveTopology([[maybe_unused]] const VKDevice& device,
300 case Maxwell::PrimitiveTopology::Patches: 301 case Maxwell::PrimitiveTopology::Patches:
301 return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; 302 return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
302 default: 303 default:
303 UNIMPLEMENTED_MSG("Unimplemented topology={}", static_cast<u32>(topology)); 304 UNIMPLEMENTED_MSG("Unimplemented topology={}", topology);
304 return {}; 305 return {};
305 } 306 }
306} 307}
@@ -490,8 +491,7 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib
490 } 491 }
491 break; 492 break;
492 } 493 }
493 UNIMPLEMENTED_MSG("Unimplemented vertex format of type={} and size={}", static_cast<u32>(type), 494 UNIMPLEMENTED_MSG("Unimplemented vertex format of type={} and size={}", type, size);
494 static_cast<u32>(size));
495 return {}; 495 return {};
496} 496}
497 497
@@ -522,11 +522,11 @@ VkCompareOp ComparisonOp(Maxwell::ComparisonOp comparison) {
522 case Maxwell::ComparisonOp::AlwaysOld: 522 case Maxwell::ComparisonOp::AlwaysOld:
523 return VK_COMPARE_OP_ALWAYS; 523 return VK_COMPARE_OP_ALWAYS;
524 } 524 }
525 UNIMPLEMENTED_MSG("Unimplemented comparison op={}", static_cast<u32>(comparison)); 525 UNIMPLEMENTED_MSG("Unimplemented comparison op={}", comparison);
526 return {}; 526 return {};
527} 527}
528 528
529VkIndexType IndexFormat(const VKDevice& device, Maxwell::IndexFormat index_format) { 529VkIndexType IndexFormat(const Device& device, Maxwell::IndexFormat index_format) {
530 switch (index_format) { 530 switch (index_format) {
531 case Maxwell::IndexFormat::UnsignedByte: 531 case Maxwell::IndexFormat::UnsignedByte:
532 if (!device.IsExtIndexTypeUint8Supported()) { 532 if (!device.IsExtIndexTypeUint8Supported()) {
@@ -539,7 +539,7 @@ VkIndexType IndexFormat(const VKDevice& device, Maxwell::IndexFormat index_forma
539 case Maxwell::IndexFormat::UnsignedInt: 539 case Maxwell::IndexFormat::UnsignedInt:
540 return VK_INDEX_TYPE_UINT32; 540 return VK_INDEX_TYPE_UINT32;
541 } 541 }
542 UNIMPLEMENTED_MSG("Unimplemented index_format={}", static_cast<u32>(index_format)); 542 UNIMPLEMENTED_MSG("Unimplemented index_format={}", index_format);
543 return {}; 543 return {};
544} 544}
545 545
@@ -570,7 +570,7 @@ VkStencilOp StencilOp(Maxwell::StencilOp stencil_op) {
570 case Maxwell::StencilOp::DecrWrapOGL: 570 case Maxwell::StencilOp::DecrWrapOGL:
571 return VK_STENCIL_OP_DECREMENT_AND_WRAP; 571 return VK_STENCIL_OP_DECREMENT_AND_WRAP;
572 } 572 }
573 UNIMPLEMENTED_MSG("Unimplemented stencil op={}", static_cast<u32>(stencil_op)); 573 UNIMPLEMENTED_MSG("Unimplemented stencil op={}", stencil_op);
574 return {}; 574 return {};
575} 575}
576 576
@@ -592,7 +592,7 @@ VkBlendOp BlendEquation(Maxwell::Blend::Equation equation) {
592 case Maxwell::Blend::Equation::MaxGL: 592 case Maxwell::Blend::Equation::MaxGL:
593 return VK_BLEND_OP_MAX; 593 return VK_BLEND_OP_MAX;
594 } 594 }
595 UNIMPLEMENTED_MSG("Unimplemented blend equation={}", static_cast<u32>(equation)); 595 UNIMPLEMENTED_MSG("Unimplemented blend equation={}", equation);
596 return {}; 596 return {};
597} 597}
598 598
@@ -656,7 +656,7 @@ VkBlendFactor BlendFactor(Maxwell::Blend::Factor factor) {
656 case Maxwell::Blend::Factor::OneMinusConstantAlphaGL: 656 case Maxwell::Blend::Factor::OneMinusConstantAlphaGL:
657 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA; 657 return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
658 } 658 }
659 UNIMPLEMENTED_MSG("Unimplemented blend factor={}", static_cast<u32>(factor)); 659 UNIMPLEMENTED_MSG("Unimplemented blend factor={}", factor);
660 return {}; 660 return {};
661} 661}
662 662
@@ -667,7 +667,7 @@ VkFrontFace FrontFace(Maxwell::FrontFace front_face) {
667 case Maxwell::FrontFace::CounterClockWise: 667 case Maxwell::FrontFace::CounterClockWise:
668 return VK_FRONT_FACE_COUNTER_CLOCKWISE; 668 return VK_FRONT_FACE_COUNTER_CLOCKWISE;
669 } 669 }
670 UNIMPLEMENTED_MSG("Unimplemented front face={}", static_cast<u32>(front_face)); 670 UNIMPLEMENTED_MSG("Unimplemented front face={}", front_face);
671 return {}; 671 return {};
672} 672}
673 673
@@ -680,7 +680,7 @@ VkCullModeFlags CullFace(Maxwell::CullFace cull_face) {
680 case Maxwell::CullFace::FrontAndBack: 680 case Maxwell::CullFace::FrontAndBack:
681 return VK_CULL_MODE_FRONT_AND_BACK; 681 return VK_CULL_MODE_FRONT_AND_BACK;
682 } 682 }
683 UNIMPLEMENTED_MSG("Unimplemented cull face={}", static_cast<u32>(cull_face)); 683 UNIMPLEMENTED_MSG("Unimplemented cull face={}", cull_face);
684 return {}; 684 return {};
685} 685}
686 686
@@ -700,7 +700,7 @@ VkComponentSwizzle SwizzleSource(Tegra::Texture::SwizzleSource swizzle) {
700 case Tegra::Texture::SwizzleSource::OneFloat: 700 case Tegra::Texture::SwizzleSource::OneFloat:
701 return VK_COMPONENT_SWIZZLE_ONE; 701 return VK_COMPONENT_SWIZZLE_ONE;
702 } 702 }
703 UNIMPLEMENTED_MSG("Unimplemented swizzle source={}", static_cast<u32>(swizzle)); 703 UNIMPLEMENTED_MSG("Unimplemented swizzle source={}", swizzle);
704 return {}; 704 return {};
705} 705}
706 706
@@ -723,8 +723,21 @@ VkViewportCoordinateSwizzleNV ViewportSwizzle(Maxwell::ViewportSwizzle swizzle)
723 case Maxwell::ViewportSwizzle::NegativeW: 723 case Maxwell::ViewportSwizzle::NegativeW:
724 return VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV; 724 return VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV;
725 } 725 }
726 UNREACHABLE_MSG("Invalid swizzle={}", static_cast<int>(swizzle)); 726 UNREACHABLE_MSG("Invalid swizzle={}", swizzle);
727 return {}; 727 return {};
728} 728}
729 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
730} // 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..537969840 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.h
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.h
@@ -6,10 +6,10 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "video_core/engines/maxwell_3d.h" 8#include "video_core/engines/maxwell_3d.h"
9#include "video_core/renderer_vulkan/vk_device.h"
10#include "video_core/renderer_vulkan/wrapper.h"
11#include "video_core/surface.h" 9#include "video_core/surface.h"
12#include "video_core/textures/texture.h" 10#include "video_core/textures/texture.h"
11#include "video_core/vulkan_common/vulkan_device.h"
12#include "video_core/vulkan_common/vulkan_wrapper.h"
13 13
14namespace Vulkan::MaxwellToVK { 14namespace Vulkan::MaxwellToVK {
15 15
@@ -22,7 +22,7 @@ VkFilter Filter(Tegra::Texture::TextureFilter filter);
22 22
23VkSamplerMipmapMode MipmapMode(Tegra::Texture::TextureMipmapFilter mipmap_filter); 23VkSamplerMipmapMode MipmapMode(Tegra::Texture::TextureMipmapFilter mipmap_filter);
24 24
25VkSamplerAddressMode WrapMode(const VKDevice& device, Tegra::Texture::WrapMode wrap_mode, 25VkSamplerAddressMode WrapMode(const Device& device, Tegra::Texture::WrapMode wrap_mode,
26 Tegra::Texture::TextureFilter filter); 26 Tegra::Texture::TextureFilter filter);
27 27
28VkCompareOp DepthCompareFunction(Tegra::Texture::DepthCompareFunc depth_compare_func); 28VkCompareOp DepthCompareFunction(Tegra::Texture::DepthCompareFunc depth_compare_func);
@@ -35,17 +35,17 @@ struct FormatInfo {
35 bool storage; 35 bool storage;
36}; 36};
37 37
38FormatInfo SurfaceFormat(const VKDevice& device, FormatType format_type, PixelFormat pixel_format); 38FormatInfo SurfaceFormat(const Device& device, FormatType format_type, PixelFormat pixel_format);
39 39
40VkShaderStageFlagBits ShaderStage(Tegra::Engines::ShaderType stage); 40VkShaderStageFlagBits ShaderStage(Tegra::Engines::ShaderType stage);
41 41
42VkPrimitiveTopology PrimitiveTopology(const VKDevice& device, Maxwell::PrimitiveTopology topology); 42VkPrimitiveTopology PrimitiveTopology(const Device& device, Maxwell::PrimitiveTopology topology);
43 43
44VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttribute::Size size); 44VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttribute::Size size);
45 45
46VkCompareOp ComparisonOp(Maxwell::ComparisonOp comparison); 46VkCompareOp ComparisonOp(Maxwell::ComparisonOp comparison);
47 47
48VkIndexType IndexFormat(const VKDevice& device, Maxwell::IndexFormat index_format); 48VkIndexType IndexFormat(const Device& device, Maxwell::IndexFormat index_format);
49 49
50VkStencilOp StencilOp(Maxwell::StencilOp stencil_op); 50VkStencilOp StencilOp(Maxwell::StencilOp stencil_op);
51 51
@@ -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/nsight_aftermath_tracker.cpp b/src/video_core/renderer_vulkan/nsight_aftermath_tracker.cpp
deleted file mode 100644
index 5b01020ec..000000000
--- a/src/video_core/renderer_vulkan/nsight_aftermath_tracker.cpp
+++ /dev/null
@@ -1,220 +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#ifdef HAS_NSIGHT_AFTERMATH
6
7#include <mutex>
8#include <string>
9#include <string_view>
10#include <utility>
11#include <vector>
12
13#include <fmt/format.h>
14
15#define VK_NO_PROTOTYPES
16#include <vulkan/vulkan.h>
17
18#include <GFSDK_Aftermath.h>
19#include <GFSDK_Aftermath_Defines.h>
20#include <GFSDK_Aftermath_GpuCrashDump.h>
21#include <GFSDK_Aftermath_GpuCrashDumpDecoding.h>
22
23#include "common/common_paths.h"
24#include "common/common_types.h"
25#include "common/file_util.h"
26#include "common/logging/log.h"
27#include "common/scope_exit.h"
28
29#include "video_core/renderer_vulkan/nsight_aftermath_tracker.h"
30
31namespace Vulkan {
32
33static constexpr char AFTERMATH_LIB_NAME[] = "GFSDK_Aftermath_Lib.x64.dll";
34
35NsightAftermathTracker::NsightAftermathTracker() = default;
36
37NsightAftermathTracker::~NsightAftermathTracker() {
38 if (initialized) {
39 (void)GFSDK_Aftermath_DisableGpuCrashDumps();
40 }
41}
42
43bool NsightAftermathTracker::Initialize() {
44 if (!dl.Open(AFTERMATH_LIB_NAME)) {
45 LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath DLL");
46 return false;
47 }
48
49 if (!dl.GetSymbol("GFSDK_Aftermath_DisableGpuCrashDumps",
50 &GFSDK_Aftermath_DisableGpuCrashDumps) ||
51 !dl.GetSymbol("GFSDK_Aftermath_EnableGpuCrashDumps",
52 &GFSDK_Aftermath_EnableGpuCrashDumps) ||
53 !dl.GetSymbol("GFSDK_Aftermath_GetShaderDebugInfoIdentifier",
54 &GFSDK_Aftermath_GetShaderDebugInfoIdentifier) ||
55 !dl.GetSymbol("GFSDK_Aftermath_GetShaderHashSpirv", &GFSDK_Aftermath_GetShaderHashSpirv) ||
56 !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_CreateDecoder",
57 &GFSDK_Aftermath_GpuCrashDump_CreateDecoder) ||
58 !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_DestroyDecoder",
59 &GFSDK_Aftermath_GpuCrashDump_DestroyDecoder) ||
60 !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_GenerateJSON",
61 &GFSDK_Aftermath_GpuCrashDump_GenerateJSON) ||
62 !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_GetJSON",
63 &GFSDK_Aftermath_GpuCrashDump_GetJSON)) {
64 LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath function pointers");
65 return false;
66 }
67
68 dump_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir) + "gpucrash";
69
70 (void)Common::FS::DeleteDirRecursively(dump_dir);
71 if (!Common::FS::CreateDir(dump_dir)) {
72 LOG_ERROR(Render_Vulkan, "Failed to create Nsight Aftermath dump directory");
73 return false;
74 }
75
76 if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_EnableGpuCrashDumps(
77 GFSDK_Aftermath_Version_API, GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_Vulkan,
78 GFSDK_Aftermath_GpuCrashDumpFeatureFlags_Default, GpuCrashDumpCallback,
79 ShaderDebugInfoCallback, CrashDumpDescriptionCallback, this))) {
80 LOG_ERROR(Render_Vulkan, "GFSDK_Aftermath_EnableGpuCrashDumps failed");
81 return false;
82 }
83
84 LOG_INFO(Render_Vulkan, "Nsight Aftermath dump directory is \"{}\"", dump_dir);
85
86 initialized = true;
87 return true;
88}
89
90void NsightAftermathTracker::SaveShader(const std::vector<u32>& spirv) const {
91 if (!initialized) {
92 return;
93 }
94
95 std::vector<u32> spirv_copy = spirv;
96 GFSDK_Aftermath_SpirvCode shader;
97 shader.pData = spirv_copy.data();
98 shader.size = static_cast<u32>(spirv_copy.size() * 4);
99
100 std::scoped_lock lock{mutex};
101
102 GFSDK_Aftermath_ShaderHash hash;
103 if (!GFSDK_Aftermath_SUCCEED(
104 GFSDK_Aftermath_GetShaderHashSpirv(GFSDK_Aftermath_Version_API, &shader, &hash))) {
105 LOG_ERROR(Render_Vulkan, "Failed to hash SPIR-V module");
106 return;
107 }
108
109 Common::FS::IOFile file(fmt::format("{}/source_{:016x}.spv", dump_dir, hash.hash), "wb");
110 if (!file.IsOpen()) {
111 LOG_ERROR(Render_Vulkan, "Failed to dump SPIR-V module with hash={:016x}", hash.hash);
112 return;
113 }
114 if (file.WriteArray(spirv.data(), spirv.size()) != spirv.size()) {
115 LOG_ERROR(Render_Vulkan, "Failed to write SPIR-V module with hash={:016x}", hash.hash);
116 return;
117 }
118}
119
120void NsightAftermathTracker::OnGpuCrashDumpCallback(const void* gpu_crash_dump,
121 u32 gpu_crash_dump_size) {
122 std::scoped_lock lock{mutex};
123
124 LOG_CRITICAL(Render_Vulkan, "called");
125
126 GFSDK_Aftermath_GpuCrashDump_Decoder decoder;
127 if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_CreateDecoder(
128 GFSDK_Aftermath_Version_API, gpu_crash_dump, gpu_crash_dump_size, &decoder))) {
129 LOG_ERROR(Render_Vulkan, "Failed to create decoder");
130 return;
131 }
132 SCOPE_EXIT({ GFSDK_Aftermath_GpuCrashDump_DestroyDecoder(decoder); });
133
134 u32 json_size = 0;
135 if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_GenerateJSON(
136 decoder, GFSDK_Aftermath_GpuCrashDumpDecoderFlags_ALL_INFO,
137 GFSDK_Aftermath_GpuCrashDumpFormatterFlags_NONE, nullptr, nullptr, nullptr, nullptr,
138 this, &json_size))) {
139 LOG_ERROR(Render_Vulkan, "Failed to generate JSON");
140 return;
141 }
142 std::vector<char> json(json_size);
143 if (!GFSDK_Aftermath_SUCCEED(
144 GFSDK_Aftermath_GpuCrashDump_GetJSON(decoder, json_size, json.data()))) {
145 LOG_ERROR(Render_Vulkan, "Failed to query JSON");
146 return;
147 }
148
149 const std::string base_name = [this] {
150 const int id = dump_id++;
151 if (id == 0) {
152 return fmt::format("{}/crash.nv-gpudmp", dump_dir);
153 } else {
154 return fmt::format("{}/crash_{}.nv-gpudmp", dump_dir, id);
155 }
156 }();
157
158 std::string_view dump_view(static_cast<const char*>(gpu_crash_dump), gpu_crash_dump_size);
159 if (Common::FS::WriteStringToFile(false, base_name, dump_view) != gpu_crash_dump_size) {
160 LOG_ERROR(Render_Vulkan, "Failed to write dump file");
161 return;
162 }
163 const std::string_view json_view(json.data(), json.size());
164 if (Common::FS::WriteStringToFile(true, base_name + ".json", json_view) != json.size()) {
165 LOG_ERROR(Render_Vulkan, "Failed to write JSON");
166 return;
167 }
168}
169
170void NsightAftermathTracker::OnShaderDebugInfoCallback(const void* shader_debug_info,
171 u32 shader_debug_info_size) {
172 std::scoped_lock lock{mutex};
173
174 GFSDK_Aftermath_ShaderDebugInfoIdentifier identifier;
175 if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GetShaderDebugInfoIdentifier(
176 GFSDK_Aftermath_Version_API, shader_debug_info, shader_debug_info_size, &identifier))) {
177 LOG_ERROR(Render_Vulkan, "GFSDK_Aftermath_GetShaderDebugInfoIdentifier failed");
178 return;
179 }
180
181 const std::string path =
182 fmt::format("{}/shader_{:016x}{:016x}.nvdbg", dump_dir, identifier.id[0], identifier.id[1]);
183 Common::FS::IOFile file(path, "wb");
184 if (!file.IsOpen()) {
185 LOG_ERROR(Render_Vulkan, "Failed to create file {}", path);
186 return;
187 }
188 if (file.WriteBytes(static_cast<const u8*>(shader_debug_info), shader_debug_info_size) !=
189 shader_debug_info_size) {
190 LOG_ERROR(Render_Vulkan, "Failed to write file {}", path);
191 return;
192 }
193}
194
195void NsightAftermathTracker::OnCrashDumpDescriptionCallback(
196 PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description) {
197 add_description(GFSDK_Aftermath_GpuCrashDumpDescriptionKey_ApplicationName, "yuzu");
198}
199
200void NsightAftermathTracker::GpuCrashDumpCallback(const void* gpu_crash_dump,
201 u32 gpu_crash_dump_size, void* user_data) {
202 static_cast<NsightAftermathTracker*>(user_data)->OnGpuCrashDumpCallback(gpu_crash_dump,
203 gpu_crash_dump_size);
204}
205
206void NsightAftermathTracker::ShaderDebugInfoCallback(const void* shader_debug_info,
207 u32 shader_debug_info_size, void* user_data) {
208 static_cast<NsightAftermathTracker*>(user_data)->OnShaderDebugInfoCallback(
209 shader_debug_info, shader_debug_info_size);
210}
211
212void NsightAftermathTracker::CrashDumpDescriptionCallback(
213 PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description, void* user_data) {
214 static_cast<NsightAftermathTracker*>(user_data)->OnCrashDumpDescriptionCallback(
215 add_description);
216}
217
218} // namespace Vulkan
219
220#endif // HAS_NSIGHT_AFTERMATH
diff --git a/src/video_core/renderer_vulkan/nsight_aftermath_tracker.h b/src/video_core/renderer_vulkan/nsight_aftermath_tracker.h
deleted file mode 100644
index afe7ae99e..000000000
--- a/src/video_core/renderer_vulkan/nsight_aftermath_tracker.h
+++ /dev/null
@@ -1,87 +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#pragma once
6
7#include <mutex>
8#include <string>
9#include <vector>
10
11#define VK_NO_PROTOTYPES
12#include <vulkan/vulkan.h>
13
14#ifdef HAS_NSIGHT_AFTERMATH
15#include <GFSDK_Aftermath_Defines.h>
16#include <GFSDK_Aftermath_GpuCrashDump.h>
17#include <GFSDK_Aftermath_GpuCrashDumpDecoding.h>
18#endif
19
20#include "common/common_types.h"
21#include "common/dynamic_library.h"
22
23namespace Vulkan {
24
25class NsightAftermathTracker {
26public:
27 NsightAftermathTracker();
28 ~NsightAftermathTracker();
29
30 NsightAftermathTracker(const NsightAftermathTracker&) = delete;
31 NsightAftermathTracker& operator=(const NsightAftermathTracker&) = delete;
32
33 // Delete move semantics because Aftermath initialization uses a pointer to this.
34 NsightAftermathTracker(NsightAftermathTracker&&) = delete;
35 NsightAftermathTracker& operator=(NsightAftermathTracker&&) = delete;
36
37 bool Initialize();
38
39 void SaveShader(const std::vector<u32>& spirv) const;
40
41private:
42#ifdef HAS_NSIGHT_AFTERMATH
43 static void GpuCrashDumpCallback(const void* gpu_crash_dump, u32 gpu_crash_dump_size,
44 void* user_data);
45
46 static void ShaderDebugInfoCallback(const void* shader_debug_info, u32 shader_debug_info_size,
47 void* user_data);
48
49 static void CrashDumpDescriptionCallback(
50 PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description, void* user_data);
51
52 void OnGpuCrashDumpCallback(const void* gpu_crash_dump, u32 gpu_crash_dump_size);
53
54 void OnShaderDebugInfoCallback(const void* shader_debug_info, u32 shader_debug_info_size);
55
56 void OnCrashDumpDescriptionCallback(
57 PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description);
58
59 mutable std::mutex mutex;
60
61 std::string dump_dir;
62 int dump_id = 0;
63
64 bool initialized = false;
65
66 Common::DynamicLibrary dl;
67 PFN_GFSDK_Aftermath_DisableGpuCrashDumps GFSDK_Aftermath_DisableGpuCrashDumps;
68 PFN_GFSDK_Aftermath_EnableGpuCrashDumps GFSDK_Aftermath_EnableGpuCrashDumps;
69 PFN_GFSDK_Aftermath_GetShaderDebugInfoIdentifier GFSDK_Aftermath_GetShaderDebugInfoIdentifier;
70 PFN_GFSDK_Aftermath_GetShaderHashSpirv GFSDK_Aftermath_GetShaderHashSpirv;
71 PFN_GFSDK_Aftermath_GpuCrashDump_CreateDecoder GFSDK_Aftermath_GpuCrashDump_CreateDecoder;
72 PFN_GFSDK_Aftermath_GpuCrashDump_DestroyDecoder GFSDK_Aftermath_GpuCrashDump_DestroyDecoder;
73 PFN_GFSDK_Aftermath_GpuCrashDump_GenerateJSON GFSDK_Aftermath_GpuCrashDump_GenerateJSON;
74 PFN_GFSDK_Aftermath_GpuCrashDump_GetJSON GFSDK_Aftermath_GpuCrashDump_GetJSON;
75#endif
76};
77
78#ifndef HAS_NSIGHT_AFTERMATH
79inline NsightAftermathTracker::NsightAftermathTracker() = default;
80inline NsightAftermathTracker::~NsightAftermathTracker() = default;
81inline bool NsightAftermathTracker::Initialize() {
82 return false;
83}
84inline void NsightAftermathTracker::SaveShader(const std::vector<u32>&) const {}
85#endif
86
87} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 715182b3b..d7437e185 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -12,8 +12,6 @@
12 12
13#include <fmt/format.h> 13#include <fmt/format.h>
14 14
15#include "common/dynamic_library.h"
16#include "common/file_util.h"
17#include "common/logging/log.h" 15#include "common/logging/log.h"
18#include "common/telemetry.h" 16#include "common/telemetry.h"
19#include "core/core.h" 17#include "core/core.h"
@@ -24,179 +22,27 @@
24#include "video_core/gpu.h" 22#include "video_core/gpu.h"
25#include "video_core/renderer_vulkan/renderer_vulkan.h" 23#include "video_core/renderer_vulkan/renderer_vulkan.h"
26#include "video_core/renderer_vulkan/vk_blit_screen.h" 24#include "video_core/renderer_vulkan/vk_blit_screen.h"
27#include "video_core/renderer_vulkan/vk_device.h"
28#include "video_core/renderer_vulkan/vk_master_semaphore.h" 25#include "video_core/renderer_vulkan/vk_master_semaphore.h"
29#include "video_core/renderer_vulkan/vk_memory_manager.h" 26#include "video_core/renderer_vulkan/vk_memory_manager.h"
30#include "video_core/renderer_vulkan/vk_rasterizer.h" 27#include "video_core/renderer_vulkan/vk_rasterizer.h"
31#include "video_core/renderer_vulkan/vk_scheduler.h" 28#include "video_core/renderer_vulkan/vk_scheduler.h"
32#include "video_core/renderer_vulkan/vk_state_tracker.h" 29#include "video_core/renderer_vulkan/vk_state_tracker.h"
33#include "video_core/renderer_vulkan/vk_swapchain.h" 30#include "video_core/renderer_vulkan/vk_swapchain.h"
34#include "video_core/renderer_vulkan/wrapper.h" 31#include "video_core/vulkan_common/vulkan_debug_callback.h"
35 32#include "video_core/vulkan_common/vulkan_device.h"
36// Include these late to avoid polluting previous headers 33#include "video_core/vulkan_common/vulkan_instance.h"
37#ifdef _WIN32 34#include "video_core/vulkan_common/vulkan_library.h"
38#include <windows.h> 35#include "video_core/vulkan_common/vulkan_surface.h"
39// ensure include order 36#include "video_core/vulkan_common/vulkan_wrapper.h"
40#include <vulkan/vulkan_win32.h>
41#endif
42
43#if !defined(_WIN32) && !defined(__APPLE__)
44#include <X11/Xlib.h>
45#include <vulkan/vulkan_wayland.h>
46#include <vulkan/vulkan_xlib.h>
47#endif
48 37
49namespace Vulkan { 38namespace Vulkan {
50
51namespace { 39namespace {
52
53using Core::Frontend::WindowSystemType;
54
55VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
56 VkDebugUtilsMessageTypeFlagsEXT type,
57 const VkDebugUtilsMessengerCallbackDataEXT* data,
58 [[maybe_unused]] void* user_data) {
59 const char* const message{data->pMessage};
60
61 if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
62 LOG_CRITICAL(Render_Vulkan, "{}", message);
63 } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
64 LOG_WARNING(Render_Vulkan, "{}", message);
65 } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
66 LOG_INFO(Render_Vulkan, "{}", message);
67 } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
68 LOG_DEBUG(Render_Vulkan, "{}", message);
69 }
70 return VK_FALSE;
71}
72
73Common::DynamicLibrary OpenVulkanLibrary() {
74 Common::DynamicLibrary library;
75#ifdef __APPLE__
76 // Check if a path to a specific Vulkan library has been specified.
77 char* libvulkan_env = getenv("LIBVULKAN_PATH");
78 if (!libvulkan_env || !library.Open(libvulkan_env)) {
79 // Use the libvulkan.dylib from the application bundle.
80 const std::string filename =
81 Common::FS::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib";
82 library.Open(filename.c_str());
83 }
84#else
85 std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);
86 if (!library.Open(filename.c_str())) {
87 // Android devices may not have libvulkan.so.1, only libvulkan.so.
88 filename = Common::DynamicLibrary::GetVersionedFilename("vulkan");
89 (void)library.Open(filename.c_str());
90 }
91#endif
92 return library;
93}
94
95vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatch& dld,
96 WindowSystemType window_type = WindowSystemType::Headless,
97 bool enable_layers = false) {
98 if (!library.IsOpen()) {
99 LOG_ERROR(Render_Vulkan, "Vulkan library not available");
100 return {};
101 }
102 if (!library.GetSymbol("vkGetInstanceProcAddr", &dld.vkGetInstanceProcAddr)) {
103 LOG_ERROR(Render_Vulkan, "vkGetInstanceProcAddr not present in Vulkan");
104 return {};
105 }
106 if (!vk::Load(dld)) {
107 LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers");
108 return {};
109 }
110
111 std::vector<const char*> extensions;
112 extensions.reserve(6);
113 switch (window_type) {
114 case Core::Frontend::WindowSystemType::Headless:
115 break;
116#ifdef _WIN32
117 case Core::Frontend::WindowSystemType::Windows:
118 extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
119 break;
120#endif
121#if !defined(_WIN32) && !defined(__APPLE__)
122 case Core::Frontend::WindowSystemType::X11:
123 extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
124 break;
125 case Core::Frontend::WindowSystemType::Wayland:
126 extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
127 break;
128#endif
129 default:
130 LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
131 break;
132 }
133 if (window_type != Core::Frontend::WindowSystemType::Headless) {
134 extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
135 }
136 if (enable_layers) {
137 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
138 }
139 extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
140
141 const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
142 if (!properties) {
143 LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
144 return {};
145 }
146
147 for (const char* extension : extensions) {
148 const auto it =
149 std::find_if(properties->begin(), properties->end(), [extension](const auto& prop) {
150 return !std::strcmp(extension, prop.extensionName);
151 });
152 if (it == properties->end()) {
153 LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension);
154 return {};
155 }
156 }
157
158 std::vector<const char*> layers;
159 layers.reserve(1);
160 if (enable_layers) {
161 layers.push_back("VK_LAYER_KHRONOS_validation");
162 }
163
164 const std::optional layer_properties = vk::EnumerateInstanceLayerProperties(dld);
165 if (!layer_properties) {
166 LOG_ERROR(Render_Vulkan, "Failed to query layer properties, disabling layers");
167 layers.clear();
168 }
169
170 for (auto layer_it = layers.begin(); layer_it != layers.end();) {
171 const char* const layer = *layer_it;
172 const auto it = std::find_if(
173 layer_properties->begin(), layer_properties->end(),
174 [layer](const VkLayerProperties& prop) { return !std::strcmp(layer, prop.layerName); });
175 if (it == layer_properties->end()) {
176 LOG_ERROR(Render_Vulkan, "Layer {} not available, removing it", layer);
177 layer_it = layers.erase(layer_it);
178 } else {
179 ++layer_it;
180 }
181 }
182
183 vk::Instance instance = vk::Instance::Create(layers, extensions, dld);
184 if (!instance) {
185 LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance");
186 return {};
187 }
188 if (!vk::Load(*instance, dld)) {
189 LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers");
190 }
191 return instance;
192}
193
194std::string GetReadableVersion(u32 version) { 40std::string GetReadableVersion(u32 version) {
195 return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), 41 return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version),
196 VK_VERSION_PATCH(version)); 42 VK_VERSION_PATCH(version));
197} 43}
198 44
199std::string GetDriverVersion(const VKDevice& device) { 45std::string GetDriverVersion(const Device& device) {
200 // Extracted from 46 // Extracted from
201 // https://github.com/SaschaWillems/vulkan.gpuinfo.org/blob/5dddea46ea1120b0df14eef8f15ff8e318e35462/functions.php#L308-L314 47 // https://github.com/SaschaWillems/vulkan.gpuinfo.org/blob/5dddea46ea1120b0df14eef8f15ff8e318e35462/functions.php#L308-L314
202 const u32 version = device.GetDriverVersion(); 48 const u32 version = device.GetDriverVersion();
@@ -213,7 +59,6 @@ std::string GetDriverVersion(const VKDevice& device) {
213 const u32 minor = version & 0x3fff; 59 const u32 minor = version & 0x3fff;
214 return fmt::format("{}.{}", major, minor); 60 return fmt::format("{}.{}", major, minor);
215 } 61 }
216
217 return GetReadableVersion(version); 62 return GetReadableVersion(version);
218} 63}
219 64
@@ -240,8 +85,8 @@ std::string BuildCommaSeparatedExtensions(std::vector<std::string> available_ext
240RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, 85RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
241 Core::Frontend::EmuWindow& emu_window, 86 Core::Frontend::EmuWindow& emu_window,
242 Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, 87 Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
243 std::unique_ptr<Core::Frontend::GraphicsContext> context) 88 std::unique_ptr<Core::Frontend::GraphicsContext> context_)
244 : RendererBase{emu_window, std::move(context)}, telemetry_session{telemetry_session_}, 89 : RendererBase{emu_window, std::move(context_)}, telemetry_session{telemetry_session_},
245 cpu_memory{cpu_memory_}, gpu{gpu_} {} 90 cpu_memory{cpu_memory_}, gpu{gpu_} {}
246 91
247RendererVulkan::~RendererVulkan() { 92RendererVulkan::~RendererVulkan() {
@@ -249,12 +94,9 @@ RendererVulkan::~RendererVulkan() {
249} 94}
250 95
251void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { 96void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
252 render_window.PollEvents();
253
254 if (!framebuffer) { 97 if (!framebuffer) {
255 return; 98 return;
256 } 99 }
257
258 const auto& layout = render_window.GetFramebufferLayout(); 100 const auto& layout = render_window.GetFramebufferLayout();
259 if (layout.width > 0 && layout.height > 0 && render_window.IsShown()) { 101 if (layout.width > 0 && layout.height > 0 && render_window.IsShown()) {
260 const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; 102 const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset;
@@ -280,17 +122,19 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
280 rasterizer->TickFrame(); 122 rasterizer->TickFrame();
281 } 123 }
282 124
283 render_window.PollEvents(); 125 render_window.OnFrameDisplayed();
284} 126}
285 127
286bool RendererVulkan::Init() { 128bool RendererVulkan::Init() try {
287 library = OpenVulkanLibrary(); 129 library = OpenLibrary();
288 instance = CreateInstance(library, dld, render_window.GetWindowInfo().type, 130 instance = CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
289 Settings::values.renderer_debug); 131 true, Settings::values.renderer_debug);
290 if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) { 132 if (Settings::values.renderer_debug) {
291 return false; 133 debug_callback = CreateDebugCallback(instance);
292 } 134 }
135 surface = CreateSurface(instance, render_window);
293 136
137 InitializeDevice();
294 Report(); 138 Report();
295 139
296 memory_manager = std::make_unique<VKMemoryManager>(*device); 140 memory_manager = std::make_unique<VKMemoryManager>(*device);
@@ -310,8 +154,11 @@ bool RendererVulkan::Init() {
310 blit_screen = 154 blit_screen =
311 std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device, 155 std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device,
312 *memory_manager, *swapchain, *scheduler, screen_info); 156 *memory_manager, *swapchain, *scheduler, screen_info);
313
314 return true; 157 return true;
158
159} catch (const vk::Exception& exception) {
160 LOG_ERROR(Render_Vulkan, "Vulkan initialization failed with error: {}", exception.what());
161 return false;
315} 162}
316 163
317void RendererVulkan::ShutDown() { 164void RendererVulkan::ShutDown() {
@@ -321,7 +168,6 @@ void RendererVulkan::ShutDown() {
321 if (const auto& dev = device->GetLogical()) { 168 if (const auto& dev = device->GetLogical()) {
322 dev.WaitIdle(); 169 dev.WaitIdle();
323 } 170 }
324
325 rasterizer.reset(); 171 rasterizer.reset();
326 blit_screen.reset(); 172 blit_screen.reset();
327 scheduler.reset(); 173 scheduler.reset();
@@ -330,94 +176,15 @@ void RendererVulkan::ShutDown() {
330 device.reset(); 176 device.reset();
331} 177}
332 178
333bool RendererVulkan::CreateDebugCallback() { 179void RendererVulkan::InitializeDevice() {
334 if (!Settings::values.renderer_debug) { 180 const std::vector<VkPhysicalDevice> devices = instance.EnumeratePhysicalDevices();
335 return true;
336 }
337 debug_callback = instance.TryCreateDebugCallback(DebugCallback);
338 if (!debug_callback) {
339 LOG_ERROR(Render_Vulkan, "Failed to create debug callback");
340 return false;
341 }
342 return true;
343}
344
345bool RendererVulkan::CreateSurface() {
346 [[maybe_unused]] const auto& window_info = render_window.GetWindowInfo();
347 VkSurfaceKHR unsafe_surface = nullptr;
348
349#ifdef _WIN32
350 if (window_info.type == Core::Frontend::WindowSystemType::Windows) {
351 const HWND hWnd = static_cast<HWND>(window_info.render_surface);
352 const VkWin32SurfaceCreateInfoKHR win32_ci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
353 nullptr, 0, nullptr, hWnd};
354 const auto vkCreateWin32SurfaceKHR = reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>(
355 dld.vkGetInstanceProcAddr(*instance, "vkCreateWin32SurfaceKHR"));
356 if (!vkCreateWin32SurfaceKHR ||
357 vkCreateWin32SurfaceKHR(*instance, &win32_ci, nullptr, &unsafe_surface) != VK_SUCCESS) {
358 LOG_ERROR(Render_Vulkan, "Failed to initialize Win32 surface");
359 return false;
360 }
361 }
362#endif
363#if !defined(_WIN32) && !defined(__APPLE__)
364 if (window_info.type == Core::Frontend::WindowSystemType::X11) {
365 const VkXlibSurfaceCreateInfoKHR xlib_ci{
366 VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0,
367 static_cast<Display*>(window_info.display_connection),
368 reinterpret_cast<Window>(window_info.render_surface)};
369 const auto vkCreateXlibSurfaceKHR = reinterpret_cast<PFN_vkCreateXlibSurfaceKHR>(
370 dld.vkGetInstanceProcAddr(*instance, "vkCreateXlibSurfaceKHR"));
371 if (!vkCreateXlibSurfaceKHR ||
372 vkCreateXlibSurfaceKHR(*instance, &xlib_ci, nullptr, &unsafe_surface) != VK_SUCCESS) {
373 LOG_ERROR(Render_Vulkan, "Failed to initialize Xlib surface");
374 return false;
375 }
376 }
377 if (window_info.type == Core::Frontend::WindowSystemType::Wayland) {
378 const VkWaylandSurfaceCreateInfoKHR wayland_ci{
379 VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0,
380 static_cast<wl_display*>(window_info.display_connection),
381 static_cast<wl_surface*>(window_info.render_surface)};
382 const auto vkCreateWaylandSurfaceKHR = reinterpret_cast<PFN_vkCreateWaylandSurfaceKHR>(
383 dld.vkGetInstanceProcAddr(*instance, "vkCreateWaylandSurfaceKHR"));
384 if (!vkCreateWaylandSurfaceKHR ||
385 vkCreateWaylandSurfaceKHR(*instance, &wayland_ci, nullptr, &unsafe_surface) !=
386 VK_SUCCESS) {
387 LOG_ERROR(Render_Vulkan, "Failed to initialize Wayland surface");
388 return false;
389 }
390 }
391#endif
392 if (!unsafe_surface) {
393 LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
394 return false;
395 }
396
397 surface = vk::SurfaceKHR(unsafe_surface, *instance, dld);
398 return true;
399}
400
401bool RendererVulkan::PickDevices() {
402 const auto devices = instance.EnumeratePhysicalDevices();
403 if (!devices) {
404 LOG_ERROR(Render_Vulkan, "Failed to enumerate physical devices");
405 return false;
406 }
407
408 const s32 device_index = Settings::values.vulkan_device.GetValue(); 181 const s32 device_index = Settings::values.vulkan_device.GetValue();
409 if (device_index < 0 || device_index >= static_cast<s32>(devices->size())) { 182 if (device_index < 0 || device_index >= static_cast<s32>(devices.size())) {
410 LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index); 183 LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index);
411 return false; 184 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
412 }
413 const vk::PhysicalDevice physical_device((*devices)[static_cast<std::size_t>(device_index)],
414 dld);
415 if (!VKDevice::IsSuitable(physical_device, *surface)) {
416 return false;
417 } 185 }
418 186 const vk::PhysicalDevice physical_device(devices[static_cast<size_t>(device_index)], dld);
419 device = std::make_unique<VKDevice>(*instance, physical_device, *surface, dld); 187 device = std::make_unique<Device>(*instance, physical_device, *surface, dld);
420 return device->Create();
421} 188}
422 189
423void RendererVulkan::Report() const { 190void RendererVulkan::Report() const {
@@ -426,7 +193,7 @@ void RendererVulkan::Report() const {
426 const std::string driver_version = GetDriverVersion(*device); 193 const std::string driver_version = GetDriverVersion(*device);
427 const std::string driver_name = fmt::format("{} {}", vendor_name, driver_version); 194 const std::string driver_name = fmt::format("{} {}", vendor_name, driver_version);
428 195
429 const std::string api_version = GetReadableVersion(device->GetApiVersion()); 196 const std::string api_version = GetReadableVersion(device->ApiVersion());
430 197
431 const std::string extensions = BuildCommaSeparatedExtensions(device->GetAvailableExtensions()); 198 const std::string extensions = BuildCommaSeparatedExtensions(device->GetAvailableExtensions());
432 199
@@ -442,25 +209,21 @@ void RendererVulkan::Report() const {
442 telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); 209 telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions);
443} 210}
444 211
445std::vector<std::string> RendererVulkan::EnumerateDevices() { 212std::vector<std::string> RendererVulkan::EnumerateDevices() try {
446 vk::InstanceDispatch dld; 213 vk::InstanceDispatch dld;
447 Common::DynamicLibrary library = OpenVulkanLibrary(); 214 const Common::DynamicLibrary library = OpenLibrary();
448 vk::Instance instance = CreateInstance(library, dld); 215 const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_0);
449 if (!instance) { 216 const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
450 return {};
451 }
452
453 const std::optional physical_devices = instance.EnumeratePhysicalDevices();
454 if (!physical_devices) {
455 return {};
456 }
457
458 std::vector<std::string> names; 217 std::vector<std::string> names;
459 names.reserve(physical_devices->size()); 218 names.reserve(physical_devices.size());
460 for (const auto& device : *physical_devices) { 219 for (const VkPhysicalDevice device : physical_devices) {
461 names.push_back(vk::PhysicalDevice(device, dld).GetProperties().deviceName); 220 names.push_back(vk::PhysicalDevice(device, dld).GetProperties().deviceName);
462 } 221 }
463 return names; 222 return names;
223
224} catch (const vk::Exception& exception) {
225 LOG_ERROR(Render_Vulkan, "Failed to enumerate devices with error: {}", exception.what());
226 return {};
464} 227}
465 228
466} // namespace Vulkan 229} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index 49a4141ec..5575ffc54 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -11,7 +11,7 @@
11#include "common/dynamic_library.h" 11#include "common/dynamic_library.h"
12 12
13#include "video_core/renderer_base.h" 13#include "video_core/renderer_base.h"
14#include "video_core/renderer_vulkan/wrapper.h" 14#include "video_core/vulkan_common/vulkan_wrapper.h"
15 15
16namespace Core { 16namespace Core {
17class TelemetrySession; 17class TelemetrySession;
@@ -27,16 +27,15 @@ class GPU;
27 27
28namespace Vulkan { 28namespace Vulkan {
29 29
30class Device;
30class StateTracker; 31class StateTracker;
31class VKBlitScreen; 32class VKBlitScreen;
32class 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{};
@@ -45,9 +44,9 @@ struct VKScreenInfo {
45class RendererVulkan final : public VideoCore::RendererBase { 44class RendererVulkan final : public VideoCore::RendererBase {
46public: 45public:
47 explicit RendererVulkan(Core::TelemetrySession& telemtry_session, 46 explicit RendererVulkan(Core::TelemetrySession& telemtry_session,
48 Core::Frontend::EmuWindow& emu_window, Core::Memory::Memory& cpu_memory, 47 Core::Frontend::EmuWindow& emu_window,
49 Tegra::GPU& gpu, 48 Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
50 std::unique_ptr<Core::Frontend::GraphicsContext> context); 49 std::unique_ptr<Core::Frontend::GraphicsContext> context_);
51 ~RendererVulkan() override; 50 ~RendererVulkan() override;
52 51
53 bool Init() override; 52 bool Init() override;
@@ -57,11 +56,7 @@ public:
57 static std::vector<std::string> EnumerateDevices(); 56 static std::vector<std::string> EnumerateDevices();
58 57
59private: 58private:
60 bool CreateDebugCallback(); 59 void InitializeDevice();
61
62 bool CreateSurface();
63
64 bool PickDevices();
65 60
66 void Report() const; 61 void Report() const;
67 62
@@ -73,12 +68,13 @@ private:
73 vk::InstanceDispatch dld; 68 vk::InstanceDispatch dld;
74 69
75 vk::Instance instance; 70 vk::Instance instance;
71
76 vk::SurfaceKHR surface; 72 vk::SurfaceKHR surface;
77 73
78 VKScreenInfo screen_info; 74 VKScreenInfo screen_info;
79 75
80 vk::DebugCallback debug_callback; 76 vk::DebugUtilsMessenger debug_callback;
81 std::unique_ptr<VKDevice> device; 77 std::unique_ptr<Device> device;
82 std::unique_ptr<VKMemoryManager> memory_manager; 78 std::unique_ptr<VKMemoryManager> memory_manager;
83 std::unique_ptr<StateTracker> state_tracker; 79 std::unique_ptr<StateTracker> state_tracker;
84 std::unique_ptr<VKScheduler> scheduler; 80 std::unique_ptr<VKScheduler> scheduler;
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..5e184eb42 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -16,121 +16,25 @@
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_image.h"
25#include "video_core/renderer_vulkan/vk_master_semaphore.h" 24#include "video_core/renderer_vulkan/vk_master_semaphore.h"
26#include "video_core/renderer_vulkan/vk_memory_manager.h" 25#include "video_core/renderer_vulkan/vk_memory_manager.h"
27#include "video_core/renderer_vulkan/vk_scheduler.h" 26#include "video_core/renderer_vulkan/vk_scheduler.h"
28#include "video_core/renderer_vulkan/vk_shader_util.h" 27#include "video_core/renderer_vulkan/vk_shader_util.h"
29#include "video_core/renderer_vulkan/vk_swapchain.h" 28#include "video_core/renderer_vulkan/vk_swapchain.h"
30#include "video_core/renderer_vulkan/wrapper.h"
31#include "video_core/surface.h" 29#include "video_core/surface.h"
30#include "video_core/textures/decoders.h"
31#include "video_core/vulkan_common/vulkan_device.h"
32#include "video_core/vulkan_common/vulkan_wrapper.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) {
@@ -210,7 +114,7 @@ struct VKBlitScreen::BufferData {
210 114
211VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_, 115VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_,
212 Core::Frontend::EmuWindow& render_window_, 116 Core::Frontend::EmuWindow& render_window_,
213 VideoCore::RasterizerInterface& rasterizer_, const VKDevice& device_, 117 VideoCore::RasterizerInterface& rasterizer_, const Device& device_,
214 VKMemoryManager& memory_manager_, VKSwapchain& swapchain_, 118 VKMemoryManager& memory_manager_, VKSwapchain& swapchain_,
215 VKScheduler& scheduler_, const VKScreenInfo& screen_info_) 119 VKScheduler& scheduler_, const VKScreenInfo& screen_info_)
216 : cpu_memory{cpu_memory_}, render_window{render_window_}, rasterizer{rasterizer_}, 120 : cpu_memory{cpu_memory_}, render_window{render_window_}, rasterizer{rasterizer_},
@@ -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..69ed61770 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.h
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.h
@@ -7,7 +7,7 @@
7#include <memory> 7#include <memory>
8 8
9#include "video_core/renderer_vulkan/vk_memory_manager.h" 9#include "video_core/renderer_vulkan/vk_memory_manager.h"
10#include "video_core/renderer_vulkan/wrapper.h" 10#include "video_core/vulkan_common/vulkan_wrapper.h"
11 11
12namespace Core { 12namespace Core {
13class System; 13class System;
@@ -33,9 +33,8 @@ namespace Vulkan {
33 33
34struct ScreenInfo; 34struct ScreenInfo;
35 35
36class Device;
36class RasterizerVulkan; 37class RasterizerVulkan;
37class VKDevice;
38class VKImage;
39class VKScheduler; 38class VKScheduler;
40class VKSwapchain; 39class VKSwapchain;
41 40
@@ -43,7 +42,7 @@ class VKBlitScreen final {
43public: 42public:
44 explicit VKBlitScreen(Core::Memory::Memory& cpu_memory, 43 explicit VKBlitScreen(Core::Memory::Memory& cpu_memory,
45 Core::Frontend::EmuWindow& render_window, 44 Core::Frontend::EmuWindow& render_window,
46 VideoCore::RasterizerInterface& rasterizer, const VKDevice& device, 45 VideoCore::RasterizerInterface& rasterizer, const Device& device,
47 VKMemoryManager& memory_manager, VKSwapchain& swapchain, 46 VKMemoryManager& memory_manager, VKSwapchain& swapchain,
48 VKScheduler& scheduler, const VKScreenInfo& screen_info); 47 VKScheduler& scheduler, const VKScreenInfo& screen_info);
49 ~VKBlitScreen(); 48 ~VKBlitScreen();
@@ -86,7 +85,7 @@ private:
86 Core::Memory::Memory& cpu_memory; 85 Core::Memory::Memory& cpu_memory;
87 Core::Frontend::EmuWindow& render_window; 86 Core::Frontend::EmuWindow& render_window;
88 VideoCore::RasterizerInterface& rasterizer; 87 VideoCore::RasterizerInterface& rasterizer;
89 const VKDevice& device; 88 const Device& device;
90 VKMemoryManager& memory_manager; 89 VKMemoryManager& memory_manager;
91 VKSwapchain& swapchain; 90 VKSwapchain& swapchain;
92 VKScheduler& scheduler; 91 VKScheduler& scheduler;
@@ -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 d9d3da9ea..4d517c547 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -9,10 +9,10 @@
9#include "core/core.h" 9#include "core/core.h"
10#include "video_core/buffer_cache/buffer_cache.h" 10#include "video_core/buffer_cache/buffer_cache.h"
11#include "video_core/renderer_vulkan/vk_buffer_cache.h" 11#include "video_core/renderer_vulkan/vk_buffer_cache.h"
12#include "video_core/renderer_vulkan/vk_device.h"
13#include "video_core/renderer_vulkan/vk_scheduler.h" 12#include "video_core/renderer_vulkan/vk_scheduler.h"
14#include "video_core/renderer_vulkan/vk_stream_buffer.h" 13#include "video_core/renderer_vulkan/vk_stream_buffer.h"
15#include "video_core/renderer_vulkan/wrapper.h" 14#include "video_core/vulkan_common/vulkan_device.h"
15#include "video_core/vulkan_common/vulkan_wrapper.h"
16 16
17namespace Vulkan { 17namespace Vulkan {
18 18
@@ -31,20 +31,24 @@ 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
34std::unique_ptr<VKStreamBuffer> CreateStreamBuffer(const VKDevice& device, VKScheduler& scheduler) { 34constexpr VkAccessFlags TRANSFORM_FEEDBACK_WRITE_ACCESS =
35 return std::make_unique<VKStreamBuffer>(device, scheduler, BUFFER_USAGE); 35 VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT;
36
37std::unique_ptr<VKStreamBuffer> CreateStreamBuffer(const Device& device, VKScheduler& scheduler) {
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 Device& 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,
46 .flags = 0, 50 .flags = 0,
47 .size = static_cast<VkDeviceSize>(size), 51 .size = static_cast<VkDeviceSize>(size_),
48 .usage = BUFFER_USAGE | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, 52 .usage = BUFFER_USAGE | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
49 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 53 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
50 .queueFamilyIndexCount = 0, 54 .queueFamilyIndexCount = 0,
@@ -57,69 +61,86 @@ Buffer::Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VKSchedu
57 61
58Buffer::~Buffer() = default; 62Buffer::~Buffer() = default;
59 63
60void Buffer::Upload(std::size_t offset, std::size_t size, const u8* data) { 64void Buffer::Upload(std::size_t offset, std::size_t data_size, const u8* data) {
61 const auto& staging = staging_pool.GetUnusedBuffer(size, true); 65 const auto& staging = staging_pool.GetUnusedBuffer(data_size, true);
62 std::memcpy(staging.commit->Map(size), data, size); 66 std::memcpy(staging.commit->Map(data_size), data, data_size);
63 67
64 scheduler.RequestOutsideRenderPassOperationContext(); 68 scheduler.RequestOutsideRenderPassOperationContext();
65 69
66 const VkBuffer handle = Handle(); 70 const VkBuffer handle = Handle();
67 scheduler.Record([staging = *staging.handle, handle, offset, size](vk::CommandBuffer cmdbuf) { 71 scheduler.Record([staging = *staging.handle, handle, offset, data_size,
68 cmdbuf.CopyBuffer(staging, handle, VkBufferCopy{0, offset, size}); 72 &device = device](vk::CommandBuffer cmdbuf) {
69 73 const VkBufferMemoryBarrier read_barrier{
70 const VkBufferMemoryBarrier barrier{
71 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 74 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
72 .pNext = nullptr, 75 .pNext = nullptr,
73 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, 76 .srcAccessMask =
74 .dstAccessMask = UPLOAD_ACCESS_BARRIERS, 77 VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT |
78 VK_ACCESS_HOST_WRITE_BIT |
79 (device.IsExtTransformFeedbackSupported() ? TRANSFORM_FEEDBACK_WRITE_ACCESS : 0),
80 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
75 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 81 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
76 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 82 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
77 .buffer = handle, 83 .buffer = handle,
78 .offset = offset, 84 .offset = offset,
79 .size = size, 85 .size = data_size,
80 }; 86 };
81 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0, {}, 87 const VkBufferMemoryBarrier write_barrier{
82 barrier, {});
83 });
84}
85
86void Buffer::Download(std::size_t offset, std::size_t size, u8* data) {
87 const auto& staging = staging_pool.GetUnusedBuffer(size, true);
88 scheduler.RequestOutsideRenderPassOperationContext();
89
90 const VkBuffer handle = Handle();
91 scheduler.Record([staging = *staging.handle, handle, offset, size](vk::CommandBuffer cmdbuf) {
92 const VkBufferMemoryBarrier barrier{
93 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 88 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
94 .pNext = nullptr, 89 .pNext = nullptr,
95 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, 90 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
96 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, 91 .dstAccessMask = UPLOAD_ACCESS_BARRIERS,
97 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 92 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
98 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 93 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
99 .buffer = handle, 94 .buffer = handle,
100 .offset = offset, 95 .offset = offset,
101 .size = size, 96 .size = data_size,
102 }; 97 };
103 98 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
104 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | 99 0, read_barrier);
105 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | 100 cmdbuf.CopyBuffer(staging, handle, VkBufferCopy{0, offset, data_size});
106 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 101 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0,
107 VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {}, barrier, {}); 102 write_barrier);
108 cmdbuf.CopyBuffer(handle, staging, VkBufferCopy{offset, 0, size});
109 }); 103 });
104}
105
106void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) {
107 const auto& staging = staging_pool.GetUnusedBuffer(data_size, true);
108 scheduler.RequestOutsideRenderPassOperationContext();
109
110 const VkBuffer handle = Handle();
111 scheduler.Record(
112 [staging = *staging.handle, handle, offset, data_size](vk::CommandBuffer cmdbuf) {
113 const VkBufferMemoryBarrier barrier{
114 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
115 .pNext = nullptr,
116 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
117 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
118 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
119 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
120 .buffer = handle,
121 .offset = offset,
122 .size = data_size,
123 };
124
125 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
126 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
127 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
128 VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {}, barrier, {});
129 cmdbuf.CopyBuffer(handle, staging, VkBufferCopy{offset, 0, data_size});
130 });
110 scheduler.Finish(); 131 scheduler.Finish();
111 132
112 std::memcpy(data, staging.commit->Map(size), size); 133 std::memcpy(data, staging.commit->Map(data_size), data_size);
113} 134}
114 135
115void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, 136void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset,
116 std::size_t size) { 137 std::size_t copy_size) {
117 scheduler.RequestOutsideRenderPassOperationContext(); 138 scheduler.RequestOutsideRenderPassOperationContext();
118 139
119 const VkBuffer dst_buffer = Handle(); 140 const VkBuffer dst_buffer = Handle();
120 scheduler.Record([src_buffer = src.Handle(), dst_buffer, src_offset, dst_offset, 141 scheduler.Record([src_buffer = src.Handle(), dst_buffer, src_offset, dst_offset,
121 size](vk::CommandBuffer cmdbuf) { 142 copy_size](vk::CommandBuffer cmdbuf) {
122 cmdbuf.CopyBuffer(src_buffer, dst_buffer, VkBufferCopy{src_offset, dst_offset, size}); 143 cmdbuf.CopyBuffer(src_buffer, dst_buffer, VkBufferCopy{src_offset, dst_offset, copy_size});
123 144
124 std::array<VkBufferMemoryBarrier, 2> barriers; 145 std::array<VkBufferMemoryBarrier, 2> barriers;
125 barriers[0].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; 146 barriers[0].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
@@ -130,7 +151,7 @@ void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst
130 barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 151 barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
131 barriers[0].buffer = src_buffer; 152 barriers[0].buffer = src_buffer;
132 barriers[0].offset = src_offset; 153 barriers[0].offset = src_offset;
133 barriers[0].size = size; 154 barriers[0].size = copy_size;
134 barriers[1].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; 155 barriers[1].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
135 barriers[1].pNext = nullptr; 156 barriers[1].pNext = nullptr;
136 barriers[1].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; 157 barriers[1].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
@@ -139,19 +160,19 @@ void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst
139 barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 160 barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
140 barriers[1].buffer = dst_buffer; 161 barriers[1].buffer = dst_buffer;
141 barriers[1].offset = dst_offset; 162 barriers[1].offset = dst_offset;
142 barriers[1].size = size; 163 barriers[1].size = copy_size;
143 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0, {}, 164 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0, {},
144 barriers, {}); 165 barriers, {});
145 }); 166 });
146} 167}
147 168
148VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer, 169VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer_,
149 Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory, 170 Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_,
150 const VKDevice& device_, VKMemoryManager& memory_manager_, 171 const Device& device_, VKMemoryManager& memory_manager_,
151 VKScheduler& scheduler_, VKStagingBufferPool& staging_pool_) 172 VKScheduler& scheduler_, VKStreamBuffer& stream_buffer_,
152 : VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer, gpu_memory, cpu_memory, 173 VKStagingBufferPool& staging_pool_)
153 CreateStreamBuffer(device_, 174 : VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer_, gpu_memory_,
154 scheduler_)}, 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 7fb5ceedf..1c39aed34 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -11,26 +11,26 @@
11#include "video_core/renderer_vulkan/vk_memory_manager.h" 11#include "video_core/renderer_vulkan/vk_memory_manager.h"
12#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 12#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
13#include "video_core/renderer_vulkan/vk_stream_buffer.h" 13#include "video_core/renderer_vulkan/vk_stream_buffer.h"
14#include "video_core/renderer_vulkan/wrapper.h" 14#include "video_core/vulkan_common/vulkan_wrapper.h"
15 15
16namespace Vulkan { 16namespace Vulkan {
17 17
18class VKDevice; 18class Device;
19class VKMemoryManager; 19class VKMemoryManager;
20class VKScheduler; 20class VKScheduler;
21 21
22class Buffer final : public VideoCommon::BufferBlock { 22class Buffer final : public VideoCommon::BufferBlock {
23public: 23public:
24 explicit Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VKScheduler& scheduler, 24 explicit Buffer(const Device& device, VKMemoryManager& memory_manager, VKScheduler& scheduler,
25 VKStagingBufferPool& staging_pool, VAddr cpu_addr, std::size_t size); 25 VKStagingBufferPool& staging_pool, VAddr cpu_addr_, std::size_t size_);
26 ~Buffer(); 26 ~Buffer();
27 27
28 void Upload(std::size_t offset, std::size_t size, const u8* data); 28 void Upload(std::size_t offset, std::size_t data_size, const u8* data);
29 29
30 void Download(std::size_t offset, std::size_t size, u8* data); 30 void Download(std::size_t offset, std::size_t data_size, u8* data);
31 31
32 void CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, 32 void CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset,
33 std::size_t size); 33 std::size_t copy_size);
34 34
35 VkBuffer Handle() const { 35 VkBuffer Handle() const {
36 return *buffer.handle; 36 return *buffer.handle;
@@ -41,6 +41,7 @@ public:
41 } 41 }
42 42
43private: 43private:
44 const Device& device;
44 VKScheduler& scheduler; 45 VKScheduler& scheduler;
45 VKStagingBufferPool& staging_pool; 46 VKStagingBufferPool& staging_pool;
46 47
@@ -51,8 +52,9 @@ class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VK
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 Device& 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;
@@ -61,7 +63,7 @@ protected:
61 std::shared_ptr<Buffer> CreateBlock(VAddr cpu_addr, std::size_t size) override; 63 std::shared_ptr<Buffer> CreateBlock(VAddr cpu_addr, std::size_t size) override;
62 64
63private: 65private:
64 const VKDevice& device; 66 const Device& device;
65 VKMemoryManager& memory_manager; 67 VKMemoryManager& memory_manager;
66 VKScheduler& scheduler; 68 VKScheduler& scheduler;
67 VKStagingBufferPool& staging_pool; 69 VKStagingBufferPool& staging_pool;
diff --git a/src/video_core/renderer_vulkan/vk_command_pool.cpp b/src/video_core/renderer_vulkan/vk_command_pool.cpp
index f1abd4b1a..a99df9323 100644
--- a/src/video_core/renderer_vulkan/vk_command_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_command_pool.cpp
@@ -5,15 +5,20 @@
5#include <cstddef> 5#include <cstddef>
6 6
7#include "video_core/renderer_vulkan/vk_command_pool.h" 7#include "video_core/renderer_vulkan/vk_command_pool.h"
8#include "video_core/renderer_vulkan/vk_device.h" 8#include "video_core/vulkan_common/vulkan_device.h"
9#include "video_core/renderer_vulkan/wrapper.h" 9#include "video_core/vulkan_common/vulkan_wrapper.h"
10 10
11namespace Vulkan { 11namespace Vulkan {
12 12
13constexpr size_t COMMAND_BUFFER_POOL_SIZE = 0x1000; 13constexpr size_t COMMAND_BUFFER_POOL_SIZE = 0x1000;
14 14
15CommandPool::CommandPool(MasterSemaphore& master_semaphore, const VKDevice& device) 15struct CommandPool::Pool {
16 : ResourcePool(master_semaphore, COMMAND_BUFFER_POOL_SIZE), device{device} {} 16 vk::CommandPool handle;
17 vk::CommandBuffers cmdbufs;
18};
19
20CommandPool::CommandPool(MasterSemaphore& master_semaphore_, const Device& device_)
21 : ResourcePool(master_semaphore_, COMMAND_BUFFER_POOL_SIZE), device{device_} {}
17 22
18CommandPool::~CommandPool() = default; 23CommandPool::~CommandPool() = default;
19 24
diff --git a/src/video_core/renderer_vulkan/vk_command_pool.h b/src/video_core/renderer_vulkan/vk_command_pool.h
index 3aee239b9..61c26a22a 100644
--- a/src/video_core/renderer_vulkan/vk_command_pool.h
+++ b/src/video_core/renderer_vulkan/vk_command_pool.h
@@ -2,33 +2,32 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once
6
5#include <cstddef> 7#include <cstddef>
6#include <vector> 8#include <vector>
7 9
8#include "video_core/renderer_vulkan/vk_resource_pool.h" 10#include "video_core/renderer_vulkan/vk_resource_pool.h"
9#include "video_core/renderer_vulkan/wrapper.h" 11#include "video_core/vulkan_common/vulkan_wrapper.h"
10 12
11namespace Vulkan { 13namespace Vulkan {
12 14
15class Device;
13class MasterSemaphore; 16class MasterSemaphore;
14class VKDevice;
15 17
16class CommandPool final : public ResourcePool { 18class CommandPool final : public ResourcePool {
17public: 19public:
18 explicit CommandPool(MasterSemaphore& master_semaphore, const VKDevice& device); 20 explicit CommandPool(MasterSemaphore& master_semaphore_, const Device& device_);
19 virtual ~CommandPool(); 21 ~CommandPool() override;
20 22
21 void Allocate(size_t begin, size_t end) override; 23 void Allocate(size_t begin, size_t end) override;
22 24
23 VkCommandBuffer Commit(); 25 VkCommandBuffer Commit();
24 26
25private: 27private:
26 struct Pool { 28 struct Pool;
27 vk::CommandPool handle;
28 vk::CommandBuffers cmdbufs;
29 };
30 29
31 const VKDevice& device; 30 const Device& device;
32 std::vector<Pool> pools; 31 std::vector<Pool> pools;
33}; 32};
34 33
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
index 9637c6059..02a6d54b7 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
@@ -10,111 +10,21 @@
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"
16#include "video_core/renderer_vulkan/vk_scheduler.h" 18#include "video_core/renderer_vulkan/vk_scheduler.h"
17#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 19#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
18#include "video_core/renderer_vulkan/vk_update_descriptor.h" 20#include "video_core/renderer_vulkan/vk_update_descriptor.h"
19#include "video_core/renderer_vulkan/wrapper.h" 21#include "video_core/vulkan_common/vulkan_device.h"
22#include "video_core/vulkan_common/vulkan_wrapper.h"
20 23
21namespace Vulkan { 24namespace 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 {
@@ -378,11 +86,11 @@ VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() {
378 86
379} // Anonymous namespace 87} // Anonymous namespace
380 88
381VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descriptor_pool, 89VKComputePass::VKComputePass(const Device& 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,
@@ -461,15 +162,15 @@ VkDescriptorSet VKComputePass::CommitDescriptorSet(
461 return set; 162 return set;
462} 163}
463 164
464QuadArrayPass::QuadArrayPass(const VKDevice& device, VKScheduler& scheduler, 165QuadArrayPass::QuadArrayPass(const Device& device_, VKScheduler& scheduler_,
465 VKDescriptorPool& descriptor_pool, 166 VKDescriptorPool& descriptor_pool_,
466 VKStagingBufferPool& staging_buffer_pool, 167 VKStagingBufferPool& staging_buffer_pool_,
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
474QuadArrayPass::~QuadArrayPass() = default; 175QuadArrayPass::~QuadArrayPass() = default;
475 176
@@ -510,14 +211,13 @@ 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 Device& 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), 219 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
519 scheduler{scheduler}, staging_buffer_pool{staging_buffer_pool}, 220 update_descriptor_queue{update_descriptor_queue_} {}
520 update_descriptor_queue{update_descriptor_queue} {}
521 221
522Uint8Pass::~Uint8Pass() = default; 222Uint8Pass::~Uint8Pass() = default;
523 223
@@ -555,16 +255,15 @@ std::pair<VkBuffer, u64> Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buff
555 return {*buffer.handle, 0}; 255 return {*buffer.handle, 0};
556} 256}
557 257
558QuadIndexedPass::QuadIndexedPass(const VKDevice& device, VKScheduler& scheduler, 258QuadIndexedPass::QuadIndexedPass(const Device& device_, VKScheduler& scheduler_,
559 VKDescriptorPool& descriptor_pool, 259 VKDescriptorPool& descriptor_pool_,
560 VKStagingBufferPool& staging_buffer_pool, 260 VKStagingBufferPool& staging_buffer_pool_,
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), 265 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
566 scheduler{scheduler}, staging_buffer_pool{staging_buffer_pool}, 266 update_descriptor_queue{update_descriptor_queue_} {}
567 update_descriptor_queue{update_descriptor_queue} {}
568 267
569QuadIndexedPass::~QuadIndexedPass() = default; 268QuadIndexedPass::~QuadIndexedPass() = default;
570 269
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h
index acc94f27e..7ddb09afb 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.h
@@ -5,27 +5,27 @@
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"
11#include "video_core/engines/maxwell_3d.h" 12#include "video_core/engines/maxwell_3d.h"
12#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 13#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
13#include "video_core/renderer_vulkan/wrapper.h" 14#include "video_core/vulkan_common/vulkan_wrapper.h"
14 15
15namespace Vulkan { 16namespace Vulkan {
16 17
17class VKDevice; 18class Device;
18class VKScheduler; 19class VKScheduler;
19class VKStagingBufferPool; 20class VKStagingBufferPool;
20class VKUpdateDescriptorQueue; 21class VKUpdateDescriptorQueue;
21 22
22class VKComputePass { 23class VKComputePass {
23public: 24public:
24 explicit VKComputePass(const VKDevice& device, VKDescriptorPool& descriptor_pool, 25 explicit VKComputePass(const Device& 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:
@@ -43,10 +43,10 @@ private:
43 43
44class QuadArrayPass final : public VKComputePass { 44class QuadArrayPass final : public VKComputePass {
45public: 45public:
46 explicit QuadArrayPass(const VKDevice& device, VKScheduler& scheduler, 46 explicit QuadArrayPass(const Device& device_, VKScheduler& scheduler_,
47 VKDescriptorPool& descriptor_pool, 47 VKDescriptorPool& descriptor_pool_,
48 VKStagingBufferPool& staging_buffer_pool, 48 VKStagingBufferPool& staging_buffer_pool_,
49 VKUpdateDescriptorQueue& update_descriptor_queue); 49 VKUpdateDescriptorQueue& update_descriptor_queue_);
50 ~QuadArrayPass(); 50 ~QuadArrayPass();
51 51
52 std::pair<VkBuffer, VkDeviceSize> Assemble(u32 num_vertices, u32 first); 52 std::pair<VkBuffer, VkDeviceSize> Assemble(u32 num_vertices, u32 first);
@@ -59,9 +59,10 @@ private:
59 59
60class Uint8Pass final : public VKComputePass { 60class Uint8Pass final : public VKComputePass {
61public: 61public:
62 explicit Uint8Pass(const VKDevice& device, VKScheduler& scheduler, 62 explicit Uint8Pass(const Device& device_, VKScheduler& scheduler_,
63 VKDescriptorPool& descriptor_pool, VKStagingBufferPool& staging_buffer_pool, 63 VKDescriptorPool& descriptor_pool_,
64 VKUpdateDescriptorQueue& update_descriptor_queue); 64 VKStagingBufferPool& staging_buffer_pool_,
65 VKUpdateDescriptorQueue& update_descriptor_queue_);
65 ~Uint8Pass(); 66 ~Uint8Pass();
66 67
67 std::pair<VkBuffer, u64> Assemble(u32 num_vertices, VkBuffer src_buffer, u64 src_offset); 68 std::pair<VkBuffer, u64> Assemble(u32 num_vertices, VkBuffer src_buffer, u64 src_offset);
@@ -74,10 +75,10 @@ private:
74 75
75class QuadIndexedPass final : public VKComputePass { 76class QuadIndexedPass final : public VKComputePass {
76public: 77public:
77 explicit QuadIndexedPass(const VKDevice& device, VKScheduler& scheduler, 78 explicit QuadIndexedPass(const Device& device_, VKScheduler& scheduler_,
78 VKDescriptorPool& descriptor_pool, 79 VKDescriptorPool& descriptor_pool_,
79 VKStagingBufferPool& staging_buffer_pool, 80 VKStagingBufferPool& staging_buffer_pool_,
80 VKUpdateDescriptorQueue& update_descriptor_queue); 81 VKUpdateDescriptorQueue& update_descriptor_queue_);
81 ~QuadIndexedPass(); 82 ~QuadIndexedPass();
82 83
83 std::pair<VkBuffer, u64> Assemble(Tegra::Engines::Maxwell3D::Regs::IndexFormat index_format, 84 std::pair<VkBuffer, u64> Assemble(Tegra::Engines::Maxwell3D::Regs::IndexFormat index_format,
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
index 9be72dc9b..3a48219b7 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -6,25 +6,25 @@
6 6
7#include "video_core/renderer_vulkan/vk_compute_pipeline.h" 7#include "video_core/renderer_vulkan/vk_compute_pipeline.h"
8#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 8#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
9#include "video_core/renderer_vulkan/vk_device.h"
10#include "video_core/renderer_vulkan/vk_pipeline_cache.h" 9#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
11#include "video_core/renderer_vulkan/vk_scheduler.h" 10#include "video_core/renderer_vulkan/vk_scheduler.h"
12#include "video_core/renderer_vulkan/vk_shader_decompiler.h" 11#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
13#include "video_core/renderer_vulkan/vk_update_descriptor.h" 12#include "video_core/renderer_vulkan/vk_update_descriptor.h"
14#include "video_core/renderer_vulkan/wrapper.h" 13#include "video_core/vulkan_common/vulkan_device.h"
14#include "video_core/vulkan_common/vulkan_wrapper.h"
15 15
16namespace Vulkan { 16namespace Vulkan {
17 17
18VKComputePipeline::VKComputePipeline(const VKDevice& device, VKScheduler& scheduler, 18VKComputePipeline::VKComputePipeline(const Device& device_, VKScheduler& scheduler_,
19 VKDescriptorPool& descriptor_pool, 19 VKDescriptorPool& descriptor_pool_,
20 VKUpdateDescriptorQueue& update_descriptor_queue, 20 VKUpdateDescriptorQueue& update_descriptor_queue_,
21 const SPIRVShader& shader) 21 const SPIRVShader& shader_)
22 : device{device}, scheduler{scheduler}, entries{shader.entries}, 22 : device{device_}, scheduler{scheduler_}, entries{shader_.entries},
23 descriptor_set_layout{CreateDescriptorSetLayout()}, 23 descriptor_set_layout{CreateDescriptorSetLayout()},
24 descriptor_allocator{descriptor_pool, *descriptor_set_layout}, 24 descriptor_allocator{descriptor_pool_, *descriptor_set_layout},
25 update_descriptor_queue{update_descriptor_queue}, layout{CreatePipelineLayout()}, 25 update_descriptor_queue{update_descriptor_queue_}, layout{CreatePipelineLayout()},
26 descriptor_template{CreateDescriptorUpdateTemplate()}, 26 descriptor_template{CreateDescriptorUpdateTemplate()},
27 shader_module{CreateShaderModule(shader.code)}, pipeline{CreatePipeline()} {} 27 shader_module{CreateShaderModule(shader_.code)}, pipeline{CreatePipeline()} {}
28 28
29VKComputePipeline::~VKComputePipeline() = default; 29VKComputePipeline::~VKComputePipeline() = default;
30 30
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h
index 6e2f22a4a..7e16575ac 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h
@@ -7,20 +7,20 @@
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 8#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
9#include "video_core/renderer_vulkan/vk_shader_decompiler.h" 9#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
10#include "video_core/renderer_vulkan/wrapper.h" 10#include "video_core/vulkan_common/vulkan_wrapper.h"
11 11
12namespace Vulkan { 12namespace Vulkan {
13 13
14class VKDevice; 14class Device;
15class VKScheduler; 15class VKScheduler;
16class VKUpdateDescriptorQueue; 16class VKUpdateDescriptorQueue;
17 17
18class VKComputePipeline final { 18class VKComputePipeline final {
19public: 19public:
20 explicit VKComputePipeline(const VKDevice& device, VKScheduler& scheduler, 20 explicit VKComputePipeline(const Device& device_, VKScheduler& scheduler_,
21 VKDescriptorPool& descriptor_pool, 21 VKDescriptorPool& descriptor_pool_,
22 VKUpdateDescriptorQueue& update_descriptor_queue, 22 VKUpdateDescriptorQueue& update_descriptor_queue_,
23 const SPIRVShader& shader); 23 const SPIRVShader& shader_);
24 ~VKComputePipeline(); 24 ~VKComputePipeline();
25 25
26 VkDescriptorSet CommitDescriptorSet(); 26 VkDescriptorSet CommitDescriptorSet();
@@ -48,7 +48,7 @@ private:
48 48
49 vk::Pipeline CreatePipeline() const; 49 vk::Pipeline CreatePipeline() const;
50 50
51 const VKDevice& device; 51 const Device& device;
52 VKScheduler& scheduler; 52 VKScheduler& scheduler;
53 ShaderEntries entries; 53 ShaderEntries entries;
54 54
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
index f38e089d5..ef9fb5910 100644
--- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
@@ -6,10 +6,10 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 8#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
9#include "video_core/renderer_vulkan/vk_device.h"
10#include "video_core/renderer_vulkan/vk_resource_pool.h" 9#include "video_core/renderer_vulkan/vk_resource_pool.h"
11#include "video_core/renderer_vulkan/vk_scheduler.h" 10#include "video_core/renderer_vulkan/vk_scheduler.h"
12#include "video_core/renderer_vulkan/wrapper.h" 11#include "video_core/vulkan_common/vulkan_device.h"
12#include "video_core/vulkan_common/vulkan_wrapper.h"
13 13
14namespace Vulkan { 14namespace Vulkan {
15 15
@@ -32,7 +32,7 @@ void DescriptorAllocator::Allocate(std::size_t begin, std::size_t end) {
32 descriptors_allocations.push_back(descriptor_pool.AllocateDescriptors(layout, end - begin)); 32 descriptors_allocations.push_back(descriptor_pool.AllocateDescriptors(layout, end - begin));
33} 33}
34 34
35VKDescriptorPool::VKDescriptorPool(const VKDevice& device_, VKScheduler& scheduler) 35VKDescriptorPool::VKDescriptorPool(const Device& device_, VKScheduler& scheduler)
36 : device{device_}, master_semaphore{scheduler.GetMasterSemaphore()}, active_pool{ 36 : device{device_}, master_semaphore{scheduler.GetMasterSemaphore()}, active_pool{
37 AllocateNewPool()} {} 37 AllocateNewPool()} {}
38 38
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.h b/src/video_core/renderer_vulkan/vk_descriptor_pool.h
index 544f32a20..f892be7be 100644
--- a/src/video_core/renderer_vulkan/vk_descriptor_pool.h
+++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.h
@@ -7,11 +7,11 @@
7#include <vector> 7#include <vector>
8 8
9#include "video_core/renderer_vulkan/vk_resource_pool.h" 9#include "video_core/renderer_vulkan/vk_resource_pool.h"
10#include "video_core/renderer_vulkan/wrapper.h" 10#include "video_core/vulkan_common/vulkan_wrapper.h"
11 11
12namespace Vulkan { 12namespace Vulkan {
13 13
14class VKDevice; 14class Device;
15class VKDescriptorPool; 15class VKDescriptorPool;
16class VKScheduler; 16class VKScheduler;
17 17
@@ -39,7 +39,7 @@ class VKDescriptorPool final {
39 friend DescriptorAllocator; 39 friend DescriptorAllocator;
40 40
41public: 41public:
42 explicit VKDescriptorPool(const VKDevice& device, VKScheduler& scheduler); 42 explicit VKDescriptorPool(const Device& device, VKScheduler& scheduler);
43 ~VKDescriptorPool(); 43 ~VKDescriptorPool();
44 44
45 VKDescriptorPool(const VKDescriptorPool&) = delete; 45 VKDescriptorPool(const VKDescriptorPool&) = delete;
@@ -50,7 +50,7 @@ private:
50 50
51 vk::DescriptorSets AllocateDescriptors(VkDescriptorSetLayout layout, std::size_t count); 51 vk::DescriptorSets AllocateDescriptors(VkDescriptorSetLayout layout, std::size_t count);
52 52
53 const VKDevice& device; 53 const Device& device;
54 MasterSemaphore& master_semaphore; 54 MasterSemaphore& master_semaphore;
55 55
56 std::vector<vk::DescriptorPool> pools; 56 std::vector<vk::DescriptorPool> pools;
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp
deleted file mode 100644
index 05e31f1de..000000000
--- a/src/video_core/renderer_vulkan/vk_device.cpp
+++ /dev/null
@@ -1,801 +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 <bitset>
6#include <chrono>
7#include <optional>
8#include <string_view>
9#include <thread>
10#include <unordered_set>
11#include <utility>
12#include <vector>
13
14#include "common/assert.h"
15#include "core/settings.h"
16#include "video_core/renderer_vulkan/vk_device.h"
17#include "video_core/renderer_vulkan/wrapper.h"
18
19namespace Vulkan {
20
21namespace {
22
23namespace Alternatives {
24
25constexpr std::array Depth24UnormS8_UINT{
26 VK_FORMAT_D32_SFLOAT_S8_UINT,
27 VK_FORMAT_D16_UNORM_S8_UINT,
28 VkFormat{},
29};
30
31constexpr std::array Depth16UnormS8_UINT{
32 VK_FORMAT_D24_UNORM_S8_UINT,
33 VK_FORMAT_D32_SFLOAT_S8_UINT,
34 VkFormat{},
35};
36
37} // namespace Alternatives
38
39constexpr std::array REQUIRED_EXTENSIONS{
40 VK_KHR_SWAPCHAIN_EXTENSION_NAME,
41 VK_KHR_16BIT_STORAGE_EXTENSION_NAME,
42 VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
43 VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
44 VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME,
45 VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
46 VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME,
47 VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME,
48 VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME,
49 VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME,
50};
51
52template <typename T>
53void SetNext(void**& next, T& data) {
54 *next = &data;
55 next = &data.pNext;
56}
57
58constexpr const VkFormat* GetFormatAlternatives(VkFormat format) {
59 switch (format) {
60 case VK_FORMAT_D24_UNORM_S8_UINT:
61 return Alternatives::Depth24UnormS8_UINT.data();
62 case VK_FORMAT_D16_UNORM_S8_UINT:
63 return Alternatives::Depth16UnormS8_UINT.data();
64 default:
65 return nullptr;
66 }
67}
68
69VkFormatFeatureFlags GetFormatFeatures(VkFormatProperties properties, FormatType format_type) {
70 switch (format_type) {
71 case FormatType::Linear:
72 return properties.linearTilingFeatures;
73 case FormatType::Optimal:
74 return properties.optimalTilingFeatures;
75 case FormatType::Buffer:
76 return properties.bufferFeatures;
77 default:
78 return {};
79 }
80}
81
82std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(
83 vk::PhysicalDevice physical, const vk::InstanceDispatch& dld) {
84 static constexpr std::array formats{
85 VK_FORMAT_A8B8G8R8_UNORM_PACK32,
86 VK_FORMAT_A8B8G8R8_UINT_PACK32,
87 VK_FORMAT_A8B8G8R8_SNORM_PACK32,
88 VK_FORMAT_A8B8G8R8_SINT_PACK32,
89 VK_FORMAT_A8B8G8R8_SRGB_PACK32,
90 VK_FORMAT_B5G6R5_UNORM_PACK16,
91 VK_FORMAT_A2B10G10R10_UNORM_PACK32,
92 VK_FORMAT_A2B10G10R10_UINT_PACK32,
93 VK_FORMAT_A1R5G5B5_UNORM_PACK16,
94 VK_FORMAT_R32G32B32A32_SFLOAT,
95 VK_FORMAT_R32G32B32A32_SINT,
96 VK_FORMAT_R32G32B32A32_UINT,
97 VK_FORMAT_R32G32_SFLOAT,
98 VK_FORMAT_R32G32_SINT,
99 VK_FORMAT_R32G32_UINT,
100 VK_FORMAT_R16G16B16A16_SINT,
101 VK_FORMAT_R16G16B16A16_UINT,
102 VK_FORMAT_R16G16B16A16_SNORM,
103 VK_FORMAT_R16G16B16A16_UNORM,
104 VK_FORMAT_R16G16_UNORM,
105 VK_FORMAT_R16G16_SNORM,
106 VK_FORMAT_R16G16_SFLOAT,
107 VK_FORMAT_R16_UNORM,
108 VK_FORMAT_R16_UINT,
109 VK_FORMAT_R8G8B8A8_SRGB,
110 VK_FORMAT_R8G8_UNORM,
111 VK_FORMAT_R8G8_SNORM,
112 VK_FORMAT_R8G8_SINT,
113 VK_FORMAT_R8G8_UINT,
114 VK_FORMAT_R8_UNORM,
115 VK_FORMAT_R8_SNORM,
116 VK_FORMAT_R8_SINT,
117 VK_FORMAT_R8_UINT,
118 VK_FORMAT_B10G11R11_UFLOAT_PACK32,
119 VK_FORMAT_R32_SFLOAT,
120 VK_FORMAT_R32_UINT,
121 VK_FORMAT_R32_SINT,
122 VK_FORMAT_R16_SFLOAT,
123 VK_FORMAT_R16G16B16A16_SFLOAT,
124 VK_FORMAT_B8G8R8A8_UNORM,
125 VK_FORMAT_B8G8R8A8_SRGB,
126 VK_FORMAT_R4G4B4A4_UNORM_PACK16,
127 VK_FORMAT_D32_SFLOAT,
128 VK_FORMAT_D16_UNORM,
129 VK_FORMAT_D16_UNORM_S8_UINT,
130 VK_FORMAT_D24_UNORM_S8_UINT,
131 VK_FORMAT_D32_SFLOAT_S8_UINT,
132 VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
133 VK_FORMAT_BC2_UNORM_BLOCK,
134 VK_FORMAT_BC3_UNORM_BLOCK,
135 VK_FORMAT_BC4_UNORM_BLOCK,
136 VK_FORMAT_BC4_SNORM_BLOCK,
137 VK_FORMAT_BC5_UNORM_BLOCK,
138 VK_FORMAT_BC5_SNORM_BLOCK,
139 VK_FORMAT_BC7_UNORM_BLOCK,
140 VK_FORMAT_BC6H_UFLOAT_BLOCK,
141 VK_FORMAT_BC6H_SFLOAT_BLOCK,
142 VK_FORMAT_BC1_RGBA_SRGB_BLOCK,
143 VK_FORMAT_BC2_SRGB_BLOCK,
144 VK_FORMAT_BC3_SRGB_BLOCK,
145 VK_FORMAT_BC7_SRGB_BLOCK,
146 VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
147 VK_FORMAT_ASTC_8x8_SRGB_BLOCK,
148 VK_FORMAT_ASTC_8x5_SRGB_BLOCK,
149 VK_FORMAT_ASTC_5x4_SRGB_BLOCK,
150 VK_FORMAT_ASTC_5x5_UNORM_BLOCK,
151 VK_FORMAT_ASTC_5x5_SRGB_BLOCK,
152 VK_FORMAT_ASTC_10x8_UNORM_BLOCK,
153 VK_FORMAT_ASTC_10x8_SRGB_BLOCK,
154 VK_FORMAT_ASTC_6x6_UNORM_BLOCK,
155 VK_FORMAT_ASTC_6x6_SRGB_BLOCK,
156 VK_FORMAT_ASTC_10x10_UNORM_BLOCK,
157 VK_FORMAT_ASTC_10x10_SRGB_BLOCK,
158 VK_FORMAT_ASTC_12x12_UNORM_BLOCK,
159 VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
160 VK_FORMAT_ASTC_8x6_UNORM_BLOCK,
161 VK_FORMAT_ASTC_8x6_SRGB_BLOCK,
162 VK_FORMAT_ASTC_6x5_UNORM_BLOCK,
163 VK_FORMAT_ASTC_6x5_SRGB_BLOCK,
164 VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,
165 };
166 std::unordered_map<VkFormat, VkFormatProperties> format_properties;
167 for (const auto format : formats) {
168 format_properties.emplace(format, physical.GetFormatProperties(format));
169 }
170 return format_properties;
171}
172
173} // Anonymous namespace
174
175VKDevice::VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface,
176 const vk::InstanceDispatch& dld)
177 : dld{dld}, physical{physical}, properties{physical.GetProperties()},
178 format_properties{GetFormatProperties(physical, dld)} {
179 SetupFamilies(surface);
180 SetupFeatures();
181}
182
183VKDevice::~VKDevice() = default;
184
185bool VKDevice::Create() {
186 const auto queue_cis = GetDeviceQueueCreateInfos();
187 const std::vector extensions = LoadExtensions();
188
189 VkPhysicalDeviceFeatures2 features2{
190 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
191 .pNext = nullptr,
192 };
193 const void* first_next = &features2;
194 void** next = &features2.pNext;
195
196 features2.features = {
197 .robustBufferAccess = false,
198 .fullDrawIndexUint32 = false,
199 .imageCubeArray = false,
200 .independentBlend = true,
201 .geometryShader = true,
202 .tessellationShader = true,
203 .sampleRateShading = false,
204 .dualSrcBlend = false,
205 .logicOp = false,
206 .multiDrawIndirect = false,
207 .drawIndirectFirstInstance = false,
208 .depthClamp = true,
209 .depthBiasClamp = true,
210 .fillModeNonSolid = false,
211 .depthBounds = false,
212 .wideLines = false,
213 .largePoints = true,
214 .alphaToOne = false,
215 .multiViewport = true,
216 .samplerAnisotropy = true,
217 .textureCompressionETC2 = false,
218 .textureCompressionASTC_LDR = is_optimal_astc_supported,
219 .textureCompressionBC = false,
220 .occlusionQueryPrecise = true,
221 .pipelineStatisticsQuery = false,
222 .vertexPipelineStoresAndAtomics = true,
223 .fragmentStoresAndAtomics = true,
224 .shaderTessellationAndGeometryPointSize = false,
225 .shaderImageGatherExtended = true,
226 .shaderStorageImageExtendedFormats = false,
227 .shaderStorageImageMultisample = false,
228 .shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported,
229 .shaderStorageImageWriteWithoutFormat = true,
230 .shaderUniformBufferArrayDynamicIndexing = false,
231 .shaderSampledImageArrayDynamicIndexing = false,
232 .shaderStorageBufferArrayDynamicIndexing = false,
233 .shaderStorageImageArrayDynamicIndexing = false,
234 .shaderClipDistance = false,
235 .shaderCullDistance = false,
236 .shaderFloat64 = false,
237 .shaderInt64 = false,
238 .shaderInt16 = false,
239 .shaderResourceResidency = false,
240 .shaderResourceMinLod = false,
241 .sparseBinding = false,
242 .sparseResidencyBuffer = false,
243 .sparseResidencyImage2D = false,
244 .sparseResidencyImage3D = false,
245 .sparseResidency2Samples = false,
246 .sparseResidency4Samples = false,
247 .sparseResidency8Samples = false,
248 .sparseResidency16Samples = false,
249 .sparseResidencyAliased = false,
250 .variableMultisampleRate = false,
251 .inheritedQueries = false,
252 };
253
254 VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore{
255 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR,
256 .pNext = nullptr,
257 .timelineSemaphore = true,
258 };
259 SetNext(next, timeline_semaphore);
260
261 VkPhysicalDevice16BitStorageFeaturesKHR bit16_storage{
262 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR,
263 .pNext = nullptr,
264 .storageBuffer16BitAccess = false,
265 .uniformAndStorageBuffer16BitAccess = true,
266 .storagePushConstant16 = false,
267 .storageInputOutput16 = false,
268 };
269 SetNext(next, bit16_storage);
270
271 VkPhysicalDevice8BitStorageFeaturesKHR bit8_storage{
272 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR,
273 .pNext = nullptr,
274 .storageBuffer8BitAccess = false,
275 .uniformAndStorageBuffer8BitAccess = true,
276 .storagePushConstant8 = false,
277 };
278 SetNext(next, bit8_storage);
279
280 VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset{
281 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT,
282 .hostQueryReset = true,
283 };
284 SetNext(next, host_query_reset);
285
286 VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8;
287 if (is_float16_supported) {
288 float16_int8 = {
289 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR,
290 .pNext = nullptr,
291 .shaderFloat16 = true,
292 .shaderInt8 = false,
293 };
294 SetNext(next, float16_int8);
295 } else {
296 LOG_INFO(Render_Vulkan, "Device doesn't support float16 natively");
297 }
298
299 if (!nv_viewport_swizzle) {
300 LOG_INFO(Render_Vulkan, "Device doesn't support viewport swizzles");
301 }
302
303 VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR std430_layout;
304 if (khr_uniform_buffer_standard_layout) {
305 std430_layout = {
306 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR,
307 .pNext = nullptr,
308 .uniformBufferStandardLayout = true,
309 };
310 SetNext(next, std430_layout);
311 } else {
312 LOG_INFO(Render_Vulkan, "Device doesn't support packed UBOs");
313 }
314
315 VkPhysicalDeviceIndexTypeUint8FeaturesEXT index_type_uint8;
316 if (ext_index_type_uint8) {
317 index_type_uint8 = {
318 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT,
319 .pNext = nullptr,
320 .indexTypeUint8 = true,
321 };
322 SetNext(next, index_type_uint8);
323 } else {
324 LOG_INFO(Render_Vulkan, "Device doesn't support uint8 indexes");
325 }
326
327 VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback;
328 if (ext_transform_feedback) {
329 transform_feedback = {
330 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT,
331 .pNext = nullptr,
332 .transformFeedback = true,
333 .geometryStreams = true,
334 };
335 SetNext(next, transform_feedback);
336 } else {
337 LOG_INFO(Render_Vulkan, "Device doesn't support transform feedbacks");
338 }
339
340 VkPhysicalDeviceCustomBorderColorFeaturesEXT custom_border;
341 if (ext_custom_border_color) {
342 custom_border = {
343 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT,
344 .pNext = nullptr,
345 .customBorderColors = VK_TRUE,
346 .customBorderColorWithoutFormat = VK_TRUE,
347 };
348 SetNext(next, custom_border);
349 } else {
350 LOG_INFO(Render_Vulkan, "Device doesn't support custom border colors");
351 }
352
353 VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state;
354 if (ext_extended_dynamic_state) {
355 dynamic_state = {
356 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT,
357 .pNext = nullptr,
358 .extendedDynamicState = VK_TRUE,
359 };
360 SetNext(next, dynamic_state);
361 } else {
362 LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state");
363 }
364
365 if (!ext_depth_range_unrestricted) {
366 LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted");
367 }
368
369 VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv;
370 if (nv_device_diagnostics_config) {
371 nsight_aftermath_tracker.Initialize();
372
373 diagnostics_nv = {
374 .sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV,
375 .pNext = &features2,
376 .flags = VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV |
377 VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV |
378 VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV,
379 };
380 first_next = &diagnostics_nv;
381 }
382
383 logical = vk::Device::Create(physical, queue_cis, extensions, first_next, dld);
384 if (!logical) {
385 LOG_ERROR(Render_Vulkan, "Failed to create logical device");
386 return false;
387 }
388
389 CollectTelemetryParameters();
390
391 if (ext_extended_dynamic_state && driver_id == VK_DRIVER_ID_AMD_PROPRIETARY_KHR) {
392 // AMD's proprietary driver supports VK_EXT_extended_dynamic_state but the <stride> field
393 // seems to be bugged. Blacklisting it for now.
394 LOG_WARNING(Render_Vulkan,
395 "Blacklisting AMD proprietary from VK_EXT_extended_dynamic_state");
396 ext_extended_dynamic_state = false;
397 }
398
399 graphics_queue = logical.GetQueue(graphics_family);
400 present_queue = logical.GetQueue(present_family);
401
402 use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue();
403 return true;
404}
405
406VkFormat VKDevice::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage,
407 FormatType format_type) const {
408 if (IsFormatSupported(wanted_format, wanted_usage, format_type)) {
409 return wanted_format;
410 }
411 // The wanted format is not supported by hardware, search for alternatives
412 const VkFormat* alternatives = GetFormatAlternatives(wanted_format);
413 if (alternatives == nullptr) {
414 UNREACHABLE_MSG("Format={} with usage={} and type={} has no defined alternatives and host "
415 "hardware does not support it",
416 wanted_format, wanted_usage, format_type);
417 return wanted_format;
418 }
419
420 std::size_t i = 0;
421 for (VkFormat alternative = *alternatives; alternative; alternative = alternatives[++i]) {
422 if (!IsFormatSupported(alternative, wanted_usage, format_type)) {
423 continue;
424 }
425 LOG_WARNING(Render_Vulkan,
426 "Emulating format={} with alternative format={} with usage={} and type={}",
427 wanted_format, alternative, wanted_usage, format_type);
428 return alternative;
429 }
430
431 // No alternatives found, panic
432 UNREACHABLE_MSG("Format={} with usage={} and type={} is not supported by the host hardware and "
433 "doesn't support any of the alternatives",
434 wanted_format, wanted_usage, format_type);
435 return wanted_format;
436}
437
438void VKDevice::ReportLoss() const {
439 LOG_CRITICAL(Render_Vulkan, "Device loss occured!");
440
441 // Wait for the log to flush and for Nsight Aftermath to dump the results
442 std::this_thread::sleep_for(std::chrono::seconds{3});
443}
444
445void VKDevice::SaveShader(const std::vector<u32>& spirv) const {
446 nsight_aftermath_tracker.SaveShader(spirv);
447}
448
449bool VKDevice::IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const {
450 // Disable for now to avoid converting ASTC twice.
451 static constexpr std::array astc_formats = {
452 VK_FORMAT_ASTC_4x4_UNORM_BLOCK, VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
453 VK_FORMAT_ASTC_5x4_UNORM_BLOCK, VK_FORMAT_ASTC_5x4_SRGB_BLOCK,
454 VK_FORMAT_ASTC_5x5_UNORM_BLOCK, VK_FORMAT_ASTC_5x5_SRGB_BLOCK,
455 VK_FORMAT_ASTC_6x5_UNORM_BLOCK, VK_FORMAT_ASTC_6x5_SRGB_BLOCK,
456 VK_FORMAT_ASTC_6x6_UNORM_BLOCK, VK_FORMAT_ASTC_6x6_SRGB_BLOCK,
457 VK_FORMAT_ASTC_8x5_UNORM_BLOCK, VK_FORMAT_ASTC_8x5_SRGB_BLOCK,
458 VK_FORMAT_ASTC_8x6_UNORM_BLOCK, VK_FORMAT_ASTC_8x6_SRGB_BLOCK,
459 VK_FORMAT_ASTC_8x8_UNORM_BLOCK, VK_FORMAT_ASTC_8x8_SRGB_BLOCK,
460 VK_FORMAT_ASTC_10x5_UNORM_BLOCK, VK_FORMAT_ASTC_10x5_SRGB_BLOCK,
461 VK_FORMAT_ASTC_10x6_UNORM_BLOCK, VK_FORMAT_ASTC_10x6_SRGB_BLOCK,
462 VK_FORMAT_ASTC_10x8_UNORM_BLOCK, VK_FORMAT_ASTC_10x8_SRGB_BLOCK,
463 VK_FORMAT_ASTC_10x10_UNORM_BLOCK, VK_FORMAT_ASTC_10x10_SRGB_BLOCK,
464 VK_FORMAT_ASTC_12x10_UNORM_BLOCK, VK_FORMAT_ASTC_12x10_SRGB_BLOCK,
465 VK_FORMAT_ASTC_12x12_UNORM_BLOCK, VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
466 };
467 if (!features.textureCompressionASTC_LDR) {
468 return false;
469 }
470 const auto format_feature_usage{
471 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT |
472 VK_FORMAT_FEATURE_BLIT_DST_BIT | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
473 VK_FORMAT_FEATURE_TRANSFER_DST_BIT};
474 for (const auto format : astc_formats) {
475 const auto format_properties{physical.GetFormatProperties(format)};
476 if (!(format_properties.optimalTilingFeatures & format_feature_usage)) {
477 return false;
478 }
479 }
480 return true;
481}
482
483bool VKDevice::IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage,
484 FormatType format_type) const {
485 const auto it = format_properties.find(wanted_format);
486 if (it == format_properties.end()) {
487 UNIMPLEMENTED_MSG("Unimplemented format query={}", wanted_format);
488 return true;
489 }
490 const auto supported_usage = GetFormatFeatures(it->second, format_type);
491 return (supported_usage & wanted_usage) == wanted_usage;
492}
493
494bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) {
495 bool is_suitable = true;
496 std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions;
497
498 for (const auto& prop : physical.EnumerateDeviceExtensionProperties()) {
499 for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
500 if (available_extensions[i]) {
501 continue;
502 }
503 const std::string_view name{prop.extensionName};
504 available_extensions[i] = name == REQUIRED_EXTENSIONS[i];
505 }
506 }
507 if (!available_extensions.all()) {
508 for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
509 if (available_extensions[i]) {
510 continue;
511 }
512 LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]);
513 is_suitable = false;
514 }
515 }
516
517 bool has_graphics{}, has_present{};
518 const std::vector queue_family_properties = physical.GetQueueFamilyProperties();
519 for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) {
520 const auto& family = queue_family_properties[i];
521 if (family.queueCount == 0) {
522 continue;
523 }
524 has_graphics |= family.queueFlags & VK_QUEUE_GRAPHICS_BIT;
525 has_present |= physical.GetSurfaceSupportKHR(i, surface);
526 }
527 if (!has_graphics || !has_present) {
528 LOG_ERROR(Render_Vulkan, "Device lacks a graphics and present queue");
529 is_suitable = false;
530 }
531
532 // TODO(Rodrigo): Check if the device matches all requeriments.
533 const auto properties{physical.GetProperties()};
534 const auto& limits{properties.limits};
535
536 constexpr u32 required_ubo_size = 65536;
537 if (limits.maxUniformBufferRange < required_ubo_size) {
538 LOG_ERROR(Render_Vulkan, "Device UBO size {} is too small, {} is required",
539 limits.maxUniformBufferRange, required_ubo_size);
540 is_suitable = false;
541 }
542
543 constexpr u32 required_num_viewports = 16;
544 if (limits.maxViewports < required_num_viewports) {
545 LOG_INFO(Render_Vulkan, "Device number of viewports {} is too small, {} is required",
546 limits.maxViewports, required_num_viewports);
547 is_suitable = false;
548 }
549
550 const auto features{physical.GetFeatures()};
551 const std::array feature_report = {
552 std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),
553 std::make_pair(features.independentBlend, "independentBlend"),
554 std::make_pair(features.depthClamp, "depthClamp"),
555 std::make_pair(features.samplerAnisotropy, "samplerAnisotropy"),
556 std::make_pair(features.largePoints, "largePoints"),
557 std::make_pair(features.multiViewport, "multiViewport"),
558 std::make_pair(features.depthBiasClamp, "depthBiasClamp"),
559 std::make_pair(features.geometryShader, "geometryShader"),
560 std::make_pair(features.tessellationShader, "tessellationShader"),
561 std::make_pair(features.occlusionQueryPrecise, "occlusionQueryPrecise"),
562 std::make_pair(features.fragmentStoresAndAtomics, "fragmentStoresAndAtomics"),
563 std::make_pair(features.shaderImageGatherExtended, "shaderImageGatherExtended"),
564 std::make_pair(features.shaderStorageImageWriteWithoutFormat,
565 "shaderStorageImageWriteWithoutFormat"),
566 };
567 for (const auto& [supported, name] : feature_report) {
568 if (supported) {
569 continue;
570 }
571 LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name);
572 is_suitable = false;
573 }
574
575 if (!is_suitable) {
576 LOG_ERROR(Render_Vulkan, "{} is not suitable", properties.deviceName);
577 }
578
579 return is_suitable;
580}
581
582std::vector<const char*> VKDevice::LoadExtensions() {
583 std::vector<const char*> extensions;
584 const auto Test = [&](const VkExtensionProperties& extension,
585 std::optional<std::reference_wrapper<bool>> status, const char* name,
586 bool push) {
587 if (extension.extensionName != std::string_view(name)) {
588 return;
589 }
590 if (push) {
591 extensions.push_back(name);
592 }
593 if (status) {
594 status->get() = true;
595 }
596 };
597
598 extensions.reserve(7 + REQUIRED_EXTENSIONS.size());
599 extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end());
600
601 bool has_khr_shader_float16_int8{};
602 bool has_ext_subgroup_size_control{};
603 bool has_ext_transform_feedback{};
604 bool has_ext_custom_border_color{};
605 bool has_ext_extended_dynamic_state{};
606 for (const auto& extension : physical.EnumerateDeviceExtensionProperties()) {
607 Test(extension, nv_viewport_swizzle, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME, true);
608 Test(extension, khr_uniform_buffer_standard_layout,
609 VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, true);
610 Test(extension, has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME,
611 false);
612 Test(extension, ext_depth_range_unrestricted,
613 VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true);
614 Test(extension, ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true);
615 Test(extension, ext_shader_viewport_index_layer,
616 VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, true);
617 Test(extension, has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME,
618 false);
619 Test(extension, has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME,
620 false);
621 Test(extension, has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME,
622 false);
623 Test(extension, has_ext_extended_dynamic_state,
624 VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false);
625 if (Settings::values.renderer_debug) {
626 Test(extension, nv_device_diagnostics_config,
627 VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, true);
628 }
629 }
630
631 VkPhysicalDeviceFeatures2KHR features;
632 features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
633
634 VkPhysicalDeviceProperties2KHR properties;
635 properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
636
637 if (has_khr_shader_float16_int8) {
638 VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8_features;
639 float16_int8_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR;
640 float16_int8_features.pNext = nullptr;
641 features.pNext = &float16_int8_features;
642
643 physical.GetFeatures2KHR(features);
644 is_float16_supported = float16_int8_features.shaderFloat16;
645 extensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME);
646 }
647
648 if (has_ext_subgroup_size_control) {
649 VkPhysicalDeviceSubgroupSizeControlFeaturesEXT subgroup_features;
650 subgroup_features.sType =
651 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT;
652 subgroup_features.pNext = nullptr;
653 features.pNext = &subgroup_features;
654 physical.GetFeatures2KHR(features);
655
656 VkPhysicalDeviceSubgroupSizeControlPropertiesEXT subgroup_properties;
657 subgroup_properties.sType =
658 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT;
659 subgroup_properties.pNext = nullptr;
660 properties.pNext = &subgroup_properties;
661 physical.GetProperties2KHR(properties);
662
663 is_warp_potentially_bigger = subgroup_properties.maxSubgroupSize > GuestWarpSize;
664
665 if (subgroup_features.subgroupSizeControl &&
666 subgroup_properties.minSubgroupSize <= GuestWarpSize &&
667 subgroup_properties.maxSubgroupSize >= GuestWarpSize) {
668 extensions.push_back(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME);
669 guest_warp_stages = subgroup_properties.requiredSubgroupSizeStages;
670 }
671 } else {
672 is_warp_potentially_bigger = true;
673 }
674
675 if (has_ext_transform_feedback) {
676 VkPhysicalDeviceTransformFeedbackFeaturesEXT tfb_features;
677 tfb_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT;
678 tfb_features.pNext = nullptr;
679 features.pNext = &tfb_features;
680 physical.GetFeatures2KHR(features);
681
682 VkPhysicalDeviceTransformFeedbackPropertiesEXT tfb_properties;
683 tfb_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
684 tfb_properties.pNext = nullptr;
685 properties.pNext = &tfb_properties;
686 physical.GetProperties2KHR(properties);
687
688 if (tfb_features.transformFeedback && tfb_features.geometryStreams &&
689 tfb_properties.maxTransformFeedbackStreams >= 4 &&
690 tfb_properties.maxTransformFeedbackBuffers && tfb_properties.transformFeedbackQueries &&
691 tfb_properties.transformFeedbackDraw) {
692 extensions.push_back(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
693 ext_transform_feedback = true;
694 }
695 }
696
697 if (has_ext_custom_border_color) {
698 VkPhysicalDeviceCustomBorderColorFeaturesEXT border_features;
699 border_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT;
700 border_features.pNext = nullptr;
701 features.pNext = &border_features;
702 physical.GetFeatures2KHR(features);
703
704 if (border_features.customBorderColors && border_features.customBorderColorWithoutFormat) {
705 extensions.push_back(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
706 ext_custom_border_color = true;
707 }
708 }
709
710 if (has_ext_extended_dynamic_state) {
711 VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state;
712 dynamic_state.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT;
713 dynamic_state.pNext = nullptr;
714 features.pNext = &dynamic_state;
715 physical.GetFeatures2KHR(features);
716
717 if (dynamic_state.extendedDynamicState) {
718 extensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
719 ext_extended_dynamic_state = true;
720 }
721 }
722
723 return extensions;
724}
725
726void VKDevice::SetupFamilies(VkSurfaceKHR surface) {
727 std::optional<u32> graphics_family_, present_family_;
728
729 const std::vector queue_family_properties = physical.GetQueueFamilyProperties();
730 for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) {
731 if (graphics_family_ && present_family_)
732 break;
733
734 const auto& queue_family = queue_family_properties[i];
735 if (queue_family.queueCount == 0)
736 continue;
737
738 if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
739 graphics_family_ = i;
740 }
741 if (physical.GetSurfaceSupportKHR(i, surface)) {
742 present_family_ = i;
743 }
744 }
745 ASSERT(graphics_family_ && present_family_);
746
747 graphics_family = *graphics_family_;
748 present_family = *present_family_;
749}
750
751void VKDevice::SetupFeatures() {
752 const auto supported_features{physical.GetFeatures()};
753 is_formatless_image_load_supported = supported_features.shaderStorageImageReadWithoutFormat;
754 is_optimal_astc_supported = IsOptimalAstcSupported(supported_features);
755}
756
757void VKDevice::CollectTelemetryParameters() {
758 VkPhysicalDeviceDriverPropertiesKHR driver{
759 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR,
760 .pNext = nullptr,
761 };
762
763 VkPhysicalDeviceProperties2KHR properties{
764 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
765 .pNext = &driver,
766 };
767 physical.GetProperties2KHR(properties);
768
769 driver_id = driver.driverID;
770 vendor_name = driver.driverName;
771
772 const std::vector extensions = physical.EnumerateDeviceExtensionProperties();
773 reported_extensions.reserve(std::size(extensions));
774 for (const auto& extension : extensions) {
775 reported_extensions.emplace_back(extension.extensionName);
776 }
777}
778
779std::vector<VkDeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() const {
780 static constexpr float QUEUE_PRIORITY = 1.0f;
781
782 std::unordered_set<u32> unique_queue_families{graphics_family, present_family};
783 std::vector<VkDeviceQueueCreateInfo> queue_cis;
784 queue_cis.reserve(unique_queue_families.size());
785
786 for (const u32 queue_family : unique_queue_families) {
787 auto& ci = queue_cis.emplace_back(VkDeviceQueueCreateInfo{
788 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
789 .pNext = nullptr,
790 .flags = 0,
791 .queueFamilyIndex = queue_family,
792 .queueCount = 1,
793 .pQueuePriorities = nullptr,
794 });
795 ci.pQueuePriorities = &QUEUE_PRIORITY;
796 }
797
798 return queue_cis;
799}
800
801} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h
deleted file mode 100644
index 26a233db1..000000000
--- a/src/video_core/renderer_vulkan/vk_device.h
+++ /dev/null
@@ -1,274 +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 <string>
8#include <string_view>
9#include <unordered_map>
10#include <vector>
11
12#include "common/common_types.h"
13#include "video_core/renderer_vulkan/nsight_aftermath_tracker.h"
14#include "video_core/renderer_vulkan/wrapper.h"
15
16namespace Vulkan {
17
18/// Format usage descriptor.
19enum class FormatType { Linear, Optimal, Buffer };
20
21/// Subgroup size of the guest emulated hardware (Nvidia has 32 threads per subgroup).
22const u32 GuestWarpSize = 32;
23
24/// Handles data specific to a physical device.
25class VKDevice final {
26public:
27 explicit VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface,
28 const vk::InstanceDispatch& dld);
29 ~VKDevice();
30
31 /// Initializes the device. Returns true on success.
32 bool Create();
33
34 /**
35 * Returns a format supported by the device for the passed requeriments.
36 * @param wanted_format The ideal format to be returned. It may not be the returned format.
37 * @param wanted_usage The usage that must be fulfilled even if the format is not supported.
38 * @param format_type Format type usage.
39 * @returns A format supported by the device.
40 */
41 VkFormat GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage,
42 FormatType format_type) const;
43
44 /// Reports a device loss.
45 void ReportLoss() const;
46
47 /// Reports a shader to Nsight Aftermath.
48 void SaveShader(const std::vector<u32>& spirv) const;
49
50 /// Returns the dispatch loader with direct function pointers of the device.
51 const vk::DeviceDispatch& GetDispatchLoader() const {
52 return dld;
53 }
54
55 /// Returns the logical device.
56 const vk::Device& GetLogical() const {
57 return logical;
58 }
59
60 /// Returns the physical device.
61 vk::PhysicalDevice GetPhysical() const {
62 return physical;
63 }
64
65 /// Returns the main graphics queue.
66 vk::Queue GetGraphicsQueue() const {
67 return graphics_queue;
68 }
69
70 /// Returns the main present queue.
71 vk::Queue GetPresentQueue() const {
72 return present_queue;
73 }
74
75 /// Returns main graphics queue family index.
76 u32 GetGraphicsFamily() const {
77 return graphics_family;
78 }
79
80 /// Returns main present queue family index.
81 u32 GetPresentFamily() const {
82 return present_family;
83 }
84
85 /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers.
86 u32 GetApiVersion() const {
87 return properties.apiVersion;
88 }
89
90 /// Returns the current driver version provided in Vulkan-formatted version numbers.
91 u32 GetDriverVersion() const {
92 return properties.driverVersion;
93 }
94
95 /// Returns the device name.
96 std::string_view GetModelName() const {
97 return properties.deviceName;
98 }
99
100 /// Returns the driver ID.
101 VkDriverIdKHR GetDriverID() const {
102 return driver_id;
103 }
104
105 /// Returns uniform buffer alignment requeriment.
106 VkDeviceSize GetUniformBufferAlignment() const {
107 return properties.limits.minUniformBufferOffsetAlignment;
108 }
109
110 /// Returns storage alignment requeriment.
111 VkDeviceSize GetStorageBufferAlignment() const {
112 return properties.limits.minStorageBufferOffsetAlignment;
113 }
114
115 /// Returns the maximum range for storage buffers.
116 VkDeviceSize GetMaxStorageBufferRange() const {
117 return properties.limits.maxStorageBufferRange;
118 }
119
120 /// Returns the maximum size for push constants.
121 VkDeviceSize GetMaxPushConstantsSize() const {
122 return properties.limits.maxPushConstantsSize;
123 }
124
125 /// Returns the maximum size for shared memory.
126 u32 GetMaxComputeSharedMemorySize() const {
127 return properties.limits.maxComputeSharedMemorySize;
128 }
129
130 /// Returns true if ASTC is natively supported.
131 bool IsOptimalAstcSupported() const {
132 return is_optimal_astc_supported;
133 }
134
135 /// Returns true if the device supports float16 natively
136 bool IsFloat16Supported() const {
137 return is_float16_supported;
138 }
139
140 /// Returns true if the device warp size can potentially be bigger than guest's warp size.
141 bool IsWarpSizePotentiallyBiggerThanGuest() const {
142 return is_warp_potentially_bigger;
143 }
144
145 /// Returns true if the device can be forced to use the guest warp size.
146 bool IsGuestWarpSizeSupported(VkShaderStageFlagBits stage) const {
147 return guest_warp_stages & stage;
148 }
149
150 /// Returns true if formatless image load is supported.
151 bool IsFormatlessImageLoadSupported() const {
152 return is_formatless_image_load_supported;
153 }
154
155 /// Returns true if the device supports VK_NV_viewport_swizzle.
156 bool IsNvViewportSwizzleSupported() const {
157 return nv_viewport_swizzle;
158 }
159
160 /// Returns true if the device supports VK_EXT_scalar_block_layout.
161 bool IsKhrUniformBufferStandardLayoutSupported() const {
162 return khr_uniform_buffer_standard_layout;
163 }
164
165 /// Returns true if the device supports VK_EXT_index_type_uint8.
166 bool IsExtIndexTypeUint8Supported() const {
167 return ext_index_type_uint8;
168 }
169
170 /// Returns true if the device supports VK_EXT_depth_range_unrestricted.
171 bool IsExtDepthRangeUnrestrictedSupported() const {
172 return ext_depth_range_unrestricted;
173 }
174
175 /// Returns true if the device supports VK_EXT_shader_viewport_index_layer.
176 bool IsExtShaderViewportIndexLayerSupported() const {
177 return ext_shader_viewport_index_layer;
178 }
179
180 /// Returns true if the device supports VK_EXT_transform_feedback.
181 bool IsExtTransformFeedbackSupported() const {
182 return ext_transform_feedback;
183 }
184
185 /// Returns true if the device supports VK_EXT_custom_border_color.
186 bool IsExtCustomBorderColorSupported() const {
187 return ext_custom_border_color;
188 }
189
190 /// Returns true if the device supports VK_EXT_extended_dynamic_state.
191 bool IsExtExtendedDynamicStateSupported() const {
192 return ext_extended_dynamic_state;
193 }
194
195 /// Returns the vendor name reported from Vulkan.
196 std::string_view GetVendorName() const {
197 return vendor_name;
198 }
199
200 /// Returns the list of available extensions.
201 const std::vector<std::string>& GetAvailableExtensions() const {
202 return reported_extensions;
203 }
204
205 /// Returns true if the setting for async shader compilation is enabled.
206 bool UseAsynchronousShaders() const {
207 return use_asynchronous_shaders;
208 }
209
210 /// Checks if the physical device is suitable.
211 static bool IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface);
212
213private:
214 /// Loads extensions into a vector and stores available ones in this object.
215 std::vector<const char*> LoadExtensions();
216
217 /// Sets up queue families.
218 void SetupFamilies(VkSurfaceKHR surface);
219
220 /// Sets up device features.
221 void SetupFeatures();
222
223 /// Collects telemetry information from the device.
224 void CollectTelemetryParameters();
225
226 /// Returns a list of queue initialization descriptors.
227 std::vector<VkDeviceQueueCreateInfo> GetDeviceQueueCreateInfos() const;
228
229 /// Returns true if ASTC textures are natively supported.
230 bool IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const;
231
232 /// Returns true if a format is supported.
233 bool IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage,
234 FormatType format_type) const;
235
236 vk::DeviceDispatch dld; ///< Device function pointers.
237 vk::PhysicalDevice physical; ///< Physical device.
238 VkPhysicalDeviceProperties properties; ///< Device properties.
239 vk::Device logical; ///< Logical device.
240 vk::Queue graphics_queue; ///< Main graphics queue.
241 vk::Queue present_queue; ///< Main present queue.
242 u32 graphics_family{}; ///< Main graphics queue family index.
243 u32 present_family{}; ///< Main present queue family index.
244 VkDriverIdKHR driver_id{}; ///< Driver ID.
245 VkShaderStageFlags guest_warp_stages{}; ///< Stages where the guest warp size can be forced.ed
246 bool is_optimal_astc_supported{}; ///< Support for native ASTC.
247 bool is_float16_supported{}; ///< Support for float16 arithmetics.
248 bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest.
249 bool is_formatless_image_load_supported{}; ///< Support for shader image read without format.
250 bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle.
251 bool khr_uniform_buffer_standard_layout{}; ///< Support for std430 on UBOs.
252 bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8.
253 bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted.
254 bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer.
255 bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback.
256 bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color.
257 bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state.
258 bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config.
259
260 // Asynchronous Graphics Pipeline setting
261 bool use_asynchronous_shaders{}; ///< Setting to use asynchronous shaders/graphics pipeline
262
263 // Telemetry parameters
264 std::string vendor_name; ///< Device's driver name.
265 std::vector<std::string> reported_extensions; ///< Reported Vulkan extensions.
266
267 /// Format properties dictionary.
268 std::unordered_map<VkFormat, VkFormatProperties> format_properties;
269
270 /// Nsight Aftermath GPU crash tracker
271 NsightAftermathTracker nsight_aftermath_tracker;
272};
273
274} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
index 5babbdd0b..4c5bc0aa1 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
@@ -6,20 +6,21 @@
6#include <thread> 6#include <thread>
7 7
8#include "video_core/renderer_vulkan/vk_buffer_cache.h" 8#include "video_core/renderer_vulkan/vk_buffer_cache.h"
9#include "video_core/renderer_vulkan/vk_device.h"
10#include "video_core/renderer_vulkan/vk_fence_manager.h" 9#include "video_core/renderer_vulkan/vk_fence_manager.h"
11#include "video_core/renderer_vulkan/vk_scheduler.h" 10#include "video_core/renderer_vulkan/vk_scheduler.h"
12#include "video_core/renderer_vulkan/vk_texture_cache.h" 11#include "video_core/renderer_vulkan/vk_texture_cache.h"
13#include "video_core/renderer_vulkan/wrapper.h" 12#include "video_core/vulkan_common/vulkan_device.h"
13#include "video_core/vulkan_common/vulkan_wrapper.h"
14 14
15namespace Vulkan { 15namespace Vulkan {
16 16
17InnerFence::InnerFence(const VKDevice& device, VKScheduler& scheduler, u32 payload, bool is_stubbed) 17InnerFence::InnerFence(const Device& device_, VKScheduler& scheduler_, u32 payload_,
18 : VideoCommon::FenceBase(payload, is_stubbed), device{device}, scheduler{scheduler} {} 18 bool is_stubbed_)
19 : FenceBase{payload_, is_stubbed_}, device{device_}, scheduler{scheduler_} {}
19 20
20InnerFence::InnerFence(const VKDevice& device, VKScheduler& scheduler, GPUVAddr address, 21InnerFence::InnerFence(const Device& device_, VKScheduler& scheduler_, GPUVAddr address_,
21 u32 payload, bool is_stubbed) 22 u32 payload_, bool is_stubbed_)
22 : VideoCommon::FenceBase(address, payload, is_stubbed), device{device}, scheduler{scheduler} {} 23 : FenceBase{address_, payload_, is_stubbed_}, device{device_}, scheduler{scheduler_} {}
23 24
24InnerFence::~InnerFence() = default; 25InnerFence::~InnerFence() = default;
25 26
@@ -71,11 +72,11 @@ bool InnerFence::IsEventSignalled() const {
71 } 72 }
72} 73}
73 74
74VKFenceManager::VKFenceManager(VideoCore::RasterizerInterface& rasterizer, Tegra::GPU& gpu, 75VKFenceManager::VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_,
75 Tegra::MemoryManager& memory_manager, VKTextureCache& texture_cache, 76 Tegra::MemoryManager& memory_manager_, TextureCache& texture_cache_,
76 VKBufferCache& buffer_cache, VKQueryCache& query_cache, 77 VKBufferCache& buffer_cache_, VKQueryCache& query_cache_,
77 const VKDevice& device_, VKScheduler& scheduler_) 78 const Device& device_, VKScheduler& scheduler_)
78 : GenericFenceManager(rasterizer, gpu, texture_cache, buffer_cache, query_cache), 79 : GenericFenceManager{rasterizer_, gpu_, texture_cache_, buffer_cache_, query_cache_},
79 device{device_}, scheduler{scheduler_} {} 80 device{device_}, scheduler{scheduler_} {}
80 81
81Fence VKFenceManager::CreateFence(u32 value, bool is_stubbed) { 82Fence VKFenceManager::CreateFence(u32 value, bool is_stubbed) {
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.h b/src/video_core/renderer_vulkan/vk_fence_manager.h
index 1547d6d30..6b51e4587 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.h
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.h
@@ -8,7 +8,8 @@
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/wrapper.h" 11#include "video_core/renderer_vulkan/vk_texture_cache.h"
12#include "video_core/vulkan_common/vulkan_wrapper.h"
12 13
13namespace Core { 14namespace Core {
14class System; 15class System;
@@ -20,18 +21,17 @@ class RasterizerInterface;
20 21
21namespace Vulkan { 22namespace Vulkan {
22 23
24class Device;
23class VKBufferCache; 25class VKBufferCache;
24class 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:
31 explicit InnerFence(const VKDevice& device, VKScheduler& scheduler, u32 payload, 31 explicit InnerFence(const Device& device_, VKScheduler& scheduler_, u32 payload_,
32 bool is_stubbed); 32 bool is_stubbed_);
33 explicit InnerFence(const VKDevice& device, VKScheduler& scheduler, GPUVAddr address, 33 explicit InnerFence(const Device& device_, VKScheduler& scheduler_, GPUVAddr address_,
34 u32 payload, bool is_stubbed); 34 u32 payload_, bool is_stubbed_);
35 ~InnerFence(); 35 ~InnerFence();
36 36
37 void Queue(); 37 void Queue();
@@ -43,7 +43,7 @@ public:
43private: 43private:
44 bool IsEventSignalled() const; 44 bool IsEventSignalled() const;
45 45
46 const VKDevice& device; 46 const Device& device;
47 VKScheduler& scheduler; 47 VKScheduler& scheduler;
48 vk::Event event; 48 vk::Event event;
49 u64 ticks = 0; 49 u64 ticks = 0;
@@ -51,14 +51,14 @@ 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 Device& device_, VKScheduler& scheduler_);
62 62
63protected: 63protected:
64 Fence CreateFence(u32 value, bool is_stubbed) override; 64 Fence CreateFence(u32 value, bool is_stubbed) override;
@@ -68,7 +68,7 @@ protected:
68 void WaitFence(Fence& fence) override; 68 void WaitFence(Fence& fence) override;
69 69
70private: 70private:
71 const VKDevice& device; 71 const Device& device;
72 VKScheduler& scheduler; 72 VKScheduler& scheduler;
73}; 73};
74 74
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index a4b9e7ef5..a5214d0bc 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -12,13 +12,12 @@
12#include "video_core/renderer_vulkan/fixed_pipeline_state.h" 12#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
13#include "video_core/renderer_vulkan/maxwell_to_vk.h" 13#include "video_core/renderer_vulkan/maxwell_to_vk.h"
14#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 14#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
15#include "video_core/renderer_vulkan/vk_device.h"
16#include "video_core/renderer_vulkan/vk_graphics_pipeline.h" 15#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
17#include "video_core/renderer_vulkan/vk_pipeline_cache.h" 16#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" 17#include "video_core/renderer_vulkan/vk_scheduler.h"
20#include "video_core/renderer_vulkan/vk_update_descriptor.h" 18#include "video_core/renderer_vulkan/vk_update_descriptor.h"
21#include "video_core/renderer_vulkan/wrapper.h" 19#include "video_core/vulkan_common/vulkan_device.h"
20#include "video_core/vulkan_common/vulkan_wrapper.h"
22 21
23namespace Vulkan { 22namespace Vulkan {
24 23
@@ -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 Device& 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,
78 const GraphicsPipelineCacheKey& key, 100 const GraphicsPipelineCacheKey& key,
79 vk::Span<VkDescriptorSetLayoutBinding> bindings, 101 vk::Span<VkDescriptorSetLayoutBinding> bindings,
80 const SPIRVProgram& program) 102 const SPIRVProgram& program, u32 num_color_buffers)
81 : device{device}, scheduler{scheduler}, cache_key{key}, hash{cache_key.Hash()}, 103 : device{device_}, scheduler{scheduler_}, cache_key{key}, hash{cache_key.Hash()},
82 descriptor_set_layout{CreateDescriptorSetLayout(bindings)}, 104 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
@@ -159,10 +180,11 @@ std::vector<vk::ShaderModule> VKGraphicsPipeline::CreateShaderModules(
159 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 180 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
160 .pNext = nullptr, 181 .pNext = nullptr,
161 .flags = 0, 182 .flags = 0,
183 .codeSize = 0,
162 }; 184 };
163 185
164 std::vector<vk::ShaderModule> modules; 186 std::vector<vk::ShaderModule> shader_modules;
165 modules.reserve(Maxwell::MaxShaderStage); 187 shader_modules.reserve(Maxwell::MaxShaderStage);
166 for (std::size_t i = 0; i < Maxwell::MaxShaderStage; ++i) { 188 for (std::size_t i = 0; i < Maxwell::MaxShaderStage; ++i) {
167 const auto& stage = program[i]; 189 const auto& stage = program[i];
168 if (!stage) { 190 if (!stage) {
@@ -173,13 +195,14 @@ std::vector<vk::ShaderModule> VKGraphicsPipeline::CreateShaderModules(
173 195
174 ci.codeSize = stage->code.size() * sizeof(u32); 196 ci.codeSize = stage->code.size() * sizeof(u32);
175 ci.pCode = stage->code.data(); 197 ci.pCode = stage->code.data();
176 modules.push_back(device.GetLogical().CreateShaderModule(ci)); 198 shader_modules.push_back(device.GetLogical().CreateShaderModule(ci));
177 } 199 }
178 return modules; 200 return shader_modules;
179} 201}
180 202
181vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpass_params, 203vk::Pipeline VKGraphicsPipeline::CreatePipeline(const SPIRVProgram& program,
182 const SPIRVProgram& program) const { 204 VkRenderPass renderpass,
205 u32 num_color_buffers) const {
183 const auto& state = cache_key.fixed_state; 206 const auto& state = cache_key.fixed_state;
184 const auto& viewport_swizzles = state.viewport_swizzles; 207 const auto& viewport_swizzles = state.viewport_swizzles;
185 208
@@ -189,11 +212,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
189 // state is ignored 212 // state is ignored
190 dynamic.raw1 = 0; 213 dynamic.raw1 = 0;
191 dynamic.raw2 = 0; 214 dynamic.raw2 = 0;
192 for (FixedPipelineState::VertexBinding& binding : dynamic.vertex_bindings) { 215 dynamic.vertex_strides.fill(0);
193 // Enable all vertex bindings
194 binding.raw = 0;
195 binding.enabled.Assign(1);
196 }
197 } else { 216 } else {
198 dynamic = state.dynamic_state; 217 dynamic = state.dynamic_state;
199 } 218 }
@@ -201,19 +220,16 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
201 std::vector<VkVertexInputBindingDescription> vertex_bindings; 220 std::vector<VkVertexInputBindingDescription> vertex_bindings;
202 std::vector<VkVertexInputBindingDivisorDescriptionEXT> vertex_binding_divisors; 221 std::vector<VkVertexInputBindingDivisorDescriptionEXT> vertex_binding_divisors;
203 for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { 222 for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) {
204 const auto& binding = dynamic.vertex_bindings[index]; 223 if (state.attributes[index].binding_index_enabled == 0) {
205 if (!binding.enabled) {
206 continue; 224 continue;
207 } 225 }
208 const bool instanced = state.binding_divisors[index] != 0; 226 const bool instanced = state.binding_divisors[index] != 0;
209 const auto rate = instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; 227 const auto rate = instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
210
211 vertex_bindings.push_back({ 228 vertex_bindings.push_back({
212 .binding = static_cast<u32>(index), 229 .binding = static_cast<u32>(index),
213 .stride = binding.stride, 230 .stride = dynamic.vertex_strides[index],
214 .inputRate = rate, 231 .inputRate = rate,
215 }); 232 });
216
217 if (instanced) { 233 if (instanced) {
218 vertex_binding_divisors.push_back({ 234 vertex_binding_divisors.push_back({
219 .binding = static_cast<u32>(index), 235 .binding = static_cast<u32>(index),
@@ -229,7 +245,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
229 if (!attribute.enabled) { 245 if (!attribute.enabled) {
230 continue; 246 continue;
231 } 247 }
232 if (input_attributes.find(static_cast<u32>(index)) == input_attributes.end()) { 248 if (!input_attributes.contains(static_cast<u32>(index))) {
233 // Skip attributes not used by the vertex shaders. 249 // Skip attributes not used by the vertex shaders.
234 continue; 250 continue;
235 } 251 }
@@ -261,12 +277,12 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
261 vertex_input_ci.pNext = &input_divisor_ci; 277 vertex_input_ci.pNext = &input_divisor_ci;
262 } 278 }
263 279
264 const auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()); 280 const auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, state.topology);
265 const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ 281 const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{
266 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, 282 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
267 .pNext = nullptr, 283 .pNext = nullptr,
268 .flags = 0, 284 .flags = 0,
269 .topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()), 285 .topology = MaxwellToVK::PrimitiveTopology(device, state.topology),
270 .primitiveRestartEnable = state.primitive_restart_enable != 0 && 286 .primitiveRestartEnable = state.primitive_restart_enable != 0 &&
271 SupportsPrimitiveRestart(input_assembly_topology), 287 SupportsPrimitiveRestart(input_assembly_topology),
272 }; 288 };
@@ -289,8 +305,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
289 }; 305 };
290 306
291 std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles; 307 std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles;
292 std::transform(viewport_swizzles.begin(), viewport_swizzles.end(), swizzles.begin(), 308 std::ranges::transform(viewport_swizzles, swizzles.begin(), UnpackViewportSwizzle);
293 UnpackViewportSwizzle);
294 VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ 309 VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{
295 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV, 310 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV,
296 .pNext = nullptr, 311 .pNext = nullptr,
@@ -325,7 +340,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
325 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, 340 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
326 .pNext = nullptr, 341 .pNext = nullptr,
327 .flags = 0, 342 .flags = 0,
328 .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, 343 .rasterizationSamples = ConvertMsaaMode(state.msaa_mode),
329 .sampleShadingEnable = VK_FALSE, 344 .sampleShadingEnable = VK_FALSE,
330 .minSampleShading = 0.0f, 345 .minSampleShading = 0.0f,
331 .pSampleMask = nullptr, 346 .pSampleMask = nullptr,
@@ -351,8 +366,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
351 }; 366 };
352 367
353 std::array<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments; 368 std::array<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments;
354 const auto num_attachments = static_cast<std::size_t>(renderpass_params.num_color_attachments); 369 for (std::size_t index = 0; index < num_color_buffers; ++index) {
355 for (std::size_t index = 0; index < num_attachments; ++index) {
356 static constexpr std::array COMPONENT_TABLE{ 370 static constexpr std::array COMPONENT_TABLE{
357 VK_COLOR_COMPONENT_R_BIT, 371 VK_COLOR_COMPONENT_R_BIT,
358 VK_COLOR_COMPONENT_G_BIT, 372 VK_COLOR_COMPONENT_G_BIT,
@@ -386,8 +400,9 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
386 .flags = 0, 400 .flags = 0,
387 .logicOpEnable = VK_FALSE, 401 .logicOpEnable = VK_FALSE,
388 .logicOp = VK_LOGIC_OP_COPY, 402 .logicOp = VK_LOGIC_OP_COPY,
389 .attachmentCount = static_cast<u32>(num_attachments), 403 .attachmentCount = num_color_buffers,
390 .pAttachments = cb_attachments.data(), 404 .pAttachments = cb_attachments.data(),
405 .blendConstants = {},
391 }; 406 };
392 407
393 std::vector dynamic_states{ 408 std::vector dynamic_states{
@@ -400,7 +415,6 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
400 static constexpr std::array extended{ 415 static constexpr std::array extended{
401 VK_DYNAMIC_STATE_CULL_MODE_EXT, 416 VK_DYNAMIC_STATE_CULL_MODE_EXT,
402 VK_DYNAMIC_STATE_FRONT_FACE_EXT, 417 VK_DYNAMIC_STATE_FRONT_FACE_EXT,
403 VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT,
404 VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT, 418 VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT,
405 VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT, 419 VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT,
406 VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT, 420 VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT,
@@ -446,8 +460,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
446 stage_ci.pNext = &subgroup_size_ci; 460 stage_ci.pNext = &subgroup_size_ci;
447 } 461 }
448 } 462 }
449 463 return device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
450 const VkGraphicsPipelineCreateInfo ci{
451 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, 464 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
452 .pNext = nullptr, 465 .pNext = nullptr,
453 .flags = 0, 466 .flags = 0,
@@ -467,8 +480,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
467 .subpass = 0, 480 .subpass = 0,
468 .basePipelineHandle = nullptr, 481 .basePipelineHandle = nullptr,
469 .basePipelineIndex = 0, 482 .basePipelineIndex = 0,
470 }; 483 });
471 return device.GetLogical().CreateGraphicsPipeline(ci);
472} 484}
473 485
474} // namespace Vulkan 486} // 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 58aa35efd..8b6a98fe0 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
@@ -8,20 +8,19 @@
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/vulkan_common/vulkan_wrapper.h"
17 17
18namespace Vulkan { 18namespace Vulkan {
19 19
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,16 +33,15 @@ 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>);
41static_assert(std::is_trivially_copyable_v<GraphicsPipelineCacheKey>); 40static_assert(std::is_trivially_copyable_v<GraphicsPipelineCacheKey>);
42static_assert(std::is_trivially_constructible_v<GraphicsPipelineCacheKey>); 41static_assert(std::is_trivially_constructible_v<GraphicsPipelineCacheKey>);
43 42
43class Device;
44class VKDescriptorPool; 44class VKDescriptorPool;
45class VKDevice;
46class VKRenderPassCache;
47class VKScheduler; 45class VKScheduler;
48class VKUpdateDescriptorQueue; 46class VKUpdateDescriptorQueue;
49 47
@@ -51,13 +49,12 @@ using SPIRVProgram = std::array<std::optional<SPIRVShader>, Maxwell::MaxShaderSt
51 49
52class VKGraphicsPipeline final { 50class VKGraphicsPipeline final {
53public: 51public:
54 explicit VKGraphicsPipeline(const VKDevice& device, VKScheduler& scheduler, 52 explicit VKGraphicsPipeline(const Device& 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,
58 const GraphicsPipelineCacheKey& key, 55 const GraphicsPipelineCacheKey& key,
59 vk::Span<VkDescriptorSetLayoutBinding> bindings, 56 vk::Span<VkDescriptorSetLayoutBinding> bindings,
60 const SPIRVProgram& program); 57 const SPIRVProgram& program, u32 num_color_buffers);
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,10 +82,10 @@ 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 Device& device;
96 VKScheduler& scheduler; 89 VKScheduler& scheduler;
97 const GraphicsPipelineCacheKey cache_key; 90 const GraphicsPipelineCacheKey cache_key;
98 const u64 hash; 91 const u64 hash;
@@ -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 1c418ea17..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, const VkImageCreateInfo& image_ci,
17 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 b4d7229e5..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_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
index ae26e558d..56ec5e380 100644
--- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
+++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
@@ -6,15 +6,15 @@
6#include <chrono> 6#include <chrono>
7 7
8#include "core/settings.h" 8#include "core/settings.h"
9#include "video_core/renderer_vulkan/vk_device.h"
10#include "video_core/renderer_vulkan/vk_master_semaphore.h" 9#include "video_core/renderer_vulkan/vk_master_semaphore.h"
11#include "video_core/renderer_vulkan/wrapper.h" 10#include "video_core/vulkan_common/vulkan_device.h"
11#include "video_core/vulkan_common/vulkan_wrapper.h"
12 12
13namespace Vulkan { 13namespace Vulkan {
14 14
15using namespace std::chrono_literals; 15using namespace std::chrono_literals;
16 16
17MasterSemaphore::MasterSemaphore(const VKDevice& device) { 17MasterSemaphore::MasterSemaphore(const Device& device) {
18 static constexpr VkSemaphoreTypeCreateInfoKHR semaphore_type_ci{ 18 static constexpr VkSemaphoreTypeCreateInfoKHR semaphore_type_ci{
19 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR, 19 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR,
20 .pNext = nullptr, 20 .pNext = nullptr,
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h
index 0e93706d7..f336f1862 100644
--- a/src/video_core/renderer_vulkan/vk_master_semaphore.h
+++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h
@@ -8,15 +8,15 @@
8#include <thread> 8#include <thread>
9 9
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "video_core/renderer_vulkan/wrapper.h" 11#include "video_core/vulkan_common/vulkan_wrapper.h"
12 12
13namespace Vulkan { 13namespace Vulkan {
14 14
15class VKDevice; 15class Device;
16 16
17class MasterSemaphore { 17class MasterSemaphore {
18public: 18public:
19 explicit MasterSemaphore(const VKDevice& device); 19 explicit MasterSemaphore(const Device& device);
20 ~MasterSemaphore(); 20 ~MasterSemaphore();
21 21
22 /// Returns the current logical tick. 22 /// Returns the current logical tick.
diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.cpp b/src/video_core/renderer_vulkan/vk_memory_manager.cpp
index 24c8960ac..a6abd0eee 100644
--- a/src/video_core/renderer_vulkan/vk_memory_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_memory_manager.cpp
@@ -11,9 +11,9 @@
11#include "common/assert.h" 11#include "common/assert.h"
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "video_core/renderer_vulkan/vk_device.h"
15#include "video_core/renderer_vulkan/vk_memory_manager.h" 14#include "video_core/renderer_vulkan/vk_memory_manager.h"
16#include "video_core/renderer_vulkan/wrapper.h" 15#include "video_core/vulkan_common/vulkan_device.h"
16#include "video_core/vulkan_common/vulkan_wrapper.h"
17 17
18namespace Vulkan { 18namespace Vulkan {
19 19
@@ -29,10 +29,10 @@ u64 GetAllocationChunkSize(u64 required_size) {
29 29
30class VKMemoryAllocation final { 30class VKMemoryAllocation final {
31public: 31public:
32 explicit VKMemoryAllocation(const VKDevice& device, vk::DeviceMemory memory, 32 explicit VKMemoryAllocation(const Device& device_, vk::DeviceMemory memory_,
33 VkMemoryPropertyFlags properties, u64 allocation_size, u32 type) 33 VkMemoryPropertyFlags properties_, u64 allocation_size_, u32 type_)
34 : device{device}, memory{std::move(memory)}, properties{properties}, 34 : device{device_}, memory{std::move(memory_)}, properties{properties_},
35 allocation_size{allocation_size}, shifted_type{ShiftType(type)} {} 35 allocation_size{allocation_size_}, shifted_type{ShiftType(type_)} {}
36 36
37 VKMemoryCommit Commit(VkDeviceSize commit_size, VkDeviceSize alignment) { 37 VKMemoryCommit Commit(VkDeviceSize commit_size, VkDeviceSize alignment) {
38 auto found = TryFindFreeSection(free_iterator, allocation_size, 38 auto found = TryFindFreeSection(free_iterator, allocation_size,
@@ -104,7 +104,7 @@ private:
104 return std::nullopt; 104 return std::nullopt;
105 } 105 }
106 106
107 const VKDevice& device; ///< Vulkan device. 107 const Device& device; ///< Vulkan device.
108 const vk::DeviceMemory memory; ///< Vulkan memory allocation handler. 108 const vk::DeviceMemory memory; ///< Vulkan memory allocation handler.
109 const VkMemoryPropertyFlags properties; ///< Vulkan properties. 109 const VkMemoryPropertyFlags properties; ///< Vulkan properties.
110 const u64 allocation_size; ///< Size of this allocation. 110 const u64 allocation_size; ///< Size of this allocation.
@@ -117,8 +117,8 @@ private:
117 std::vector<const VKMemoryCommitImpl*> commits; 117 std::vector<const VKMemoryCommitImpl*> commits;
118}; 118};
119 119
120VKMemoryManager::VKMemoryManager(const VKDevice& device) 120VKMemoryManager::VKMemoryManager(const Device& device_)
121 : device{device}, properties{device.GetPhysical().GetMemoryProperties()} {} 121 : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()} {}
122 122
123VKMemoryManager::~VKMemoryManager() = default; 123VKMemoryManager::~VKMemoryManager() = default;
124 124
@@ -207,16 +207,16 @@ VKMemoryCommit VKMemoryManager::TryAllocCommit(const VkMemoryRequirements& requi
207 return {}; 207 return {};
208} 208}
209 209
210VKMemoryCommitImpl::VKMemoryCommitImpl(const VKDevice& device, VKMemoryAllocation* allocation, 210VKMemoryCommitImpl::VKMemoryCommitImpl(const Device& device_, VKMemoryAllocation* allocation_,
211 const vk::DeviceMemory& memory, u64 begin, u64 end) 211 const vk::DeviceMemory& memory_, u64 begin_, u64 end_)
212 : device{device}, memory{memory}, interval{begin, end}, allocation{allocation} {} 212 : device{device_}, memory{memory_}, interval{begin_, end_}, allocation{allocation_} {}
213 213
214VKMemoryCommitImpl::~VKMemoryCommitImpl() { 214VKMemoryCommitImpl::~VKMemoryCommitImpl() {
215 allocation->Free(this); 215 allocation->Free(this);
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 1af88e3d4..2452bca4e 100644
--- a/src/video_core/renderer_vulkan/vk_memory_manager.h
+++ b/src/video_core/renderer_vulkan/vk_memory_manager.h
@@ -5,15 +5,16 @@
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"
11#include "video_core/renderer_vulkan/wrapper.h" 12#include "video_core/vulkan_common/vulkan_wrapper.h"
12 13
13namespace Vulkan { 14namespace Vulkan {
14 15
16class Device;
15class MemoryMap; 17class MemoryMap;
16class VKDevice;
17class VKMemoryAllocation; 18class VKMemoryAllocation;
18class VKMemoryCommitImpl; 19class VKMemoryCommitImpl;
19 20
@@ -21,7 +22,7 @@ using VKMemoryCommit = std::unique_ptr<VKMemoryCommitImpl>;
21 22
22class VKMemoryManager final { 23class VKMemoryManager final {
23public: 24public:
24 explicit VKMemoryManager(const VKDevice& device); 25 explicit VKMemoryManager(const Device& device_);
25 VKMemoryManager(const VKMemoryManager&) = delete; 26 VKMemoryManager(const VKMemoryManager&) = delete;
26 ~VKMemoryManager(); 27 ~VKMemoryManager();
27 28
@@ -48,7 +49,7 @@ private:
48 VKMemoryCommit TryAllocCommit(const VkMemoryRequirements& requirements, 49 VKMemoryCommit TryAllocCommit(const VkMemoryRequirements& requirements,
49 VkMemoryPropertyFlags wanted_properties); 50 VkMemoryPropertyFlags wanted_properties);
50 51
51 const VKDevice& device; ///< Device handler. 52 const Device& device; ///< Device handler.
52 const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. 53 const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties.
53 std::vector<std::unique_ptr<VKMemoryAllocation>> allocations; ///< Current allocations. 54 std::vector<std::unique_ptr<VKMemoryAllocation>> allocations; ///< Current allocations.
54}; 55};
@@ -58,8 +59,8 @@ class VKMemoryCommitImpl final {
58 friend MemoryMap; 59 friend MemoryMap;
59 60
60public: 61public:
61 explicit VKMemoryCommitImpl(const VKDevice& device, VKMemoryAllocation* allocation, 62 explicit VKMemoryCommitImpl(const Device& device_, VKMemoryAllocation* allocation_,
62 const vk::DeviceMemory& memory, u64 begin, u64 end); 63 const vk::DeviceMemory& memory_, u64 begin_, u64 end_);
63 ~VKMemoryCommitImpl(); 64 ~VKMemoryCommitImpl();
64 65
65 /// Maps a memory region and returns a pointer to it. 66 /// Maps a memory region and returns a pointer to it.
@@ -84,7 +85,7 @@ private:
84 /// Unmaps memory. 85 /// Unmaps memory.
85 void Unmap() const; 86 void Unmap() const;
86 87
87 const VKDevice& device; ///< Vulkan device. 88 const Device& device; ///< Vulkan device.
88 const vk::DeviceMemory& memory; ///< Vulkan device memory handler. 89 const vk::DeviceMemory& memory; ///< Vulkan device memory handler.
89 std::pair<u64, u64> interval{}; ///< Interval where the commit exists. 90 std::pair<u64, u64> interval{}; ///< Interval where the commit exists.
90 VKMemoryAllocation* allocation{}; ///< Pointer to the large memory allocation. 91 VKMemoryAllocation* allocation{}; ///< Pointer to the large memory allocation.
@@ -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 5c038f4bc..02282e36f 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -7,6 +7,8 @@
7#include <memory> 7#include <memory>
8#include <vector> 8#include <vector>
9 9
10#include "common/bit_cast.h"
11#include "common/cityhash.h"
10#include "common/microprofile.h" 12#include "common/microprofile.h"
11#include "core/core.h" 13#include "core/core.h"
12#include "core/memory.h" 14#include "core/memory.h"
@@ -17,18 +19,17 @@
17#include "video_core/renderer_vulkan/maxwell_to_vk.h" 19#include "video_core/renderer_vulkan/maxwell_to_vk.h"
18#include "video_core/renderer_vulkan/vk_compute_pipeline.h" 20#include "video_core/renderer_vulkan/vk_compute_pipeline.h"
19#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 21#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
20#include "video_core/renderer_vulkan/vk_device.h"
21#include "video_core/renderer_vulkan/vk_graphics_pipeline.h" 22#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
22#include "video_core/renderer_vulkan/vk_pipeline_cache.h" 23#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
23#include "video_core/renderer_vulkan/vk_rasterizer.h" 24#include "video_core/renderer_vulkan/vk_rasterizer.h"
24#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
25#include "video_core/renderer_vulkan/vk_scheduler.h" 25#include "video_core/renderer_vulkan/vk_scheduler.h"
26#include "video_core/renderer_vulkan/vk_update_descriptor.h" 26#include "video_core/renderer_vulkan/vk_update_descriptor.h"
27#include "video_core/renderer_vulkan/wrapper.h"
28#include "video_core/shader/compiler_settings.h" 27#include "video_core/shader/compiler_settings.h"
29#include "video_core/shader/memory_util.h" 28#include "video_core/shader/memory_util.h"
30#include "video_core/shader_cache.h" 29#include "video_core/shader_cache.h"
31#include "video_core/shader_notify.h" 30#include "video_core/shader_notify.h"
31#include "video_core/vulkan_common/vulkan_device.h"
32#include "video_core/vulkan_common/vulkan_wrapper.h"
32 33
33namespace Vulkan { 34namespace Vulkan {
34 35
@@ -51,7 +52,9 @@ constexpr VkDescriptorType STORAGE_TEXEL_BUFFER = VK_DESCRIPTOR_TYPE_STORAGE_TEX
51constexpr VkDescriptorType STORAGE_IMAGE = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; 52constexpr VkDescriptorType STORAGE_IMAGE = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
52 53
53constexpr VideoCommon::Shader::CompilerSettings compiler_settings{ 54constexpr VideoCommon::Shader::CompilerSettings compiler_settings{
54 VideoCommon::Shader::CompileDepth::FullDecompile}; 55 .depth = VideoCommon::Shader::CompileDepth::FullDecompile,
56 .disable_else_derivation = true,
57};
55 58
56constexpr std::size_t GetStageFromProgram(std::size_t program) { 59constexpr std::size_t GetStageFromProgram(std::size_t program) {
57 return program == 0 ? 0 : program - 1; 60 return program == 0 ? 0 : program - 1;
@@ -74,7 +77,7 @@ ShaderType GetShaderType(Maxwell::ShaderProgram program) {
74 case Maxwell::ShaderProgram::Fragment: 77 case Maxwell::ShaderProgram::Fragment:
75 return ShaderType::Fragment; 78 return ShaderType::Fragment;
76 default: 79 default:
77 UNIMPLEMENTED_MSG("program={}", static_cast<u32>(program)); 80 UNIMPLEMENTED_MSG("program={}", program);
78 return ShaderType::Vertex; 81 return ShaderType::Vertex;
79 } 82 }
80} 83}
@@ -135,26 +138,24 @@ bool ComputePipelineCacheKey::operator==(const ComputePipelineCacheKey& rhs) con
135 return std::memcmp(&rhs, this, sizeof *this) == 0; 138 return std::memcmp(&rhs, this, sizeof *this) == 0;
136} 139}
137 140
138Shader::Shader(Tegra::Engines::ConstBufferEngineInterface& engine, Tegra::Engines::ShaderType stage, 141Shader::Shader(Tegra::Engines::ConstBufferEngineInterface& engine_, ShaderType stage_,
139 GPUVAddr gpu_addr_, VAddr cpu_addr, VideoCommon::Shader::ProgramCode program_code_, 142 GPUVAddr gpu_addr_, VAddr cpu_addr_, ProgramCode program_code_, u32 main_offset_)
140 u32 main_offset) 143 : gpu_addr(gpu_addr_), program_code(std::move(program_code_)), registry(stage_, engine_),
141 : gpu_addr(gpu_addr_), program_code(std::move(program_code_)), registry(stage, engine), 144 shader_ir(program_code, main_offset_, compiler_settings, registry),
142 shader_ir(program_code, main_offset, compiler_settings, registry),
143 entries(GenerateShaderEntries(shader_ir)) {} 145 entries(GenerateShaderEntries(shader_ir)) {}
144 146
145Shader::~Shader() = default; 147Shader::~Shader() = default;
146 148
147VKPipelineCache::VKPipelineCache(RasterizerVulkan& rasterizer, Tegra::GPU& gpu_, 149VKPipelineCache::VKPipelineCache(RasterizerVulkan& rasterizer_, Tegra::GPU& gpu_,
148 Tegra::Engines::Maxwell3D& maxwell3d_, 150 Tegra::Engines::Maxwell3D& maxwell3d_,
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 Device& 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 : VideoCommon::ShaderCache<Shader>{rasterizer}, gpu{gpu_}, maxwell3d{maxwell3d_},
155 kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, device{device_}, 156 kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, device{device_},
156 scheduler{scheduler_}, descriptor_pool{descriptor_pool_}, 157 scheduler{scheduler_}, descriptor_pool{descriptor_pool_}, update_descriptor_queue{
157 update_descriptor_queue{update_descriptor_queue_}, renderpass_cache{renderpass_cache_} {} 158 update_descriptor_queue_} {}
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();
@@ -331,8 +333,7 @@ void VKPipelineCache::OnShaderRemoval(Shader* shader) {
331std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>> 333std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>>
332VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) { 334VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) {
333 Specialization specialization; 335 Specialization specialization;
334 if (fixed_state.dynamic_state.Topology() == Maxwell::PrimitiveTopology::Points || 336 if (fixed_state.topology == Maxwell::PrimitiveTopology::Points) {
335 device.IsExtExtendedDynamicStateSupported()) {
336 float point_size; 337 float point_size;
337 std::memcpy(&point_size, &fixed_state.point_size, sizeof(float)); 338 std::memcpy(&point_size, &fixed_state.point_size, sizeof(float));
338 specialization.point_size = point_size; 339 specialization.point_size = point_size;
@@ -344,6 +345,12 @@ VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) {
344 specialization.attribute_types[i] = attribute.Type(); 345 specialization.attribute_types[i] = attribute.Type();
345 } 346 }
346 specialization.ndc_minus_one_to_one = fixed_state.ndc_minus_one_to_one; 347 specialization.ndc_minus_one_to_one = fixed_state.ndc_minus_one_to_one;
348 specialization.early_fragment_tests = fixed_state.early_z;
349
350 // Alpha test
351 specialization.alpha_test_func =
352 FixedPipelineState::UnpackComparisonOp(fixed_state.alpha_test_func.Value());
353 specialization.alpha_test_ref = Common::BitCast<float>(fixed_state.alpha_test_ref);
347 354
348 SPIRVProgram program; 355 SPIRVProgram program;
349 std::vector<VkDescriptorSetLayoutBinding> bindings; 356 std::vector<VkDescriptorSetLayoutBinding> bindings;
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index e558e6658..89d635a3d 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -19,14 +19,13 @@
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"
25#include "video_core/shader/async_shaders.h" 23#include "video_core/shader/async_shaders.h"
26#include "video_core/shader/memory_util.h" 24#include "video_core/shader/memory_util.h"
27#include "video_core/shader/registry.h" 25#include "video_core/shader/registry.h"
28#include "video_core/shader/shader_ir.h" 26#include "video_core/shader/shader_ir.h"
29#include "video_core/shader_cache.h" 27#include "video_core/shader_cache.h"
28#include "video_core/vulkan_common/vulkan_wrapper.h"
30 29
31namespace Core { 30namespace Core {
32class System; 31class System;
@@ -34,10 +33,10 @@ class System;
34 33
35namespace Vulkan { 34namespace Vulkan {
36 35
36class Device;
37class RasterizerVulkan; 37class RasterizerVulkan;
38class VKComputePipeline; 38class VKComputePipeline;
39class VKDescriptorPool; 39class VKDescriptorPool;
40class VKDevice;
41class VKScheduler; 40class VKScheduler;
42class VKUpdateDescriptorQueue; 41class VKUpdateDescriptorQueue;
43 42
@@ -84,9 +83,9 @@ namespace Vulkan {
84 83
85class Shader { 84class Shader {
86public: 85public:
87 explicit Shader(Tegra::Engines::ConstBufferEngineInterface& engine, 86 explicit Shader(Tegra::Engines::ConstBufferEngineInterface& engine_,
88 Tegra::Engines::ShaderType stage, GPUVAddr gpu_addr, VAddr cpu_addr, 87 Tegra::Engines::ShaderType stage_, GPUVAddr gpu_addr, VAddr cpu_addr_,
89 VideoCommon::Shader::ProgramCode program_code, u32 main_offset); 88 VideoCommon::Shader::ProgramCode program_code, u32 main_offset_);
90 ~Shader(); 89 ~Shader();
91 90
92 GPUVAddr GetGpuAddr() const { 91 GPUVAddr GetGpuAddr() const {
@@ -122,15 +121,15 @@ public:
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 Device& 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);
@@ -149,11 +148,10 @@ private:
149 Tegra::Engines::KeplerCompute& kepler_compute; 148 Tegra::Engines::KeplerCompute& kepler_compute;
150 Tegra::MemoryManager& gpu_memory; 149 Tegra::MemoryManager& gpu_memory;
151 150
152 const VKDevice& device; 151 const Device& device;
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_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index ee2d871e3..7cadd5147 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -7,11 +7,11 @@
7#include <utility> 7#include <utility>
8#include <vector> 8#include <vector>
9 9
10#include "video_core/renderer_vulkan/vk_device.h"
11#include "video_core/renderer_vulkan/vk_query_cache.h" 10#include "video_core/renderer_vulkan/vk_query_cache.h"
12#include "video_core/renderer_vulkan/vk_resource_pool.h" 11#include "video_core/renderer_vulkan/vk_resource_pool.h"
13#include "video_core/renderer_vulkan/vk_scheduler.h" 12#include "video_core/renderer_vulkan/vk_scheduler.h"
14#include "video_core/renderer_vulkan/wrapper.h" 13#include "video_core/vulkan_common/vulkan_device.h"
14#include "video_core/vulkan_common/vulkan_wrapper.h"
15 15
16namespace Vulkan { 16namespace Vulkan {
17 17
@@ -27,7 +27,7 @@ constexpr VkQueryType GetTarget(QueryType type) {
27 27
28} // Anonymous namespace 28} // Anonymous namespace
29 29
30QueryPool::QueryPool(const VKDevice& device_, VKScheduler& scheduler, QueryType type_) 30QueryPool::QueryPool(const Device& device_, VKScheduler& scheduler, QueryType type_)
31 : ResourcePool{scheduler.GetMasterSemaphore(), GROW_STEP}, device{device_}, type{type_} {} 31 : ResourcePool{scheduler.GetMasterSemaphore(), GROW_STEP}, device{device_}, type{type_} {}
32 32
33QueryPool::~QueryPool() = default; 33QueryPool::~QueryPool() = default;
@@ -66,15 +66,13 @@ void QueryPool::Reserve(std::pair<VkQueryPool, u32> query) {
66 usage[pool_index * GROW_STEP + static_cast<std::ptrdiff_t>(query.second)] = false; 66 usage[pool_index * GROW_STEP + static_cast<std::ptrdiff_t>(query.second)] = false;
67} 67}
68 68
69VKQueryCache::VKQueryCache(VideoCore::RasterizerInterface& rasterizer, 69VKQueryCache::VKQueryCache(VideoCore::RasterizerInterface& rasterizer_,
70 Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory, 70 Tegra::Engines::Maxwell3D& maxwell3d_, Tegra::MemoryManager& gpu_memory_,
71 const VKDevice& device, VKScheduler& scheduler) 71 const Device& device_, VKScheduler& scheduler_)
72 : VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, 72 : QueryCacheBase{rasterizer_, maxwell3d_, gpu_memory_}, device{device_}, scheduler{scheduler_},
73 HostCounter>{rasterizer, maxwell3d, gpu_memory}, 73 query_pools{
74 device{device}, scheduler{scheduler}, query_pools{ 74 QueryPool{device_, scheduler_, QueryType::SamplesPassed},
75 QueryPool{device, scheduler, 75 } {}
76 QueryType::SamplesPassed},
77 } {}
78 76
79VKQueryCache::~VKQueryCache() { 77VKQueryCache::~VKQueryCache() {
80 // TODO(Rodrigo): This is a hack to destroy all HostCounter instances before the base class 78 // TODO(Rodrigo): This is a hack to destroy all HostCounter instances before the base class
@@ -95,12 +93,12 @@ void VKQueryCache::Reserve(QueryType type, std::pair<VkQueryPool, u32> query) {
95 query_pools[static_cast<std::size_t>(type)].Reserve(query); 93 query_pools[static_cast<std::size_t>(type)].Reserve(query);
96} 94}
97 95
98HostCounter::HostCounter(VKQueryCache& cache, std::shared_ptr<HostCounter> dependency, 96HostCounter::HostCounter(VKQueryCache& cache_, std::shared_ptr<HostCounter> dependency_,
99 QueryType type) 97 QueryType type_)
100 : VideoCommon::HostCounterBase<VKQueryCache, HostCounter>{std::move(dependency)}, cache{cache}, 98 : HostCounterBase{std::move(dependency_)}, cache{cache_}, type{type_},
101 type{type}, query{cache.AllocateQuery(type)}, tick{cache.Scheduler().CurrentTick()} { 99 query{cache_.AllocateQuery(type_)}, tick{cache_.GetScheduler().CurrentTick()} {
102 const vk::Device* logical = &cache.Device().GetLogical(); 100 const vk::Device* logical = &cache.GetDevice().GetLogical();
103 cache.Scheduler().Record([logical, query = query](vk::CommandBuffer cmdbuf) { 101 cache.GetScheduler().Record([logical, query = query](vk::CommandBuffer cmdbuf) {
104 logical->ResetQueryPoolEXT(query.first, query.second, 1); 102 logical->ResetQueryPoolEXT(query.first, query.second, 1);
105 cmdbuf.BeginQuery(query.first, query.second, VK_QUERY_CONTROL_PRECISE_BIT); 103 cmdbuf.BeginQuery(query.first, query.second, VK_QUERY_CONTROL_PRECISE_BIT);
106 }); 104 });
@@ -111,26 +109,28 @@ HostCounter::~HostCounter() {
111} 109}
112 110
113void HostCounter::EndQuery() { 111void HostCounter::EndQuery() {
114 cache.Scheduler().Record( 112 cache.GetScheduler().Record(
115 [query = query](vk::CommandBuffer cmdbuf) { cmdbuf.EndQuery(query.first, query.second); }); 113 [query = query](vk::CommandBuffer cmdbuf) { cmdbuf.EndQuery(query.first, query.second); });
116} 114}
117 115
118u64 HostCounter::BlockingQuery() const { 116u64 HostCounter::BlockingQuery() const {
119 if (tick >= cache.Scheduler().CurrentTick()) { 117 if (tick >= cache.GetScheduler().CurrentTick()) {
120 cache.Scheduler().Flush(); 118 cache.GetScheduler().Flush();
121 } 119 }
120
122 u64 data; 121 u64 data;
123 const VkResult result = cache.Device().GetLogical().GetQueryResults( 122 const VkResult query_result = cache.GetDevice().GetLogical().GetQueryResults(
124 query.first, query.second, 1, sizeof(data), &data, sizeof(data), 123 query.first, query.second, 1, sizeof(data), &data, sizeof(data),
125 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT); 124 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
126 switch (result) { 125
126 switch (query_result) {
127 case VK_SUCCESS: 127 case VK_SUCCESS:
128 return data; 128 return data;
129 case VK_ERROR_DEVICE_LOST: 129 case VK_ERROR_DEVICE_LOST:
130 cache.Device().ReportLoss(); 130 cache.GetDevice().ReportLoss();
131 [[fallthrough]]; 131 [[fallthrough]];
132 default: 132 default:
133 throw vk::Exception(result); 133 throw vk::Exception(query_result);
134 } 134 }
135} 135}
136 136
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.h b/src/video_core/renderer_vulkan/vk_query_cache.h
index 2e57fb75d..7190946b9 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.h
+++ b/src/video_core/renderer_vulkan/vk_query_cache.h
@@ -12,7 +12,7 @@
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "video_core/query_cache.h" 13#include "video_core/query_cache.h"
14#include "video_core/renderer_vulkan/vk_resource_pool.h" 14#include "video_core/renderer_vulkan/vk_resource_pool.h"
15#include "video_core/renderer_vulkan/wrapper.h" 15#include "video_core/vulkan_common/vulkan_wrapper.h"
16 16
17namespace VideoCore { 17namespace VideoCore {
18class RasterizerInterface; 18class RasterizerInterface;
@@ -21,8 +21,8 @@ class RasterizerInterface;
21namespace Vulkan { 21namespace Vulkan {
22 22
23class CachedQuery; 23class CachedQuery;
24class Device;
24class HostCounter; 25class HostCounter;
25class VKDevice;
26class VKQueryCache; 26class VKQueryCache;
27class VKScheduler; 27class VKScheduler;
28 28
@@ -30,7 +30,7 @@ using CounterStream = VideoCommon::CounterStreamBase<VKQueryCache, HostCounter>;
30 30
31class QueryPool final : public ResourcePool { 31class QueryPool final : public ResourcePool {
32public: 32public:
33 explicit QueryPool(const VKDevice& device, VKScheduler& scheduler, VideoCore::QueryType type); 33 explicit QueryPool(const Device& device, VKScheduler& scheduler, VideoCore::QueryType type);
34 ~QueryPool() override; 34 ~QueryPool() override;
35 35
36 std::pair<VkQueryPool, u32> Commit(); 36 std::pair<VkQueryPool, u32> Commit();
@@ -43,7 +43,7 @@ protected:
43private: 43private:
44 static constexpr std::size_t GROW_STEP = 512; 44 static constexpr std::size_t GROW_STEP = 512;
45 45
46 const VKDevice& device; 46 const Device& device;
47 const VideoCore::QueryType type; 47 const VideoCore::QueryType type;
48 48
49 std::vector<vk::QueryPool> pools; 49 std::vector<vk::QueryPool> pools;
@@ -53,33 +53,33 @@ private:
53class VKQueryCache final 53class VKQueryCache final
54 : public VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter> { 54 : public VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter> {
55public: 55public:
56 explicit VKQueryCache(VideoCore::RasterizerInterface& rasterizer, 56 explicit VKQueryCache(VideoCore::RasterizerInterface& rasterizer_,
57 Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory, 57 Tegra::Engines::Maxwell3D& maxwell3d_, Tegra::MemoryManager& gpu_memory_,
58 const VKDevice& device, VKScheduler& scheduler); 58 const Device& device_, VKScheduler& scheduler_);
59 ~VKQueryCache(); 59 ~VKQueryCache();
60 60
61 std::pair<VkQueryPool, u32> AllocateQuery(VideoCore::QueryType type); 61 std::pair<VkQueryPool, u32> AllocateQuery(VideoCore::QueryType type);
62 62
63 void Reserve(VideoCore::QueryType type, std::pair<VkQueryPool, u32> query); 63 void Reserve(VideoCore::QueryType type, std::pair<VkQueryPool, u32> query);
64 64
65 const VKDevice& Device() const noexcept { 65 const Device& GetDevice() const noexcept {
66 return device; 66 return device;
67 } 67 }
68 68
69 VKScheduler& Scheduler() const noexcept { 69 VKScheduler& GetScheduler() const noexcept {
70 return scheduler; 70 return scheduler;
71 } 71 }
72 72
73private: 73private:
74 const VKDevice& device; 74 const Device& device;
75 VKScheduler& scheduler; 75 VKScheduler& scheduler;
76 std::array<QueryPool, VideoCore::NumQueryTypes> query_pools; 76 std::array<QueryPool, VideoCore::NumQueryTypes> query_pools;
77}; 77};
78 78
79class HostCounter final : public VideoCommon::HostCounterBase<VKQueryCache, HostCounter> { 79class HostCounter final : public VideoCommon::HostCounterBase<VKQueryCache, HostCounter> {
80public: 80public:
81 explicit HostCounter(VKQueryCache& cache, std::shared_ptr<HostCounter> dependency, 81 explicit HostCounter(VKQueryCache& cache_, std::shared_ptr<HostCounter> dependency_,
82 VideoCore::QueryType type); 82 VideoCore::QueryType type_);
83 ~HostCounter(); 83 ~HostCounter();
84 84
85 void EndQuery(); 85 void EndQuery();
@@ -95,8 +95,8 @@ private:
95 95
96class CachedQuery : public VideoCommon::CachedQueryBase<HostCounter> { 96class CachedQuery : public VideoCommon::CachedQueryBase<HostCounter> {
97public: 97public:
98 explicit CachedQuery(VKQueryCache&, VideoCore::QueryType, VAddr cpu_addr, u8* host_ptr) 98 explicit CachedQuery(VKQueryCache&, VideoCore::QueryType, VAddr cpu_addr_, u8* host_ptr_)
99 : VideoCommon::CachedQueryBase<HostCounter>{cpu_addr, host_ptr} {} 99 : CachedQueryBase{cpu_addr_, host_ptr_} {}
100}; 100};
101 101
102} // namespace Vulkan 102} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index f3c2483c8..93fbea510 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"
@@ -26,23 +27,24 @@
26#include "video_core/renderer_vulkan/vk_compute_pass.h" 27#include "video_core/renderer_vulkan/vk_compute_pass.h"
27#include "video_core/renderer_vulkan/vk_compute_pipeline.h" 28#include "video_core/renderer_vulkan/vk_compute_pipeline.h"
28#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 29#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
29#include "video_core/renderer_vulkan/vk_device.h"
30#include "video_core/renderer_vulkan/vk_graphics_pipeline.h" 30#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
31#include "video_core/renderer_vulkan/vk_pipeline_cache.h" 31#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
32#include "video_core/renderer_vulkan/vk_rasterizer.h" 32#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" 33#include "video_core/renderer_vulkan/vk_scheduler.h"
36#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 34#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
37#include "video_core/renderer_vulkan/vk_state_tracker.h" 35#include "video_core/renderer_vulkan/vk_state_tracker.h"
38#include "video_core/renderer_vulkan/vk_texture_cache.h" 36#include "video_core/renderer_vulkan/vk_texture_cache.h"
39#include "video_core/renderer_vulkan/vk_update_descriptor.h" 37#include "video_core/renderer_vulkan/vk_update_descriptor.h"
40#include "video_core/renderer_vulkan/wrapper.h"
41#include "video_core/shader_cache.h" 38#include "video_core/shader_cache.h"
39#include "video_core/texture_cache/texture_cache.h"
40#include "video_core/vulkan_common/vulkan_device.h"
41#include "video_core/vulkan_common/vulkan_wrapper.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 Device& 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(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(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 {
@@ -213,7 +239,7 @@ public:
213 index.type = type; 239 index.type = type;
214 } 240 }
215 241
216 void Bind(const VKDevice& device, VKScheduler& scheduler) const { 242 void Bind(const Device& device, VKScheduler& scheduler) const {
217 // Use this large switch case to avoid dispatching more memory in the record lambda than 243 // Use this large switch case to avoid dispatching more memory in the record lambda than
218 // what we need. It looks horrible, but it's the best we can do on standard C++. 244 // what we need. It looks horrible, but it's the best we can do on standard C++.
219 switch (vertex.num_buffers) { 245 switch (vertex.num_buffers) {
@@ -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,8 +329,8 @@ 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 Device& device, VKScheduler& scheduler) const {
308 if (device.IsExtExtendedDynamicStateSupported()) { 334 if (device.IsExtExtendedDynamicStateSupported()) {
309 if (index.buffer) { 335 if (index.buffer) {
310 BindStatic<N, true, true>(scheduler); 336 BindStatic<N, true, true>(scheduler);
@@ -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) {
@@ -380,28 +406,31 @@ void RasterizerVulkan::DrawParameters::Draw(vk::CommandBuffer cmdbuf) const {
380 } 406 }
381} 407}
382 408
383RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu_, 409RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
384 Tegra::MemoryManager& gpu_memory_, 410 Tegra::MemoryManager& gpu_memory_,
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 Device& 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_) {
405 scheduler.SetQueryCache(query_cache); 434 scheduler.SetQueryCache(query_cache);
406 if (device.UseAsynchronousShaders()) { 435 if (device.UseAsynchronousShaders()) {
407 async_shaders.AllocateWorkers(); 436 async_shaders.AllocateWorkers();
@@ -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();
501 522 const VkExtent2D render_area = framebuffer->RenderArea();
502 const VkRenderPass renderpass = renderpass_cache.GetRenderPass(GetRenderPassParams(0)); 523 scheduler.RequestRenderpass(framebuffer);
503 const auto [framebuffer, render_area] = ConfigureFramebuffers(renderpass);
504 scheduler.RequestRenderpass(renderpass, framebuffer, render_area);
505 524
506 VkClearRect clear_rect; 525 VkClearRect clear_rect{
507 clear_rect.baseArrayLayer = regs.clear_buffers.layer; 526 .rect = GetScissorState(regs, 0),
508 clear_rect.layerCount = 1; 527 .baseArrayLayer = regs.clear_buffers.layer,
509 clear_rect.rect = GetScissorState(regs, 0); 528 .layerCount = 1,
510 clear_rect.rect.extent.width = std::min(clear_rect.rect.extent.width, render_area.width); 529 };
511 clear_rect.rect.extent.height = std::min(clear_rect.rect.extent.height, render_area.height); 530 if (clear_rect.rect.extent.width == 0 || clear_rect.rect.extent.height == 0) {
531 return;
532 }
533 clear_rect.rect.extent = VkExtent2D{
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,30 +592,46 @@ 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);
609
610 buffer_cache.Map(CalculateComputeStreamBufferSize());
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);
584 621
585 TransitionImages(sampled_views, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 622 buffer_cache.Unmap();
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 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 if (descriptor_set) {
596 descriptor_set, {}); 632 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout,
633 DESCRIPTOR_SET, descriptor_set, nullptr);
634 }
597 cmdbuf.Dispatch(grid_x, grid_y, grid_z); 635 cmdbuf.Dispatch(grid_x, grid_y, grid_z);
598 }); 636 });
599} 637}
@@ -613,7 +651,10 @@ void RasterizerVulkan::FlushRegion(VAddr addr, u64 size) {
613 if (addr == 0 || size == 0) { 651 if (addr == 0 || size == 0) {
614 return; 652 return;
615 } 653 }
616 texture_cache.FlushRegion(addr, size); 654 {
655 auto lock = texture_cache.AcquireLock();
656 texture_cache.DownloadMemory(addr, size);
657 }
617 buffer_cache.FlushRegion(addr, size); 658 buffer_cache.FlushRegion(addr, size);
618 query_cache.FlushRegion(addr, size); 659 query_cache.FlushRegion(addr, size);
619} 660}
@@ -622,14 +663,18 @@ bool RasterizerVulkan::MustFlushRegion(VAddr addr, u64 size) {
622 if (!Settings::IsGPULevelHigh()) { 663 if (!Settings::IsGPULevelHigh()) {
623 return buffer_cache.MustFlushRegion(addr, size); 664 return buffer_cache.MustFlushRegion(addr, size);
624 } 665 }
625 return texture_cache.MustFlushRegion(addr, size) || buffer_cache.MustFlushRegion(addr, size); 666 return texture_cache.IsRegionGpuModified(addr, size) ||
667 buffer_cache.MustFlushRegion(addr, size);
626} 668}
627 669
628void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size) { 670void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size) {
629 if (addr == 0 || size == 0) { 671 if (addr == 0 || size == 0) {
630 return; 672 return;
631 } 673 }
632 texture_cache.InvalidateRegion(addr, size); 674 {
675 auto lock = texture_cache.AcquireLock();
676 texture_cache.WriteMemory(addr, size);
677 }
633 pipeline_cache.InvalidateRegion(addr, size); 678 pipeline_cache.InvalidateRegion(addr, size);
634 buffer_cache.InvalidateRegion(addr, size); 679 buffer_cache.InvalidateRegion(addr, size);
635 query_cache.InvalidateRegion(addr, size); 680 query_cache.InvalidateRegion(addr, size);
@@ -639,17 +684,28 @@ void RasterizerVulkan::OnCPUWrite(VAddr addr, u64 size) {
639 if (addr == 0 || size == 0) { 684 if (addr == 0 || size == 0) {
640 return; 685 return;
641 } 686 }
642 texture_cache.OnCPUWrite(addr, size); 687 {
688 auto lock = texture_cache.AcquireLock();
689 texture_cache.WriteMemory(addr, size);
690 }
643 pipeline_cache.OnCPUWrite(addr, size); 691 pipeline_cache.OnCPUWrite(addr, size);
644 buffer_cache.OnCPUWrite(addr, size); 692 buffer_cache.OnCPUWrite(addr, size);
645} 693}
646 694
647void RasterizerVulkan::SyncGuestHost() { 695void RasterizerVulkan::SyncGuestHost() {
648 texture_cache.SyncGuestHost();
649 buffer_cache.SyncGuestHost(); 696 buffer_cache.SyncGuestHost();
650 pipeline_cache.SyncGuestHost(); 697 pipeline_cache.SyncGuestHost();
651} 698}
652 699
700void RasterizerVulkan::UnmapMemory(VAddr addr, u64 size) {
701 {
702 auto lock = texture_cache.AcquireLock();
703 texture_cache.UnmapMemory(addr, size);
704 }
705 buffer_cache.OnCPUWrite(addr, size);
706 pipeline_cache.OnCPUWrite(addr, size);
707}
708
653void RasterizerVulkan::SignalSemaphore(GPUVAddr addr, u32 value) { 709void RasterizerVulkan::SignalSemaphore(GPUVAddr addr, u32 value) {
654 if (!gpu.IsAsync()) { 710 if (!gpu.IsAsync()) {
655 gpu_memory.Write<u32>(addr, value); 711 gpu_memory.Write<u32>(addr, value);
@@ -700,6 +756,14 @@ void RasterizerVulkan::WaitForIdle() {
700 }); 756 });
701} 757}
702 758
759void RasterizerVulkan::FragmentBarrier() {
760 // We already put barriers when a render pass finishes
761}
762
763void RasterizerVulkan::TiledCacheBarrier() {
764 // TODO: Implementing tiled barriers requires rewriting a good chunk of the Vulkan backend
765}
766
703void RasterizerVulkan::FlushCommands() { 767void RasterizerVulkan::FlushCommands() {
704 if (draw_counter > 0) { 768 if (draw_counter > 0) {
705 draw_counter = 0; 769 draw_counter = 0;
@@ -710,14 +774,20 @@ void RasterizerVulkan::FlushCommands() {
710void RasterizerVulkan::TickFrame() { 774void RasterizerVulkan::TickFrame() {
711 draw_counter = 0; 775 draw_counter = 0;
712 update_descriptor_queue.TickFrame(); 776 update_descriptor_queue.TickFrame();
777 fence_manager.TickFrame();
713 buffer_cache.TickFrame(); 778 buffer_cache.TickFrame();
714 staging_pool.TickFrame(); 779 staging_pool.TickFrame();
780 {
781 auto lock = texture_cache.AcquireLock();
782 texture_cache.TickFrame();
783 }
715} 784}
716 785
717bool RasterizerVulkan::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, 786bool RasterizerVulkan::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src,
718 const Tegra::Engines::Fermi2D::Regs::Surface& dst, 787 const Tegra::Engines::Fermi2D::Surface& dst,
719 const Tegra::Engines::Fermi2D::Config& copy_config) { 788 const Tegra::Engines::Fermi2D::Config& copy_config) {
720 texture_cache.DoFermiCopy(src, dst, copy_config); 789 auto lock = texture_cache.AcquireLock();
790 texture_cache.BlitImage(dst, src, copy_config);
721 return true; 791 return true;
722} 792}
723 793
@@ -727,20 +797,16 @@ bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config,
727 return false; 797 return false;
728 } 798 }
729 799
730 const auto surface{texture_cache.TryFindFramebufferSurface(framebuffer_addr)}; 800 auto lock = texture_cache.AcquireLock();
731 if (!surface) { 801 ImageView* const image_view = texture_cache.TryFindFramebufferImageView(framebuffer_addr);
802 if (!image_view) {
732 return false; 803 return false;
733 } 804 }
734 805
735 // Verify that the cached surface is the same size and format as the requested framebuffer 806 screen_info.image_view = image_view->Handle(VideoCommon::ImageViewType::e2D);
736 const auto& params{surface->GetSurfaceParams()}; 807 screen_info.width = image_view->size.width;
737 ASSERT_MSG(params.width == config.width, "Framebuffer width is different"); 808 screen_info.height = image_view->size.height;
738 ASSERT_MSG(params.height == config.height, "Framebuffer height is different"); 809 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; 810 return true;
745} 811}
746 812
@@ -765,103 +831,6 @@ void RasterizerVulkan::FlushWork() {
765 draw_counter = 0; 831 draw_counter = 0;
766} 832}
767 833
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, 834RasterizerVulkan::DrawParameters RasterizerVulkan::SetupGeometry(FixedPipelineState& fixed_state,
866 BufferBindings& buffer_bindings, 835 BufferBindings& buffer_bindings,
867 bool is_indexed, 836 bool is_indexed,
@@ -885,51 +854,37 @@ RasterizerVulkan::DrawParameters RasterizerVulkan::SetupGeometry(FixedPipelineSt
885 854
886void RasterizerVulkan::SetupShaderDescriptors( 855void RasterizerVulkan::SetupShaderDescriptors(
887 const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders) { 856 const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders) {
888 texture_cache.GuardSamplers(true); 857 image_view_indices.clear();
889 858 sampler_handles.clear();
890 for (std::size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) { 859 for (size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) {
891 // Skip VertexA stage
892 Shader* const shader = shaders[stage + 1]; 860 Shader* const shader = shaders[stage + 1];
893 if (!shader) { 861 if (!shader) {
894 continue; 862 continue;
895 } 863 }
896 const auto& entries = shader->GetEntries(); 864 const auto& entries = shader->GetEntries();
897 SetupGraphicsConstBuffers(entries, stage);
898 SetupGraphicsGlobalBuffers(entries, stage);
899 SetupGraphicsUniformTexels(entries, stage); 865 SetupGraphicsUniformTexels(entries, stage);
900 SetupGraphicsTextures(entries, stage); 866 SetupGraphicsTextures(entries, stage);
901 SetupGraphicsStorageTexels(entries, stage); 867 SetupGraphicsStorageTexels(entries, stage);
902 SetupGraphicsImages(entries, stage); 868 SetupGraphicsImages(entries, stage);
903 } 869 }
904 texture_cache.GuardSamplers(false); 870 const std::span indices_span(image_view_indices.data(), image_view_indices.size());
905} 871 texture_cache.FillGraphicsImageViews(indices_span, image_view_ids);
906 872
907void RasterizerVulkan::SetupImageTransitions( 873 update_descriptor_queue.Acquire();
908 Texceptions texceptions, const std::array<View, Maxwell::NumRenderTargets>& color_attachments,
909 const View& zeta_attachment) {
910 TransitionImages(sampled_views, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_ACCESS_SHADER_READ_BIT);
911 TransitionImages(image_views, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
912 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT);
913 874
914 for (std::size_t rt = 0; rt < std::size(color_attachments); ++rt) { 875 ImageViewId* image_view_id_ptr = image_view_ids.data();
915 const auto color_attachment = color_attachments[rt]; 876 VkSampler* sampler_ptr = sampler_handles.data();
916 if (color_attachment == nullptr) { 877 for (size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) {
878 // Skip VertexA stage
879 Shader* const shader = shaders[stage + 1];
880 if (!shader) {
917 continue; 881 continue;
918 } 882 }
919 const auto image_layout = 883 const auto& entries = shader->GetEntries();
920 texceptions[rt] ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 884 SetupGraphicsConstBuffers(entries, stage);
921 color_attachment->Transition(image_layout, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 885 SetupGraphicsGlobalBuffers(entries, stage);
922 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | 886 PushImageDescriptors(entries, texture_cache, update_descriptor_queue, image_view_id_ptr,
923 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); 887 sampler_ptr);
924 }
925
926 if (zeta_attachment != nullptr) {
927 const auto image_layout = texceptions[ZETA_TEXCEPTION_INDEX]
928 ? VK_IMAGE_LAYOUT_GENERAL
929 : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
930 zeta_attachment->Transition(image_layout, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
931 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
932 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);
933 } 888 }
934} 889}
935 890
@@ -948,7 +903,6 @@ void RasterizerVulkan::UpdateDynamicStates() {
948 UpdateDepthWriteEnable(regs); 903 UpdateDepthWriteEnable(regs);
949 UpdateDepthCompareOp(regs); 904 UpdateDepthCompareOp(regs);
950 UpdateFrontFace(regs); 905 UpdateFrontFace(regs);
951 UpdatePrimitiveTopology(regs);
952 UpdateStencilOp(regs); 906 UpdateStencilOp(regs);
953 UpdateStencilTestEnable(regs); 907 UpdateStencilTestEnable(regs);
954 } 908 }
@@ -1002,7 +956,7 @@ void RasterizerVulkan::EndTransformFeedback() {
1002void RasterizerVulkan::SetupVertexArrays(BufferBindings& buffer_bindings) { 956void RasterizerVulkan::SetupVertexArrays(BufferBindings& buffer_bindings) {
1003 const auto& regs = maxwell3d.regs; 957 const auto& regs = maxwell3d.regs;
1004 958
1005 for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { 959 for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) {
1006 const auto& vertex_array = regs.vertex_array[index]; 960 const auto& vertex_array = regs.vertex_array[index];
1007 if (!vertex_array.IsEnabled()) { 961 if (!vertex_array.IsEnabled()) {
1008 continue; 962 continue;
@@ -1011,7 +965,7 @@ void RasterizerVulkan::SetupVertexArrays(BufferBindings& buffer_bindings) {
1011 const GPUVAddr end{regs.vertex_array_limit[index].LimitAddress()}; 965 const GPUVAddr end{regs.vertex_array_limit[index].LimitAddress()};
1012 966
1013 ASSERT(end >= start); 967 ASSERT(end >= start);
1014 const std::size_t size = end - start; 968 const size_t size = end - start;
1015 if (size == 0) { 969 if (size == 0) {
1016 buffer_bindings.AddVertexBinding(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE, 0); 970 buffer_bindings.AddVertexBinding(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE, 0);
1017 continue; 971 continue;
@@ -1072,7 +1026,7 @@ void RasterizerVulkan::SetupIndexBuffer(BufferBindings& buffer_bindings, DrawPar
1072 } 1026 }
1073} 1027}
1074 1028
1075void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, std::size_t stage) { 1029void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, size_t stage) {
1076 MICROPROFILE_SCOPE(Vulkan_ConstBuffers); 1030 MICROPROFILE_SCOPE(Vulkan_ConstBuffers);
1077 const auto& shader_stage = maxwell3d.state.shader_stages[stage]; 1031 const auto& shader_stage = maxwell3d.state.shader_stages[stage];
1078 for (const auto& entry : entries.const_buffers) { 1032 for (const auto& entry : entries.const_buffers) {
@@ -1080,7 +1034,7 @@ void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, s
1080 } 1034 }
1081} 1035}
1082 1036
1083void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries, std::size_t stage) { 1037void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries, size_t stage) {
1084 MICROPROFILE_SCOPE(Vulkan_GlobalBuffers); 1038 MICROPROFILE_SCOPE(Vulkan_GlobalBuffers);
1085 const auto& cbufs{maxwell3d.state.shader_stages[stage]}; 1039 const auto& cbufs{maxwell3d.state.shader_stages[stage]};
1086 1040
@@ -1090,37 +1044,49 @@ void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries,
1090 } 1044 }
1091} 1045}
1092 1046
1093void RasterizerVulkan::SetupGraphicsUniformTexels(const ShaderEntries& entries, std::size_t stage) { 1047void RasterizerVulkan::SetupGraphicsUniformTexels(const ShaderEntries& entries, size_t stage) {
1094 MICROPROFILE_SCOPE(Vulkan_Textures); 1048 MICROPROFILE_SCOPE(Vulkan_Textures);
1049 const auto& regs = maxwell3d.regs;
1050 const bool via_header_index = regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex;
1095 for (const auto& entry : entries.uniform_texels) { 1051 for (const auto& entry : entries.uniform_texels) {
1096 const auto image = GetTextureInfo(maxwell3d, entry, stage).tic; 1052 const TextureHandle handle = GetTextureInfo(maxwell3d, via_header_index, entry, stage);
1097 SetupUniformTexels(image, entry); 1053 image_view_indices.push_back(handle.image);
1098 } 1054 }
1099} 1055}
1100 1056
1101void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, std::size_t stage) { 1057void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, size_t stage) {
1102 MICROPROFILE_SCOPE(Vulkan_Textures); 1058 MICROPROFILE_SCOPE(Vulkan_Textures);
1059 const auto& regs = maxwell3d.regs;
1060 const bool via_header_index = regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex;
1103 for (const auto& entry : entries.samplers) { 1061 for (const auto& entry : entries.samplers) {
1104 for (std::size_t i = 0; i < entry.size; ++i) { 1062 for (size_t index = 0; index < entry.size; ++index) {
1105 const auto texture = GetTextureInfo(maxwell3d, entry, stage, i); 1063 const TextureHandle handle =
1106 SetupTexture(texture, entry); 1064 GetTextureInfo(maxwell3d, via_header_index, entry, stage, index);
1065 image_view_indices.push_back(handle.image);
1066
1067 Sampler* const sampler = texture_cache.GetGraphicsSampler(handle.sampler);
1068 sampler_handles.push_back(sampler->Handle());
1107 } 1069 }
1108 } 1070 }
1109} 1071}
1110 1072
1111void RasterizerVulkan::SetupGraphicsStorageTexels(const ShaderEntries& entries, std::size_t stage) { 1073void RasterizerVulkan::SetupGraphicsStorageTexels(const ShaderEntries& entries, size_t stage) {
1112 MICROPROFILE_SCOPE(Vulkan_Textures); 1074 MICROPROFILE_SCOPE(Vulkan_Textures);
1075 const auto& regs = maxwell3d.regs;
1076 const bool via_header_index = regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex;
1113 for (const auto& entry : entries.storage_texels) { 1077 for (const auto& entry : entries.storage_texels) {
1114 const auto image = GetTextureInfo(maxwell3d, entry, stage).tic; 1078 const TextureHandle handle = GetTextureInfo(maxwell3d, via_header_index, entry, stage);
1115 SetupStorageTexel(image, entry); 1079 image_view_indices.push_back(handle.image);
1116 } 1080 }
1117} 1081}
1118 1082
1119void RasterizerVulkan::SetupGraphicsImages(const ShaderEntries& entries, std::size_t stage) { 1083void RasterizerVulkan::SetupGraphicsImages(const ShaderEntries& entries, size_t stage) {
1120 MICROPROFILE_SCOPE(Vulkan_Images); 1084 MICROPROFILE_SCOPE(Vulkan_Images);
1085 const auto& regs = maxwell3d.regs;
1086 const bool via_header_index = regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex;
1121 for (const auto& entry : entries.images) { 1087 for (const auto& entry : entries.images) {
1122 const auto tic = GetTextureInfo(maxwell3d, entry, stage).tic; 1088 const TextureHandle handle = GetTextureInfo(maxwell3d, via_header_index, entry, stage);
1123 SetupImage(tic, entry); 1089 image_view_indices.push_back(handle.image);
1124 } 1090 }
1125} 1091}
1126 1092
@@ -1130,11 +1096,12 @@ void RasterizerVulkan::SetupComputeConstBuffers(const ShaderEntries& entries) {
1130 for (const auto& entry : entries.const_buffers) { 1096 for (const auto& entry : entries.const_buffers) {
1131 const auto& config = launch_desc.const_buffer_config[entry.GetIndex()]; 1097 const auto& config = launch_desc.const_buffer_config[entry.GetIndex()];
1132 const std::bitset<8> mask = launch_desc.const_buffer_enable_mask.Value(); 1098 const std::bitset<8> mask = launch_desc.const_buffer_enable_mask.Value();
1133 Tegra::Engines::ConstBufferInfo buffer; 1099 const Tegra::Engines::ConstBufferInfo info{
1134 buffer.address = config.Address(); 1100 .address = config.Address(),
1135 buffer.size = config.size; 1101 .size = config.size,
1136 buffer.enabled = mask[entry.GetIndex()]; 1102 .enabled = mask[entry.GetIndex()],
1137 SetupConstBuffer(entry, buffer); 1103 };
1104 SetupConstBuffer(entry, info);
1138 } 1105 }
1139} 1106}
1140 1107
@@ -1149,35 +1116,46 @@ void RasterizerVulkan::SetupComputeGlobalBuffers(const ShaderEntries& entries) {
1149 1116
1150void RasterizerVulkan::SetupComputeUniformTexels(const ShaderEntries& entries) { 1117void RasterizerVulkan::SetupComputeUniformTexels(const ShaderEntries& entries) {
1151 MICROPROFILE_SCOPE(Vulkan_Textures); 1118 MICROPROFILE_SCOPE(Vulkan_Textures);
1119 const bool via_header_index = kepler_compute.launch_description.linked_tsc;
1152 for (const auto& entry : entries.uniform_texels) { 1120 for (const auto& entry : entries.uniform_texels) {
1153 const auto image = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic; 1121 const TextureHandle handle =
1154 SetupUniformTexels(image, entry); 1122 GetTextureInfo(kepler_compute, via_header_index, entry, COMPUTE_SHADER_INDEX);
1123 image_view_indices.push_back(handle.image);
1155 } 1124 }
1156} 1125}
1157 1126
1158void RasterizerVulkan::SetupComputeTextures(const ShaderEntries& entries) { 1127void RasterizerVulkan::SetupComputeTextures(const ShaderEntries& entries) {
1159 MICROPROFILE_SCOPE(Vulkan_Textures); 1128 MICROPROFILE_SCOPE(Vulkan_Textures);
1129 const bool via_header_index = kepler_compute.launch_description.linked_tsc;
1160 for (const auto& entry : entries.samplers) { 1130 for (const auto& entry : entries.samplers) {
1161 for (std::size_t i = 0; i < entry.size; ++i) { 1131 for (size_t index = 0; index < entry.size; ++index) {
1162 const auto texture = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex, i); 1132 const TextureHandle handle = GetTextureInfo(kepler_compute, via_header_index, entry,
1163 SetupTexture(texture, entry); 1133 COMPUTE_SHADER_INDEX, index);
1134 image_view_indices.push_back(handle.image);
1135
1136 Sampler* const sampler = texture_cache.GetComputeSampler(handle.sampler);
1137 sampler_handles.push_back(sampler->Handle());
1164 } 1138 }
1165 } 1139 }
1166} 1140}
1167 1141
1168void RasterizerVulkan::SetupComputeStorageTexels(const ShaderEntries& entries) { 1142void RasterizerVulkan::SetupComputeStorageTexels(const ShaderEntries& entries) {
1169 MICROPROFILE_SCOPE(Vulkan_Textures); 1143 MICROPROFILE_SCOPE(Vulkan_Textures);
1144 const bool via_header_index = kepler_compute.launch_description.linked_tsc;
1170 for (const auto& entry : entries.storage_texels) { 1145 for (const auto& entry : entries.storage_texels) {
1171 const auto image = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic; 1146 const TextureHandle handle =
1172 SetupStorageTexel(image, entry); 1147 GetTextureInfo(kepler_compute, via_header_index, entry, COMPUTE_SHADER_INDEX);
1148 image_view_indices.push_back(handle.image);
1173 } 1149 }
1174} 1150}
1175 1151
1176void RasterizerVulkan::SetupComputeImages(const ShaderEntries& entries) { 1152void RasterizerVulkan::SetupComputeImages(const ShaderEntries& entries) {
1177 MICROPROFILE_SCOPE(Vulkan_Images); 1153 MICROPROFILE_SCOPE(Vulkan_Images);
1154 const bool via_header_index = kepler_compute.launch_description.linked_tsc;
1178 for (const auto& entry : entries.images) { 1155 for (const auto& entry : entries.images) {
1179 const auto tic = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic; 1156 const TextureHandle handle =
1180 SetupImage(tic, entry); 1157 GetTextureInfo(kepler_compute, via_header_index, entry, COMPUTE_SHADER_INDEX);
1158 image_view_indices.push_back(handle.image);
1181 } 1159 }
1182} 1160}
1183 1161
@@ -1188,14 +1166,12 @@ void RasterizerVulkan::SetupConstBuffer(const ConstBufferEntry& entry,
1188 update_descriptor_queue.AddBuffer(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE); 1166 update_descriptor_queue.AddBuffer(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE);
1189 return; 1167 return;
1190 } 1168 }
1191
1192 // Align the size to avoid bad std140 interactions 1169 // Align the size to avoid bad std140 interactions
1193 const std::size_t size = 1170 const size_t size = Common::AlignUp(CalculateConstBufferSize(entry, buffer), 4 * sizeof(float));
1194 Common::AlignUp(CalculateConstBufferSize(entry, buffer), 4 * sizeof(float));
1195 ASSERT(size <= MaxConstbufferSize); 1171 ASSERT(size <= MaxConstbufferSize);
1196 1172
1197 const auto info = 1173 const u64 alignment = device.GetUniformBufferAlignment();
1198 buffer_cache.UploadMemory(buffer.address, size, device.GetUniformBufferAlignment()); 1174 const auto info = buffer_cache.UploadMemory(buffer.address, size, alignment);
1199 update_descriptor_queue.AddBuffer(info.handle, info.offset, size); 1175 update_descriptor_queue.AddBuffer(info.handle, info.offset, size);
1200} 1176}
1201 1177
@@ -1208,7 +1184,7 @@ void RasterizerVulkan::SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAdd
1208 // because Vulkan doesn't like empty buffers. 1184 // because Vulkan doesn't like empty buffers.
1209 // Note: Do *not* use DefaultBuffer() here, storage buffers can be written breaking the 1185 // Note: Do *not* use DefaultBuffer() here, storage buffers can be written breaking the
1210 // default buffer. 1186 // default buffer.
1211 static constexpr std::size_t dummy_size = 4; 1187 static constexpr size_t dummy_size = 4;
1212 const auto info = buffer_cache.GetEmptyBuffer(dummy_size); 1188 const auto info = buffer_cache.GetEmptyBuffer(dummy_size);
1213 update_descriptor_queue.AddBuffer(info.handle, info.offset, dummy_size); 1189 update_descriptor_queue.AddBuffer(info.handle, info.offset, dummy_size);
1214 return; 1190 return;
@@ -1219,55 +1195,6 @@ void RasterizerVulkan::SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAdd
1219 update_descriptor_queue.AddBuffer(info.handle, info.offset, size); 1195 update_descriptor_queue.AddBuffer(info.handle, info.offset, size);
1220} 1196}
1221 1197
1222void RasterizerVulkan::SetupUniformTexels(const Tegra::Texture::TICEntry& tic,
1223 const UniformTexelEntry& entry) {
1224 const auto view = texture_cache.GetTextureSurface(tic, entry);
1225 ASSERT(view->IsBufferView());
1226
1227 update_descriptor_queue.AddTexelBuffer(view->GetBufferView());
1228}
1229
1230void RasterizerVulkan::SetupTexture(const Tegra::Texture::FullTextureInfo& texture,
1231 const SamplerEntry& entry) {
1232 auto view = texture_cache.GetTextureSurface(texture.tic, entry);
1233 ASSERT(!view->IsBufferView());
1234
1235 const VkImageView image_view = view->GetImageView(texture.tic.x_source, texture.tic.y_source,
1236 texture.tic.z_source, texture.tic.w_source);
1237 const auto sampler = sampler_cache.GetSampler(texture.tsc);
1238 update_descriptor_queue.AddSampledImage(sampler, image_view);
1239
1240 VkImageLayout* const image_layout = update_descriptor_queue.LastImageLayout();
1241 *image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1242 sampled_views.push_back(ImageView{std::move(view), image_layout});
1243}
1244
1245void RasterizerVulkan::SetupStorageTexel(const Tegra::Texture::TICEntry& tic,
1246 const StorageTexelEntry& entry) {
1247 const auto view = texture_cache.GetImageSurface(tic, entry);
1248 ASSERT(view->IsBufferView());
1249
1250 update_descriptor_queue.AddTexelBuffer(view->GetBufferView());
1251}
1252
1253void RasterizerVulkan::SetupImage(const Tegra::Texture::TICEntry& tic, const ImageEntry& entry) {
1254 auto view = texture_cache.GetImageSurface(tic, entry);
1255
1256 if (entry.is_written) {
1257 view->MarkAsModified(texture_cache.Tick());
1258 }
1259
1260 UNIMPLEMENTED_IF(tic.IsBuffer());
1261
1262 const VkImageView image_view =
1263 view->GetImageView(tic.x_source, tic.y_source, tic.z_source, tic.w_source);
1264 update_descriptor_queue.AddImage(image_view);
1265
1266 VkImageLayout* const image_layout = update_descriptor_queue.LastImageLayout();
1267 *image_layout = VK_IMAGE_LAYOUT_GENERAL;
1268 image_views.push_back(ImageView{std::move(view), image_layout});
1269}
1270
1271void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs) { 1198void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs) {
1272 if (!state_tracker.TouchViewports()) { 1199 if (!state_tracker.TouchViewports()) {
1273 return; 1200 return;
@@ -1418,16 +1345,6 @@ void RasterizerVulkan::UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs) {
1418 [front_face](vk::CommandBuffer cmdbuf) { cmdbuf.SetFrontFaceEXT(front_face); }); 1345 [front_face](vk::CommandBuffer cmdbuf) { cmdbuf.SetFrontFaceEXT(front_face); });
1419} 1346}
1420 1347
1421void RasterizerVulkan::UpdatePrimitiveTopology(Tegra::Engines::Maxwell3D::Regs& regs) {
1422 const Maxwell::PrimitiveTopology primitive_topology = regs.draw.topology.Value();
1423 if (!state_tracker.ChangePrimitiveTopology(primitive_topology)) {
1424 return;
1425 }
1426 scheduler.Record([this, primitive_topology](vk::CommandBuffer cmdbuf) {
1427 cmdbuf.SetPrimitiveTopologyEXT(MaxwellToVK::PrimitiveTopology(device, primitive_topology));
1428 });
1429}
1430
1431void RasterizerVulkan::UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs) { 1348void RasterizerVulkan::UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs) {
1432 if (!state_tracker.TouchStencilOp()) { 1349 if (!state_tracker.TouchStencilOp()) {
1433 return; 1350 return;
@@ -1469,8 +1386,8 @@ void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs&
1469 }); 1386 });
1470} 1387}
1471 1388
1472std::size_t RasterizerVulkan::CalculateGraphicsStreamBufferSize(bool is_indexed) const { 1389size_t RasterizerVulkan::CalculateGraphicsStreamBufferSize(bool is_indexed) const {
1473 std::size_t size = CalculateVertexArraysSize(); 1390 size_t size = CalculateVertexArraysSize();
1474 if (is_indexed) { 1391 if (is_indexed) {
1475 size = Common::AlignUp(size, 4) + CalculateIndexBufferSize(); 1392 size = Common::AlignUp(size, 4) + CalculateIndexBufferSize();
1476 } 1393 }
@@ -1478,15 +1395,15 @@ std::size_t RasterizerVulkan::CalculateGraphicsStreamBufferSize(bool is_indexed)
1478 return size; 1395 return size;
1479} 1396}
1480 1397
1481std::size_t RasterizerVulkan::CalculateComputeStreamBufferSize() const { 1398size_t RasterizerVulkan::CalculateComputeStreamBufferSize() const {
1482 return Tegra::Engines::KeplerCompute::NumConstBuffers * 1399 return Tegra::Engines::KeplerCompute::NumConstBuffers *
1483 (Maxwell::MaxConstBufferSize + device.GetUniformBufferAlignment()); 1400 (Maxwell::MaxConstBufferSize + device.GetUniformBufferAlignment());
1484} 1401}
1485 1402
1486std::size_t RasterizerVulkan::CalculateVertexArraysSize() const { 1403size_t RasterizerVulkan::CalculateVertexArraysSize() const {
1487 const auto& regs = maxwell3d.regs; 1404 const auto& regs = maxwell3d.regs;
1488 1405
1489 std::size_t size = 0; 1406 size_t size = 0;
1490 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { 1407 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
1491 // This implementation assumes that all attributes are used in the shader. 1408 // This implementation assumes that all attributes are used in the shader.
1492 const GPUVAddr start{regs.vertex_array[index].StartAddress()}; 1409 const GPUVAddr start{regs.vertex_array[index].StartAddress()};
@@ -1498,12 +1415,12 @@ std::size_t RasterizerVulkan::CalculateVertexArraysSize() const {
1498 return size; 1415 return size;
1499} 1416}
1500 1417
1501std::size_t RasterizerVulkan::CalculateIndexBufferSize() const { 1418size_t RasterizerVulkan::CalculateIndexBufferSize() const {
1502 return static_cast<std::size_t>(maxwell3d.regs.index_array.count) * 1419 return static_cast<size_t>(maxwell3d.regs.index_array.count) *
1503 static_cast<std::size_t>(maxwell3d.regs.index_array.FormatSizeInBytes()); 1420 static_cast<size_t>(maxwell3d.regs.index_array.FormatSizeInBytes());
1504} 1421}
1505 1422
1506std::size_t RasterizerVulkan::CalculateConstBufferSize( 1423size_t RasterizerVulkan::CalculateConstBufferSize(
1507 const ConstBufferEntry& entry, const Tegra::Engines::ConstBufferInfo& buffer) const { 1424 const ConstBufferEntry& entry, const Tegra::Engines::ConstBufferInfo& buffer) const {
1508 if (entry.IsIndirect()) { 1425 if (entry.IsIndirect()) {
1509 // Buffer is accessed indirectly, so upload the entire thing 1426 // Buffer is accessed indirectly, so upload the entire thing
@@ -1514,37 +1431,10 @@ std::size_t RasterizerVulkan::CalculateConstBufferSize(
1514 } 1431 }
1515} 1432}
1516 1433
1517RenderPassParams RasterizerVulkan::GetRenderPassParams(Texceptions texceptions) const {
1518 const auto& regs = maxwell3d.regs;
1519 const std::size_t num_attachments = static_cast<std::size_t>(regs.rt_control.count);
1520
1521 RenderPassParams params;
1522 params.color_formats = {};
1523 std::size_t color_texceptions = 0;
1524
1525 std::size_t index = 0;
1526 for (std::size_t rt = 0; rt < num_attachments; ++rt) {
1527 const auto& rendertarget = regs.rt[rt];
1528 if (rendertarget.Address() == 0 || rendertarget.format == Tegra::RenderTargetFormat::NONE) {
1529 continue;
1530 }
1531 params.color_formats[index] = static_cast<u8>(rendertarget.format);
1532 color_texceptions |= (texceptions[rt] ? 1ULL : 0ULL) << index;
1533 ++index;
1534 }
1535 params.num_color_attachments = static_cast<u8>(index);
1536 params.texceptions = static_cast<u8>(color_texceptions);
1537
1538 params.zeta_format = regs.zeta_enable ? static_cast<u8>(regs.zeta.format) : 0;
1539 params.zeta_texception = texceptions[ZETA_TEXCEPTION_INDEX];
1540 return params;
1541}
1542
1543VkBuffer RasterizerVulkan::DefaultBuffer() { 1434VkBuffer RasterizerVulkan::DefaultBuffer() {
1544 if (default_buffer) { 1435 if (default_buffer) {
1545 return *default_buffer; 1436 return *default_buffer;
1546 } 1437 }
1547
1548 default_buffer = device.GetLogical().CreateBuffer({ 1438 default_buffer = device.GetLogical().CreateBuffer({
1549 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 1439 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1550 .pNext = nullptr, 1440 .pNext = nullptr,
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index b47c8fc13..4695718e9 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,14 +24,13 @@
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"
34#include "video_core/shader/async_shaders.h" 32#include "video_core/shader/async_shaders.h"
33#include "video_core/vulkan_common/vulkan_wrapper.h"
35 34
36namespace Core { 35namespace Core {
37class System; 36class System;
@@ -49,67 +48,16 @@ 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_,
109 Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory, 57 Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_,
110 VKScreenInfo& screen_info, const VKDevice& device, 58 VKScreenInfo& screen_info_, const Device& device_,
111 VKMemoryManager& memory_manager, StateTracker& state_tracker, 59 VKMemoryManager& memory_manager_, StateTracker& state_tracker_,
112 VKScheduler& scheduler); 60 VKScheduler& scheduler_);
113 ~RasterizerVulkan() override; 61 ~RasterizerVulkan() override;
114 62
115 void Draw(bool is_indexed, bool is_instanced) override; 63 void Draw(bool is_indexed, bool is_instanced) override;
@@ -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,20 +117,8 @@ private:
160 bool is_indexed = 0; 117 bool is_indexed = 0;
161 }; 118 };
162 119
163 using Texceptions = std::bitset<Maxwell::NumRenderTargets + 1>;
164
165 static constexpr std::size_t ZETA_TEXCEPTION_INDEX = 8;
166 static constexpr VkDeviceSize DEFAULT_BUFFER_SIZE = 4 * sizeof(float);
167
168 void FlushWork(); 120 void FlushWork();
169 121
170 /// @brief Updates the currently bound attachments
171 /// @param is_clear True when the framebuffer is updated as a clear
172 /// @return Bitfield of attachments being used as sampled textures
173 Texceptions UpdateAttachments(bool is_clear);
174
175 std::tuple<VkFramebuffer, VkExtent2D> ConfigureFramebuffers(VkRenderPass renderpass);
176
177 /// Setups geometry buffers and state. 122 /// Setups geometry buffers and state.
178 DrawParameters SetupGeometry(FixedPipelineState& fixed_state, BufferBindings& buffer_bindings, 123 DrawParameters SetupGeometry(FixedPipelineState& fixed_state, BufferBindings& buffer_bindings,
179 bool is_indexed, bool is_instanced); 124 bool is_indexed, bool is_instanced);
@@ -181,18 +126,12 @@ private:
181 /// Setup descriptors in the graphics pipeline. 126 /// Setup descriptors in the graphics pipeline.
182 void SetupShaderDescriptors(const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders); 127 void SetupShaderDescriptors(const std::array<Shader*, Maxwell::MaxShaderProgram>& shaders);
183 128
184 void SetupImageTransitions(Texceptions texceptions,
185 const std::array<View, Maxwell::NumRenderTargets>& color_attachments,
186 const View& zeta_attachment);
187
188 void UpdateDynamicStates(); 129 void UpdateDynamicStates();
189 130
190 void BeginTransformFeedback(); 131 void BeginTransformFeedback();
191 132
192 void EndTransformFeedback(); 133 void EndTransformFeedback();
193 134
194 bool WalkAttachmentOverlaps(const CachedSurfaceView& attachment);
195
196 void SetupVertexArrays(BufferBindings& buffer_bindings); 135 void SetupVertexArrays(BufferBindings& buffer_bindings);
197 136
198 void SetupIndexBuffer(BufferBindings& buffer_bindings, DrawParameters& params, bool is_indexed); 137 void SetupIndexBuffer(BufferBindings& buffer_bindings, DrawParameters& params, bool is_indexed);
@@ -238,14 +177,6 @@ private:
238 177
239 void SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAddr address); 178 void SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAddr address);
240 179
241 void SetupUniformTexels(const Tegra::Texture::TICEntry& image, const UniformTexelEntry& entry);
242
243 void SetupTexture(const Tegra::Texture::FullTextureInfo& texture, const SamplerEntry& entry);
244
245 void SetupStorageTexel(const Tegra::Texture::TICEntry& tic, const StorageTexelEntry& entry);
246
247 void SetupImage(const Tegra::Texture::TICEntry& tic, const ImageEntry& entry);
248
249 void UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs); 180 void UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs);
250 void UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs); 181 void UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs);
251 void UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs); 182 void UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs);
@@ -259,22 +190,19 @@ private:
259 void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs); 190 void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs);
260 void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs); 191 void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs);
261 void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs); 192 void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs);
262 void UpdatePrimitiveTopology(Tegra::Engines::Maxwell3D::Regs& regs);
263 void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs); 193 void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs);
264 void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs); 194 void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
265 195
266 std::size_t CalculateGraphicsStreamBufferSize(bool is_indexed) const; 196 size_t CalculateGraphicsStreamBufferSize(bool is_indexed) const;
267
268 std::size_t CalculateComputeStreamBufferSize() const;
269 197
270 std::size_t CalculateVertexArraysSize() const; 198 size_t CalculateComputeStreamBufferSize() const;
271 199
272 std::size_t CalculateIndexBufferSize() const; 200 size_t CalculateVertexArraysSize() const;
273 201
274 std::size_t CalculateConstBufferSize(const ConstBufferEntry& entry, 202 size_t CalculateIndexBufferSize() const;
275 const Tegra::Engines::ConstBufferInfo& buffer) const;
276 203
277 RenderPassParams GetRenderPassParams(Texceptions texceptions) const; 204 size_t CalculateConstBufferSize(const ConstBufferEntry& entry,
205 const Tegra::Engines::ConstBufferInfo& buffer) const;
278 206
279 VkBuffer DefaultBuffer(); 207 VkBuffer DefaultBuffer();
280 208
@@ -284,23 +212,24 @@ private:
284 Tegra::Engines::KeplerCompute& kepler_compute; 212 Tegra::Engines::KeplerCompute& kepler_compute;
285 213
286 VKScreenInfo& screen_info; 214 VKScreenInfo& screen_info;
287 const VKDevice& device; 215 const Device& device;
288 VKMemoryManager& memory_manager; 216 VKMemoryManager& memory_manager;
289 StateTracker& state_tracker; 217 StateTracker& state_tracker;
290 VKScheduler& scheduler; 218 VKScheduler& scheduler;
291 219
220 VKStreamBuffer stream_buffer;
292 VKStagingBufferPool staging_pool; 221 VKStagingBufferPool staging_pool;
293 VKDescriptorPool descriptor_pool; 222 VKDescriptorPool descriptor_pool;
294 VKUpdateDescriptorQueue update_descriptor_queue; 223 VKUpdateDescriptorQueue update_descriptor_queue;
295 VKRenderPassCache renderpass_cache; 224 BlitImageHelper blit_image;
296 QuadArrayPass quad_array_pass; 225 QuadArrayPass quad_array_pass;
297 QuadIndexedPass quad_indexed_pass; 226 QuadIndexedPass quad_indexed_pass;
298 Uint8Pass uint8_pass; 227 Uint8Pass uint8_pass;
299 228
300 VKTextureCache texture_cache; 229 TextureCacheRuntime texture_cache_runtime;
230 TextureCache texture_cache;
301 VKPipelineCache pipeline_cache; 231 VKPipelineCache pipeline_cache;
302 VKBufferCache buffer_cache; 232 VKBufferCache buffer_cache;
303 VKSamplerCache sampler_cache;
304 VKQueryCache query_cache; 233 VKQueryCache query_cache;
305 VKFenceManager fence_manager; 234 VKFenceManager fence_manager;
306 235
@@ -309,16 +238,11 @@ private:
309 vk::Event wfi_event; 238 vk::Event wfi_event;
310 VideoCommon::Shader::AsyncShaders async_shaders; 239 VideoCommon::Shader::AsyncShaders async_shaders;
311 240
312 std::array<View, Maxwell::NumRenderTargets> color_attachments; 241 boost::container::static_vector<u32, MAX_IMAGE_VIEWS> image_view_indices;
313 View zeta_attachment; 242 std::array<VideoCommon::ImageViewId, MAX_IMAGE_VIEWS> image_view_ids;
314 243 boost::container::static_vector<VkSampler, MAX_TEXTURES> sampler_handles;
315 std::vector<ImageView> sampled_views;
316 std::vector<ImageView> image_views;
317 244
318 u32 draw_counter = 0; 245 u32 draw_counter = 0;
319
320 // TODO(Rodrigo): Invalidate on image destruction
321 std::unordered_map<FramebufferCacheKey, vk::Framebuffer> framebuffer_cache;
322}; 246};
323 247
324} // 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 80284cf92..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 8b0fec720..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 b068888f9..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 a33d1c0ee..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..66004f9c0 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -11,12 +11,13 @@
11#include "common/microprofile.h" 11#include "common/microprofile.h"
12#include "common/thread.h" 12#include "common/thread.h"
13#include "video_core/renderer_vulkan/vk_command_pool.h" 13#include "video_core/renderer_vulkan/vk_command_pool.h"
14#include "video_core/renderer_vulkan/vk_device.h"
15#include "video_core/renderer_vulkan/vk_master_semaphore.h" 14#include "video_core/renderer_vulkan/vk_master_semaphore.h"
16#include "video_core/renderer_vulkan/vk_query_cache.h" 15#include "video_core/renderer_vulkan/vk_query_cache.h"
17#include "video_core/renderer_vulkan/vk_scheduler.h" 16#include "video_core/renderer_vulkan/vk_scheduler.h"
18#include "video_core/renderer_vulkan/vk_state_tracker.h" 17#include "video_core/renderer_vulkan/vk_state_tracker.h"
19#include "video_core/renderer_vulkan/wrapper.h" 18#include "video_core/renderer_vulkan/vk_texture_cache.h"
19#include "video_core/vulkan_common/vulkan_device.h"
20#include "video_core/vulkan_common/vulkan_wrapper.h"
20 21
21namespace Vulkan { 22namespace Vulkan {
22 23
@@ -36,7 +37,7 @@ void VKScheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf) {
36 last = nullptr; 37 last = nullptr;
37} 38}
38 39
39VKScheduler::VKScheduler(const VKDevice& device_, StateTracker& state_tracker_) 40VKScheduler::VKScheduler(const Device& device_, StateTracker& state_tracker_)
40 : device{device_}, state_tracker{state_tracker_}, 41 : device{device_}, state_tracker{state_tracker_},
41 master_semaphore{std::make_unique<MasterSemaphore>(device)}, 42 master_semaphore{std::make_unique<MasterSemaphore>(device)},
42 command_pool{std::make_unique<CommandPool>(*master_semaphore, device)} { 43 command_pool{std::make_unique<CommandPool>(*master_semaphore, device)} {
@@ -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 7be8a19f0..4cd43e425 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.h
+++ b/src/video_core/renderer_vulkan/vk_scheduler.h
@@ -12,21 +12,22 @@
12#include <utility> 12#include <utility>
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/threadsafe_queue.h" 14#include "common/threadsafe_queue.h"
15#include "video_core/renderer_vulkan/wrapper.h" 15#include "video_core/vulkan_common/vulkan_wrapper.h"
16 16
17namespace Vulkan { 17namespace Vulkan {
18 18
19class CommandPool; 19class CommandPool;
20class Device;
21class Framebuffer;
20class MasterSemaphore; 22class MasterSemaphore;
21class StateTracker; 23class StateTracker;
22class VKDevice;
23class VKQueryCache; 24class VKQueryCache;
24 25
25/// The scheduler abstracts command buffer and fence management with an interface that's able to do 26/// The scheduler abstracts command buffer and fence management with an interface that's able to do
26/// OpenGL-like operations on Vulkan command buffers. 27/// OpenGL-like operations on Vulkan command buffers.
27class VKScheduler { 28class VKScheduler {
28public: 29public:
29 explicit VKScheduler(const VKDevice& device, StateTracker& state_tracker); 30 explicit VKScheduler(const Device& device, StateTracker& state_tracker);
30 ~VKScheduler(); 31 ~VKScheduler();
31 32
32 /// Returns the current command buffer tick. 33 /// Returns the current command buffer tick.
@@ -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_;
@@ -104,7 +107,7 @@ private:
104 template <typename T> 107 template <typename T>
105 class TypedCommand final : public Command { 108 class TypedCommand final : public Command {
106 public: 109 public:
107 explicit TypedCommand(T&& command) : command{std::move(command)} {} 110 explicit TypedCommand(T&& command_) : command{std::move(command_)} {}
108 ~TypedCommand() override = default; 111 ~TypedCommand() override = default;
109 112
110 TypedCommand(TypedCommand&&) = delete; 113 TypedCommand(TypedCommand&&) = delete;
@@ -170,15 +173,13 @@ 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();
178 179
179 void AcquireNewChunk(); 180 void AcquireNewChunk();
180 181
181 const VKDevice& device; 182 const Device& device;
182 StateTracker& state_tracker; 183 StateTracker& state_tracker;
183 184
184 std::unique_ptr<MasterSemaphore> master_semaphore; 185 std::unique_ptr<MasterSemaphore> master_semaphore;
@@ -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 cd7d7a4e4..89cbe01ad 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -22,11 +22,11 @@
22#include "video_core/engines/shader_bytecode.h" 22#include "video_core/engines/shader_bytecode.h"
23#include "video_core/engines/shader_header.h" 23#include "video_core/engines/shader_header.h"
24#include "video_core/engines/shader_type.h" 24#include "video_core/engines/shader_type.h"
25#include "video_core/renderer_vulkan/vk_device.h"
26#include "video_core/renderer_vulkan/vk_shader_decompiler.h" 25#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
27#include "video_core/shader/node.h" 26#include "video_core/shader/node.h"
28#include "video_core/shader/shader_ir.h" 27#include "video_core/shader/shader_ir.h"
29#include "video_core/shader/transform_feedback.h" 28#include "video_core/shader/transform_feedback.h"
29#include "video_core/vulkan_common/vulkan_device.h"
30 30
31namespace Vulkan { 31namespace Vulkan {
32 32
@@ -55,8 +55,8 @@ enum class Type { Void, Bool, Bool2, Float, Int, Uint, HalfFloat };
55 55
56class Expression final { 56class Expression final {
57public: 57public:
58 Expression(Id id, Type type) : id{id}, type{type} { 58 Expression(Id id_, Type type_) : id{id_}, type{type_} {
59 ASSERT(type != Type::Void); 59 ASSERT(type_ != Type::Void);
60 } 60 }
61 Expression() : type{Type::Void} {} 61 Expression() : type{Type::Void} {}
62 62
@@ -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:
@@ -114,12 +114,12 @@ spv::Dim GetSamplerDim(const Sampler& sampler) {
114 case Tegra::Shader::TextureType::TextureCube: 114 case Tegra::Shader::TextureType::TextureCube:
115 return spv::Dim::Cube; 115 return spv::Dim::Cube;
116 default: 116 default:
117 UNIMPLEMENTED_MSG("Unimplemented sampler type={}", static_cast<int>(sampler.type)); 117 UNIMPLEMENTED_MSG("Unimplemented sampler type={}", sampler.type);
118 return spv::Dim::Dim2D; 118 return spv::Dim::Dim2D;
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};
@@ -134,7 +134,7 @@ std::pair<spv::Dim, bool> GetImageDim(const Image& image) {
134 case Tegra::Shader::ImageType::Texture3D: 134 case Tegra::Shader::ImageType::Texture3D:
135 return {spv::Dim::Dim3D, false}; 135 return {spv::Dim::Dim3D, false};
136 default: 136 default:
137 UNIMPLEMENTED_MSG("Unimplemented image type={}", static_cast<int>(image.type)); 137 UNIMPLEMENTED_MSG("Unimplemented image type={}", image.type);
138 return {spv::Dim::Dim2D, false}; 138 return {spv::Dim::Dim2D, false};
139 } 139 }
140} 140}
@@ -274,12 +274,12 @@ bool IsPrecise(Operation operand) {
274 274
275class SPIRVDecompiler final : public Sirit::Module { 275class SPIRVDecompiler final : public Sirit::Module {
276public: 276public:
277 explicit SPIRVDecompiler(const VKDevice& device, const ShaderIR& ir, ShaderType stage, 277 explicit SPIRVDecompiler(const Device& device_, const ShaderIR& ir_, ShaderType stage_,
278 const Registry& registry, const Specialization& specialization) 278 const Registry& registry_, const Specialization& specialization_)
279 : Module(0x00010300), device{device}, ir{ir}, stage{stage}, header{ir.GetHeader()}, 279 : Module(0x00010300), device{device_}, ir{ir_}, stage{stage_}, header{ir_.GetHeader()},
280 registry{registry}, specialization{specialization} { 280 registry{registry_}, specialization{specialization_} {
281 if (stage != ShaderType::Compute) { 281 if (stage_ != ShaderType::Compute) {
282 transform_feedback = BuildTransformFeedback(registry.GetGraphicsInfo()); 282 transform_feedback = BuildTransformFeedback(registry_.GetGraphicsInfo());
283 } 283 }
284 284
285 AddCapability(spv::Capability::Shader); 285 AddCapability(spv::Capability::Shader);
@@ -293,6 +293,7 @@ public:
293 AddCapability(spv::Capability::DrawParameters); 293 AddCapability(spv::Capability::DrawParameters);
294 AddCapability(spv::Capability::SubgroupBallotKHR); 294 AddCapability(spv::Capability::SubgroupBallotKHR);
295 AddCapability(spv::Capability::SubgroupVoteKHR); 295 AddCapability(spv::Capability::SubgroupVoteKHR);
296 AddExtension("SPV_KHR_16bit_storage");
296 AddExtension("SPV_KHR_shader_ballot"); 297 AddExtension("SPV_KHR_shader_ballot");
297 AddExtension("SPV_KHR_subgroup_vote"); 298 AddExtension("SPV_KHR_subgroup_vote");
298 AddExtension("SPV_KHR_storage_buffer_storage_class"); 299 AddExtension("SPV_KHR_storage_buffer_storage_class");
@@ -307,7 +308,6 @@ public:
307 "supported on this device"); 308 "supported on this device");
308 } 309 }
309 } 310 }
310
311 if (ir.UsesLayer() || ir.UsesViewportIndex()) { 311 if (ir.UsesLayer() || ir.UsesViewportIndex()) {
312 if (ir.UsesViewportIndex()) { 312 if (ir.UsesViewportIndex()) {
313 AddCapability(spv::Capability::MultiViewport); 313 AddCapability(spv::Capability::MultiViewport);
@@ -317,15 +317,13 @@ public:
317 AddCapability(spv::Capability::ShaderViewportIndexLayerEXT); 317 AddCapability(spv::Capability::ShaderViewportIndexLayerEXT);
318 } 318 }
319 } 319 }
320
321 if (device.IsFormatlessImageLoadSupported()) { 320 if (device.IsFormatlessImageLoadSupported()) {
322 AddCapability(spv::Capability::StorageImageReadWithoutFormat); 321 AddCapability(spv::Capability::StorageImageReadWithoutFormat);
323 } 322 }
324
325 if (device.IsFloat16Supported()) { 323 if (device.IsFloat16Supported()) {
326 AddCapability(spv::Capability::Float16); 324 AddCapability(spv::Capability::Float16);
327 } 325 }
328 t_scalar_half = Name(TypeFloat(device.IsFloat16Supported() ? 16 : 32), "scalar_half"); 326 t_scalar_half = Name(TypeFloat(device_.IsFloat16Supported() ? 16 : 32), "scalar_half");
329 t_half = Name(TypeVector(t_scalar_half, 2), "half"); 327 t_half = Name(TypeVector(t_scalar_half, 2), "half");
330 328
331 const Id main = Decompile(); 329 const Id main = Decompile();
@@ -369,6 +367,9 @@ public:
369 if (header.ps.omap.depth) { 367 if (header.ps.omap.depth) {
370 AddExecutionMode(main, spv::ExecutionMode::DepthReplacing); 368 AddExecutionMode(main, spv::ExecutionMode::DepthReplacing);
371 } 369 }
370 if (specialization.early_fragment_tests) {
371 AddExecutionMode(main, spv::ExecutionMode::EarlyFragmentTests);
372 }
372 break; 373 break;
373 case ShaderType::Compute: 374 case ShaderType::Compute:
374 const auto workgroup_size = specialization.workgroup_size; 375 const auto workgroup_size = specialization.workgroup_size;
@@ -972,7 +973,7 @@ private:
972 return binding; 973 return binding;
973 } 974 }
974 975
975 void DeclareImage(const Image& image, u32& binding) { 976 void DeclareImage(const ImageEntry& image, u32& binding) {
976 const auto [dim, arrayed] = GetImageDim(image); 977 const auto [dim, arrayed] = GetImageDim(image);
977 constexpr int depth = 0; 978 constexpr int depth = 0;
978 constexpr bool ms = false; 979 constexpr bool ms = false;
@@ -1080,9 +1081,9 @@ private:
1080 indices.point_size = AddBuiltIn(t_float, spv::BuiltIn::PointSize, "point_size"); 1081 indices.point_size = AddBuiltIn(t_float, spv::BuiltIn::PointSize, "point_size");
1081 } 1082 }
1082 1083
1083 const auto& output_attributes = ir.GetOutputAttributes(); 1084 const auto& ir_output_attributes = ir.GetOutputAttributes();
1084 const bool declare_clip_distances = 1085 const bool declare_clip_distances = std::any_of(
1085 std::any_of(output_attributes.begin(), output_attributes.end(), [](const auto& index) { 1086 ir_output_attributes.begin(), ir_output_attributes.end(), [](const auto& index) {
1086 return index == Attribute::Index::ClipDistances0123 || 1087 return index == Attribute::Index::ClipDistances0123 ||
1087 index == Attribute::Index::ClipDistances4567; 1088 index == Attribute::Index::ClipDistances4567;
1088 }); 1089 });
@@ -1246,7 +1247,7 @@ private:
1246 const Id pointer = ArrayPass(type_descriptor.scalar, attribute_id, elements); 1247 const Id pointer = ArrayPass(type_descriptor.scalar, attribute_id, elements);
1247 return {OpLoad(GetTypeDefinition(type), pointer), type}; 1248 return {OpLoad(GetTypeDefinition(type), pointer), type};
1248 } 1249 }
1249 UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute)); 1250 UNIMPLEMENTED_MSG("Unhandled input attribute: {}", attribute);
1250 return {v_float_zero, Type::Float}; 1251 return {v_float_zero, Type::Float};
1251 } 1252 }
1252 1253
@@ -1882,7 +1883,7 @@ private:
1882 case Tegra::Shader::TextureType::Texture3D: 1883 case Tegra::Shader::TextureType::Texture3D:
1883 return 3; 1884 return 3;
1884 default: 1885 default:
1885 UNREACHABLE_MSG("Invalid texture type={}", static_cast<int>(type)); 1886 UNREACHABLE_MSG("Invalid texture type={}", type);
1886 return 2; 1887 return 2;
1887 } 1888 }
1888 }(); 1889 }();
@@ -2067,6 +2068,46 @@ private:
2067 return {}; 2068 return {};
2068 } 2069 }
2069 2070
2071 Id MaxwellToSpirvComparison(Maxwell::ComparisonOp compare_op, Id operand_1, Id operand_2) {
2072 using Compare = Maxwell::ComparisonOp;
2073 switch (compare_op) {
2074 case Compare::NeverOld:
2075 return v_false; // Never let the test pass
2076 case Compare::LessOld:
2077 return OpFOrdLessThan(t_bool, operand_1, operand_2);
2078 case Compare::EqualOld:
2079 return OpFOrdEqual(t_bool, operand_1, operand_2);
2080 case Compare::LessEqualOld:
2081 return OpFOrdLessThanEqual(t_bool, operand_1, operand_2);
2082 case Compare::GreaterOld:
2083 return OpFOrdGreaterThan(t_bool, operand_1, operand_2);
2084 case Compare::NotEqualOld:
2085 return OpFOrdNotEqual(t_bool, operand_1, operand_2);
2086 case Compare::GreaterEqualOld:
2087 return OpFOrdGreaterThanEqual(t_bool, operand_1, operand_2);
2088 default:
2089 UNREACHABLE();
2090 return v_true;
2091 }
2092 }
2093
2094 void AlphaTest(Id pointer) {
2095 if (specialization.alpha_test_func == Maxwell::ComparisonOp::AlwaysOld) {
2096 return;
2097 }
2098 const Id true_label = OpLabel();
2099 const Id discard_label = OpLabel();
2100 const Id alpha_reference = Constant(t_float, specialization.alpha_test_ref);
2101 const Id alpha_value = OpLoad(t_float, pointer);
2102 const Id condition =
2103 MaxwellToSpirvComparison(specialization.alpha_test_func, alpha_value, alpha_reference);
2104
2105 OpBranchConditional(condition, true_label, discard_label);
2106 AddLabel(discard_label);
2107 OpKill();
2108 AddLabel(true_label);
2109 }
2110
2070 void PreExit() { 2111 void PreExit() {
2071 if (stage == ShaderType::Vertex && specialization.ndc_minus_one_to_one) { 2112 if (stage == ShaderType::Vertex && specialization.ndc_minus_one_to_one) {
2072 const u32 position_index = out_indices.position.value(); 2113 const u32 position_index = out_indices.position.value();
@@ -2078,8 +2119,7 @@ private:
2078 OpStore(z_pointer, depth); 2119 OpStore(z_pointer, depth);
2079 } 2120 }
2080 if (stage == ShaderType::Fragment) { 2121 if (stage == ShaderType::Fragment) {
2081 const auto SafeGetRegister = [&](u32 reg) { 2122 const auto SafeGetRegister = [this](u32 reg) {
2082 // TODO(Rodrigo): Replace with contains once C++20 releases
2083 if (const auto it = registers.find(reg); it != registers.end()) { 2123 if (const auto it = registers.find(reg); it != registers.end()) {
2084 return OpLoad(t_float, it->second); 2124 return OpLoad(t_float, it->second);
2085 } 2125 }
@@ -2089,8 +2129,6 @@ private:
2089 UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, 2129 UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0,
2090 "Sample mask write is unimplemented"); 2130 "Sample mask write is unimplemented");
2091 2131
2092 // TODO(Rodrigo): Alpha testing
2093
2094 // Write the color outputs using the data in the shader registers, disabled 2132 // Write the color outputs using the data in the shader registers, disabled
2095 // rendertargets/components are skipped in the register assignment. 2133 // rendertargets/components are skipped in the register assignment.
2096 u32 current_reg = 0; 2134 u32 current_reg = 0;
@@ -2102,6 +2140,9 @@ private:
2102 } 2140 }
2103 const Id pointer = AccessElement(t_out_float, frag_colors[rt], component); 2141 const Id pointer = AccessElement(t_out_float, frag_colors[rt], component);
2104 OpStore(pointer, SafeGetRegister(current_reg)); 2142 OpStore(pointer, SafeGetRegister(current_reg));
2143 if (rt == 0 && component == 3) {
2144 AlphaTest(pointer);
2145 }
2105 ++current_reg; 2146 ++current_reg;
2106 } 2147 }
2107 } 2148 }
@@ -2701,7 +2742,7 @@ private:
2701 }; 2742 };
2702 static_assert(operation_decompilers.size() == static_cast<std::size_t>(OperationCode::Amount)); 2743 static_assert(operation_decompilers.size() == static_cast<std::size_t>(OperationCode::Amount));
2703 2744
2704 const VKDevice& device; 2745 const Device& device;
2705 const ShaderIR& ir; 2746 const ShaderIR& ir;
2706 const ShaderType stage; 2747 const ShaderType stage;
2707 const Tegra::Shader::Header header; 2748 const Tegra::Shader::Header header;
@@ -2843,7 +2884,7 @@ private:
2843 2884
2844class ExprDecompiler { 2885class ExprDecompiler {
2845public: 2886public:
2846 explicit ExprDecompiler(SPIRVDecompiler& decomp) : decomp{decomp} {} 2887 explicit ExprDecompiler(SPIRVDecompiler& decomp_) : decomp{decomp_} {}
2847 2888
2848 Id operator()(const ExprAnd& expr) { 2889 Id operator()(const ExprAnd& expr) {
2849 const Id type_def = decomp.GetTypeDefinition(Type::Bool); 2890 const Id type_def = decomp.GetTypeDefinition(Type::Bool);
@@ -2899,7 +2940,7 @@ private:
2899 2940
2900class ASTDecompiler { 2941class ASTDecompiler {
2901public: 2942public:
2902 explicit ASTDecompiler(SPIRVDecompiler& decomp) : decomp{decomp} {} 2943 explicit ASTDecompiler(SPIRVDecompiler& decomp_) : decomp{decomp_} {}
2903 2944
2904 void operator()(const ASTProgram& ast) { 2945 void operator()(const ASTProgram& ast) {
2905 ASTNode current = ast.nodes.GetFirst(); 2946 ASTNode current = ast.nodes.GetFirst();
@@ -3089,7 +3130,7 @@ ShaderEntries GenerateShaderEntries(const VideoCommon::Shader::ShaderIR& ir) {
3089 return entries; 3130 return entries;
3090} 3131}
3091 3132
3092std::vector<u32> Decompile(const VKDevice& device, const VideoCommon::Shader::ShaderIR& ir, 3133std::vector<u32> Decompile(const Device& device, const VideoCommon::Shader::ShaderIR& ir,
3093 ShaderType stage, const VideoCommon::Shader::Registry& registry, 3134 ShaderType stage, const VideoCommon::Shader::Registry& registry,
3094 const Specialization& specialization) { 3135 const Specialization& specialization) {
3095 return SPIRVDecompiler(device, ir, stage, registry, specialization).Assemble(); 3136 return SPIRVDecompiler(device, ir, stage, registry, specialization).Assemble();
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.h b/src/video_core/renderer_vulkan/vk_shader_decompiler.h
index 2b0e90396..26381e444 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.h
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.h
@@ -15,23 +15,21 @@
15#include "video_core/shader/shader_ir.h" 15#include "video_core/shader/shader_ir.h"
16 16
17namespace Vulkan { 17namespace Vulkan {
18class VKDevice;
19}
20 18
21namespace Vulkan { 19class Device;
22 20
23using Maxwell = Tegra::Engines::Maxwell3D::Regs; 21using Maxwell = Tegra::Engines::Maxwell3D::Regs;
24using UniformTexelEntry = VideoCommon::Shader::Sampler; 22using UniformTexelEntry = VideoCommon::Shader::SamplerEntry;
25using SamplerEntry = VideoCommon::Shader::Sampler; 23using SamplerEntry = VideoCommon::Shader::SamplerEntry;
26using StorageTexelEntry = VideoCommon::Shader::Image; 24using StorageTexelEntry = VideoCommon::Shader::ImageEntry;
27using ImageEntry = VideoCommon::Shader::Image; 25using ImageEntry = VideoCommon::Shader::ImageEntry;
28 26
29constexpr u32 DESCRIPTOR_SET = 0; 27constexpr u32 DESCRIPTOR_SET = 0;
30 28
31class ConstBufferEntry : public VideoCommon::Shader::ConstBuffer { 29class ConstBufferEntry : public VideoCommon::Shader::ConstBuffer {
32public: 30public:
33 explicit constexpr ConstBufferEntry(const VideoCommon::Shader::ConstBuffer& entry, u32 index) 31 explicit constexpr ConstBufferEntry(const ConstBuffer& entry_, u32 index_)
34 : VideoCommon::Shader::ConstBuffer{entry}, index{index} {} 32 : ConstBuffer{entry_}, index{index_} {}
35 33
36 constexpr u32 GetIndex() const { 34 constexpr u32 GetIndex() const {
37 return index; 35 return index;
@@ -43,8 +41,8 @@ private:
43 41
44class GlobalBufferEntry { 42class GlobalBufferEntry {
45public: 43public:
46 constexpr explicit GlobalBufferEntry(u32 cbuf_index, u32 cbuf_offset, bool is_written) 44 constexpr explicit GlobalBufferEntry(u32 cbuf_index_, u32 cbuf_offset_, bool is_written_)
47 : cbuf_index{cbuf_index}, cbuf_offset{cbuf_offset}, is_written{is_written} {} 45 : cbuf_index{cbuf_index_}, cbuf_offset{cbuf_offset_}, is_written{is_written_} {}
48 46
49 constexpr u32 GetCbufIndex() const { 47 constexpr u32 GetCbufIndex() const {
50 return cbuf_index; 48 return cbuf_index;
@@ -95,6 +93,9 @@ struct Specialization final {
95 std::bitset<Maxwell::NumVertexAttributes> enabled_attributes; 93 std::bitset<Maxwell::NumVertexAttributes> enabled_attributes;
96 std::array<Maxwell::VertexAttribute::Type, Maxwell::NumVertexAttributes> attribute_types{}; 94 std::array<Maxwell::VertexAttribute::Type, Maxwell::NumVertexAttributes> attribute_types{};
97 bool ndc_minus_one_to_one{}; 95 bool ndc_minus_one_to_one{};
96 bool early_fragment_tests{};
97 float alpha_test_ref{};
98 Maxwell::ComparisonOp alpha_test_func{};
98}; 99};
99// Old gcc versions don't consider this trivially copyable. 100// Old gcc versions don't consider this trivially copyable.
100// static_assert(std::is_trivially_copyable_v<Specialization>); 101// static_assert(std::is_trivially_copyable_v<Specialization>);
@@ -106,7 +107,7 @@ struct SPIRVShader {
106 107
107ShaderEntries GenerateShaderEntries(const VideoCommon::Shader::ShaderIR& ir); 108ShaderEntries GenerateShaderEntries(const VideoCommon::Shader::ShaderIR& ir);
108 109
109std::vector<u32> Decompile(const VKDevice& device, const VideoCommon::Shader::ShaderIR& ir, 110std::vector<u32> Decompile(const Device& device, const VideoCommon::Shader::ShaderIR& ir,
110 Tegra::Engines::ShaderType stage, 111 Tegra::Engines::ShaderType stage,
111 const VideoCommon::Shader::Registry& registry, 112 const VideoCommon::Shader::Registry& registry,
112 const Specialization& specialization); 113 const Specialization& specialization);
diff --git a/src/video_core/renderer_vulkan/vk_shader_util.cpp b/src/video_core/renderer_vulkan/vk_shader_util.cpp
index c1a218d76..aaad4f292 100644
--- a/src/video_core/renderer_vulkan/vk_shader_util.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_util.cpp
@@ -7,24 +7,19 @@
7 7
8#include "common/assert.h" 8#include "common/assert.h"
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/renderer_vulkan/vk_device.h"
11#include "video_core/renderer_vulkan/vk_shader_util.h" 10#include "video_core/renderer_vulkan/vk_shader_util.h"
12#include "video_core/renderer_vulkan/wrapper.h" 11#include "video_core/vulkan_common/vulkan_device.h"
12#include "video_core/vulkan_common/vulkan_wrapper.h"
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 Device& 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..9517cbe84 100644
--- a/src/video_core/renderer_vulkan/vk_shader_util.h
+++ b/src/video_core/renderer_vulkan/vk_shader_util.h
@@ -4,13 +4,15 @@
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/vulkan_common/vulkan_wrapper.h"
9 11
10namespace Vulkan { 12namespace Vulkan {
11 13
12class VKDevice; 14class Device;
13 15
14vk::ShaderModule BuildShader(const VKDevice& device, std::size_t code_size, const u8* code_data); 16vk::ShaderModule BuildShader(const Device& device, std::span<const u32> code);
15 17
16} // namespace Vulkan 18} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
index 2fd3b7f39..1e0b8b922 100644
--- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
@@ -9,17 +9,17 @@
9 9
10#include "common/bit_util.h" 10#include "common/bit_util.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/renderer_vulkan/vk_device.h"
13#include "video_core/renderer_vulkan/vk_scheduler.h" 12#include "video_core/renderer_vulkan/vk_scheduler.h"
14#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 13#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
15#include "video_core/renderer_vulkan/wrapper.h" 14#include "video_core/vulkan_common/vulkan_device.h"
15#include "video_core/vulkan_common/vulkan_wrapper.h"
16 16
17namespace Vulkan { 17namespace Vulkan {
18 18
19VKStagingBufferPool::StagingBuffer::StagingBuffer(std::unique_ptr<VKBuffer> buffer_) 19VKStagingBufferPool::StagingBuffer::StagingBuffer(std::unique_ptr<VKBuffer> buffer_)
20 : buffer{std::move(buffer_)} {} 20 : buffer{std::move(buffer_)} {}
21 21
22VKStagingBufferPool::VKStagingBufferPool(const VKDevice& device_, VKMemoryManager& memory_manager_, 22VKStagingBufferPool::VKStagingBufferPool(const Device& device_, VKMemoryManager& memory_manager_,
23 VKScheduler& scheduler_) 23 VKScheduler& scheduler_)
24 : device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_} {} 24 : device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_} {}
25 25
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
index 2dd5049ac..90dadcbbe 100644
--- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
@@ -10,11 +10,11 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11 11
12#include "video_core/renderer_vulkan/vk_memory_manager.h" 12#include "video_core/renderer_vulkan/vk_memory_manager.h"
13#include "video_core/renderer_vulkan/wrapper.h" 13#include "video_core/vulkan_common/vulkan_wrapper.h"
14 14
15namespace Vulkan { 15namespace Vulkan {
16 16
17class VKDevice; 17class Device;
18class VKScheduler; 18class VKScheduler;
19 19
20struct VKBuffer final { 20struct VKBuffer final {
@@ -24,7 +24,7 @@ struct VKBuffer final {
24 24
25class VKStagingBufferPool final { 25class VKStagingBufferPool final {
26public: 26public:
27 explicit VKStagingBufferPool(const VKDevice& device, VKMemoryManager& memory_manager, 27 explicit VKStagingBufferPool(const Device& device, VKMemoryManager& memory_manager,
28 VKScheduler& scheduler); 28 VKScheduler& scheduler);
29 ~VKStagingBufferPool(); 29 ~VKStagingBufferPool();
30 30
@@ -58,7 +58,7 @@ private:
58 58
59 u64 ReleaseLevel(StagingBuffersCache& cache, std::size_t log2); 59 u64 ReleaseLevel(StagingBuffersCache& cache, std::size_t log2);
60 60
61 const VKDevice& device; 61 const Device& device;
62 VKMemoryManager& memory_manager; 62 VKMemoryManager& memory_manager;
63 VKScheduler& scheduler; 63 VKScheduler& scheduler;
64 64
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp
index 5d2c4a796..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
@@ -14,7 +15,7 @@
14#include "video_core/renderer_vulkan/vk_state_tracker.h" 15#include "video_core/renderer_vulkan/vk_state_tracker.h"
15 16
16#define OFF(field_name) MAXWELL3D_REG_INDEX(field_name) 17#define OFF(field_name) MAXWELL3D_REG_INDEX(field_name)
17#define NUM(field_name) (sizeof(Maxwell3D::Regs::field_name) / sizeof(u32)) 18#define NUM(field_name) (sizeof(Maxwell3D::Regs::field_name) / (sizeof(u32)))
18 19
19namespace Vulkan { 20namespace Vulkan {
20 21
@@ -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 5218c875b..a09fe084e 100644
--- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
+++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
@@ -10,15 +10,19 @@
10 10
11#include "common/alignment.h" 11#include "common/alignment.h"
12#include "common/assert.h" 12#include "common/assert.h"
13#include "video_core/renderer_vulkan/vk_device.h"
14#include "video_core/renderer_vulkan/vk_scheduler.h" 13#include "video_core/renderer_vulkan/vk_scheduler.h"
15#include "video_core/renderer_vulkan/vk_stream_buffer.h" 14#include "video_core/renderer_vulkan/vk_stream_buffer.h"
16#include "video_core/renderer_vulkan/wrapper.h" 15#include "video_core/vulkan_common/vulkan_device.h"
16#include "video_core/vulkan_common/vulkan_wrapper.h"
17 17
18namespace Vulkan { 18namespace 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 Device& 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,20 +113,21 @@ 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;
120 120
121 // Substract from the preferred heap size some bytes to avoid getting out of memory. 121 // Substract from the preferred heap size some bytes to avoid getting out of memory.
122 const VkDeviceSize heap_size = memory_properties.memoryHeaps[preferred_heap].size; 122 const VkDeviceSize heap_size = memory_properties.memoryHeaps[preferred_heap].size;
123 const VkDeviceSize allocable_size = heap_size - 9 * 1024 * 1024; 123 // As per DXVK's example, using `heap_size / 2`
124 const VkDeviceSize allocable_size = heap_size / 2;
124 buffer = device.GetLogical().CreateBuffer({ 125 buffer = device.GetLogical().CreateBuffer({
125 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 126 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
126 .pNext = nullptr, 127 .pNext = nullptr,
127 .flags = 0, 128 .flags = 0,
128 .size = std::min(PREFERRED_STREAM_BUFFER_SIZE, allocable_size), 129 .size = std::min(PREFERRED_STREAM_BUFFER_SIZE, allocable_size),
129 .usage = usage, 130 .usage = BUFFER_USAGE,
130 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 131 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
131 .queueFamilyIndexCount = 0, 132 .queueFamilyIndexCount = 0,
132 .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..2e9c8cb46 100644
--- a/src/video_core/renderer_vulkan/vk_stream_buffer.h
+++ b/src/video_core/renderer_vulkan/vk_stream_buffer.h
@@ -5,31 +5,29 @@
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"
12#include "video_core/renderer_vulkan/wrapper.h" 12#include "video_core/vulkan_common/vulkan_wrapper.h"
13 13
14namespace Vulkan { 14namespace Vulkan {
15 15
16class VKDevice; 16class Device;
17class VKFenceWatch; 17class VKFenceWatch;
18class VKScheduler; 18class VKScheduler;
19 19
20class VKStreamBuffer final { 20class VKStreamBuffer final {
21public: 21public:
22 explicit VKStreamBuffer(const VKDevice& device, VKScheduler& scheduler, 22 explicit VKStreamBuffer(const Device& 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,14 +47,14 @@ 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);
56 54
57 void WaitPendingOperations(u64 requested_upper_bound); 55 void WaitPendingOperations(u64 requested_upper_bound);
58 56
59 const VKDevice& device; ///< Vulkan device manager. 57 const Device& device; ///< Vulkan device manager.
60 VKScheduler& scheduler; ///< Command scheduler. 58 VKScheduler& scheduler; ///< Command scheduler.
61 59
62 vk::Buffer buffer; ///< Mapped buffer. 60 vk::Buffer buffer; ///< Mapped buffer.
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index 9636a7c65..725a2a05d 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -11,10 +11,10 @@
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "core/core.h" 12#include "core/core.h"
13#include "core/frontend/framebuffer_layout.h" 13#include "core/frontend/framebuffer_layout.h"
14#include "video_core/renderer_vulkan/vk_device.h"
15#include "video_core/renderer_vulkan/vk_scheduler.h" 14#include "video_core/renderer_vulkan/vk_scheduler.h"
16#include "video_core/renderer_vulkan/vk_swapchain.h" 15#include "video_core/renderer_vulkan/vk_swapchain.h"
17#include "video_core/renderer_vulkan/wrapper.h" 16#include "video_core/vulkan_common/vulkan_device.h"
17#include "video_core/vulkan_common/vulkan_wrapper.h"
18 18
19namespace Vulkan { 19namespace Vulkan {
20 20
@@ -56,7 +56,7 @@ VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 wi
56 56
57} // Anonymous namespace 57} // Anonymous namespace
58 58
59VKSwapchain::VKSwapchain(VkSurfaceKHR surface_, const VKDevice& device_, VKScheduler& scheduler_) 59VKSwapchain::VKSwapchain(VkSurfaceKHR surface_, const Device& device_, VKScheduler& scheduler_)
60 : surface{surface_}, device{device_}, scheduler{scheduler_} {} 60 : surface{surface_}, device{device_}, scheduler{scheduler_} {}
61 61
62VKSwapchain::~VKSwapchain() = default; 62VKSwapchain::~VKSwapchain() = default;
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h
index 6b39befdf..2eadd62b3 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.h
+++ b/src/video_core/renderer_vulkan/vk_swapchain.h
@@ -7,7 +7,7 @@
7#include <vector> 7#include <vector>
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/renderer_vulkan/wrapper.h" 10#include "video_core/vulkan_common/vulkan_wrapper.h"
11 11
12namespace Layout { 12namespace Layout {
13struct FramebufferLayout; 13struct FramebufferLayout;
@@ -15,12 +15,12 @@ struct FramebufferLayout;
15 15
16namespace Vulkan { 16namespace Vulkan {
17 17
18class VKDevice; 18class Device;
19class VKScheduler; 19class VKScheduler;
20 20
21class VKSwapchain { 21class VKSwapchain {
22public: 22public:
23 explicit VKSwapchain(VkSurfaceKHR surface, const VKDevice& device, VKScheduler& scheduler); 23 explicit VKSwapchain(VkSurfaceKHR surface, const Device& device, VKScheduler& scheduler);
24 ~VKSwapchain(); 24 ~VKSwapchain();
25 25
26 /// Creates (or recreates) the swapchain with a given size. 26 /// Creates (or recreates) the swapchain with a given size.
@@ -73,7 +73,7 @@ private:
73 void Destroy(); 73 void Destroy();
74 74
75 const VkSurfaceKHR surface; 75 const VkSurfaceKHR surface;
76 const VKDevice& device; 76 const Device& device;
77 VKScheduler& scheduler; 77 VKScheduler& scheduler;
78 78
79 vk::SwapchainKHR swapchain; 79 vk::SwapchainKHR swapchain;
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index f2c8f2ae1..bd11de012 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -4,613 +4,1105 @@
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"
20#include "video_core/renderer_vulkan/vk_memory_manager.h" 13#include "video_core/renderer_vulkan/vk_memory_manager.h"
21#include "video_core/renderer_vulkan/vk_rasterizer.h" 14#include "video_core/renderer_vulkan/vk_rasterizer.h"
22#include "video_core/renderer_vulkan/vk_scheduler.h" 15#include "video_core/renderer_vulkan/vk_scheduler.h"
23#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 16#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
24#include "video_core/renderer_vulkan/vk_texture_cache.h" 17#include "video_core/renderer_vulkan/vk_texture_cache.h"
25#include "video_core/renderer_vulkan/wrapper.h" 18#include "video_core/vulkan_common/vulkan_device.h"
26#include "video_core/surface.h" 19#include "video_core/vulkan_common/vulkan_wrapper.h"
27 20
28namespace Vulkan { 21namespace Vulkan {
29 22
30using VideoCore::MortonSwizzle; 23using Tegra::Engines::Fermi2D;
31using VideoCore::MortonSwizzleMode;
32
33using Tegra::Texture::SwizzleSource; 24using Tegra::Texture::SwizzleSource;
34using VideoCore::Surface::PixelFormat; 25using Tegra::Texture::TextureMipmapFilter;
35using VideoCore::Surface::SurfaceTarget; 26using VideoCommon::BufferImageCopy;
27using VideoCommon::ImageInfo;
28using VideoCommon::ImageType;
29using VideoCommon::SubresourceRange;
30using VideoCore::Surface::IsPixelFormatASTC;
36 31
37namespace { 32namespace {
38 33
39VkImageType SurfaceTargetToImage(SurfaceTarget target) { 34constexpr std::array ATTACHMENT_REFERENCES{
40 switch (target) { 35 VkAttachmentReference{0, VK_IMAGE_LAYOUT_GENERAL},
41 case SurfaceTarget::Texture1D: 36 VkAttachmentReference{1, VK_IMAGE_LAYOUT_GENERAL},
42 case SurfaceTarget::Texture1DArray: 37 VkAttachmentReference{2, VK_IMAGE_LAYOUT_GENERAL},
38 VkAttachmentReference{3, VK_IMAGE_LAYOUT_GENERAL},
39 VkAttachmentReference{4, VK_IMAGE_LAYOUT_GENERAL},
40 VkAttachmentReference{5, VK_IMAGE_LAYOUT_GENERAL},
41 VkAttachmentReference{6, VK_IMAGE_LAYOUT_GENERAL},
42 VkAttachmentReference{7, VK_IMAGE_LAYOUT_GENERAL},
43 VkAttachmentReference{8, VK_IMAGE_LAYOUT_GENERAL},
44};
45
46constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
47 if (color == std::array<float, 4>{0, 0, 0, 0}) {
48 return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
49 } else if (color == std::array<float, 4>{0, 0, 0, 1}) {
50 return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
51 } else if (color == std::array<float, 4>{1, 1, 1, 1}) {
52 return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
53 }
54 if (color[0] + color[1] + color[2] > 1.35f) {
55 // If color elements are brighter than roughly 0.5 average, use white border
56 return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
57 } else if (color[3] > 0.5f) {
58 return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
59 } else {
60 return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
61 }
62}
63
64[[nodiscard]] VkImageType ConvertImageType(const ImageType type) {
65 switch (type) {
66 case ImageType::e1D:
43 return VK_IMAGE_TYPE_1D; 67 return VK_IMAGE_TYPE_1D;
44 case SurfaceTarget::Texture2D: 68 case ImageType::e2D:
45 case SurfaceTarget::Texture2DArray: 69 case ImageType::Linear:
46 case SurfaceTarget::TextureCubemap:
47 case SurfaceTarget::TextureCubeArray:
48 return VK_IMAGE_TYPE_2D; 70 return VK_IMAGE_TYPE_2D;
49 case SurfaceTarget::Texture3D: 71 case ImageType::e3D:
50 return VK_IMAGE_TYPE_3D; 72 return VK_IMAGE_TYPE_3D;
51 case SurfaceTarget::TextureBuffer: 73 case ImageType::Buffer:
52 UNREACHABLE(); 74 break;
53 return {};
54 } 75 }
55 UNREACHABLE_MSG("Unknown texture target={}", static_cast<u32>(target)); 76 UNREACHABLE_MSG("Invalid image type={}", type);
56 return {}; 77 return {};
57} 78}
58 79
59VkImageAspectFlags PixelFormatToImageAspect(PixelFormat pixel_format) { 80[[nodiscard]] VkSampleCountFlagBits ConvertSampleCount(u32 num_samples) {
60 if (pixel_format < PixelFormat::MaxColorFormat) { 81 switch (num_samples) {
61 return VK_IMAGE_ASPECT_COLOR_BIT; 82 case 1:
62 } else if (pixel_format < PixelFormat::MaxDepthFormat) { 83 return VK_SAMPLE_COUNT_1_BIT;
63 return VK_IMAGE_ASPECT_DEPTH_BIT; 84 case 2:
64 } else if (pixel_format < PixelFormat::MaxDepthStencilFormat) { 85 return VK_SAMPLE_COUNT_2_BIT;
65 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; 86 case 4:
66 } else { 87 return VK_SAMPLE_COUNT_4_BIT;
67 UNREACHABLE_MSG("Invalid pixel format={}", static_cast<int>(pixel_format)); 88 case 8:
68 return VK_IMAGE_ASPECT_COLOR_BIT; 89 return VK_SAMPLE_COUNT_8_BIT;
90 case 16:
91 return VK_SAMPLE_COUNT_16_BIT;
92 default:
93 UNREACHABLE_MSG("Invalid number of samples={}", num_samples);
94 return VK_SAMPLE_COUNT_1_BIT;
69 } 95 }
70} 96}
71 97
72VkImageViewType GetImageViewType(SurfaceTarget target) { 98[[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info) {
73 switch (target) { 99 const auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, info.format);
74 case SurfaceTarget::Texture1D: 100 VkImageCreateFlags flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
75 return VK_IMAGE_VIEW_TYPE_1D; 101 if (info.type == ImageType::e2D && info.resources.layers >= 6 &&
76 case SurfaceTarget::Texture2D: 102 info.size.width == info.size.height) {
77 return VK_IMAGE_VIEW_TYPE_2D; 103 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 } 104 }
91 UNREACHABLE(); 105 if (info.type == ImageType::e3D) {
92 return {}; 106 flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
93} 107 }
94 108 VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
95vk::Buffer CreateBuffer(const VKDevice& device, const SurfaceParams& params, 109 VK_IMAGE_USAGE_SAMPLED_BIT;
96 std::size_t host_memory_size) { 110 if (format_info.attachable) {
97 // TODO(Rodrigo): Move texture buffer creation to the buffer cache 111 switch (VideoCore::Surface::GetFormatType(info.format)) {
98 return device.GetLogical().CreateBuffer({ 112 case VideoCore::Surface::SurfaceType::ColorTexture:
99 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 113 usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
114 break;
115 case VideoCore::Surface::SurfaceType::Depth:
116 case VideoCore::Surface::SurfaceType::DepthStencil:
117 usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
118 break;
119 default:
120 UNREACHABLE_MSG("Invalid surface type");
121 }
122 }
123 if (format_info.storage) {
124 usage |= VK_IMAGE_USAGE_STORAGE_BIT;
125 }
126 const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(info.num_samples);
127 return VkImageCreateInfo{
128 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
100 .pNext = nullptr, 129 .pNext = nullptr,
101 .flags = 0, 130 .flags = flags,
102 .size = static_cast<VkDeviceSize>(host_memory_size), 131 .imageType = ConvertImageType(info.type),
103 .usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | 132 .format = format_info.format,
104 VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | 133 .extent =
105 VK_BUFFER_USAGE_TRANSFER_DST_BIT, 134 {
135 .width = info.size.width >> samples_x,
136 .height = info.size.height >> samples_y,
137 .depth = info.size.depth,
138 },
139 .mipLevels = static_cast<u32>(info.resources.levels),
140 .arrayLayers = static_cast<u32>(info.resources.layers),
141 .samples = ConvertSampleCount(info.num_samples),
142 .tiling = VK_IMAGE_TILING_OPTIMAL,
143 .usage = usage,
106 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 144 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
107 .queueFamilyIndexCount = 0, 145 .queueFamilyIndexCount = 0,
108 .pQueueFamilyIndices = nullptr, 146 .pQueueFamilyIndices = nullptr,
109 }); 147 .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 }; 148 };
127} 149}
128 150
129VkImageCreateInfo GenerateImageCreateInfo(const VKDevice& device, const SurfaceParams& params) { 151[[nodiscard]] vk::Image MakeImage(const Device& device, const ImageInfo& info) {
130 ASSERT(!params.IsBuffer()); 152 if (info.type == ImageType::Buffer) {
131 153 return vk::Image{};
132 const auto [format, attachable, storage] = 154 }
133 MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, params.pixel_format); 155 return device.GetLogical().CreateImage(MakeImageCreateInfo(device, info));
156}
134 157
135 VkImageCreateInfo ci{ 158[[nodiscard]] vk::Buffer MakeBuffer(const Device& device, const ImageInfo& info) {
136 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 159 if (info.type != ImageType::Buffer) {
160 return vk::Buffer{};
161 }
162 const size_t bytes_per_block = VideoCore::Surface::BytesPerBlock(info.format);
163 return device.GetLogical().CreateBuffer(VkBufferCreateInfo{
164 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
137 .pNext = nullptr, 165 .pNext = nullptr,
138 .flags = 0, 166 .flags = 0,
139 .imageType = SurfaceTargetToImage(params.target), 167 .size = info.size.width * bytes_per_block,
140 .format = format, 168 .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
141 .extent = {}, 169 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT |
142 .mipLevels = params.num_levels, 170 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, 171 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
149 .queueFamilyIndexCount = 0, 172 .queueFamilyIndexCount = 0,
150 .pQueueFamilyIndices = nullptr, 173 .pQueueFamilyIndices = nullptr,
151 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 174 });
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} 175}
182 176
183u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source, Tegra::Texture::SwizzleSource y_source, 177[[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) {
184 Tegra::Texture::SwizzleSource z_source, Tegra::Texture::SwizzleSource w_source) { 178 switch (VideoCore::Surface::GetFormatType(format)) {
185 return (static_cast<u32>(x_source) << 24) | (static_cast<u32>(y_source) << 16) | 179 case VideoCore::Surface::SurfaceType::ColorTexture:
186 (static_cast<u32>(z_source) << 8) | static_cast<u32>(w_source); 180 return VK_IMAGE_ASPECT_COLOR_BIT;
181 case VideoCore::Surface::SurfaceType::Depth:
182 return VK_IMAGE_ASPECT_DEPTH_BIT;
183 case VideoCore::Surface::SurfaceType::DepthStencil:
184 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
185 default:
186 UNREACHABLE_MSG("Invalid surface type");
187 return VkImageAspectFlags{};
188 }
187} 189}
188 190
189} // Anonymous namespace 191[[nodiscard]] VkImageAspectFlags ImageViewAspectMask(const VideoCommon::ImageViewInfo& info) {
190 192 if (info.IsRenderTarget()) {
191CachedSurface::CachedSurface(const VKDevice& device, VKMemoryManager& memory_manager, 193 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 } 194 }
212 195 const bool is_first = info.Swizzle()[0] == SwizzleSource::R;
213 // TODO(Rodrigo): Move this to a virtual function. 196 switch (info.format) {
214 u32 num_layers = 1; 197 case PixelFormat::D24_UNORM_S8_UINT:
215 if (params.is_layered || params.target == SurfaceTarget::Texture3D) { 198 case PixelFormat::D32_FLOAT_S8_UINT:
216 num_layers = params.depth; 199 return is_first ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT;
200 case PixelFormat::S8_UINT_D24_UNORM:
201 return is_first ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT;
202 case PixelFormat::D16_UNORM:
203 case PixelFormat::D32_FLOAT:
204 return VK_IMAGE_ASPECT_DEPTH_BIT;
205 default:
206 return VK_IMAGE_ASPECT_COLOR_BIT;
217 } 207 }
218 main_view = CreateView(ViewParams(params.target, 0, num_layers, 0, params.num_levels));
219} 208}
220 209
221CachedSurface::~CachedSurface() = default; 210[[nodiscard]] VkAttachmentDescription AttachmentDescription(const Device& device,
222 211 const ImageView* image_view) {
223void CachedSurface::UploadTexture(const std::vector<u8>& staging_buffer) { 212 const auto pixel_format = image_view->format;
224 // To upload data we have to be outside of a renderpass 213 return VkAttachmentDescription{
225 scheduler.RequestOutsideRenderPassOperationContext(); 214 .flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT,
215 .format = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, pixel_format).format,
216 .samples = image_view->Samples(),
217 .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
218 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
219 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
220 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE,
221 .initialLayout = VK_IMAGE_LAYOUT_GENERAL,
222 .finalLayout = VK_IMAGE_LAYOUT_GENERAL,
223 };
224}
226 225
227 if (params.IsBuffer()) { 226[[nodiscard]] VkComponentSwizzle ComponentSwizzle(SwizzleSource swizzle) {
228 UploadBuffer(staging_buffer); 227 switch (swizzle) {
229 } else { 228 case SwizzleSource::Zero:
230 UploadImage(staging_buffer); 229 return VK_COMPONENT_SWIZZLE_ZERO;
230 case SwizzleSource::R:
231 return VK_COMPONENT_SWIZZLE_R;
232 case SwizzleSource::G:
233 return VK_COMPONENT_SWIZZLE_G;
234 case SwizzleSource::B:
235 return VK_COMPONENT_SWIZZLE_B;
236 case SwizzleSource::A:
237 return VK_COMPONENT_SWIZZLE_A;
238 case SwizzleSource::OneFloat:
239 case SwizzleSource::OneInt:
240 return VK_COMPONENT_SWIZZLE_ONE;
231 } 241 }
242 UNREACHABLE_MSG("Invalid swizzle={}", swizzle);
243 return VK_COMPONENT_SWIZZLE_ZERO;
232} 244}
233 245
234void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) { 246[[nodiscard]] VkImageViewType ImageViewType(VideoCommon::ImageViewType type) {
235 UNIMPLEMENTED_IF(params.IsBuffer()); 247 switch (type) {
236 248 case VideoCommon::ImageViewType::e1D:
237 if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5_UNORM) { 249 return VK_IMAGE_VIEW_TYPE_1D;
238 LOG_WARNING(Render_Vulkan, "A1B5G5R5 flushing is stubbed"); 250 case VideoCommon::ImageViewType::e2D:
251 return VK_IMAGE_VIEW_TYPE_2D;
252 case VideoCommon::ImageViewType::Cube:
253 return VK_IMAGE_VIEW_TYPE_CUBE;
254 case VideoCommon::ImageViewType::e3D:
255 return VK_IMAGE_VIEW_TYPE_3D;
256 case VideoCommon::ImageViewType::e1DArray:
257 return VK_IMAGE_VIEW_TYPE_1D_ARRAY;
258 case VideoCommon::ImageViewType::e2DArray:
259 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
260 case VideoCommon::ImageViewType::CubeArray:
261 return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
262 case VideoCommon::ImageViewType::Rect:
263 LOG_WARNING(Render_Vulkan, "Unnormalized image view type not supported");
264 return VK_IMAGE_VIEW_TYPE_2D;
265 case VideoCommon::ImageViewType::Buffer:
266 UNREACHABLE_MSG("Texture buffers can't be image views");
267 return VK_IMAGE_VIEW_TYPE_1D;
239 } 268 }
269 UNREACHABLE_MSG("Invalid image view type={}", type);
270 return VK_IMAGE_VIEW_TYPE_2D;
271}
240 272
241 // We can't copy images to buffers inside a renderpass 273[[nodiscard]] VkImageSubresourceLayers MakeImageSubresourceLayers(
242 scheduler.RequestOutsideRenderPassOperationContext(); 274 VideoCommon::SubresourceLayers subresource, VkImageAspectFlags aspect_mask) {
275 return VkImageSubresourceLayers{
276 .aspectMask = aspect_mask,
277 .mipLevel = static_cast<u32>(subresource.base_level),
278 .baseArrayLayer = static_cast<u32>(subresource.base_layer),
279 .layerCount = static_cast<u32>(subresource.num_layers),
280 };
281}
243 282
244 FullTransition(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, 283[[nodiscard]] VkOffset3D MakeOffset3D(VideoCommon::Offset3D offset3d) {
245 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); 284 return VkOffset3D{
285 .x = offset3d.x,
286 .y = offset3d.y,
287 .z = offset3d.z,
288 };
289}
246 290
247 const auto& buffer = staging_pool.GetUnusedBuffer(host_memory_size, true); 291[[nodiscard]] VkExtent3D MakeExtent3D(VideoCommon::Extent3D extent3d) {
248 // TODO(Rodrigo): Do this in a single copy 292 return VkExtent3D{
249 for (u32 level = 0; level < params.num_levels; ++level) { 293 .width = static_cast<u32>(extent3d.width),
250 scheduler.Record([image = *image->GetHandle(), buffer = *buffer.handle, 294 .height = static_cast<u32>(extent3d.height),
251 copy = GetBufferImageCopy(level)](vk::CommandBuffer cmdbuf) { 295 .depth = static_cast<u32>(extent3d.depth),
252 cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, copy); 296 };
253 }); 297}
254 }
255 scheduler.Finish();
256 298
257 // TODO(Rodrigo): Use an intern buffer for staging buffers and avoid this unnecessary memcpy. 299[[nodiscard]] VkImageCopy MakeImageCopy(const VideoCommon::ImageCopy& copy,
258 std::memcpy(staging_buffer.data(), buffer.commit->Map(host_memory_size), host_memory_size); 300 VkImageAspectFlags aspect_mask) noexcept {
301 return VkImageCopy{
302 .srcSubresource = MakeImageSubresourceLayers(copy.src_subresource, aspect_mask),
303 .srcOffset = MakeOffset3D(copy.src_offset),
304 .dstSubresource = MakeImageSubresourceLayers(copy.dst_subresource, aspect_mask),
305 .dstOffset = MakeOffset3D(copy.dst_offset),
306 .extent = MakeExtent3D(copy.extent),
307 };
259} 308}
260 309
261void CachedSurface::DecorateSurfaceName() { 310[[nodiscard]] std::vector<VkBufferCopy> TransformBufferCopies(
262 // TODO(Rodrigo): Add name decorations 311 std::span<const VideoCommon::BufferCopy> copies, size_t buffer_offset) {
312 std::vector<VkBufferCopy> result(copies.size());
313 std::ranges::transform(
314 copies, result.begin(), [buffer_offset](const VideoCommon::BufferCopy& copy) {
315 return VkBufferCopy{
316 .srcOffset = static_cast<VkDeviceSize>(copy.src_offset + buffer_offset),
317 .dstOffset = static_cast<VkDeviceSize>(copy.dst_offset),
318 .size = static_cast<VkDeviceSize>(copy.size),
319 };
320 });
321 return result;
263} 322}
264 323
265View CachedSurface::CreateView(const ViewParams& params) { 324[[nodiscard]] std::vector<VkBufferImageCopy> TransformBufferImageCopies(
266 // TODO(Rodrigo): Add name decorations 325 std::span<const BufferImageCopy> copies, size_t buffer_offset, VkImageAspectFlags aspect_mask) {
267 return views[params] = std::make_shared<CachedSurfaceView>(device, *this, params); 326 struct Maker {
327 VkBufferImageCopy operator()(const BufferImageCopy& copy) const {
328 return VkBufferImageCopy{
329 .bufferOffset = copy.buffer_offset + buffer_offset,
330 .bufferRowLength = copy.buffer_row_length,
331 .bufferImageHeight = copy.buffer_image_height,
332 .imageSubresource =
333 {
334 .aspectMask = aspect_mask,
335 .mipLevel = static_cast<u32>(copy.image_subresource.base_level),
336 .baseArrayLayer = static_cast<u32>(copy.image_subresource.base_layer),
337 .layerCount = static_cast<u32>(copy.image_subresource.num_layers),
338 },
339 .imageOffset =
340 {
341 .x = copy.image_offset.x,
342 .y = copy.image_offset.y,
343 .z = copy.image_offset.z,
344 },
345 .imageExtent =
346 {
347 .width = copy.image_extent.width,
348 .height = copy.image_extent.height,
349 .depth = copy.image_extent.depth,
350 },
351 };
352 }
353 size_t buffer_offset;
354 VkImageAspectFlags aspect_mask;
355 };
356 if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
357 std::vector<VkBufferImageCopy> result(copies.size() * 2);
358 std::ranges::transform(copies, result.begin(),
359 Maker{buffer_offset, VK_IMAGE_ASPECT_DEPTH_BIT});
360 std::ranges::transform(copies, result.begin() + copies.size(),
361 Maker{buffer_offset, VK_IMAGE_ASPECT_STENCIL_BIT});
362 return result;
363 } else {
364 std::vector<VkBufferImageCopy> result(copies.size());
365 std::ranges::transform(copies, result.begin(), Maker{buffer_offset, aspect_mask});
366 return result;
367 }
268} 368}
269 369
270void CachedSurface::UploadBuffer(const std::vector<u8>& staging_buffer) { 370[[nodiscard]] VkImageSubresourceRange MakeSubresourceRange(VkImageAspectFlags aspect_mask,
271 const auto& src_buffer = staging_pool.GetUnusedBuffer(host_memory_size, true); 371 const SubresourceRange& range) {
272 std::memcpy(src_buffer.commit->Map(host_memory_size), staging_buffer.data(), host_memory_size); 372 return VkImageSubresourceRange{
373 .aspectMask = aspect_mask,
374 .baseMipLevel = static_cast<u32>(range.base.level),
375 .levelCount = static_cast<u32>(range.extent.levels),
376 .baseArrayLayer = static_cast<u32>(range.base.layer),
377 .layerCount = static_cast<u32>(range.extent.layers),
378 };
379}
273 380
274 scheduler.Record([src_buffer = *src_buffer.handle, dst_buffer = *buffer, 381[[nodiscard]] VkImageSubresourceRange MakeSubresourceRange(const ImageView* image_view) {
275 size = host_memory_size](vk::CommandBuffer cmdbuf) { 382 SubresourceRange range = image_view->range;
276 VkBufferCopy copy; 383 if (True(image_view->flags & VideoCommon::ImageViewFlagBits::Slice)) {
277 copy.srcOffset = 0; 384 // Slice image views always affect a single layer, but their subresource range corresponds
278 copy.dstOffset = 0; 385 // to the slice. Override the value to affect a single layer.
279 copy.size = size; 386 range.base.layer = 0;
280 cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy); 387 range.extent.layers = 1;
388 }
389 return MakeSubresourceRange(ImageAspectMask(image_view->format), range);
390}
281 391
282 VkBufferMemoryBarrier barrier; 392[[nodiscard]] VkImageSubresourceLayers MakeSubresourceLayers(const ImageView* image_view) {
283 barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; 393 return VkImageSubresourceLayers{
284 barrier.pNext = nullptr; 394 .aspectMask = ImageAspectMask(image_view->format),
285 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; 395 .mipLevel = static_cast<u32>(image_view->range.base.level),
286 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; 396 .baseArrayLayer = static_cast<u32>(image_view->range.base.layer),
287 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // They'll be ignored anyway 397 .layerCount = static_cast<u32>(image_view->range.extent.layers),
288 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 398 };
289 barrier.buffer = dst_buffer;
290 barrier.offset = 0;
291 barrier.size = size;
292 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
293 0, {}, barrier, {});
294 });
295} 399}
296 400
297void CachedSurface::UploadImage(const std::vector<u8>& staging_buffer) { 401[[nodiscard]] constexpr SwizzleSource ConvertGreenRed(SwizzleSource value) {
298 const auto& src_buffer = staging_pool.GetUnusedBuffer(host_memory_size, true); 402 switch (value) {
299 std::memcpy(src_buffer.commit->Map(host_memory_size), staging_buffer.data(), host_memory_size); 403 case SwizzleSource::G:
300 404 return SwizzleSource::R;
301 FullTransition(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, 405 default:
302 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); 406 return value;
303
304 for (u32 level = 0; level < params.num_levels; ++level) {
305 const VkBufferImageCopy copy = GetBufferImageCopy(level);
306 if (image->GetAspectMask() == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
307 scheduler.Record([buffer = *src_buffer.handle, image = *image->GetHandle(),
308 copy](vk::CommandBuffer cmdbuf) {
309 std::array<VkBufferImageCopy, 2> copies = {copy, copy};
310 copies[0].imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
311 copies[1].imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
312 cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
313 copies);
314 });
315 } else {
316 scheduler.Record([buffer = *src_buffer.handle, image = *image->GetHandle(),
317 copy](vk::CommandBuffer cmdbuf) {
318 cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy);
319 });
320 }
321 } 407 }
322} 408}
323 409
324VkBufferImageCopy CachedSurface::GetBufferImageCopy(u32 level) const { 410void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage image,
325 return { 411 VkImageAspectFlags aspect_mask, bool is_initialized,
326 .bufferOffset = params.GetHostMipmapLevelOffset(level, is_converted), 412 std::span<const VkBufferImageCopy> copies) {
327 .bufferRowLength = 0, 413 static constexpr VkAccessFlags ACCESS_FLAGS = VK_ACCESS_SHADER_WRITE_BIT |
328 .bufferImageHeight = 0, 414 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
329 .imageSubresource = 415 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
416 const VkImageMemoryBarrier read_barrier{
417 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
418 .pNext = nullptr,
419 .srcAccessMask = ACCESS_FLAGS,
420 .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
421 .oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
422 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
423 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
424 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
425 .image = image,
426 .subresourceRange =
330 { 427 {
331 .aspectMask = image->GetAspectMask(), 428 .aspectMask = aspect_mask,
332 .mipLevel = level, 429 .baseMipLevel = 0,
430 .levelCount = VK_REMAINING_MIP_LEVELS,
333 .baseArrayLayer = 0, 431 .baseArrayLayer = 0,
334 .layerCount = static_cast<u32>(params.GetNumLayers()), 432 .layerCount = VK_REMAINING_ARRAY_LAYERS,
335 }, 433 },
336 .imageOffset = {.x = 0, .y = 0, .z = 0}, 434 };
337 .imageExtent = 435 const VkImageMemoryBarrier write_barrier{
436 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
437 .pNext = nullptr,
438 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
439 .dstAccessMask = ACCESS_FLAGS,
440 .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
441 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
442 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
443 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
444 .image = image,
445 .subresourceRange =
338 { 446 {
339 .width = params.GetMipWidth(level), 447 .aspectMask = aspect_mask,
340 .height = params.GetMipHeight(level), 448 .baseMipLevel = 0,
341 .depth = params.target == SurfaceTarget::Texture3D ? params.GetMipDepth(level) : 1U, 449 .levelCount = VK_REMAINING_MIP_LEVELS,
450 .baseArrayLayer = 0,
451 .layerCount = VK_REMAINING_ARRAY_LAYERS,
342 }, 452 },
343 }; 453 };
454 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
455 read_barrier);
456 cmdbuf.CopyBufferToImage(src_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copies);
457 // TODO: Move this to another API
458 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,
459 write_barrier);
344} 460}
345 461
346VkImageSubresourceRange CachedSurface::GetImageSubresourceRange() const { 462[[nodiscard]] VkImageBlit MakeImageBlit(const std::array<Offset2D, 2>& dst_region,
347 return {image->GetAspectMask(), 0, params.num_levels, 0, 463 const std::array<Offset2D, 2>& src_region,
348 static_cast<u32>(params.GetNumLayers())}; 464 const VkImageSubresourceLayers& dst_layers,
465 const VkImageSubresourceLayers& src_layers) {
466 return VkImageBlit{
467 .srcSubresource = src_layers,
468 .srcOffsets =
469 {
470 {
471 .x = src_region[0].x,
472 .y = src_region[0].y,
473 .z = 0,
474 },
475 {
476 .x = src_region[1].x,
477 .y = src_region[1].y,
478 .z = 1,
479 },
480 },
481 .dstSubresource = dst_layers,
482 .dstOffsets =
483 {
484 {
485 .x = dst_region[0].x,
486 .y = dst_region[0].y,
487 .z = 0,
488 },
489 {
490 .x = dst_region[1].x,
491 .y = dst_region[1].y,
492 .z = 1,
493 },
494 },
495 };
349} 496}
350 497
351CachedSurfaceView::CachedSurfaceView(const VKDevice& device, CachedSurface& surface, 498[[nodiscard]] VkImageResolve MakeImageResolve(const std::array<Offset2D, 2>& dst_region,
352 const ViewParams& params) 499 const std::array<Offset2D, 2>& src_region,
353 : VideoCommon::ViewBase{params}, params{surface.GetSurfaceParams()}, 500 const VkImageSubresourceLayers& dst_layers,
354 image{surface.GetImageHandle()}, buffer_view{surface.GetBufferViewHandle()}, 501 const VkImageSubresourceLayers& src_layers) {
355 aspect_mask{surface.GetAspectMask()}, device{device}, surface{surface}, 502 return VkImageResolve{
356 base_level{params.base_level}, num_levels{params.num_levels}, 503 .srcSubresource = src_layers,
357 image_view_type{image ? GetImageViewType(params.target) : VK_IMAGE_VIEW_TYPE_1D} { 504 .srcOffset =
358 if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) { 505 {
359 base_layer = 0; 506 .x = src_region[0].x,
360 num_layers = 1; 507 .y = src_region[0].y,
361 base_slice = params.base_layer; 508 .z = 0,
362 num_slices = params.num_layers; 509 },
363 } else { 510 .dstSubresource = dst_layers,
364 base_layer = params.base_layer; 511 .dstOffset =
365 num_layers = params.num_layers; 512 {
366 } 513 .x = dst_region[0].x,
514 .y = dst_region[0].y,
515 .z = 0,
516 },
517 .extent =
518 {
519 .width = static_cast<u32>(dst_region[1].x - dst_region[0].x),
520 .height = static_cast<u32>(dst_region[1].y - dst_region[0].y),
521 .depth = 1,
522 },
523 };
367} 524}
368 525
369CachedSurfaceView::~CachedSurfaceView() = default; 526struct RangedBarrierRange {
370 527 u32 min_mip = std::numeric_limits<u32>::max();
371VkImageView CachedSurfaceView::GetImageView(SwizzleSource x_source, SwizzleSource y_source, 528 u32 max_mip = std::numeric_limits<u32>::min();
372 SwizzleSource z_source, SwizzleSource w_source) { 529 u32 min_layer = std::numeric_limits<u32>::max();
373 const u32 new_swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source); 530 u32 max_layer = std::numeric_limits<u32>::min();
374 if (last_image_view && last_swizzle == new_swizzle) { 531
375 return last_image_view; 532 void AddLayers(const VkImageSubresourceLayers& layers) {
533 min_mip = std::min(min_mip, layers.mipLevel);
534 max_mip = std::max(max_mip, layers.mipLevel + 1);
535 min_layer = std::min(min_layer, layers.baseArrayLayer);
536 max_layer = std::max(max_layer, layers.baseArrayLayer + layers.layerCount);
376 } 537 }
377 last_swizzle = new_swizzle;
378 538
379 const auto [entry, is_cache_miss] = view_cache.try_emplace(new_swizzle); 539 VkImageSubresourceRange SubresourceRange(VkImageAspectFlags aspect_mask) const noexcept {
380 auto& image_view = entry->second; 540 return VkImageSubresourceRange{
381 if (!is_cache_miss) { 541 .aspectMask = aspect_mask,
382 return last_image_view = *image_view; 542 .baseMipLevel = min_mip,
543 .levelCount = max_mip - min_mip,
544 .baseArrayLayer = min_layer,
545 .layerCount = max_layer - min_layer,
546 };
383 } 547 }
548};
384 549
385 std::array swizzle{MaxwellToVK::SwizzleSource(x_source), MaxwellToVK::SwizzleSource(y_source), 550} // Anonymous namespace
386 MaxwellToVK::SwizzleSource(z_source), MaxwellToVK::SwizzleSource(w_source)};
387 if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5_UNORM) {
388 // A1B5G5R5 is implemented as A1R5G5B5, we have to change the swizzle here.
389 std::swap(swizzle[0], swizzle[2]);
390 }
391 551
392 // Games can sample depth or stencil values on textures. This is decided by the swizzle value on 552void TextureCacheRuntime::Finish() {
393 // hardware. To emulate this on Vulkan we specify it in the aspect. 553 scheduler.Finish();
394 VkImageAspectFlags aspect = aspect_mask; 554}
395 if (aspect == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
396 UNIMPLEMENTED_IF(x_source != SwizzleSource::R && x_source != SwizzleSource::G);
397 const bool is_first = x_source == SwizzleSource::R;
398 switch (params.pixel_format) {
399 case VideoCore::Surface::PixelFormat::D24_UNORM_S8_UINT:
400 case VideoCore::Surface::PixelFormat::D32_FLOAT_S8_UINT:
401 aspect = is_first ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT;
402 break;
403 case VideoCore::Surface::PixelFormat::S8_UINT_D24_UNORM:
404 aspect = is_first ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT;
405 break;
406 default:
407 aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
408 UNIMPLEMENTED();
409 }
410 555
411 // Make sure we sample the first component 556ImageBufferMap TextureCacheRuntime::MapUploadBuffer(size_t size) {
412 std::transform( 557 const auto& buffer = staging_buffer_pool.GetUnusedBuffer(size, true);
413 swizzle.begin(), swizzle.end(), swizzle.begin(), [](VkComponentSwizzle component) { 558 return ImageBufferMap{
414 return component == VK_COMPONENT_SWIZZLE_G ? VK_COMPONENT_SWIZZLE_R : component; 559 .handle = *buffer.handle,
415 }); 560 .map = buffer.commit->Map(size),
416 } 561 };
562}
417 563
418 if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) { 564void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src,
419 ASSERT(base_slice == 0); 565 const std::array<Offset2D, 2>& dst_region,
420 ASSERT(num_slices == params.depth); 566 const std::array<Offset2D, 2>& src_region,
567 Tegra::Engines::Fermi2D::Filter filter,
568 Tegra::Engines::Fermi2D::Operation operation) {
569 const VkImageAspectFlags aspect_mask = ImageAspectMask(src.format);
570 const bool is_dst_msaa = dst.Samples() != VK_SAMPLE_COUNT_1_BIT;
571 const bool is_src_msaa = src.Samples() != VK_SAMPLE_COUNT_1_BIT;
572 ASSERT(aspect_mask == ImageAspectMask(dst.format));
573 if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT && !is_src_msaa && !is_dst_msaa) {
574 blit_image_helper.BlitColor(dst_framebuffer, src, dst_region, src_region, filter,
575 operation);
576 return;
421 } 577 }
422 578 if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
423 image_view = device.GetLogical().CreateImageView({ 579 if (!device.IsBlitDepthStencilSupported()) {
424 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 580 UNIMPLEMENTED_IF(is_src_msaa || is_dst_msaa);
425 .pNext = nullptr, 581 blit_image_helper.BlitDepthStencil(dst_framebuffer, src.DepthView(), src.StencilView(),
426 .flags = 0, 582 dst_region, src_region, filter, operation);
427 .image = surface.GetImageHandle(), 583 return;
428 .viewType = image_view_type, 584 }
429 .format = surface.GetImage().GetFormat(), 585 }
430 .components = 586 ASSERT(src.ImageFormat() == dst.ImageFormat());
431 { 587 ASSERT(!(is_dst_msaa && !is_src_msaa));
432 .r = swizzle[0], 588 ASSERT(operation == Fermi2D::Operation::SrcCopy);
433 .g = swizzle[1], 589
434 .b = swizzle[2], 590 const VkImage dst_image = dst.ImageHandle();
435 .a = swizzle[3], 591 const VkImage src_image = src.ImageHandle();
592 const VkImageSubresourceLayers dst_layers = MakeSubresourceLayers(&dst);
593 const VkImageSubresourceLayers src_layers = MakeSubresourceLayers(&src);
594 const bool is_resolve = is_src_msaa && !is_dst_msaa;
595 scheduler.RequestOutsideRenderPassOperationContext();
596 scheduler.Record([filter, dst_region, src_region, dst_image, src_image, dst_layers, src_layers,
597 aspect_mask, is_resolve](vk::CommandBuffer cmdbuf) {
598 const std::array read_barriers{
599 VkImageMemoryBarrier{
600 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
601 .pNext = nullptr,
602 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT |
603 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
604 VK_ACCESS_TRANSFER_WRITE_BIT,
605 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
606 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
607 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
608 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
609 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
610 .image = src_image,
611 .subresourceRange{
612 .aspectMask = aspect_mask,
613 .baseMipLevel = 0,
614 .levelCount = VK_REMAINING_MIP_LEVELS,
615 .baseArrayLayer = 0,
616 .layerCount = VK_REMAINING_ARRAY_LAYERS,
617 },
436 }, 618 },
437 .subresourceRange = 619 VkImageMemoryBarrier{
438 { 620 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
439 .aspectMask = aspect, 621 .pNext = nullptr,
440 .baseMipLevel = base_level, 622 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT |
441 .levelCount = num_levels, 623 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
442 .baseArrayLayer = base_layer, 624 VK_ACCESS_TRANSFER_WRITE_BIT,
443 .layerCount = num_layers, 625 .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
626 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
627 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
628 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
629 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
630 .image = dst_image,
631 .subresourceRange{
632 .aspectMask = aspect_mask,
633 .baseMipLevel = 0,
634 .levelCount = VK_REMAINING_MIP_LEVELS,
635 .baseArrayLayer = 0,
636 .layerCount = VK_REMAINING_ARRAY_LAYERS,
637 },
638 },
639 };
640 VkImageMemoryBarrier write_barrier{
641 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
642 .pNext = nullptr,
643 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
644 .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
645 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
646 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
647 VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
648 .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
649 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
650 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
651 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
652 .image = dst_image,
653 .subresourceRange{
654 .aspectMask = aspect_mask,
655 .baseMipLevel = 0,
656 .levelCount = VK_REMAINING_MIP_LEVELS,
657 .baseArrayLayer = 0,
658 .layerCount = VK_REMAINING_ARRAY_LAYERS,
444 }, 659 },
660 };
661 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
662 0, nullptr, nullptr, read_barriers);
663 if (is_resolve) {
664 cmdbuf.ResolveImage(src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image,
665 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
666 MakeImageResolve(dst_region, src_region, dst_layers, src_layers));
667 } else {
668 const bool is_linear = filter == Fermi2D::Filter::Bilinear;
669 const VkFilter vk_filter = is_linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
670 cmdbuf.BlitImage(
671 src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
672 MakeImageBlit(dst_region, src_region, dst_layers, src_layers), vk_filter);
673 }
674 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
675 0, write_barrier);
445 }); 676 });
446
447 return last_image_view = *image_view;
448} 677}
449 678
450VkImageView CachedSurfaceView::GetAttachment() { 679void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) {
451 if (render_target) { 680 switch (dst_view.format) {
452 return *render_target; 681 case PixelFormat::R16_UNORM:
682 if (src_view.format == PixelFormat::D16_UNORM) {
683 return blit_image_helper.ConvertD16ToR16(dst, src_view);
684 }
685 break;
686 case PixelFormat::R32_FLOAT:
687 if (src_view.format == PixelFormat::D32_FLOAT) {
688 return blit_image_helper.ConvertD32ToR32(dst, src_view);
689 }
690 break;
691 case PixelFormat::D16_UNORM:
692 if (src_view.format == PixelFormat::R16_UNORM) {
693 return blit_image_helper.ConvertR16ToD16(dst, src_view);
694 }
695 break;
696 case PixelFormat::D32_FLOAT:
697 if (src_view.format == PixelFormat::R32_FLOAT) {
698 return blit_image_helper.ConvertR32ToD32(dst, src_view);
699 }
700 break;
701 default:
702 break;
453 } 703 }
704 UNIMPLEMENTED_MSG("Unimplemented format copy from {} to {}", src_view.format, dst_view.format);
705}
454 706
455 VkImageViewCreateInfo ci{ 707void TextureCacheRuntime::CopyImage(Image& dst, Image& src,
456 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 708 std::span<const VideoCommon::ImageCopy> copies) {
457 .pNext = nullptr, 709 std::vector<VkImageCopy> vk_copies(copies.size());
458 .flags = 0, 710 const VkImageAspectFlags aspect_mask = dst.AspectMask();
459 .image = surface.GetImageHandle(), 711 ASSERT(aspect_mask == src.AspectMask());
460 .viewType = VK_IMAGE_VIEW_TYPE_1D, 712
461 .format = surface.GetImage().GetFormat(), 713 std::ranges::transform(copies, vk_copies.begin(), [aspect_mask](const auto& copy) {
462 .components = 714 return MakeImageCopy(copy, aspect_mask);
463 { 715 });
464 .r = VK_COMPONENT_SWIZZLE_IDENTITY, 716 const VkImage dst_image = dst.Handle();
465 .g = VK_COMPONENT_SWIZZLE_IDENTITY, 717 const VkImage src_image = src.Handle();
466 .b = VK_COMPONENT_SWIZZLE_IDENTITY, 718 scheduler.RequestOutsideRenderPassOperationContext();
467 .a = VK_COMPONENT_SWIZZLE_IDENTITY, 719 scheduler.Record([dst_image, src_image, aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) {
720 RangedBarrierRange dst_range;
721 RangedBarrierRange src_range;
722 for (const VkImageCopy& copy : vk_copies) {
723 dst_range.AddLayers(copy.dstSubresource);
724 src_range.AddLayers(copy.srcSubresource);
725 }
726 const std::array read_barriers{
727 VkImageMemoryBarrier{
728 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
729 .pNext = nullptr,
730 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
731 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
732 VK_ACCESS_TRANSFER_WRITE_BIT,
733 .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
734 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
735 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
736 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
737 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
738 .image = src_image,
739 .subresourceRange = src_range.SubresourceRange(aspect_mask),
468 }, 740 },
469 .subresourceRange = 741 VkImageMemoryBarrier{
470 { 742 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
471 .aspectMask = aspect_mask, 743 .pNext = nullptr,
472 .baseMipLevel = base_level, 744 .srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
473 .levelCount = num_levels, 745 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
474 .baseArrayLayer = 0, 746 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
475 .layerCount = 0, 747 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
748 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
749 VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
750 .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
751 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
752 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
753 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
754 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
755 .image = dst_image,
756 .subresourceRange = dst_range.SubresourceRange(aspect_mask),
476 }, 757 },
477 }; 758 };
478 if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) { 759 const VkImageMemoryBarrier write_barrier{
479 ci.viewType = num_slices > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D; 760 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
480 ci.subresourceRange.baseArrayLayer = base_slice; 761 .pNext = nullptr,
481 ci.subresourceRange.layerCount = num_slices; 762 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
763 .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
764 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
765 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
766 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
767 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
768 VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
769 .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
770 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
771 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
772 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
773 .image = dst_image,
774 .subresourceRange = dst_range.SubresourceRange(aspect_mask),
775 };
776 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
777 0, {}, {}, read_barriers);
778 cmdbuf.CopyImage(src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image,
779 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vk_copies);
780 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
781 0, write_barrier);
782 });
783}
784
785Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_addr_,
786 VAddr cpu_addr_)
787 : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime.scheduler},
788 image(MakeImage(runtime.device, info)), buffer(MakeBuffer(runtime.device, info)),
789 aspect_mask(ImageAspectMask(info.format)) {
790 if (image) {
791 commit = runtime.memory_manager.Commit(image, false);
482 } else { 792 } else {
483 ci.viewType = image_view_type; 793 commit = runtime.memory_manager.Commit(buffer, false);
484 ci.subresourceRange.baseArrayLayer = base_layer; 794 }
485 ci.subresourceRange.layerCount = num_layers; 795 if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) {
796 flags |= VideoCommon::ImageFlagBits::Converted;
797 }
798 if (runtime.device.HasDebuggingToolAttached()) {
799 if (image) {
800 image.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
801 } else {
802 buffer.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
803 }
486 } 804 }
487 render_target = device.GetLogical().CreateImageView(ci);
488 return *render_target;
489} 805}
490 806
491VKTextureCache::VKTextureCache(VideoCore::RasterizerInterface& rasterizer, 807void Image::UploadMemory(const ImageBufferMap& map, size_t buffer_offset,
492 Tegra::Engines::Maxwell3D& maxwell3d, 808 std::span<const BufferImageCopy> copies) {
493 Tegra::MemoryManager& gpu_memory, const VKDevice& device_, 809 // TODO: Move this to another API
494 VKMemoryManager& memory_manager_, VKScheduler& scheduler_, 810 scheduler->RequestOutsideRenderPassOperationContext();
495 VKStagingBufferPool& staging_pool_) 811 std::vector vk_copies = TransformBufferImageCopies(copies, buffer_offset, aspect_mask);
496 : TextureCache(rasterizer, maxwell3d, gpu_memory, device_.IsOptimalAstcSupported()), 812 const VkBuffer src_buffer = map.handle;
497 device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{ 813 const VkImage vk_image = *image;
498 staging_pool_} {} 814 const VkImageAspectFlags vk_aspect_mask = aspect_mask;
499 815 const bool is_initialized = std::exchange(initialized, true);
500VKTextureCache::~VKTextureCache() = default; 816 scheduler->Record([src_buffer, vk_image, vk_aspect_mask, is_initialized,
501 817 vk_copies](vk::CommandBuffer cmdbuf) {
502Surface VKTextureCache::CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) { 818 CopyBufferToImage(cmdbuf, src_buffer, vk_image, vk_aspect_mask, is_initialized, vk_copies);
503 return std::make_shared<CachedSurface>(device, memory_manager, scheduler, staging_pool, 819 });
504 gpu_addr, params);
505} 820}
506 821
507void VKTextureCache::ImageCopy(Surface& src_surface, Surface& dst_surface, 822void Image::UploadMemory(const ImageBufferMap& map, size_t buffer_offset,
508 const VideoCommon::CopyParams& copy_params) { 823 std::span<const VideoCommon::BufferCopy> copies) {
509 const bool src_3d = src_surface->GetSurfaceParams().target == SurfaceTarget::Texture3D; 824 // TODO: Move this to another API
510 const bool dst_3d = dst_surface->GetSurfaceParams().target == SurfaceTarget::Texture3D; 825 scheduler->RequestOutsideRenderPassOperationContext();
511 UNIMPLEMENTED_IF(src_3d); 826 std::vector vk_copies = TransformBufferCopies(copies, buffer_offset);
827 const VkBuffer src_buffer = map.handle;
828 const VkBuffer dst_buffer = *buffer;
829 scheduler->Record([src_buffer, dst_buffer, vk_copies](vk::CommandBuffer cmdbuf) {
830 // TODO: Barriers
831 cmdbuf.CopyBuffer(src_buffer, dst_buffer, vk_copies);
832 });
833}
512 834
513 // The texture cache handles depth in OpenGL terms, we have to handle it as subresource and 835void Image::DownloadMemory(const ImageBufferMap& map, size_t buffer_offset,
514 // dimension respectively. 836 std::span<const BufferImageCopy> copies) {
515 const u32 dst_base_layer = dst_3d ? 0 : copy_params.dest_z; 837 std::vector vk_copies = TransformBufferImageCopies(copies, buffer_offset, aspect_mask);
516 const u32 dst_offset_z = dst_3d ? copy_params.dest_z : 0; 838 scheduler->Record([buffer = map.handle, image = *image, aspect_mask = aspect_mask,
839 vk_copies](vk::CommandBuffer cmdbuf) {
840 // TODO: Barriers
841 cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_GENERAL, buffer, vk_copies);
842 });
843}
517 844
518 const u32 extent_z = dst_3d ? copy_params.depth : 1; 845ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
519 const u32 num_layers = dst_3d ? 1 : copy_params.depth; 846 ImageId image_id_, Image& image)
847 : VideoCommon::ImageViewBase{info, image.info, image_id_}, device{&runtime.device},
848 image_handle{image.Handle()}, image_format{image.info.format}, samples{ConvertSampleCount(
849 image.info.num_samples)} {
850 const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info);
851 std::array<SwizzleSource, 4> swizzle{
852 SwizzleSource::R,
853 SwizzleSource::G,
854 SwizzleSource::B,
855 SwizzleSource::A,
856 };
857 if (!info.IsRenderTarget()) {
858 swizzle = info.Swizzle();
859 if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) {
860 std::ranges::transform(swizzle, swizzle.begin(), ConvertGreenRed);
861 }
862 }
863 const VkFormat vk_format =
864 MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, format).format;
865 const VkImageViewCreateInfo create_info{
866 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
867 .pNext = nullptr,
868 .flags = 0,
869 .image = image.Handle(),
870 .viewType = VkImageViewType{},
871 .format = vk_format,
872 .components{
873 .r = ComponentSwizzle(swizzle[0]),
874 .g = ComponentSwizzle(swizzle[1]),
875 .b = ComponentSwizzle(swizzle[2]),
876 .a = ComponentSwizzle(swizzle[3]),
877 },
878 .subresourceRange = MakeSubresourceRange(aspect_mask, info.range),
879 };
880 const auto create = [&](VideoCommon::ImageViewType view_type, std::optional<u32> num_layers) {
881 VkImageViewCreateInfo ci{create_info};
882 ci.viewType = ImageViewType(view_type);
883 if (num_layers) {
884 ci.subresourceRange.layerCount = *num_layers;
885 }
886 vk::ImageView handle = device->GetLogical().CreateImageView(ci);
887 if (device->HasDebuggingToolAttached()) {
888 handle.SetObjectNameEXT(VideoCommon::Name(*this, view_type).c_str());
889 }
890 image_views[static_cast<size_t>(view_type)] = std::move(handle);
891 };
892 switch (info.type) {
893 case VideoCommon::ImageViewType::e1D:
894 case VideoCommon::ImageViewType::e1DArray:
895 create(VideoCommon::ImageViewType::e1D, 1);
896 create(VideoCommon::ImageViewType::e1DArray, std::nullopt);
897 render_target = Handle(VideoCommon::ImageViewType::e1DArray);
898 break;
899 case VideoCommon::ImageViewType::e2D:
900 case VideoCommon::ImageViewType::e2DArray:
901 create(VideoCommon::ImageViewType::e2D, 1);
902 create(VideoCommon::ImageViewType::e2DArray, std::nullopt);
903 render_target = Handle(VideoCommon::ImageViewType::e2DArray);
904 break;
905 case VideoCommon::ImageViewType::e3D:
906 create(VideoCommon::ImageViewType::e3D, std::nullopt);
907 render_target = Handle(VideoCommon::ImageViewType::e3D);
908 break;
909 case VideoCommon::ImageViewType::Cube:
910 case VideoCommon::ImageViewType::CubeArray:
911 create(VideoCommon::ImageViewType::Cube, 6);
912 create(VideoCommon::ImageViewType::CubeArray, std::nullopt);
913 break;
914 case VideoCommon::ImageViewType::Rect:
915 UNIMPLEMENTED();
916 break;
917 case VideoCommon::ImageViewType::Buffer:
918 buffer_view = device->GetLogical().CreateBufferView(VkBufferViewCreateInfo{
919 .sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
920 .pNext = nullptr,
921 .flags = 0,
922 .buffer = image.Buffer(),
923 .format = vk_format,
924 .offset = 0, // TODO: Redesign buffer cache to support this
925 .range = image.guest_size_bytes,
926 });
927 break;
928 }
929}
520 930
521 // We can't copy inside a renderpass 931ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::NullImageParams& params)
522 scheduler.RequestOutsideRenderPassOperationContext(); 932 : VideoCommon::ImageViewBase{params} {}
523 933
524 src_surface->Transition(copy_params.source_z, copy_params.depth, copy_params.source_level, 1, 934VkImageView ImageView::DepthView() {
525 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, 935 if (depth_view) {
526 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); 936 return *depth_view;
527 dst_surface->Transition(dst_base_layer, num_layers, copy_params.dest_level, 1, 937 }
528 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, 938 depth_view = MakeDepthStencilView(VK_IMAGE_ASPECT_DEPTH_BIT);
529 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); 939 return *depth_view;
940}
530 941
531 const VkImageCopy copy{ 942VkImageView ImageView::StencilView() {
532 .srcSubresource = 943 if (stencil_view) {
533 { 944 return *stencil_view;
534 .aspectMask = src_surface->GetAspectMask(), 945 }
535 .mipLevel = copy_params.source_level, 946 stencil_view = MakeDepthStencilView(VK_IMAGE_ASPECT_STENCIL_BIT);
536 .baseArrayLayer = copy_params.source_z, 947 return *stencil_view;
537 .layerCount = num_layers, 948}
538 },
539 .srcOffset =
540 {
541 .x = static_cast<s32>(copy_params.source_x),
542 .y = static_cast<s32>(copy_params.source_y),
543 .z = 0,
544 },
545 .dstSubresource =
546 {
547 .aspectMask = dst_surface->GetAspectMask(),
548 .mipLevel = copy_params.dest_level,
549 .baseArrayLayer = dst_base_layer,
550 .layerCount = num_layers,
551 },
552 .dstOffset =
553 {
554 .x = static_cast<s32>(copy_params.dest_x),
555 .y = static_cast<s32>(copy_params.dest_y),
556 .z = static_cast<s32>(dst_offset_z),
557 },
558 .extent =
559 {
560 .width = copy_params.width,
561 .height = copy_params.height,
562 .depth = extent_z,
563 },
564 };
565 949
566 const VkImage src_image = src_surface->GetImageHandle(); 950vk::ImageView ImageView::MakeDepthStencilView(VkImageAspectFlags aspect_mask) {
567 const VkImage dst_image = dst_surface->GetImageHandle(); 951 return device->GetLogical().CreateImageView({
568 scheduler.Record([src_image, dst_image, copy](vk::CommandBuffer cmdbuf) { 952 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
569 cmdbuf.CopyImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image, 953 .pNext = nullptr,
570 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); 954 .flags = 0,
955 .image = image_handle,
956 .viewType = ImageViewType(type),
957 .format = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, format).format,
958 .components{
959 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
960 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
961 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
962 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
963 },
964 .subresourceRange = MakeSubresourceRange(aspect_mask, range),
571 }); 965 });
572} 966}
573 967
574void VKTextureCache::ImageBlit(View& src_view, View& dst_view, 968Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& tsc) {
575 const Tegra::Engines::Fermi2D::Config& copy_config) { 969 const auto& device = runtime.device;
576 // We can't blit inside a renderpass 970 const bool arbitrary_borders = runtime.device.IsExtCustomBorderColorSupported();
577 scheduler.RequestOutsideRenderPassOperationContext(); 971 const std::array<float, 4> color = tsc.BorderColor();
578 972 // C++20 bit_cast
579 src_view->Transition(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, 973 VkClearColorValue border_color;
580 VK_ACCESS_TRANSFER_READ_BIT); 974 std::memcpy(&border_color, &color, sizeof(color));
581 dst_view->Transition(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, 975 const VkSamplerCustomBorderColorCreateInfoEXT border_ci{
582 VK_ACCESS_TRANSFER_WRITE_BIT); 976 .sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT,
583 977 .pNext = nullptr,
584 VkImageBlit blit; 978 .customBorderColor = border_color,
585 blit.srcSubresource = src_view->GetImageSubresourceLayers(); 979 .format = VK_FORMAT_UNDEFINED,
586 blit.srcOffsets[0].x = copy_config.src_rect.left; 980 };
587 blit.srcOffsets[0].y = copy_config.src_rect.top; 981 const void* pnext = nullptr;
588 blit.srcOffsets[0].z = 0; 982 if (arbitrary_borders) {
589 blit.srcOffsets[1].x = copy_config.src_rect.right; 983 pnext = &border_ci;
590 blit.srcOffsets[1].y = copy_config.src_rect.bottom; 984 }
591 blit.srcOffsets[1].z = 1; 985 const VkSamplerReductionModeCreateInfoEXT reduction_ci{
592 blit.dstSubresource = dst_view->GetImageSubresourceLayers(); 986 .sType = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT,
593 blit.dstOffsets[0].x = copy_config.dst_rect.left; 987 .pNext = pnext,
594 blit.dstOffsets[0].y = copy_config.dst_rect.top; 988 .reductionMode = MaxwellToVK::SamplerReduction(tsc.reduction_filter),
595 blit.dstOffsets[0].z = 0; 989 };
596 blit.dstOffsets[1].x = copy_config.dst_rect.right; 990 if (runtime.device.IsExtSamplerFilterMinmaxSupported()) {
597 blit.dstOffsets[1].y = copy_config.dst_rect.bottom; 991 pnext = &reduction_ci;
598 blit.dstOffsets[1].z = 1; 992 } else if (reduction_ci.reductionMode != VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT) {
599 993 LOG_WARNING(Render_Vulkan, "VK_EXT_sampler_filter_minmax is required");
600 const bool is_linear = copy_config.filter == Tegra::Engines::Fermi2D::Filter::Linear; 994 }
601 995 // Some games have samplers with garbage. Sanitize them here.
602 scheduler.Record([src_image = src_view->GetImage(), dst_image = dst_view->GetImage(), blit, 996 const float max_anisotropy = std::clamp(tsc.MaxAnisotropy(), 1.0f, 16.0f);
603 is_linear](vk::CommandBuffer cmdbuf) { 997 sampler = device.GetLogical().CreateSampler(VkSamplerCreateInfo{
604 cmdbuf.BlitImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image, 998 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
605 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, blit, 999 .pNext = pnext,
606 is_linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST); 1000 .flags = 0,
1001 .magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter),
1002 .minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter),
1003 .mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter),
1004 .addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter),
1005 .addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter),
1006 .addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter),
1007 .mipLodBias = tsc.LodBias(),
1008 .anisotropyEnable = static_cast<VkBool32>(max_anisotropy > 1.0f ? VK_TRUE : VK_FALSE),
1009 .maxAnisotropy = max_anisotropy,
1010 .compareEnable = tsc.depth_compare_enabled,
1011 .compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func),
1012 .minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(),
1013 .maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(),
1014 .borderColor =
1015 arbitrary_borders ? VK_BORDER_COLOR_INT_CUSTOM_EXT : ConvertBorderColor(color),
1016 .unnormalizedCoordinates = VK_FALSE,
607 }); 1017 });
608} 1018}
609 1019
610void VKTextureCache::BufferCopy(Surface& src_surface, Surface& dst_surface) { 1020Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM_RT> color_buffers,
611 // Currently unimplemented. PBO copies should be dropped and we should use a render pass to 1021 ImageView* depth_buffer, const VideoCommon::RenderTargets& key) {
612 // convert from color to depth and viceversa. 1022 std::vector<VkAttachmentDescription> descriptions;
613 LOG_WARNING(Render_Vulkan, "Unimplemented"); 1023 std::vector<VkImageView> attachments;
1024 RenderPassKey renderpass_key{};
1025 s32 num_layers = 1;
1026
1027 for (size_t index = 0; index < NUM_RT; ++index) {
1028 const ImageView* const color_buffer = color_buffers[index];
1029 if (!color_buffer) {
1030 renderpass_key.color_formats[index] = PixelFormat::Invalid;
1031 continue;
1032 }
1033 descriptions.push_back(AttachmentDescription(runtime.device, color_buffer));
1034 attachments.push_back(color_buffer->RenderTarget());
1035 renderpass_key.color_formats[index] = color_buffer->format;
1036 num_layers = std::max(num_layers, color_buffer->range.extent.layers);
1037 images[num_images] = color_buffer->ImageHandle();
1038 image_ranges[num_images] = MakeSubresourceRange(color_buffer);
1039 samples = color_buffer->Samples();
1040 ++num_images;
1041 }
1042 const size_t num_colors = attachments.size();
1043 const VkAttachmentReference* depth_attachment =
1044 depth_buffer ? &ATTACHMENT_REFERENCES[num_colors] : nullptr;
1045 if (depth_buffer) {
1046 descriptions.push_back(AttachmentDescription(runtime.device, depth_buffer));
1047 attachments.push_back(depth_buffer->RenderTarget());
1048 renderpass_key.depth_format = depth_buffer->format;
1049 num_layers = std::max(num_layers, depth_buffer->range.extent.layers);
1050 images[num_images] = depth_buffer->ImageHandle();
1051 image_ranges[num_images] = MakeSubresourceRange(depth_buffer);
1052 samples = depth_buffer->Samples();
1053 ++num_images;
1054 } else {
1055 renderpass_key.depth_format = PixelFormat::Invalid;
1056 }
1057 renderpass_key.samples = samples;
1058
1059 const auto& device = runtime.device.GetLogical();
1060 const auto [cache_pair, is_new] = runtime.renderpass_cache.try_emplace(renderpass_key);
1061 if (is_new) {
1062 const VkSubpassDescription subpass{
1063 .flags = 0,
1064 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
1065 .inputAttachmentCount = 0,
1066 .pInputAttachments = nullptr,
1067 .colorAttachmentCount = static_cast<u32>(num_colors),
1068 .pColorAttachments = num_colors != 0 ? ATTACHMENT_REFERENCES.data() : nullptr,
1069 .pResolveAttachments = nullptr,
1070 .pDepthStencilAttachment = depth_attachment,
1071 .preserveAttachmentCount = 0,
1072 .pPreserveAttachments = nullptr,
1073 };
1074 cache_pair->second = device.CreateRenderPass(VkRenderPassCreateInfo{
1075 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
1076 .pNext = nullptr,
1077 .flags = 0,
1078 .attachmentCount = static_cast<u32>(descriptions.size()),
1079 .pAttachments = descriptions.data(),
1080 .subpassCount = 1,
1081 .pSubpasses = &subpass,
1082 .dependencyCount = 0,
1083 .pDependencies = nullptr,
1084 });
1085 }
1086 renderpass = *cache_pair->second;
1087 render_area = VkExtent2D{
1088 .width = key.size.width,
1089 .height = key.size.height,
1090 };
1091 num_color_buffers = static_cast<u32>(num_colors);
1092 framebuffer = device.CreateFramebuffer(VkFramebufferCreateInfo{
1093 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
1094 .pNext = nullptr,
1095 .flags = 0,
1096 .renderPass = renderpass,
1097 .attachmentCount = static_cast<u32>(attachments.size()),
1098 .pAttachments = attachments.data(),
1099 .width = key.size.width,
1100 .height = key.size.height,
1101 .layers = static_cast<u32>(num_layers),
1102 });
1103 if (runtime.device.HasDebuggingToolAttached()) {
1104 framebuffer.SetObjectNameEXT(VideoCommon::Name(key).c_str());
1105 }
614} 1106}
615 1107
616} // namespace Vulkan 1108} // 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 39202feba..92a7aad8b 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -4,216 +4,270 @@
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"
15#include "video_core/texture_cache/surface_base.h"
16#include "video_core/texture_cache/texture_cache.h" 11#include "video_core/texture_cache/texture_cache.h"
17 12#include "video_core/vulkan_common/vulkan_wrapper.h"
18namespace VideoCore {
19class RasterizerInterface;
20}
21 13
22namespace Vulkan { 14namespace Vulkan {
23 15
24class RasterizerVulkan; 16using VideoCommon::ImageId;
25class VKDevice; 17using VideoCommon::NUM_RT;
18using VideoCommon::Offset2D;
19using VideoCommon::RenderTargets;
20using VideoCore::Surface::PixelFormat;
21
26class VKScheduler; 22class VKScheduler;
27class VKStagingBufferPool; 23class VKStagingBufferPool;
28 24
29class CachedSurfaceView; 25class BlitImageHelper;
30class CachedSurface; 26class Device;
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 Device& device;
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();
79
80 [[nodiscard]] ImageBufferMap MapUploadBuffer(size_t size);
81
82 [[nodiscard]] ImageBufferMap MapDownloadBuffer(size_t size) {
83 // TODO: Have a special function for this
84 return MapUploadBuffer(size);
70 } 85 }
71 86
72 VkImage GetImageHandle() const { 87 void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src,
73 return *image->GetHandle(); 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;
74 } 99 }
75 100
76 VkImageAspectFlags GetAspectMask() const { 101 void AccelerateImageUpload(Image&, const ImageBufferMap&, size_t,
77 return image->GetAspectMask(); 102 std::span<const VideoCommon::SwizzleParameters>) {
103 UNREACHABLE();
78 } 104 }
79 105
80 VkBufferView GetBufferViewHandle() const { 106 void InsertUploadMemoryBarrier() {}
81 return *buffer_view; 107
108 bool HasBrokenTextureViewFormats() const noexcept {
109 // No known Vulkan driver has broken image views
110 return false;
82 } 111 }
112};
83 113
84protected: 114class Image : public VideoCommon::ImageBase {
85 void DecorateSurfaceName(); 115public:
116 explicit Image(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, GPUVAddr gpu_addr,
117 VAddr cpu_addr);
86 118
87 View CreateView(const ViewParams& params) override; 119 void UploadMemory(const ImageBufferMap& map, size_t buffer_offset,
120 std::span<const VideoCommon::BufferImageCopy> copies);
88 121
89private: 122 void UploadMemory(const ImageBufferMap& map, size_t buffer_offset,
90 void UploadBuffer(const std::vector<u8>& staging_buffer); 123 std::span<const VideoCommon::BufferCopy> copies);
91 124
92 void UploadImage(const std::vector<u8>& staging_buffer); 125 void DownloadMemory(const ImageBufferMap& map, size_t buffer_offset,
126 std::span<const VideoCommon::BufferImageCopy> copies);
93 127
94 VkBufferImageCopy GetBufferImageCopy(u32 level) const; 128 [[nodiscard]] VkImage Handle() const noexcept {
129 return *image;
130 }
95 131
96 VkImageSubresourceRange GetImageSubresourceRange() const; 132 [[nodiscard]] VkBuffer Buffer() const noexcept {
133 return *buffer;
134 }
97 135
98 const VKDevice& device; 136 [[nodiscard]] VkImageCreateFlags AspectMask() const noexcept {
99 VKMemoryManager& memory_manager; 137 return aspect_mask;
100 VKScheduler& scheduler; 138 }
101 VKStagingBufferPool& staging_pool;
102 139
103 std::optional<VKImage> image; 140private:
141 VKScheduler* scheduler;
142 vk::Image image;
104 vk::Buffer buffer; 143 vk::Buffer buffer;
105 vk::BufferView buffer_view;
106 VKMemoryCommit commit; 144 VKMemoryCommit commit;
107 145 VkImageAspectFlags aspect_mask = 0;
108 VkFormat format = VK_FORMAT_UNDEFINED; 146 bool initialized = false;
109}; 147};
110 148
111class CachedSurfaceView final : public VideoCommon::ViewBase { 149class ImageView : public VideoCommon::ImageViewBase {
112public: 150public:
113 explicit CachedSurfaceView(const VKDevice& device, CachedSurface& surface, 151 explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&);
114 const ViewParams& params); 152 explicit ImageView(TextureCacheRuntime&, const VideoCommon::NullImageParams&);
115 ~CachedSurfaceView();
116 153
117 VkImageView GetImageView(Tegra::Texture::SwizzleSource x_source, 154 [[nodiscard]] VkImageView DepthView();
118 Tegra::Texture::SwizzleSource y_source,
119 Tegra::Texture::SwizzleSource z_source,
120 Tegra::Texture::SwizzleSource w_source);
121 155
122 VkImageView GetAttachment(); 156 [[nodiscard]] VkImageView StencilView();
123 157
124 bool IsSameSurface(const CachedSurfaceView& rhs) const { 158 [[nodiscard]] VkImageView Handle(VideoCommon::ImageViewType query_type) const noexcept {
125 return &surface == &rhs.surface; 159 return *image_views[static_cast<size_t>(query_type)];
126 } 160 }
127 161
128 u32 GetWidth() const { 162 [[nodiscard]] VkBufferView BufferView() const noexcept {
129 return params.GetMipWidth(base_level); 163 return *buffer_view;
130 } 164 }
131 165
132 u32 GetHeight() const { 166 [[nodiscard]] VkImage ImageHandle() const noexcept {
133 return params.GetMipHeight(base_level); 167 return image_handle;
134 } 168 }
135 169
136 u32 GetNumLayers() const { 170 [[nodiscard]] VkImageView RenderTarget() const noexcept {
137 return num_layers; 171 return render_target;
138 } 172 }
139 173
140 bool IsBufferView() const { 174 [[nodiscard]] PixelFormat ImageFormat() const noexcept {
141 return buffer_view; 175 return image_format;
142 } 176 }
143 177
144 VkImage GetImage() const { 178 [[nodiscard]] VkSampleCountFlagBits Samples() const noexcept {
145 return image; 179 return samples;
146 } 180 }
147 181
148 VkBufferView GetBufferView() const { 182private:
149 return buffer_view; 183 [[nodiscard]] vk::ImageView MakeDepthStencilView(VkImageAspectFlags aspect_mask);
150 }
151 184
152 VkImageSubresourceRange GetImageSubresourceRange() const { 185 const Device* device = nullptr;
153 return {aspect_mask, base_level, num_levels, base_layer, num_layers}; 186 std::array<vk::ImageView, VideoCommon::NUM_IMAGE_VIEW_TYPES> image_views;
154 } 187 vk::ImageView depth_view;
188 vk::ImageView stencil_view;
189 vk::BufferView buffer_view;
190 VkImage image_handle = VK_NULL_HANDLE;
191 VkImageView render_target = VK_NULL_HANDLE;
192 PixelFormat image_format = PixelFormat::Invalid;
193 VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
194};
155 195
156 VkImageSubresourceLayers GetImageSubresourceLayers() const { 196class ImageAlloc : public VideoCommon::ImageAllocBase {};
157 return {surface.GetAspectMask(), base_level, base_layer, num_layers};
158 }
159 197
160 void Transition(VkImageLayout new_layout, VkPipelineStageFlags new_stage_mask, 198class Sampler {
161 VkAccessFlags new_access) const { 199public:
162 surface.Transition(base_layer, num_layers, base_level, num_levels, new_stage_mask, 200 explicit Sampler(TextureCacheRuntime&, const Tegra::Texture::TSCEntry&);
163 new_access, new_layout);
164 }
165 201
166 void MarkAsModified(u64 tick) { 202 [[nodiscard]] VkSampler Handle() const noexcept {
167 surface.MarkAsModified(true, tick); 203 return *sampler;
168 } 204 }
169 205
170private: 206private:
171 // Store a copy of these values to avoid double dereference when reading them 207 vk::Sampler sampler;
172 const SurfaceParams 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}; 208};
193 209
194class VKTextureCache final : public TextureCacheBase { 210class Framebuffer {
195public: 211public:
196 explicit VKTextureCache(VideoCore::RasterizerInterface& rasterizer, 212 explicit Framebuffer(TextureCacheRuntime&, std::span<ImageView*, NUM_RT> color_buffers,
197 Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory, 213 ImageView* depth_buffer, const VideoCommon::RenderTargets& key);
198 const VKDevice& device, VKMemoryManager& memory_manager,
199 VKScheduler& scheduler, VKStagingBufferPool& staging_pool);
200 ~VKTextureCache();
201 214
202private: 215 [[nodiscard]] VkFramebuffer Handle() const noexcept {
203 Surface CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) override; 216 return *framebuffer;
217 }
204 218
205 void ImageCopy(Surface& src_surface, Surface& dst_surface, 219 [[nodiscard]] VkRenderPass RenderPass() const noexcept {
206 const VideoCommon::CopyParams& copy_params) override; 220 return renderpass;
221 }
207 222
208 void ImageBlit(View& src_view, View& dst_view, 223 [[nodiscard]] VkExtent2D RenderArea() const noexcept {
209 const Tegra::Engines::Fermi2D::Config& copy_config) override; 224 return render_area;
225 }
210 226
211 void BufferCopy(Surface& src_surface, Surface& dst_surface) override; 227 [[nodiscard]] VkSampleCountFlagBits Samples() const noexcept {
228 return samples;
229 }
212 230
213 const VKDevice& device; 231 [[nodiscard]] u32 NumColorBuffers() const noexcept {
214 VKMemoryManager& memory_manager; 232 return num_color_buffers;
215 VKScheduler& scheduler; 233 }
216 VKStagingBufferPool& staging_pool; 234
235 [[nodiscard]] u32 NumImages() const noexcept {
236 return num_images;
237 }
238
239 [[nodiscard]] const std::array<VkImage, 9>& Images() const noexcept {
240 return images;
241 }
242
243 [[nodiscard]] const std::array<VkImageSubresourceRange, 9>& ImageRanges() const noexcept {
244 return image_ranges;
245 }
246
247private:
248 vk::Framebuffer framebuffer;
249 VkRenderPass renderpass{};
250 VkExtent2D render_area{};
251 VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
252 u32 num_color_buffers = 0;
253 u32 num_images = 0;
254 std::array<VkImage, 9> images{};
255 std::array<VkImageSubresourceRange, 9> image_ranges{};
217}; 256};
218 257
258struct TextureCacheParams {
259 static constexpr bool ENABLE_VALIDATION = true;
260 static constexpr bool FRAMEBUFFER_BLITS = false;
261 static constexpr bool HAS_EMULATED_COPIES = false;
262
263 using Runtime = Vulkan::TextureCacheRuntime;
264 using Image = Vulkan::Image;
265 using ImageAlloc = Vulkan::ImageAlloc;
266 using ImageView = Vulkan::ImageView;
267 using Sampler = Vulkan::Sampler;
268 using Framebuffer = Vulkan::Framebuffer;
269};
270
271using TextureCache = VideoCommon::TextureCache<TextureCacheParams>;
272
219} // namespace Vulkan 273} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.cpp b/src/video_core/renderer_vulkan/vk_update_descriptor.cpp
index 351c048d2..f99273c6a 100644
--- a/src/video_core/renderer_vulkan/vk_update_descriptor.cpp
+++ b/src/video_core/renderer_vulkan/vk_update_descriptor.cpp
@@ -7,15 +7,15 @@
7 7
8#include "common/assert.h" 8#include "common/assert.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "video_core/renderer_vulkan/vk_device.h"
11#include "video_core/renderer_vulkan/vk_scheduler.h" 10#include "video_core/renderer_vulkan/vk_scheduler.h"
12#include "video_core/renderer_vulkan/vk_update_descriptor.h" 11#include "video_core/renderer_vulkan/vk_update_descriptor.h"
13#include "video_core/renderer_vulkan/wrapper.h" 12#include "video_core/vulkan_common/vulkan_device.h"
13#include "video_core/vulkan_common/vulkan_wrapper.h"
14 14
15namespace Vulkan { 15namespace Vulkan {
16 16
17VKUpdateDescriptorQueue::VKUpdateDescriptorQueue(const VKDevice& device, VKScheduler& scheduler) 17VKUpdateDescriptorQueue::VKUpdateDescriptorQueue(const Device& device_, VKScheduler& scheduler_)
18 : device{device}, scheduler{scheduler} {} 18 : device{device_}, scheduler{scheduler_} {}
19 19
20VKUpdateDescriptorQueue::~VKUpdateDescriptorQueue() = default; 20VKUpdateDescriptorQueue::~VKUpdateDescriptorQueue() = default;
21 21
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.h b/src/video_core/renderer_vulkan/vk_update_descriptor.h
index 945320c72..e214f7195 100644
--- a/src/video_core/renderer_vulkan/vk_update_descriptor.h
+++ b/src/video_core/renderer_vulkan/vk_update_descriptor.h
@@ -8,11 +8,11 @@
8#include <boost/container/static_vector.hpp> 8#include <boost/container/static_vector.hpp>
9 9
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "video_core/renderer_vulkan/wrapper.h" 11#include "video_core/vulkan_common/vulkan_wrapper.h"
12 12
13namespace Vulkan { 13namespace Vulkan {
14 14
15class VKDevice; 15class Device;
16class VKScheduler; 16class VKScheduler;
17 17
18struct DescriptorUpdateEntry { 18struct DescriptorUpdateEntry {
@@ -31,7 +31,7 @@ struct DescriptorUpdateEntry {
31 31
32class VKUpdateDescriptorQueue final { 32class VKUpdateDescriptorQueue final {
33public: 33public:
34 explicit VKUpdateDescriptorQueue(const VKDevice& device, VKScheduler& scheduler); 34 explicit VKUpdateDescriptorQueue(const Device& device_, VKScheduler& scheduler_);
35 ~VKUpdateDescriptorQueue(); 35 ~VKUpdateDescriptorQueue();
36 36
37 void TickFrame(); 37 void TickFrame();
@@ -40,32 +40,36 @@ 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 Device& device;
69 VKScheduler& scheduler; 73 VKScheduler& scheduler;
70 74
71 const DescriptorUpdateEntry* upload_start = nullptr; 75 const DescriptorUpdateEntry* upload_start = nullptr;
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp
deleted file mode 100644
index 1fb14e190..000000000
--- a/src/video_core/renderer_vulkan/wrapper.cpp
+++ /dev/null
@@ -1,826 +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#include <algorithm>
6#include <exception>
7#include <memory>
8#include <optional>
9#include <utility>
10#include <vector>
11
12#include "common/common_types.h"
13
14#include "video_core/renderer_vulkan/wrapper.h"
15
16namespace Vulkan::vk {
17
18namespace {
19
20void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld) {
21 std::stable_sort(devices.begin(), devices.end(), [&](auto lhs, auto rhs) {
22 // This will call Vulkan more than needed, but these calls are cheap.
23 const auto lhs_properties = vk::PhysicalDevice(lhs, dld).GetProperties();
24 const auto rhs_properties = vk::PhysicalDevice(rhs, dld).GetProperties();
25
26 // Prefer discrete GPUs, Nvidia over AMD, AMD over Intel, Intel over the rest.
27 const bool preferred =
28 (lhs_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
29 rhs_properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) ||
30 (lhs_properties.vendorID == 0x10DE && rhs_properties.vendorID != 0x10DE) ||
31 (lhs_properties.vendorID == 0x1002 && rhs_properties.vendorID != 0x1002) ||
32 (lhs_properties.vendorID == 0x8086 && rhs_properties.vendorID != 0x8086);
33 return !preferred;
34 });
35}
36
37template <typename T>
38bool Proc(T& result, const InstanceDispatch& dld, const char* proc_name,
39 VkInstance instance = nullptr) noexcept {
40 result = reinterpret_cast<T>(dld.vkGetInstanceProcAddr(instance, proc_name));
41 return result != nullptr;
42}
43
44template <typename T>
45void Proc(T& result, const DeviceDispatch& dld, const char* proc_name, VkDevice device) noexcept {
46 result = reinterpret_cast<T>(dld.vkGetDeviceProcAddr(device, proc_name));
47}
48
49void Load(VkDevice device, DeviceDispatch& dld) noexcept {
50#define X(name) Proc(dld.name, dld, #name, device)
51 X(vkAcquireNextImageKHR);
52 X(vkAllocateCommandBuffers);
53 X(vkAllocateDescriptorSets);
54 X(vkAllocateMemory);
55 X(vkBeginCommandBuffer);
56 X(vkBindBufferMemory);
57 X(vkBindImageMemory);
58 X(vkCmdBeginQuery);
59 X(vkCmdBeginRenderPass);
60 X(vkCmdBeginTransformFeedbackEXT);
61 X(vkCmdBindDescriptorSets);
62 X(vkCmdBindIndexBuffer);
63 X(vkCmdBindPipeline);
64 X(vkCmdBindTransformFeedbackBuffersEXT);
65 X(vkCmdBindVertexBuffers);
66 X(vkCmdBlitImage);
67 X(vkCmdClearAttachments);
68 X(vkCmdCopyBuffer);
69 X(vkCmdCopyBufferToImage);
70 X(vkCmdCopyImage);
71 X(vkCmdCopyImageToBuffer);
72 X(vkCmdDispatch);
73 X(vkCmdDraw);
74 X(vkCmdDrawIndexed);
75 X(vkCmdEndQuery);
76 X(vkCmdEndRenderPass);
77 X(vkCmdEndTransformFeedbackEXT);
78 X(vkCmdFillBuffer);
79 X(vkCmdPipelineBarrier);
80 X(vkCmdPushConstants);
81 X(vkCmdSetBlendConstants);
82 X(vkCmdSetDepthBias);
83 X(vkCmdSetDepthBounds);
84 X(vkCmdSetEvent);
85 X(vkCmdSetScissor);
86 X(vkCmdSetStencilCompareMask);
87 X(vkCmdSetStencilReference);
88 X(vkCmdSetStencilWriteMask);
89 X(vkCmdSetViewport);
90 X(vkCmdWaitEvents);
91 X(vkCmdBindVertexBuffers2EXT);
92 X(vkCmdSetCullModeEXT);
93 X(vkCmdSetDepthBoundsTestEnableEXT);
94 X(vkCmdSetDepthCompareOpEXT);
95 X(vkCmdSetDepthTestEnableEXT);
96 X(vkCmdSetDepthWriteEnableEXT);
97 X(vkCmdSetFrontFaceEXT);
98 X(vkCmdSetPrimitiveTopologyEXT);
99 X(vkCmdSetStencilOpEXT);
100 X(vkCmdSetStencilTestEnableEXT);
101 X(vkCreateBuffer);
102 X(vkCreateBufferView);
103 X(vkCreateCommandPool);
104 X(vkCreateComputePipelines);
105 X(vkCreateDescriptorPool);
106 X(vkCreateDescriptorSetLayout);
107 X(vkCreateDescriptorUpdateTemplateKHR);
108 X(vkCreateEvent);
109 X(vkCreateFence);
110 X(vkCreateFramebuffer);
111 X(vkCreateGraphicsPipelines);
112 X(vkCreateImage);
113 X(vkCreateImageView);
114 X(vkCreatePipelineLayout);
115 X(vkCreateQueryPool);
116 X(vkCreateRenderPass);
117 X(vkCreateSampler);
118 X(vkCreateSemaphore);
119 X(vkCreateShaderModule);
120 X(vkCreateSwapchainKHR);
121 X(vkDestroyBuffer);
122 X(vkDestroyBufferView);
123 X(vkDestroyCommandPool);
124 X(vkDestroyDescriptorPool);
125 X(vkDestroyDescriptorSetLayout);
126 X(vkDestroyDescriptorUpdateTemplateKHR);
127 X(vkDestroyEvent);
128 X(vkDestroyFence);
129 X(vkDestroyFramebuffer);
130 X(vkDestroyImage);
131 X(vkDestroyImageView);
132 X(vkDestroyPipeline);
133 X(vkDestroyPipelineLayout);
134 X(vkDestroyQueryPool);
135 X(vkDestroyRenderPass);
136 X(vkDestroySampler);
137 X(vkDestroySemaphore);
138 X(vkDestroyShaderModule);
139 X(vkDestroySwapchainKHR);
140 X(vkDeviceWaitIdle);
141 X(vkEndCommandBuffer);
142 X(vkFreeCommandBuffers);
143 X(vkFreeDescriptorSets);
144 X(vkFreeMemory);
145 X(vkGetBufferMemoryRequirements);
146 X(vkGetDeviceQueue);
147 X(vkGetEventStatus);
148 X(vkGetFenceStatus);
149 X(vkGetImageMemoryRequirements);
150 X(vkGetQueryPoolResults);
151 X(vkGetSemaphoreCounterValueKHR);
152 X(vkMapMemory);
153 X(vkQueueSubmit);
154 X(vkResetFences);
155 X(vkResetQueryPoolEXT);
156 X(vkUnmapMemory);
157 X(vkUpdateDescriptorSetWithTemplateKHR);
158 X(vkUpdateDescriptorSets);
159 X(vkWaitForFences);
160 X(vkWaitSemaphoresKHR);
161#undef X
162}
163
164} // Anonymous namespace
165
166bool Load(InstanceDispatch& dld) noexcept {
167#define X(name) Proc(dld.name, dld, #name)
168 return X(vkCreateInstance) && X(vkEnumerateInstanceExtensionProperties) &&
169 X(vkEnumerateInstanceLayerProperties);
170#undef X
171}
172
173bool Load(VkInstance instance, InstanceDispatch& dld) noexcept {
174#define X(name) Proc(dld.name, dld, #name, instance)
175 // These functions may fail to load depending on the enabled extensions.
176 // Don't return a failure on these.
177 X(vkCreateDebugUtilsMessengerEXT);
178 X(vkDestroyDebugUtilsMessengerEXT);
179 X(vkDestroySurfaceKHR);
180 X(vkGetPhysicalDeviceFeatures2KHR);
181 X(vkGetPhysicalDeviceProperties2KHR);
182 X(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
183 X(vkGetPhysicalDeviceSurfaceFormatsKHR);
184 X(vkGetPhysicalDeviceSurfacePresentModesKHR);
185 X(vkGetPhysicalDeviceSurfaceSupportKHR);
186 X(vkGetSwapchainImagesKHR);
187 X(vkQueuePresentKHR);
188
189 return X(vkCreateDevice) && X(vkDestroyDevice) && X(vkDestroyDevice) &&
190 X(vkEnumerateDeviceExtensionProperties) && X(vkEnumeratePhysicalDevices) &&
191 X(vkGetDeviceProcAddr) && X(vkGetPhysicalDeviceFormatProperties) &&
192 X(vkGetPhysicalDeviceMemoryProperties) && X(vkGetPhysicalDeviceProperties) &&
193 X(vkGetPhysicalDeviceQueueFamilyProperties);
194#undef X
195}
196
197const char* Exception::what() const noexcept {
198 return ToString(result);
199}
200
201const char* ToString(VkResult result) noexcept {
202 switch (result) {
203 case VkResult::VK_SUCCESS:
204 return "VK_SUCCESS";
205 case VkResult::VK_NOT_READY:
206 return "VK_NOT_READY";
207 case VkResult::VK_TIMEOUT:
208 return "VK_TIMEOUT";
209 case VkResult::VK_EVENT_SET:
210 return "VK_EVENT_SET";
211 case VkResult::VK_EVENT_RESET:
212 return "VK_EVENT_RESET";
213 case VkResult::VK_INCOMPLETE:
214 return "VK_INCOMPLETE";
215 case VkResult::VK_ERROR_OUT_OF_HOST_MEMORY:
216 return "VK_ERROR_OUT_OF_HOST_MEMORY";
217 case VkResult::VK_ERROR_OUT_OF_DEVICE_MEMORY:
218 return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
219 case VkResult::VK_ERROR_INITIALIZATION_FAILED:
220 return "VK_ERROR_INITIALIZATION_FAILED";
221 case VkResult::VK_ERROR_DEVICE_LOST:
222 return "VK_ERROR_DEVICE_LOST";
223 case VkResult::VK_ERROR_MEMORY_MAP_FAILED:
224 return "VK_ERROR_MEMORY_MAP_FAILED";
225 case VkResult::VK_ERROR_LAYER_NOT_PRESENT:
226 return "VK_ERROR_LAYER_NOT_PRESENT";
227 case VkResult::VK_ERROR_EXTENSION_NOT_PRESENT:
228 return "VK_ERROR_EXTENSION_NOT_PRESENT";
229 case VkResult::VK_ERROR_FEATURE_NOT_PRESENT:
230 return "VK_ERROR_FEATURE_NOT_PRESENT";
231 case VkResult::VK_ERROR_INCOMPATIBLE_DRIVER:
232 return "VK_ERROR_INCOMPATIBLE_DRIVER";
233 case VkResult::VK_ERROR_TOO_MANY_OBJECTS:
234 return "VK_ERROR_TOO_MANY_OBJECTS";
235 case VkResult::VK_ERROR_FORMAT_NOT_SUPPORTED:
236 return "VK_ERROR_FORMAT_NOT_SUPPORTED";
237 case VkResult::VK_ERROR_FRAGMENTED_POOL:
238 return "VK_ERROR_FRAGMENTED_POOL";
239 case VkResult::VK_ERROR_OUT_OF_POOL_MEMORY:
240 return "VK_ERROR_OUT_OF_POOL_MEMORY";
241 case VkResult::VK_ERROR_INVALID_EXTERNAL_HANDLE:
242 return "VK_ERROR_INVALID_EXTERNAL_HANDLE";
243 case VkResult::VK_ERROR_SURFACE_LOST_KHR:
244 return "VK_ERROR_SURFACE_LOST_KHR";
245 case VkResult::VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
246 return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
247 case VkResult::VK_SUBOPTIMAL_KHR:
248 return "VK_SUBOPTIMAL_KHR";
249 case VkResult::VK_ERROR_OUT_OF_DATE_KHR:
250 return "VK_ERROR_OUT_OF_DATE_KHR";
251 case VkResult::VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
252 return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
253 case VkResult::VK_ERROR_VALIDATION_FAILED_EXT:
254 return "VK_ERROR_VALIDATION_FAILED_EXT";
255 case VkResult::VK_ERROR_INVALID_SHADER_NV:
256 return "VK_ERROR_INVALID_SHADER_NV";
257 case VkResult::VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT:
258 return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT";
259 case VkResult::VK_ERROR_FRAGMENTATION_EXT:
260 return "VK_ERROR_FRAGMENTATION_EXT";
261 case VkResult::VK_ERROR_NOT_PERMITTED_EXT:
262 return "VK_ERROR_NOT_PERMITTED_EXT";
263 case VkResult::VK_ERROR_INVALID_DEVICE_ADDRESS_EXT:
264 return "VK_ERROR_INVALID_DEVICE_ADDRESS_EXT";
265 case VkResult::VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
266 return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT";
267 case VkResult::VK_ERROR_UNKNOWN:
268 return "VK_ERROR_UNKNOWN";
269 case VkResult::VK_ERROR_INCOMPATIBLE_VERSION_KHR:
270 return "VK_ERROR_INCOMPATIBLE_VERSION_KHR";
271 case VkResult::VK_THREAD_IDLE_KHR:
272 return "VK_THREAD_IDLE_KHR";
273 case VkResult::VK_THREAD_DONE_KHR:
274 return "VK_THREAD_DONE_KHR";
275 case VkResult::VK_OPERATION_DEFERRED_KHR:
276 return "VK_OPERATION_DEFERRED_KHR";
277 case VkResult::VK_OPERATION_NOT_DEFERRED_KHR:
278 return "VK_OPERATION_NOT_DEFERRED_KHR";
279 case VkResult::VK_PIPELINE_COMPILE_REQUIRED_EXT:
280 return "VK_PIPELINE_COMPILE_REQUIRED_EXT";
281 case VkResult::VK_RESULT_MAX_ENUM:
282 return "VK_RESULT_MAX_ENUM";
283 }
284 return "Unknown";
285}
286
287void Destroy(VkInstance instance, const InstanceDispatch& dld) noexcept {
288 dld.vkDestroyInstance(instance, nullptr);
289}
290
291void Destroy(VkDevice device, const InstanceDispatch& dld) noexcept {
292 dld.vkDestroyDevice(device, nullptr);
293}
294
295void Destroy(VkDevice device, VkBuffer handle, const DeviceDispatch& dld) noexcept {
296 dld.vkDestroyBuffer(device, handle, nullptr);
297}
298
299void Destroy(VkDevice device, VkBufferView handle, const DeviceDispatch& dld) noexcept {
300 dld.vkDestroyBufferView(device, handle, nullptr);
301}
302
303void Destroy(VkDevice device, VkCommandPool handle, const DeviceDispatch& dld) noexcept {
304 dld.vkDestroyCommandPool(device, handle, nullptr);
305}
306
307void Destroy(VkDevice device, VkDescriptorPool handle, const DeviceDispatch& dld) noexcept {
308 dld.vkDestroyDescriptorPool(device, handle, nullptr);
309}
310
311void Destroy(VkDevice device, VkDescriptorSetLayout handle, const DeviceDispatch& dld) noexcept {
312 dld.vkDestroyDescriptorSetLayout(device, handle, nullptr);
313}
314
315void Destroy(VkDevice device, VkDescriptorUpdateTemplateKHR handle,
316 const DeviceDispatch& dld) noexcept {
317 dld.vkDestroyDescriptorUpdateTemplateKHR(device, handle, nullptr);
318}
319
320void Destroy(VkDevice device, VkDeviceMemory handle, const DeviceDispatch& dld) noexcept {
321 dld.vkFreeMemory(device, handle, nullptr);
322}
323
324void Destroy(VkDevice device, VkEvent handle, const DeviceDispatch& dld) noexcept {
325 dld.vkDestroyEvent(device, handle, nullptr);
326}
327
328void Destroy(VkDevice device, VkFence handle, const DeviceDispatch& dld) noexcept {
329 dld.vkDestroyFence(device, handle, nullptr);
330}
331
332void Destroy(VkDevice device, VkFramebuffer handle, const DeviceDispatch& dld) noexcept {
333 dld.vkDestroyFramebuffer(device, handle, nullptr);
334}
335
336void Destroy(VkDevice device, VkImage handle, const DeviceDispatch& dld) noexcept {
337 dld.vkDestroyImage(device, handle, nullptr);
338}
339
340void Destroy(VkDevice device, VkImageView handle, const DeviceDispatch& dld) noexcept {
341 dld.vkDestroyImageView(device, handle, nullptr);
342}
343
344void Destroy(VkDevice device, VkPipeline handle, const DeviceDispatch& dld) noexcept {
345 dld.vkDestroyPipeline(device, handle, nullptr);
346}
347
348void Destroy(VkDevice device, VkPipelineLayout handle, const DeviceDispatch& dld) noexcept {
349 dld.vkDestroyPipelineLayout(device, handle, nullptr);
350}
351
352void Destroy(VkDevice device, VkQueryPool handle, const DeviceDispatch& dld) noexcept {
353 dld.vkDestroyQueryPool(device, handle, nullptr);
354}
355
356void Destroy(VkDevice device, VkRenderPass handle, const DeviceDispatch& dld) noexcept {
357 dld.vkDestroyRenderPass(device, handle, nullptr);
358}
359
360void Destroy(VkDevice device, VkSampler handle, const DeviceDispatch& dld) noexcept {
361 dld.vkDestroySampler(device, handle, nullptr);
362}
363
364void Destroy(VkDevice device, VkSwapchainKHR handle, const DeviceDispatch& dld) noexcept {
365 dld.vkDestroySwapchainKHR(device, handle, nullptr);
366}
367
368void Destroy(VkDevice device, VkSemaphore handle, const DeviceDispatch& dld) noexcept {
369 dld.vkDestroySemaphore(device, handle, nullptr);
370}
371
372void Destroy(VkDevice device, VkShaderModule handle, const DeviceDispatch& dld) noexcept {
373 dld.vkDestroyShaderModule(device, handle, nullptr);
374}
375
376void Destroy(VkInstance instance, VkDebugUtilsMessengerEXT handle,
377 const InstanceDispatch& dld) noexcept {
378 dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr);
379}
380
381void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept {
382 dld.vkDestroySurfaceKHR(instance, handle, nullptr);
383}
384
385VkResult Free(VkDevice device, VkDescriptorPool handle, Span<VkDescriptorSet> sets,
386 const DeviceDispatch& dld) noexcept {
387 return dld.vkFreeDescriptorSets(device, handle, sets.size(), sets.data());
388}
389
390VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffers,
391 const DeviceDispatch& dld) noexcept {
392 dld.vkFreeCommandBuffers(device, handle, buffers.size(), buffers.data());
393 return VK_SUCCESS;
394}
395
396Instance Instance::Create(Span<const char*> layers, Span<const char*> extensions,
397 InstanceDispatch& dld) noexcept {
398 static constexpr VkApplicationInfo application_info{
399 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
400 .pNext = nullptr,
401 .pApplicationName = "yuzu Emulator",
402 .applicationVersion = VK_MAKE_VERSION(0, 1, 0),
403 .pEngineName = "yuzu Emulator",
404 .engineVersion = VK_MAKE_VERSION(0, 1, 0),
405 .apiVersion = VK_API_VERSION_1_1,
406 };
407
408 const VkInstanceCreateInfo ci{
409 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
410 .pNext = nullptr,
411 .flags = 0,
412 .pApplicationInfo = &application_info,
413 .enabledLayerCount = layers.size(),
414 .ppEnabledLayerNames = layers.data(),
415 .enabledExtensionCount = extensions.size(),
416 .ppEnabledExtensionNames = extensions.data(),
417 };
418
419 VkInstance instance;
420 if (dld.vkCreateInstance(&ci, nullptr, &instance) != VK_SUCCESS) {
421 // Failed to create the instance.
422 return {};
423 }
424 if (!Proc(dld.vkDestroyInstance, dld, "vkDestroyInstance", instance)) {
425 // We successfully created an instance but the destroy function couldn't be loaded.
426 // This is a good moment to panic.
427 return {};
428 }
429
430 return Instance(instance, dld);
431}
432
433std::optional<std::vector<VkPhysicalDevice>> Instance::EnumeratePhysicalDevices() {
434 u32 num;
435 if (dld->vkEnumeratePhysicalDevices(handle, &num, nullptr) != VK_SUCCESS) {
436 return std::nullopt;
437 }
438 std::vector<VkPhysicalDevice> physical_devices(num);
439 if (dld->vkEnumeratePhysicalDevices(handle, &num, physical_devices.data()) != VK_SUCCESS) {
440 return std::nullopt;
441 }
442 SortPhysicalDevices(physical_devices, *dld);
443 return std::make_optional(std::move(physical_devices));
444}
445
446DebugCallback Instance::TryCreateDebugCallback(
447 PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept {
448 const VkDebugUtilsMessengerCreateInfoEXT ci{
449 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
450 .pNext = nullptr,
451 .flags = 0,
452 .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
453 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
454 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
455 VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
456 .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
457 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
458 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
459 .pfnUserCallback = callback,
460 .pUserData = nullptr,
461 };
462
463 VkDebugUtilsMessengerEXT messenger;
464 if (dld->vkCreateDebugUtilsMessengerEXT(handle, &ci, nullptr, &messenger) != VK_SUCCESS) {
465 return {};
466 }
467 return DebugCallback(messenger, handle, *dld);
468}
469
470void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const {
471 Check(dld->vkBindBufferMemory(owner, handle, memory, offset));
472}
473
474void Image::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const {
475 Check(dld->vkBindImageMemory(owner, handle, memory, offset));
476}
477
478DescriptorSets DescriptorPool::Allocate(const VkDescriptorSetAllocateInfo& ai) const {
479 const std::size_t num = ai.descriptorSetCount;
480 std::unique_ptr sets = std::make_unique<VkDescriptorSet[]>(num);
481 switch (const VkResult result = dld->vkAllocateDescriptorSets(owner, &ai, sets.get())) {
482 case VK_SUCCESS:
483 return DescriptorSets(std::move(sets), num, owner, handle, *dld);
484 case VK_ERROR_OUT_OF_POOL_MEMORY:
485 return {};
486 default:
487 throw Exception(result);
488 }
489}
490
491CommandBuffers CommandPool::Allocate(std::size_t num_buffers, VkCommandBufferLevel level) const {
492 const VkCommandBufferAllocateInfo ai{
493 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
494 .pNext = nullptr,
495 .commandPool = handle,
496 .level = level,
497 .commandBufferCount = static_cast<u32>(num_buffers),
498 };
499
500 std::unique_ptr buffers = std::make_unique<VkCommandBuffer[]>(num_buffers);
501 switch (const VkResult result = dld->vkAllocateCommandBuffers(owner, &ai, buffers.get())) {
502 case VK_SUCCESS:
503 return CommandBuffers(std::move(buffers), num_buffers, owner, handle, *dld);
504 case VK_ERROR_OUT_OF_POOL_MEMORY:
505 return {};
506 default:
507 throw Exception(result);
508 }
509}
510
511std::vector<VkImage> SwapchainKHR::GetImages() const {
512 u32 num;
513 Check(dld->vkGetSwapchainImagesKHR(owner, handle, &num, nullptr));
514 std::vector<VkImage> images(num);
515 Check(dld->vkGetSwapchainImagesKHR(owner, handle, &num, images.data()));
516 return images;
517}
518
519Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,
520 Span<const char*> enabled_extensions, const void* next,
521 DeviceDispatch& dld) noexcept {
522 const VkDeviceCreateInfo ci{
523 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
524 .pNext = next,
525 .flags = 0,
526 .queueCreateInfoCount = queues_ci.size(),
527 .pQueueCreateInfos = queues_ci.data(),
528 .enabledLayerCount = 0,
529 .ppEnabledLayerNames = nullptr,
530 .enabledExtensionCount = enabled_extensions.size(),
531 .ppEnabledExtensionNames = enabled_extensions.data(),
532 .pEnabledFeatures = nullptr,
533 };
534
535 VkDevice device;
536 if (dld.vkCreateDevice(physical_device, &ci, nullptr, &device) != VK_SUCCESS) {
537 return {};
538 }
539 Load(device, dld);
540 return Device(device, dld);
541}
542
543Queue Device::GetQueue(u32 family_index) const noexcept {
544 VkQueue queue;
545 dld->vkGetDeviceQueue(handle, family_index, 0, &queue);
546 return Queue(queue, *dld);
547}
548
549Buffer Device::CreateBuffer(const VkBufferCreateInfo& ci) const {
550 VkBuffer object;
551 Check(dld->vkCreateBuffer(handle, &ci, nullptr, &object));
552 return Buffer(object, handle, *dld);
553}
554
555BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const {
556 VkBufferView object;
557 Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object));
558 return BufferView(object, handle, *dld);
559}
560
561Image Device::CreateImage(const VkImageCreateInfo& ci) const {
562 VkImage object;
563 Check(dld->vkCreateImage(handle, &ci, nullptr, &object));
564 return Image(object, handle, *dld);
565}
566
567ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const {
568 VkImageView object;
569 Check(dld->vkCreateImageView(handle, &ci, nullptr, &object));
570 return ImageView(object, handle, *dld);
571}
572
573Semaphore Device::CreateSemaphore() const {
574 static constexpr VkSemaphoreCreateInfo ci{
575 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
576 .pNext = nullptr,
577 .flags = 0,
578 };
579 return CreateSemaphore(ci);
580}
581
582Semaphore Device::CreateSemaphore(const VkSemaphoreCreateInfo& ci) const {
583 VkSemaphore object;
584 Check(dld->vkCreateSemaphore(handle, &ci, nullptr, &object));
585 return Semaphore(object, handle, *dld);
586}
587
588Fence Device::CreateFence(const VkFenceCreateInfo& ci) const {
589 VkFence object;
590 Check(dld->vkCreateFence(handle, &ci, nullptr, &object));
591 return Fence(object, handle, *dld);
592}
593
594DescriptorPool Device::CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const {
595 VkDescriptorPool object;
596 Check(dld->vkCreateDescriptorPool(handle, &ci, nullptr, &object));
597 return DescriptorPool(object, handle, *dld);
598}
599
600RenderPass Device::CreateRenderPass(const VkRenderPassCreateInfo& ci) const {
601 VkRenderPass object;
602 Check(dld->vkCreateRenderPass(handle, &ci, nullptr, &object));
603 return RenderPass(object, handle, *dld);
604}
605
606DescriptorSetLayout Device::CreateDescriptorSetLayout(
607 const VkDescriptorSetLayoutCreateInfo& ci) const {
608 VkDescriptorSetLayout object;
609 Check(dld->vkCreateDescriptorSetLayout(handle, &ci, nullptr, &object));
610 return DescriptorSetLayout(object, handle, *dld);
611}
612
613PipelineLayout Device::CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const {
614 VkPipelineLayout object;
615 Check(dld->vkCreatePipelineLayout(handle, &ci, nullptr, &object));
616 return PipelineLayout(object, handle, *dld);
617}
618
619Pipeline Device::CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci) const {
620 VkPipeline object;
621 Check(dld->vkCreateGraphicsPipelines(handle, nullptr, 1, &ci, nullptr, &object));
622 return Pipeline(object, handle, *dld);
623}
624
625Pipeline Device::CreateComputePipeline(const VkComputePipelineCreateInfo& ci) const {
626 VkPipeline object;
627 Check(dld->vkCreateComputePipelines(handle, nullptr, 1, &ci, nullptr, &object));
628 return Pipeline(object, handle, *dld);
629}
630
631Sampler Device::CreateSampler(const VkSamplerCreateInfo& ci) const {
632 VkSampler object;
633 Check(dld->vkCreateSampler(handle, &ci, nullptr, &object));
634 return Sampler(object, handle, *dld);
635}
636
637Framebuffer Device::CreateFramebuffer(const VkFramebufferCreateInfo& ci) const {
638 VkFramebuffer object;
639 Check(dld->vkCreateFramebuffer(handle, &ci, nullptr, &object));
640 return Framebuffer(object, handle, *dld);
641}
642
643CommandPool Device::CreateCommandPool(const VkCommandPoolCreateInfo& ci) const {
644 VkCommandPool object;
645 Check(dld->vkCreateCommandPool(handle, &ci, nullptr, &object));
646 return CommandPool(object, handle, *dld);
647}
648
649DescriptorUpdateTemplateKHR Device::CreateDescriptorUpdateTemplateKHR(
650 const VkDescriptorUpdateTemplateCreateInfoKHR& ci) const {
651 VkDescriptorUpdateTemplateKHR object;
652 Check(dld->vkCreateDescriptorUpdateTemplateKHR(handle, &ci, nullptr, &object));
653 return DescriptorUpdateTemplateKHR(object, handle, *dld);
654}
655
656QueryPool Device::CreateQueryPool(const VkQueryPoolCreateInfo& ci) const {
657 VkQueryPool object;
658 Check(dld->vkCreateQueryPool(handle, &ci, nullptr, &object));
659 return QueryPool(object, handle, *dld);
660}
661
662ShaderModule Device::CreateShaderModule(const VkShaderModuleCreateInfo& ci) const {
663 VkShaderModule object;
664 Check(dld->vkCreateShaderModule(handle, &ci, nullptr, &object));
665 return ShaderModule(object, handle, *dld);
666}
667
668Event Device::CreateEvent() const {
669 static constexpr VkEventCreateInfo ci{
670 .sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO,
671 .pNext = nullptr,
672 .flags = 0,
673 };
674
675 VkEvent object;
676 Check(dld->vkCreateEvent(handle, &ci, nullptr, &object));
677 return Event(object, handle, *dld);
678}
679
680SwapchainKHR Device::CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const {
681 VkSwapchainKHR object;
682 Check(dld->vkCreateSwapchainKHR(handle, &ci, nullptr, &object));
683 return SwapchainKHR(object, handle, *dld);
684}
685
686DeviceMemory Device::TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept {
687 VkDeviceMemory memory;
688 if (dld->vkAllocateMemory(handle, &ai, nullptr, &memory) != VK_SUCCESS) {
689 return {};
690 }
691 return DeviceMemory(memory, handle, *dld);
692}
693
694DeviceMemory Device::AllocateMemory(const VkMemoryAllocateInfo& ai) const {
695 VkDeviceMemory memory;
696 Check(dld->vkAllocateMemory(handle, &ai, nullptr, &memory));
697 return DeviceMemory(memory, handle, *dld);
698}
699
700VkMemoryRequirements Device::GetBufferMemoryRequirements(VkBuffer buffer) const noexcept {
701 VkMemoryRequirements requirements;
702 dld->vkGetBufferMemoryRequirements(handle, buffer, &requirements);
703 return requirements;
704}
705
706VkMemoryRequirements Device::GetImageMemoryRequirements(VkImage image) const noexcept {
707 VkMemoryRequirements requirements;
708 dld->vkGetImageMemoryRequirements(handle, image, &requirements);
709 return requirements;
710}
711
712void Device::UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes,
713 Span<VkCopyDescriptorSet> copies) const noexcept {
714 dld->vkUpdateDescriptorSets(handle, writes.size(), writes.data(), copies.size(), copies.data());
715}
716
717VkPhysicalDeviceProperties PhysicalDevice::GetProperties() const noexcept {
718 VkPhysicalDeviceProperties properties;
719 dld->vkGetPhysicalDeviceProperties(physical_device, &properties);
720 return properties;
721}
722
723void PhysicalDevice::GetProperties2KHR(VkPhysicalDeviceProperties2KHR& properties) const noexcept {
724 dld->vkGetPhysicalDeviceProperties2KHR(physical_device, &properties);
725}
726
727VkPhysicalDeviceFeatures PhysicalDevice::GetFeatures() const noexcept {
728 VkPhysicalDeviceFeatures2KHR features2;
729 features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
730 features2.pNext = nullptr;
731 dld->vkGetPhysicalDeviceFeatures2KHR(physical_device, &features2);
732 return features2.features;
733}
734
735void PhysicalDevice::GetFeatures2KHR(VkPhysicalDeviceFeatures2KHR& features) const noexcept {
736 dld->vkGetPhysicalDeviceFeatures2KHR(physical_device, &features);
737}
738
739VkFormatProperties PhysicalDevice::GetFormatProperties(VkFormat format) const noexcept {
740 VkFormatProperties properties;
741 dld->vkGetPhysicalDeviceFormatProperties(physical_device, format, &properties);
742 return properties;
743}
744
745std::vector<VkExtensionProperties> PhysicalDevice::EnumerateDeviceExtensionProperties() const {
746 u32 num;
747 dld->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &num, nullptr);
748 std::vector<VkExtensionProperties> properties(num);
749 dld->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &num, properties.data());
750 return properties;
751}
752
753std::vector<VkQueueFamilyProperties> PhysicalDevice::GetQueueFamilyProperties() const {
754 u32 num;
755 dld->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &num, nullptr);
756 std::vector<VkQueueFamilyProperties> properties(num);
757 dld->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &num, properties.data());
758 return properties;
759}
760
761bool PhysicalDevice::GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR surface) const {
762 VkBool32 supported;
763 Check(dld->vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue_family_index, surface,
764 &supported));
765 return supported == VK_TRUE;
766}
767
768VkSurfaceCapabilitiesKHR PhysicalDevice::GetSurfaceCapabilitiesKHR(VkSurfaceKHR surface) const {
769 VkSurfaceCapabilitiesKHR capabilities;
770 Check(dld->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &capabilities));
771 return capabilities;
772}
773
774std::vector<VkSurfaceFormatKHR> PhysicalDevice::GetSurfaceFormatsKHR(VkSurfaceKHR surface) const {
775 u32 num;
776 Check(dld->vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &num, nullptr));
777 std::vector<VkSurfaceFormatKHR> formats(num);
778 Check(
779 dld->vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &num, formats.data()));
780 return formats;
781}
782
783std::vector<VkPresentModeKHR> PhysicalDevice::GetSurfacePresentModesKHR(
784 VkSurfaceKHR surface) const {
785 u32 num;
786 Check(dld->vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &num, nullptr));
787 std::vector<VkPresentModeKHR> modes(num);
788 Check(dld->vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &num,
789 modes.data()));
790 return modes;
791}
792
793VkPhysicalDeviceMemoryProperties PhysicalDevice::GetMemoryProperties() const noexcept {
794 VkPhysicalDeviceMemoryProperties properties;
795 dld->vkGetPhysicalDeviceMemoryProperties(physical_device, &properties);
796 return properties;
797}
798
799std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties(
800 const InstanceDispatch& dld) {
801 u32 num;
802 if (dld.vkEnumerateInstanceExtensionProperties(nullptr, &num, nullptr) != VK_SUCCESS) {
803 return std::nullopt;
804 }
805 std::vector<VkExtensionProperties> properties(num);
806 if (dld.vkEnumerateInstanceExtensionProperties(nullptr, &num, properties.data()) !=
807 VK_SUCCESS) {
808 return std::nullopt;
809 }
810 return std::move(properties);
811}
812
813std::optional<std::vector<VkLayerProperties>> EnumerateInstanceLayerProperties(
814 const InstanceDispatch& dld) {
815 u32 num;
816 if (dld.vkEnumerateInstanceLayerProperties(&num, nullptr) != VK_SUCCESS) {
817 return std::nullopt;
818 }
819 std::vector<VkLayerProperties> properties(num);
820 if (dld.vkEnumerateInstanceLayerProperties(&num, properties.data()) != VK_SUCCESS) {
821 return std::nullopt;
822 }
823 return properties;
824}
825
826} // namespace Vulkan::vk
diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h
deleted file mode 100644
index 234e01693..000000000
--- a/src/video_core/renderer_vulkan/wrapper.h
+++ /dev/null
@@ -1,1099 +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#pragma once
6
7#include <exception>
8#include <iterator>
9#include <limits>
10#include <memory>
11#include <optional>
12#include <type_traits>
13#include <utility>
14#include <vector>
15
16#define VK_NO_PROTOTYPES
17#include <vulkan/vulkan.h>
18
19#include "common/common_types.h"
20
21namespace Vulkan::vk {
22
23/**
24 * Span for Vulkan arrays.
25 * Based on std::span but optimized for array access instead of iterators.
26 * Size returns uint32_t instead of size_t to ease interaction with Vulkan functions.
27 */
28template <typename T>
29class Span {
30public:
31 using value_type = T;
32 using size_type = u32;
33 using difference_type = std::ptrdiff_t;
34 using reference = const T&;
35 using const_reference = const T&;
36 using pointer = const T*;
37 using const_pointer = const T*;
38 using iterator = const T*;
39 using const_iterator = const T*;
40
41 /// Construct an empty span.
42 constexpr Span() noexcept = default;
43
44 /// Construct a span from a single element.
45 constexpr Span(const T& value) noexcept : ptr{&value}, num{1} {}
46
47 /// Construct a span from a range.
48 template <typename Range>
49 // requires std::data(const Range&)
50 // requires std::size(const Range&)
51 constexpr Span(const Range& range) : ptr{std::data(range)}, num{std::size(range)} {}
52
53 /// Construct a span from a pointer and a size.
54 /// This is inteded for subranges.
55 constexpr Span(const T* ptr, std::size_t num) noexcept : ptr{ptr}, num{num} {}
56
57 /// Returns the data pointer by the span.
58 constexpr const T* data() const noexcept {
59 return ptr;
60 }
61
62 /// Returns the number of elements in the span.
63 /// @note Returns a 32 bits integer because most Vulkan functions expect this type.
64 constexpr u32 size() const noexcept {
65 return static_cast<u32>(num);
66 }
67
68 /// Returns true when the span is empty.
69 constexpr bool empty() const noexcept {
70 return num == 0;
71 }
72
73 /// Returns a reference to the element in the passed index.
74 /// @pre: index < size()
75 constexpr const T& operator[](std::size_t index) const noexcept {
76 return ptr[index];
77 }
78
79 /// Returns an iterator to the beginning of the span.
80 constexpr const T* begin() const noexcept {
81 return ptr;
82 }
83
84 /// Returns an iterator to the end of the span.
85 constexpr const T* end() const noexcept {
86 return ptr + num;
87 }
88
89 /// Returns an iterator to the beginning of the span.
90 constexpr const T* cbegin() const noexcept {
91 return ptr;
92 }
93
94 /// Returns an iterator to the end of the span.
95 constexpr const T* cend() const noexcept {
96 return ptr + num;
97 }
98
99private:
100 const T* ptr = nullptr;
101 std::size_t num = 0;
102};
103
104/// Vulkan exception generated from a VkResult.
105class Exception final : public std::exception {
106public:
107 /// Construct the exception with a result.
108 /// @pre result != VK_SUCCESS
109 explicit Exception(VkResult result_) : result{result_} {}
110 virtual ~Exception() = default;
111
112 const char* what() const noexcept override;
113
114private:
115 VkResult result;
116};
117
118/// Converts a VkResult enum into a rodata string
119const char* ToString(VkResult) noexcept;
120
121/// Throws a Vulkan exception if result is not success.
122inline void Check(VkResult result) {
123 if (result != VK_SUCCESS) {
124 throw Exception(result);
125 }
126}
127
128/// Throws a Vulkan exception if result is an error.
129/// @return result
130inline VkResult Filter(VkResult result) {
131 if (result < 0) {
132 throw Exception(result);
133 }
134 return result;
135}
136
137/// Table holding Vulkan instance function pointers.
138struct InstanceDispatch {
139 PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
140
141 PFN_vkCreateInstance vkCreateInstance;
142 PFN_vkDestroyInstance vkDestroyInstance;
143 PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
144 PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties;
145
146 PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT;
147 PFN_vkCreateDevice vkCreateDevice;
148 PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT;
149 PFN_vkDestroyDevice vkDestroyDevice;
150 PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;
151 PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
152 PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
153 PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
154 PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR;
155 PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties;
156 PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
157 PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
158 PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
159 PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties;
160 PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
161 PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
162 PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
163 PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR;
164 PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
165 PFN_vkQueuePresentKHR vkQueuePresentKHR;
166};
167
168/// Table holding Vulkan device function pointers.
169struct DeviceDispatch : public InstanceDispatch {
170 PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
171 PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
172 PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets;
173 PFN_vkAllocateMemory vkAllocateMemory;
174 PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
175 PFN_vkBindBufferMemory vkBindBufferMemory;
176 PFN_vkBindImageMemory vkBindImageMemory;
177 PFN_vkCmdBeginQuery vkCmdBeginQuery;
178 PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass;
179 PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT;
180 PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets;
181 PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer;
182 PFN_vkCmdBindPipeline vkCmdBindPipeline;
183 PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT;
184 PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers;
185 PFN_vkCmdBlitImage vkCmdBlitImage;
186 PFN_vkCmdClearAttachments vkCmdClearAttachments;
187 PFN_vkCmdCopyBuffer vkCmdCopyBuffer;
188 PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage;
189 PFN_vkCmdCopyImage vkCmdCopyImage;
190 PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer;
191 PFN_vkCmdDispatch vkCmdDispatch;
192 PFN_vkCmdDraw vkCmdDraw;
193 PFN_vkCmdDrawIndexed vkCmdDrawIndexed;
194 PFN_vkCmdEndQuery vkCmdEndQuery;
195 PFN_vkCmdEndRenderPass vkCmdEndRenderPass;
196 PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT;
197 PFN_vkCmdFillBuffer vkCmdFillBuffer;
198 PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier;
199 PFN_vkCmdPushConstants vkCmdPushConstants;
200 PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants;
201 PFN_vkCmdSetDepthBias vkCmdSetDepthBias;
202 PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds;
203 PFN_vkCmdSetEvent vkCmdSetEvent;
204 PFN_vkCmdSetScissor vkCmdSetScissor;
205 PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask;
206 PFN_vkCmdSetStencilReference vkCmdSetStencilReference;
207 PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask;
208 PFN_vkCmdSetViewport vkCmdSetViewport;
209 PFN_vkCmdWaitEvents vkCmdWaitEvents;
210 PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT;
211 PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT;
212 PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT;
213 PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT;
214 PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT;
215 PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT;
216 PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT;
217 PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT;
218 PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT;
219 PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT;
220 PFN_vkCreateBuffer vkCreateBuffer;
221 PFN_vkCreateBufferView vkCreateBufferView;
222 PFN_vkCreateCommandPool vkCreateCommandPool;
223 PFN_vkCreateComputePipelines vkCreateComputePipelines;
224 PFN_vkCreateDescriptorPool vkCreateDescriptorPool;
225 PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout;
226 PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR;
227 PFN_vkCreateEvent vkCreateEvent;
228 PFN_vkCreateFence vkCreateFence;
229 PFN_vkCreateFramebuffer vkCreateFramebuffer;
230 PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines;
231 PFN_vkCreateImage vkCreateImage;
232 PFN_vkCreateImageView vkCreateImageView;
233 PFN_vkCreatePipelineLayout vkCreatePipelineLayout;
234 PFN_vkCreateQueryPool vkCreateQueryPool;
235 PFN_vkCreateRenderPass vkCreateRenderPass;
236 PFN_vkCreateSampler vkCreateSampler;
237 PFN_vkCreateSemaphore vkCreateSemaphore;
238 PFN_vkCreateShaderModule vkCreateShaderModule;
239 PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR;
240 PFN_vkDestroyBuffer vkDestroyBuffer;
241 PFN_vkDestroyBufferView vkDestroyBufferView;
242 PFN_vkDestroyCommandPool vkDestroyCommandPool;
243 PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool;
244 PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout;
245 PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR;
246 PFN_vkDestroyEvent vkDestroyEvent;
247 PFN_vkDestroyFence vkDestroyFence;
248 PFN_vkDestroyFramebuffer vkDestroyFramebuffer;
249 PFN_vkDestroyImage vkDestroyImage;
250 PFN_vkDestroyImageView vkDestroyImageView;
251 PFN_vkDestroyPipeline vkDestroyPipeline;
252 PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout;
253 PFN_vkDestroyQueryPool vkDestroyQueryPool;
254 PFN_vkDestroyRenderPass vkDestroyRenderPass;
255 PFN_vkDestroySampler vkDestroySampler;
256 PFN_vkDestroySemaphore vkDestroySemaphore;
257 PFN_vkDestroyShaderModule vkDestroyShaderModule;
258 PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
259 PFN_vkDeviceWaitIdle vkDeviceWaitIdle;
260 PFN_vkEndCommandBuffer vkEndCommandBuffer;
261 PFN_vkFreeCommandBuffers vkFreeCommandBuffers;
262 PFN_vkFreeDescriptorSets vkFreeDescriptorSets;
263 PFN_vkFreeMemory vkFreeMemory;
264 PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements;
265 PFN_vkGetDeviceQueue vkGetDeviceQueue;
266 PFN_vkGetEventStatus vkGetEventStatus;
267 PFN_vkGetFenceStatus vkGetFenceStatus;
268 PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements;
269 PFN_vkGetQueryPoolResults vkGetQueryPoolResults;
270 PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR;
271 PFN_vkMapMemory vkMapMemory;
272 PFN_vkQueueSubmit vkQueueSubmit;
273 PFN_vkResetFences vkResetFences;
274 PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT;
275 PFN_vkUnmapMemory vkUnmapMemory;
276 PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR;
277 PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets;
278 PFN_vkWaitForFences vkWaitForFences;
279 PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR;
280};
281
282/// Loads instance agnostic function pointers.
283/// @return True on success, false on error.
284bool Load(InstanceDispatch&) noexcept;
285
286/// Loads instance function pointers.
287/// @return True on success, false on error.
288bool Load(VkInstance, InstanceDispatch&) noexcept;
289
290void Destroy(VkInstance, const InstanceDispatch&) noexcept;
291void Destroy(VkDevice, const InstanceDispatch&) noexcept;
292
293void Destroy(VkDevice, VkBuffer, const DeviceDispatch&) noexcept;
294void Destroy(VkDevice, VkBufferView, const DeviceDispatch&) noexcept;
295void Destroy(VkDevice, VkCommandPool, const DeviceDispatch&) noexcept;
296void Destroy(VkDevice, VkDescriptorPool, const DeviceDispatch&) noexcept;
297void Destroy(VkDevice, VkDescriptorSetLayout, const DeviceDispatch&) noexcept;
298void Destroy(VkDevice, VkDescriptorUpdateTemplateKHR, const DeviceDispatch&) noexcept;
299void Destroy(VkDevice, VkDeviceMemory, const DeviceDispatch&) noexcept;
300void Destroy(VkDevice, VkEvent, const DeviceDispatch&) noexcept;
301void Destroy(VkDevice, VkFence, const DeviceDispatch&) noexcept;
302void Destroy(VkDevice, VkFramebuffer, const DeviceDispatch&) noexcept;
303void Destroy(VkDevice, VkImage, const DeviceDispatch&) noexcept;
304void Destroy(VkDevice, VkImageView, const DeviceDispatch&) noexcept;
305void Destroy(VkDevice, VkPipeline, const DeviceDispatch&) noexcept;
306void Destroy(VkDevice, VkPipelineLayout, const DeviceDispatch&) noexcept;
307void Destroy(VkDevice, VkQueryPool, const DeviceDispatch&) noexcept;
308void Destroy(VkDevice, VkRenderPass, const DeviceDispatch&) noexcept;
309void Destroy(VkDevice, VkSampler, const DeviceDispatch&) noexcept;
310void Destroy(VkDevice, VkSwapchainKHR, const DeviceDispatch&) noexcept;
311void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept;
312void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept;
313void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept;
314void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept;
315
316VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept;
317VkResult Free(VkDevice, VkCommandPool, Span<VkCommandBuffer>, const DeviceDispatch&) noexcept;
318
319template <typename Type, typename OwnerType, typename Dispatch>
320class Handle;
321
322/// Handle with an owning type.
323/// Analogue to std::unique_ptr.
324template <typename Type, typename OwnerType, typename Dispatch>
325class Handle {
326public:
327 /// Construct a handle and hold it's ownership.
328 explicit Handle(Type handle_, OwnerType owner_, const Dispatch& dld_) noexcept
329 : handle{handle_}, owner{owner_}, dld{&dld_} {}
330
331 /// Construct an empty handle.
332 Handle() = default;
333
334 /// Copying Vulkan objects is not supported and will never be.
335 Handle(const Handle&) = delete;
336 Handle& operator=(const Handle&) = delete;
337
338 /// Construct a handle transfering the ownership from another handle.
339 Handle(Handle&& rhs) noexcept
340 : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, dld{rhs.dld} {}
341
342 /// Assign the current handle transfering the ownership from another handle.
343 /// Destroys any previously held object.
344 Handle& operator=(Handle&& rhs) noexcept {
345 Release();
346 handle = std::exchange(rhs.handle, nullptr);
347 owner = rhs.owner;
348 dld = rhs.dld;
349 return *this;
350 }
351
352 /// Destroys the current handle if it existed.
353 ~Handle() noexcept {
354 Release();
355 }
356
357 /// Destroys any held object.
358 void reset() noexcept {
359 Release();
360 handle = nullptr;
361 }
362
363 /// Returns the address of the held object.
364 /// Intended for Vulkan structures that expect a pointer to an array.
365 const Type* address() const noexcept {
366 return std::addressof(handle);
367 }
368
369 /// Returns the held Vulkan handle.
370 Type operator*() const noexcept {
371 return handle;
372 }
373
374 /// Returns true when there's a held object.
375 explicit operator bool() const noexcept {
376 return handle != nullptr;
377 }
378
379protected:
380 Type handle = nullptr;
381 OwnerType owner = nullptr;
382 const Dispatch* dld = nullptr;
383
384private:
385 /// Destroys the held object if it exists.
386 void Release() noexcept {
387 if (handle) {
388 Destroy(owner, handle, *dld);
389 }
390 }
391};
392
393/// Dummy type used to specify a handle has no owner.
394struct NoOwner {};
395
396/// Handle without an owning type.
397/// Analogue to std::unique_ptr
398template <typename Type, typename Dispatch>
399class Handle<Type, NoOwner, Dispatch> {
400public:
401 /// Construct a handle and hold it's ownership.
402 explicit Handle(Type handle_, const Dispatch& dld_) noexcept : handle{handle_}, dld{&dld_} {}
403
404 /// Construct an empty handle.
405 Handle() noexcept = default;
406
407 /// Copying Vulkan objects is not supported and will never be.
408 Handle(const Handle&) = delete;
409 Handle& operator=(const Handle&) = delete;
410
411 /// Construct a handle transfering ownership from another handle.
412 Handle(Handle&& rhs) noexcept : handle{std::exchange(rhs.handle, nullptr)}, dld{rhs.dld} {}
413
414 /// Assign the current handle transfering the ownership from another handle.
415 /// Destroys any previously held object.
416 Handle& operator=(Handle&& rhs) noexcept {
417 Release();
418 handle = std::exchange(rhs.handle, nullptr);
419 dld = rhs.dld;
420 return *this;
421 }
422
423 /// Destroys the current handle if it existed.
424 ~Handle() noexcept {
425 Release();
426 }
427
428 /// Destroys any held object.
429 void reset() noexcept {
430 Release();
431 handle = nullptr;
432 }
433
434 /// Returns the address of the held object.
435 /// Intended for Vulkan structures that expect a pointer to an array.
436 const Type* address() const noexcept {
437 return std::addressof(handle);
438 }
439
440 /// Returns the held Vulkan handle.
441 Type operator*() const noexcept {
442 return handle;
443 }
444
445 /// Returns true when there's a held object.
446 operator bool() const noexcept {
447 return handle != nullptr;
448 }
449
450protected:
451 Type handle = nullptr;
452 const Dispatch* dld = nullptr;
453
454private:
455 /// Destroys the held object if it exists.
456 void Release() noexcept {
457 if (handle) {
458 Destroy(handle, *dld);
459 }
460 }
461};
462
463/// Array of a pool allocation.
464/// Analogue to std::vector
465template <typename AllocationType, typename PoolType>
466class PoolAllocations {
467public:
468 /// Construct an empty allocation.
469 PoolAllocations() = default;
470
471 /// Construct an allocation. Errors are reported through IsOutOfPoolMemory().
472 explicit PoolAllocations(std::unique_ptr<AllocationType[]> allocations, std::size_t num,
473 VkDevice device, PoolType pool, const DeviceDispatch& dld) noexcept
474 : allocations{std::move(allocations)}, num{num}, device{device}, pool{pool}, dld{&dld} {}
475
476 /// Copying Vulkan allocations is not supported and will never be.
477 PoolAllocations(const PoolAllocations&) = delete;
478 PoolAllocations& operator=(const PoolAllocations&) = delete;
479
480 /// Construct an allocation transfering ownership from another allocation.
481 PoolAllocations(PoolAllocations&& rhs) noexcept
482 : allocations{std::move(rhs.allocations)}, num{rhs.num}, device{rhs.device}, pool{rhs.pool},
483 dld{rhs.dld} {}
484
485 /// Assign an allocation transfering ownership from another allocation.
486 /// Releases any previously held allocation.
487 PoolAllocations& operator=(PoolAllocations&& rhs) noexcept {
488 Release();
489 allocations = std::move(rhs.allocations);
490 num = rhs.num;
491 device = rhs.device;
492 pool = rhs.pool;
493 dld = rhs.dld;
494 return *this;
495 }
496
497 /// Destroys any held allocation.
498 ~PoolAllocations() {
499 Release();
500 }
501
502 /// Returns the number of allocations.
503 std::size_t size() const noexcept {
504 return num;
505 }
506
507 /// Returns a pointer to the array of allocations.
508 AllocationType const* data() const noexcept {
509 return allocations.get();
510 }
511
512 /// Returns the allocation in the specified index.
513 /// @pre index < size()
514 AllocationType operator[](std::size_t index) const noexcept {
515 return allocations[index];
516 }
517
518 /// True when a pool fails to construct.
519 bool IsOutOfPoolMemory() const noexcept {
520 return !device;
521 }
522
523private:
524 /// Destroys the held allocations if they exist.
525 void Release() noexcept {
526 if (!allocations) {
527 return;
528 }
529 const Span<AllocationType> span(allocations.get(), num);
530 const VkResult result = Free(device, pool, span, *dld);
531 // There's no way to report errors from a destructor.
532 if (result != VK_SUCCESS) {
533 std::terminate();
534 }
535 }
536
537 std::unique_ptr<AllocationType[]> allocations;
538 std::size_t num = 0;
539 VkDevice device = nullptr;
540 PoolType pool = nullptr;
541 const DeviceDispatch* dld = nullptr;
542};
543
544using BufferView = Handle<VkBufferView, VkDevice, DeviceDispatch>;
545using DebugCallback = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>;
546using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>;
547using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>;
548using Framebuffer = Handle<VkFramebuffer, VkDevice, DeviceDispatch>;
549using ImageView = Handle<VkImageView, VkDevice, DeviceDispatch>;
550using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>;
551using PipelineLayout = Handle<VkPipelineLayout, VkDevice, DeviceDispatch>;
552using QueryPool = Handle<VkQueryPool, VkDevice, DeviceDispatch>;
553using RenderPass = Handle<VkRenderPass, VkDevice, DeviceDispatch>;
554using Sampler = Handle<VkSampler, VkDevice, DeviceDispatch>;
555using ShaderModule = Handle<VkShaderModule, VkDevice, DeviceDispatch>;
556using SurfaceKHR = Handle<VkSurfaceKHR, VkInstance, InstanceDispatch>;
557
558using DescriptorSets = PoolAllocations<VkDescriptorSet, VkDescriptorPool>;
559using CommandBuffers = PoolAllocations<VkCommandBuffer, VkCommandPool>;
560
561/// Vulkan instance owning handle.
562class Instance : public Handle<VkInstance, NoOwner, InstanceDispatch> {
563 using Handle<VkInstance, NoOwner, InstanceDispatch>::Handle;
564
565public:
566 /// Creates a Vulkan instance. Use "operator bool" for error handling.
567 static Instance Create(Span<const char*> layers, Span<const char*> extensions,
568 InstanceDispatch& dld) noexcept;
569
570 /// Enumerates physical devices.
571 /// @return Physical devices and an empty handle on failure.
572 std::optional<std::vector<VkPhysicalDevice>> EnumeratePhysicalDevices();
573
574 /// Tries to create a debug callback messenger. Returns an empty handle on failure.
575 DebugCallback TryCreateDebugCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept;
576};
577
578class Queue {
579public:
580 /// Construct an empty queue handle.
581 constexpr Queue() noexcept = default;
582
583 /// Construct a queue handle.
584 constexpr Queue(VkQueue queue, const DeviceDispatch& dld) noexcept : queue{queue}, dld{&dld} {}
585
586 VkResult Submit(Span<VkSubmitInfo> submit_infos,
587 VkFence fence = VK_NULL_HANDLE) const noexcept {
588 return dld->vkQueueSubmit(queue, submit_infos.size(), submit_infos.data(), fence);
589 }
590
591 VkResult Present(const VkPresentInfoKHR& present_info) const noexcept {
592 return dld->vkQueuePresentKHR(queue, &present_info);
593 }
594
595private:
596 VkQueue queue = nullptr;
597 const DeviceDispatch* dld = nullptr;
598};
599
600class Buffer : public Handle<VkBuffer, VkDevice, DeviceDispatch> {
601 using Handle<VkBuffer, VkDevice, DeviceDispatch>::Handle;
602
603public:
604 /// Attaches a memory allocation.
605 void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
606};
607
608class Image : public Handle<VkImage, VkDevice, DeviceDispatch> {
609 using Handle<VkImage, VkDevice, DeviceDispatch>::Handle;
610
611public:
612 /// Attaches a memory allocation.
613 void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
614};
615
616class DeviceMemory : public Handle<VkDeviceMemory, VkDevice, DeviceDispatch> {
617 using Handle<VkDeviceMemory, VkDevice, DeviceDispatch>::Handle;
618
619public:
620 u8* Map(VkDeviceSize offset, VkDeviceSize size) const {
621 void* data;
622 Check(dld->vkMapMemory(owner, handle, offset, size, 0, &data));
623 return static_cast<u8*>(data);
624 }
625
626 void Unmap() const noexcept {
627 dld->vkUnmapMemory(owner, handle);
628 }
629};
630
631class Fence : public Handle<VkFence, VkDevice, DeviceDispatch> {
632 using Handle<VkFence, VkDevice, DeviceDispatch>::Handle;
633
634public:
635 VkResult Wait(u64 timeout = std::numeric_limits<u64>::max()) const noexcept {
636 return dld->vkWaitForFences(owner, 1, &handle, true, timeout);
637 }
638
639 VkResult GetStatus() const noexcept {
640 return dld->vkGetFenceStatus(owner, handle);
641 }
642
643 void Reset() const {
644 Check(dld->vkResetFences(owner, 1, &handle));
645 }
646};
647
648class DescriptorPool : public Handle<VkDescriptorPool, VkDevice, DeviceDispatch> {
649 using Handle<VkDescriptorPool, VkDevice, DeviceDispatch>::Handle;
650
651public:
652 DescriptorSets Allocate(const VkDescriptorSetAllocateInfo& ai) const;
653};
654
655class CommandPool : public Handle<VkCommandPool, VkDevice, DeviceDispatch> {
656 using Handle<VkCommandPool, VkDevice, DeviceDispatch>::Handle;
657
658public:
659 CommandBuffers Allocate(std::size_t num_buffers,
660 VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY) const;
661};
662
663class SwapchainKHR : public Handle<VkSwapchainKHR, VkDevice, DeviceDispatch> {
664 using Handle<VkSwapchainKHR, VkDevice, DeviceDispatch>::Handle;
665
666public:
667 std::vector<VkImage> GetImages() const;
668};
669
670class Event : public Handle<VkEvent, VkDevice, DeviceDispatch> {
671 using Handle<VkEvent, VkDevice, DeviceDispatch>::Handle;
672
673public:
674 VkResult GetStatus() const noexcept {
675 return dld->vkGetEventStatus(owner, handle);
676 }
677};
678
679class Semaphore : public Handle<VkSemaphore, VkDevice, DeviceDispatch> {
680 using Handle<VkSemaphore, VkDevice, DeviceDispatch>::Handle;
681
682public:
683 [[nodiscard]] u64 GetCounter() const {
684 u64 value;
685 Check(dld->vkGetSemaphoreCounterValueKHR(owner, handle, &value));
686 return value;
687 }
688
689 /**
690 * Waits for a timeline semaphore on the host.
691 *
692 * @param value Value to wait
693 * @param timeout Time in nanoseconds to timeout
694 * @return True on successful wait, false on timeout
695 */
696 bool Wait(u64 value, u64 timeout = std::numeric_limits<u64>::max()) const {
697 const VkSemaphoreWaitInfoKHR wait_info{
698 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR,
699 .pNext = nullptr,
700 .flags = 0,
701 .semaphoreCount = 1,
702 .pSemaphores = &handle,
703 .pValues = &value,
704 };
705 const VkResult result = dld->vkWaitSemaphoresKHR(owner, &wait_info, timeout);
706 switch (result) {
707 case VK_SUCCESS:
708 return true;
709 case VK_TIMEOUT:
710 return false;
711 default:
712 throw Exception(result);
713 }
714 }
715};
716
717class Device : public Handle<VkDevice, NoOwner, DeviceDispatch> {
718 using Handle<VkDevice, NoOwner, DeviceDispatch>::Handle;
719
720public:
721 static Device Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,
722 Span<const char*> enabled_extensions, const void* next,
723 DeviceDispatch& dld) noexcept;
724
725 Queue GetQueue(u32 family_index) const noexcept;
726
727 Buffer CreateBuffer(const VkBufferCreateInfo& ci) const;
728
729 BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const;
730
731 Image CreateImage(const VkImageCreateInfo& ci) const;
732
733 ImageView CreateImageView(const VkImageViewCreateInfo& ci) const;
734
735 Semaphore CreateSemaphore() const;
736
737 Semaphore CreateSemaphore(const VkSemaphoreCreateInfo& ci) const;
738
739 Fence CreateFence(const VkFenceCreateInfo& ci) const;
740
741 DescriptorPool CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const;
742
743 RenderPass CreateRenderPass(const VkRenderPassCreateInfo& ci) const;
744
745 DescriptorSetLayout CreateDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo& ci) const;
746
747 PipelineLayout CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const;
748
749 Pipeline CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci) const;
750
751 Pipeline CreateComputePipeline(const VkComputePipelineCreateInfo& ci) const;
752
753 Sampler CreateSampler(const VkSamplerCreateInfo& ci) const;
754
755 Framebuffer CreateFramebuffer(const VkFramebufferCreateInfo& ci) const;
756
757 CommandPool CreateCommandPool(const VkCommandPoolCreateInfo& ci) const;
758
759 DescriptorUpdateTemplateKHR CreateDescriptorUpdateTemplateKHR(
760 const VkDescriptorUpdateTemplateCreateInfoKHR& ci) const;
761
762 QueryPool CreateQueryPool(const VkQueryPoolCreateInfo& ci) const;
763
764 ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const;
765
766 Event CreateEvent() const;
767
768 SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const;
769
770 DeviceMemory TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept;
771
772 DeviceMemory AllocateMemory(const VkMemoryAllocateInfo& ai) const;
773
774 VkMemoryRequirements GetBufferMemoryRequirements(VkBuffer buffer) const noexcept;
775
776 VkMemoryRequirements GetImageMemoryRequirements(VkImage image) const noexcept;
777
778 void UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes,
779 Span<VkCopyDescriptorSet> copies) const noexcept;
780
781 void UpdateDescriptorSet(VkDescriptorSet set, VkDescriptorUpdateTemplateKHR update_template,
782 const void* data) const noexcept {
783 dld->vkUpdateDescriptorSetWithTemplateKHR(handle, set, update_template, data);
784 }
785
786 VkResult AcquireNextImageKHR(VkSwapchainKHR swapchain, u64 timeout, VkSemaphore semaphore,
787 VkFence fence, u32* image_index) const noexcept {
788 return dld->vkAcquireNextImageKHR(handle, swapchain, timeout, semaphore, fence,
789 image_index);
790 }
791
792 VkResult WaitIdle() const noexcept {
793 return dld->vkDeviceWaitIdle(handle);
794 }
795
796 void ResetQueryPoolEXT(VkQueryPool query_pool, u32 first, u32 count) const noexcept {
797 dld->vkResetQueryPoolEXT(handle, query_pool, first, count);
798 }
799
800 VkResult GetQueryResults(VkQueryPool query_pool, u32 first, u32 count, std::size_t data_size,
801 void* data, VkDeviceSize stride,
802 VkQueryResultFlags flags) const noexcept {
803 return dld->vkGetQueryPoolResults(handle, query_pool, first, count, data_size, data, stride,
804 flags);
805 }
806};
807
808class PhysicalDevice {
809public:
810 constexpr PhysicalDevice() noexcept = default;
811
812 constexpr PhysicalDevice(VkPhysicalDevice physical_device, const InstanceDispatch& dld) noexcept
813 : physical_device{physical_device}, dld{&dld} {}
814
815 constexpr operator VkPhysicalDevice() const noexcept {
816 return physical_device;
817 }
818
819 VkPhysicalDeviceProperties GetProperties() const noexcept;
820
821 void GetProperties2KHR(VkPhysicalDeviceProperties2KHR&) const noexcept;
822
823 VkPhysicalDeviceFeatures GetFeatures() const noexcept;
824
825 void GetFeatures2KHR(VkPhysicalDeviceFeatures2KHR&) const noexcept;
826
827 VkFormatProperties GetFormatProperties(VkFormat) const noexcept;
828
829 std::vector<VkExtensionProperties> EnumerateDeviceExtensionProperties() const;
830
831 std::vector<VkQueueFamilyProperties> GetQueueFamilyProperties() const;
832
833 bool GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR) const;
834
835 VkSurfaceCapabilitiesKHR GetSurfaceCapabilitiesKHR(VkSurfaceKHR) const;
836
837 std::vector<VkSurfaceFormatKHR> GetSurfaceFormatsKHR(VkSurfaceKHR) const;
838
839 std::vector<VkPresentModeKHR> GetSurfacePresentModesKHR(VkSurfaceKHR) const;
840
841 VkPhysicalDeviceMemoryProperties GetMemoryProperties() const noexcept;
842
843private:
844 VkPhysicalDevice physical_device = nullptr;
845 const InstanceDispatch* dld = nullptr;
846};
847
848class CommandBuffer {
849public:
850 CommandBuffer() noexcept = default;
851
852 explicit CommandBuffer(VkCommandBuffer handle, const DeviceDispatch& dld) noexcept
853 : handle{handle}, dld{&dld} {}
854
855 const VkCommandBuffer* address() const noexcept {
856 return &handle;
857 }
858
859 void Begin(const VkCommandBufferBeginInfo& begin_info) const {
860 Check(dld->vkBeginCommandBuffer(handle, &begin_info));
861 }
862
863 void End() const {
864 Check(dld->vkEndCommandBuffer(handle));
865 }
866
867 void BeginRenderPass(const VkRenderPassBeginInfo& renderpass_bi,
868 VkSubpassContents contents) const noexcept {
869 dld->vkCmdBeginRenderPass(handle, &renderpass_bi, contents);
870 }
871
872 void EndRenderPass() const noexcept {
873 dld->vkCmdEndRenderPass(handle);
874 }
875
876 void BeginQuery(VkQueryPool query_pool, u32 query, VkQueryControlFlags flags) const noexcept {
877 dld->vkCmdBeginQuery(handle, query_pool, query, flags);
878 }
879
880 void EndQuery(VkQueryPool query_pool, u32 query) const noexcept {
881 dld->vkCmdEndQuery(handle, query_pool, query);
882 }
883
884 void BindDescriptorSets(VkPipelineBindPoint bind_point, VkPipelineLayout layout, u32 first,
885 Span<VkDescriptorSet> sets, Span<u32> dynamic_offsets) const noexcept {
886 dld->vkCmdBindDescriptorSets(handle, bind_point, layout, first, sets.size(), sets.data(),
887 dynamic_offsets.size(), dynamic_offsets.data());
888 }
889
890 void BindPipeline(VkPipelineBindPoint bind_point, VkPipeline pipeline) const noexcept {
891 dld->vkCmdBindPipeline(handle, bind_point, pipeline);
892 }
893
894 void BindIndexBuffer(VkBuffer buffer, VkDeviceSize offset,
895 VkIndexType index_type) const noexcept {
896 dld->vkCmdBindIndexBuffer(handle, buffer, offset, index_type);
897 }
898
899 void BindVertexBuffers(u32 first, u32 count, const VkBuffer* buffers,
900 const VkDeviceSize* offsets) const noexcept {
901 dld->vkCmdBindVertexBuffers(handle, first, count, buffers, offsets);
902 }
903
904 void BindVertexBuffer(u32 binding, VkBuffer buffer, VkDeviceSize offset) const noexcept {
905 BindVertexBuffers(binding, 1, &buffer, &offset);
906 }
907
908 void Draw(u32 vertex_count, u32 instance_count, u32 first_vertex,
909 u32 first_instance) const noexcept {
910 dld->vkCmdDraw(handle, vertex_count, instance_count, first_vertex, first_instance);
911 }
912
913 void DrawIndexed(u32 index_count, u32 instance_count, u32 first_index, u32 vertex_offset,
914 u32 first_instance) const noexcept {
915 dld->vkCmdDrawIndexed(handle, index_count, instance_count, first_index, vertex_offset,
916 first_instance);
917 }
918
919 void ClearAttachments(Span<VkClearAttachment> attachments,
920 Span<VkClearRect> rects) const noexcept {
921 dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(),
922 rects.data());
923 }
924
925 void BlitImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image,
926 VkImageLayout dst_layout, Span<VkImageBlit> regions,
927 VkFilter filter) const noexcept {
928 dld->vkCmdBlitImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(),
929 regions.data(), filter);
930 }
931
932 void Dispatch(u32 x, u32 y, u32 z) const noexcept {
933 dld->vkCmdDispatch(handle, x, y, z);
934 }
935
936 void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
937 VkDependencyFlags dependency_flags, Span<VkMemoryBarrier> memory_barriers,
938 Span<VkBufferMemoryBarrier> buffer_barriers,
939 Span<VkImageMemoryBarrier> image_barriers) const noexcept {
940 dld->vkCmdPipelineBarrier(handle, src_stage_mask, dst_stage_mask, dependency_flags,
941 memory_barriers.size(), memory_barriers.data(),
942 buffer_barriers.size(), buffer_barriers.data(),
943 image_barriers.size(), image_barriers.data());
944 }
945
946 void CopyBufferToImage(VkBuffer src_buffer, VkImage dst_image, VkImageLayout dst_image_layout,
947 Span<VkBufferImageCopy> regions) const noexcept {
948 dld->vkCmdCopyBufferToImage(handle, src_buffer, dst_image, dst_image_layout, regions.size(),
949 regions.data());
950 }
951
952 void CopyBuffer(VkBuffer src_buffer, VkBuffer dst_buffer,
953 Span<VkBufferCopy> regions) const noexcept {
954 dld->vkCmdCopyBuffer(handle, src_buffer, dst_buffer, regions.size(), regions.data());
955 }
956
957 void CopyImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image,
958 VkImageLayout dst_layout, Span<VkImageCopy> regions) const noexcept {
959 dld->vkCmdCopyImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(),
960 regions.data());
961 }
962
963 void CopyImageToBuffer(VkImage src_image, VkImageLayout src_layout, VkBuffer dst_buffer,
964 Span<VkBufferImageCopy> regions) const noexcept {
965 dld->vkCmdCopyImageToBuffer(handle, src_image, src_layout, dst_buffer, regions.size(),
966 regions.data());
967 }
968
969 void FillBuffer(VkBuffer dst_buffer, VkDeviceSize dst_offset, VkDeviceSize size,
970 u32 data) const noexcept {
971 dld->vkCmdFillBuffer(handle, dst_buffer, dst_offset, size, data);
972 }
973
974 void PushConstants(VkPipelineLayout layout, VkShaderStageFlags flags, u32 offset, u32 size,
975 const void* values) const noexcept {
976 dld->vkCmdPushConstants(handle, layout, flags, offset, size, values);
977 }
978
979 void SetViewport(u32 first, Span<VkViewport> viewports) const noexcept {
980 dld->vkCmdSetViewport(handle, first, viewports.size(), viewports.data());
981 }
982
983 void SetScissor(u32 first, Span<VkRect2D> scissors) const noexcept {
984 dld->vkCmdSetScissor(handle, first, scissors.size(), scissors.data());
985 }
986
987 void SetBlendConstants(const float blend_constants[4]) const noexcept {
988 dld->vkCmdSetBlendConstants(handle, blend_constants);
989 }
990
991 void SetStencilCompareMask(VkStencilFaceFlags face_mask, u32 compare_mask) const noexcept {
992 dld->vkCmdSetStencilCompareMask(handle, face_mask, compare_mask);
993 }
994
995 void SetStencilReference(VkStencilFaceFlags face_mask, u32 reference) const noexcept {
996 dld->vkCmdSetStencilReference(handle, face_mask, reference);
997 }
998
999 void SetStencilWriteMask(VkStencilFaceFlags face_mask, u32 write_mask) const noexcept {
1000 dld->vkCmdSetStencilWriteMask(handle, face_mask, write_mask);
1001 }
1002
1003 void SetDepthBias(float constant_factor, float clamp, float slope_factor) const noexcept {
1004 dld->vkCmdSetDepthBias(handle, constant_factor, clamp, slope_factor);
1005 }
1006
1007 void SetDepthBounds(float min_depth_bounds, float max_depth_bounds) const noexcept {
1008 dld->vkCmdSetDepthBounds(handle, min_depth_bounds, max_depth_bounds);
1009 }
1010
1011 void SetEvent(VkEvent event, VkPipelineStageFlags stage_flags) const noexcept {
1012 dld->vkCmdSetEvent(handle, event, stage_flags);
1013 }
1014
1015 void WaitEvents(Span<VkEvent> events, VkPipelineStageFlags src_stage_mask,
1016 VkPipelineStageFlags dst_stage_mask, Span<VkMemoryBarrier> memory_barriers,
1017 Span<VkBufferMemoryBarrier> buffer_barriers,
1018 Span<VkImageMemoryBarrier> image_barriers) const noexcept {
1019 dld->vkCmdWaitEvents(handle, events.size(), events.data(), src_stage_mask, dst_stage_mask,
1020 memory_barriers.size(), memory_barriers.data(), buffer_barriers.size(),
1021 buffer_barriers.data(), image_barriers.size(), image_barriers.data());
1022 }
1023
1024 void BindVertexBuffers2EXT(u32 first_binding, u32 binding_count, const VkBuffer* buffers,
1025 const VkDeviceSize* offsets, const VkDeviceSize* sizes,
1026 const VkDeviceSize* strides) const noexcept {
1027 dld->vkCmdBindVertexBuffers2EXT(handle, first_binding, binding_count, buffers, offsets,
1028 sizes, strides);
1029 }
1030
1031 void SetCullModeEXT(VkCullModeFlags cull_mode) const noexcept {
1032 dld->vkCmdSetCullModeEXT(handle, cull_mode);
1033 }
1034
1035 void SetDepthBoundsTestEnableEXT(bool enable) const noexcept {
1036 dld->vkCmdSetDepthBoundsTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
1037 }
1038
1039 void SetDepthCompareOpEXT(VkCompareOp compare_op) const noexcept {
1040 dld->vkCmdSetDepthCompareOpEXT(handle, compare_op);
1041 }
1042
1043 void SetDepthTestEnableEXT(bool enable) const noexcept {
1044 dld->vkCmdSetDepthTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
1045 }
1046
1047 void SetDepthWriteEnableEXT(bool enable) const noexcept {
1048 dld->vkCmdSetDepthWriteEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
1049 }
1050
1051 void SetFrontFaceEXT(VkFrontFace front_face) const noexcept {
1052 dld->vkCmdSetFrontFaceEXT(handle, front_face);
1053 }
1054
1055 void SetPrimitiveTopologyEXT(VkPrimitiveTopology primitive_topology) const noexcept {
1056 dld->vkCmdSetPrimitiveTopologyEXT(handle, primitive_topology);
1057 }
1058
1059 void SetStencilOpEXT(VkStencilFaceFlags face_mask, VkStencilOp fail_op, VkStencilOp pass_op,
1060 VkStencilOp depth_fail_op, VkCompareOp compare_op) const noexcept {
1061 dld->vkCmdSetStencilOpEXT(handle, face_mask, fail_op, pass_op, depth_fail_op, compare_op);
1062 }
1063
1064 void SetStencilTestEnableEXT(bool enable) const noexcept {
1065 dld->vkCmdSetStencilTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
1066 }
1067
1068 void BindTransformFeedbackBuffersEXT(u32 first, u32 count, const VkBuffer* buffers,
1069 const VkDeviceSize* offsets,
1070 const VkDeviceSize* sizes) const noexcept {
1071 dld->vkCmdBindTransformFeedbackBuffersEXT(handle, first, count, buffers, offsets, sizes);
1072 }
1073
1074 void BeginTransformFeedbackEXT(u32 first_counter_buffer, u32 counter_buffers_count,
1075 const VkBuffer* counter_buffers,
1076 const VkDeviceSize* counter_buffer_offsets) const noexcept {
1077 dld->vkCmdBeginTransformFeedbackEXT(handle, first_counter_buffer, counter_buffers_count,
1078 counter_buffers, counter_buffer_offsets);
1079 }
1080
1081 void EndTransformFeedbackEXT(u32 first_counter_buffer, u32 counter_buffers_count,
1082 const VkBuffer* counter_buffers,
1083 const VkDeviceSize* counter_buffer_offsets) const noexcept {
1084 dld->vkCmdEndTransformFeedbackEXT(handle, first_counter_buffer, counter_buffers_count,
1085 counter_buffers, counter_buffer_offsets);
1086 }
1087
1088private:
1089 VkCommandBuffer handle;
1090 const DeviceDispatch* dld;
1091};
1092
1093std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties(
1094 const InstanceDispatch& dld);
1095
1096std::optional<std::vector<VkLayerProperties>> EnumerateInstanceLayerProperties(
1097 const InstanceDispatch& dld);
1098
1099} // namespace Vulkan::vk