summaryrefslogtreecommitdiff
path: root/src/video_core/vulkan_common
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2020-12-26 01:19:46 -0300
committerGravatar ReinUsesLisp2021-01-04 02:22:22 -0300
commit3753553b6a7b493a03f4e6f0e0f726c334502eb0 (patch)
tree6ddfefa9e9f522cfe69b1b00dc1274749fe549be /src/video_core/vulkan_common
parentMerge pull request #5286 from ReinUsesLisp/rename-vk-device (diff)
downloadyuzu-3753553b6a7b493a03f4e6f0e0f726c334502eb0.tar.gz
yuzu-3753553b6a7b493a03f4e6f0e0f726c334502eb0.tar.xz
yuzu-3753553b6a7b493a03f4e6f0e0f726c334502eb0.zip
renderer_vulkan: Move device abstraction to vulkan_common
Diffstat (limited to 'src/video_core/vulkan_common')
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp883
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h306
2 files changed, 1189 insertions, 0 deletions
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
new file mode 100644
index 000000000..67183eed8
--- /dev/null
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -0,0 +1,883 @@
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/vulkan_common/vulkan_device.h"
17#include "video_core/vulkan_common/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_MAINTENANCE1_EXTENSION_NAME,
42 VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME,
43 VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME,
44 VK_KHR_16BIT_STORAGE_EXTENSION_NAME,
45 VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
46 VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
47 VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME,
48 VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
49 VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME,
50 VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME,
51 VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME,
52 VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME,
53 VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME,
54};
55
56template <typename T>
57void SetNext(void**& next, T& data) {
58 *next = &data;
59 next = &data.pNext;
60}
61
62constexpr const VkFormat* GetFormatAlternatives(VkFormat format) {
63 switch (format) {
64 case VK_FORMAT_D24_UNORM_S8_UINT:
65 return Alternatives::Depth24UnormS8_UINT.data();
66 case VK_FORMAT_D16_UNORM_S8_UINT:
67 return Alternatives::Depth16UnormS8_UINT.data();
68 default:
69 return nullptr;
70 }
71}
72
73VkFormatFeatureFlags GetFormatFeatures(VkFormatProperties properties, FormatType format_type) {
74 switch (format_type) {
75 case FormatType::Linear:
76 return properties.linearTilingFeatures;
77 case FormatType::Optimal:
78 return properties.optimalTilingFeatures;
79 case FormatType::Buffer:
80 return properties.bufferFeatures;
81 default:
82 return {};
83 }
84}
85
86[[nodiscard]] bool IsRDNA(std::string_view device_name, VkDriverIdKHR driver_id) {
87 static constexpr std::array RDNA_DEVICES{
88 "5700",
89 "5600",
90 "5500",
91 "5300",
92 };
93 if (driver_id != VK_DRIVER_ID_AMD_PROPRIETARY_KHR) {
94 return false;
95 }
96 return std::any_of(RDNA_DEVICES.begin(), RDNA_DEVICES.end(), [device_name](const char* name) {
97 return device_name.find(name) != std::string_view::npos;
98 });
99}
100
101std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(
102 vk::PhysicalDevice physical, const vk::InstanceDispatch& dld) {
103 static constexpr std::array formats{
104 VK_FORMAT_A8B8G8R8_UNORM_PACK32,
105 VK_FORMAT_A8B8G8R8_UINT_PACK32,
106 VK_FORMAT_A8B8G8R8_SNORM_PACK32,
107 VK_FORMAT_A8B8G8R8_SINT_PACK32,
108 VK_FORMAT_A8B8G8R8_SRGB_PACK32,
109 VK_FORMAT_B5G6R5_UNORM_PACK16,
110 VK_FORMAT_A2B10G10R10_UNORM_PACK32,
111 VK_FORMAT_A2B10G10R10_UINT_PACK32,
112 VK_FORMAT_A1R5G5B5_UNORM_PACK16,
113 VK_FORMAT_R32G32B32A32_SFLOAT,
114 VK_FORMAT_R32G32B32A32_SINT,
115 VK_FORMAT_R32G32B32A32_UINT,
116 VK_FORMAT_R32G32_SFLOAT,
117 VK_FORMAT_R32G32_SINT,
118 VK_FORMAT_R32G32_UINT,
119 VK_FORMAT_R16G16B16A16_SINT,
120 VK_FORMAT_R16G16B16A16_UINT,
121 VK_FORMAT_R16G16B16A16_SNORM,
122 VK_FORMAT_R16G16B16A16_UNORM,
123 VK_FORMAT_R16G16_UNORM,
124 VK_FORMAT_R16G16_SNORM,
125 VK_FORMAT_R16G16_SFLOAT,
126 VK_FORMAT_R16G16_SINT,
127 VK_FORMAT_R16_UNORM,
128 VK_FORMAT_R16_UINT,
129 VK_FORMAT_R8G8B8A8_SRGB,
130 VK_FORMAT_R8G8_UNORM,
131 VK_FORMAT_R8G8_SNORM,
132 VK_FORMAT_R8G8_SINT,
133 VK_FORMAT_R8G8_UINT,
134 VK_FORMAT_R8_UNORM,
135 VK_FORMAT_R8_SNORM,
136 VK_FORMAT_R8_SINT,
137 VK_FORMAT_R8_UINT,
138 VK_FORMAT_B10G11R11_UFLOAT_PACK32,
139 VK_FORMAT_R32_SFLOAT,
140 VK_FORMAT_R32_UINT,
141 VK_FORMAT_R32_SINT,
142 VK_FORMAT_R16_SFLOAT,
143 VK_FORMAT_R16G16B16A16_SFLOAT,
144 VK_FORMAT_B8G8R8A8_UNORM,
145 VK_FORMAT_B8G8R8A8_SRGB,
146 VK_FORMAT_R4G4B4A4_UNORM_PACK16,
147 VK_FORMAT_D32_SFLOAT,
148 VK_FORMAT_D16_UNORM,
149 VK_FORMAT_D16_UNORM_S8_UINT,
150 VK_FORMAT_D24_UNORM_S8_UINT,
151 VK_FORMAT_D32_SFLOAT_S8_UINT,
152 VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
153 VK_FORMAT_BC2_UNORM_BLOCK,
154 VK_FORMAT_BC3_UNORM_BLOCK,
155 VK_FORMAT_BC4_UNORM_BLOCK,
156 VK_FORMAT_BC4_SNORM_BLOCK,
157 VK_FORMAT_BC5_UNORM_BLOCK,
158 VK_FORMAT_BC5_SNORM_BLOCK,
159 VK_FORMAT_BC7_UNORM_BLOCK,
160 VK_FORMAT_BC6H_UFLOAT_BLOCK,
161 VK_FORMAT_BC6H_SFLOAT_BLOCK,
162 VK_FORMAT_BC1_RGBA_SRGB_BLOCK,
163 VK_FORMAT_BC2_SRGB_BLOCK,
164 VK_FORMAT_BC3_SRGB_BLOCK,
165 VK_FORMAT_BC7_SRGB_BLOCK,
166 VK_FORMAT_ASTC_4x4_UNORM_BLOCK,
167 VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
168 VK_FORMAT_ASTC_5x4_UNORM_BLOCK,
169 VK_FORMAT_ASTC_5x4_SRGB_BLOCK,
170 VK_FORMAT_ASTC_5x5_UNORM_BLOCK,
171 VK_FORMAT_ASTC_5x5_SRGB_BLOCK,
172 VK_FORMAT_ASTC_6x5_UNORM_BLOCK,
173 VK_FORMAT_ASTC_6x5_SRGB_BLOCK,
174 VK_FORMAT_ASTC_6x6_UNORM_BLOCK,
175 VK_FORMAT_ASTC_6x6_SRGB_BLOCK,
176 VK_FORMAT_ASTC_8x5_UNORM_BLOCK,
177 VK_FORMAT_ASTC_8x5_SRGB_BLOCK,
178 VK_FORMAT_ASTC_8x6_UNORM_BLOCK,
179 VK_FORMAT_ASTC_8x6_SRGB_BLOCK,
180 VK_FORMAT_ASTC_8x8_UNORM_BLOCK,
181 VK_FORMAT_ASTC_8x8_SRGB_BLOCK,
182 VK_FORMAT_ASTC_10x5_UNORM_BLOCK,
183 VK_FORMAT_ASTC_10x5_SRGB_BLOCK,
184 VK_FORMAT_ASTC_10x6_UNORM_BLOCK,
185 VK_FORMAT_ASTC_10x6_SRGB_BLOCK,
186 VK_FORMAT_ASTC_10x8_UNORM_BLOCK,
187 VK_FORMAT_ASTC_10x8_SRGB_BLOCK,
188 VK_FORMAT_ASTC_10x10_UNORM_BLOCK,
189 VK_FORMAT_ASTC_10x10_SRGB_BLOCK,
190 VK_FORMAT_ASTC_12x10_UNORM_BLOCK,
191 VK_FORMAT_ASTC_12x10_SRGB_BLOCK,
192 VK_FORMAT_ASTC_12x12_UNORM_BLOCK,
193 VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
194 VK_FORMAT_ASTC_8x6_UNORM_BLOCK,
195 VK_FORMAT_ASTC_8x6_SRGB_BLOCK,
196 VK_FORMAT_ASTC_6x5_UNORM_BLOCK,
197 VK_FORMAT_ASTC_6x5_SRGB_BLOCK,
198 VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,
199 };
200 std::unordered_map<VkFormat, VkFormatProperties> format_properties;
201 for (const auto format : formats) {
202 format_properties.emplace(format, physical.GetFormatProperties(format));
203 }
204 return format_properties;
205}
206
207} // Anonymous namespace
208
209Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface,
210 const vk::InstanceDispatch& dld_)
211 : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()},
212 format_properties{GetFormatProperties(physical, dld)} {
213 CheckSuitability();
214 SetupFamilies(surface);
215 SetupFeatures();
216
217 const auto queue_cis = GetDeviceQueueCreateInfos();
218 const std::vector extensions = LoadExtensions();
219
220 VkPhysicalDeviceFeatures2 features2{
221 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
222 .pNext = nullptr,
223 };
224 const void* first_next = &features2;
225 void** next = &features2.pNext;
226
227 features2.features = {
228 .robustBufferAccess = false,
229 .fullDrawIndexUint32 = false,
230 .imageCubeArray = true,
231 .independentBlend = true,
232 .geometryShader = true,
233 .tessellationShader = true,
234 .sampleRateShading = false,
235 .dualSrcBlend = false,
236 .logicOp = false,
237 .multiDrawIndirect = false,
238 .drawIndirectFirstInstance = false,
239 .depthClamp = true,
240 .depthBiasClamp = true,
241 .fillModeNonSolid = false,
242 .depthBounds = false,
243 .wideLines = false,
244 .largePoints = true,
245 .alphaToOne = false,
246 .multiViewport = true,
247 .samplerAnisotropy = true,
248 .textureCompressionETC2 = false,
249 .textureCompressionASTC_LDR = is_optimal_astc_supported,
250 .textureCompressionBC = false,
251 .occlusionQueryPrecise = true,
252 .pipelineStatisticsQuery = false,
253 .vertexPipelineStoresAndAtomics = true,
254 .fragmentStoresAndAtomics = true,
255 .shaderTessellationAndGeometryPointSize = false,
256 .shaderImageGatherExtended = true,
257 .shaderStorageImageExtendedFormats = false,
258 .shaderStorageImageMultisample = true,
259 .shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported,
260 .shaderStorageImageWriteWithoutFormat = true,
261 .shaderUniformBufferArrayDynamicIndexing = false,
262 .shaderSampledImageArrayDynamicIndexing = false,
263 .shaderStorageBufferArrayDynamicIndexing = false,
264 .shaderStorageImageArrayDynamicIndexing = false,
265 .shaderClipDistance = false,
266 .shaderCullDistance = false,
267 .shaderFloat64 = false,
268 .shaderInt64 = false,
269 .shaderInt16 = false,
270 .shaderResourceResidency = false,
271 .shaderResourceMinLod = false,
272 .sparseBinding = false,
273 .sparseResidencyBuffer = false,
274 .sparseResidencyImage2D = false,
275 .sparseResidencyImage3D = false,
276 .sparseResidency2Samples = false,
277 .sparseResidency4Samples = false,
278 .sparseResidency8Samples = false,
279 .sparseResidency16Samples = false,
280 .sparseResidencyAliased = false,
281 .variableMultisampleRate = false,
282 .inheritedQueries = false,
283 };
284 VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore{
285 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR,
286 .pNext = nullptr,
287 .timelineSemaphore = true,
288 };
289 SetNext(next, timeline_semaphore);
290
291 VkPhysicalDevice16BitStorageFeaturesKHR bit16_storage{
292 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR,
293 .pNext = nullptr,
294 .storageBuffer16BitAccess = false,
295 .uniformAndStorageBuffer16BitAccess = true,
296 .storagePushConstant16 = false,
297 .storageInputOutput16 = false,
298 };
299 SetNext(next, bit16_storage);
300
301 VkPhysicalDevice8BitStorageFeaturesKHR bit8_storage{
302 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR,
303 .pNext = nullptr,
304 .storageBuffer8BitAccess = false,
305 .uniformAndStorageBuffer8BitAccess = true,
306 .storagePushConstant8 = false,
307 };
308 SetNext(next, bit8_storage);
309
310 VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset{
311 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT,
312 .hostQueryReset = true,
313 };
314 SetNext(next, host_query_reset);
315
316 VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8;
317 if (is_float16_supported) {
318 float16_int8 = {
319 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR,
320 .pNext = nullptr,
321 .shaderFloat16 = true,
322 .shaderInt8 = false,
323 };
324 SetNext(next, float16_int8);
325 } else {
326 LOG_INFO(Render_Vulkan, "Device doesn't support float16 natively");
327 }
328
329 if (!nv_viewport_swizzle) {
330 LOG_INFO(Render_Vulkan, "Device doesn't support viewport swizzles");
331 }
332
333 VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR std430_layout;
334 if (khr_uniform_buffer_standard_layout) {
335 std430_layout = {
336 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR,
337 .pNext = nullptr,
338 .uniformBufferStandardLayout = true,
339 };
340 SetNext(next, std430_layout);
341 } else {
342 LOG_INFO(Render_Vulkan, "Device doesn't support packed UBOs");
343 }
344
345 VkPhysicalDeviceIndexTypeUint8FeaturesEXT index_type_uint8;
346 if (ext_index_type_uint8) {
347 index_type_uint8 = {
348 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT,
349 .pNext = nullptr,
350 .indexTypeUint8 = true,
351 };
352 SetNext(next, index_type_uint8);
353 } else {
354 LOG_INFO(Render_Vulkan, "Device doesn't support uint8 indexes");
355 }
356
357 VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback;
358 if (ext_transform_feedback) {
359 transform_feedback = {
360 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT,
361 .pNext = nullptr,
362 .transformFeedback = true,
363 .geometryStreams = true,
364 };
365 SetNext(next, transform_feedback);
366 } else {
367 LOG_INFO(Render_Vulkan, "Device doesn't support transform feedbacks");
368 }
369
370 VkPhysicalDeviceCustomBorderColorFeaturesEXT custom_border;
371 if (ext_custom_border_color) {
372 custom_border = {
373 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT,
374 .pNext = nullptr,
375 .customBorderColors = VK_TRUE,
376 .customBorderColorWithoutFormat = VK_TRUE,
377 };
378 SetNext(next, custom_border);
379 } else {
380 LOG_INFO(Render_Vulkan, "Device doesn't support custom border colors");
381 }
382
383 VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state;
384 if (ext_extended_dynamic_state) {
385 dynamic_state = {
386 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT,
387 .pNext = nullptr,
388 .extendedDynamicState = VK_TRUE,
389 };
390 SetNext(next, dynamic_state);
391 } else {
392 LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state");
393 }
394
395 VkPhysicalDeviceRobustness2FeaturesEXT robustness2;
396 if (ext_robustness2) {
397 robustness2 = {
398 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT,
399 .pNext = nullptr,
400 .robustBufferAccess2 = false,
401 .robustImageAccess2 = true,
402 .nullDescriptor = true,
403 };
404 SetNext(next, robustness2);
405 } else {
406 LOG_INFO(Render_Vulkan, "Device doesn't support robustness2");
407 }
408
409 if (!ext_depth_range_unrestricted) {
410 LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted");
411 }
412
413 VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv;
414 if (nv_device_diagnostics_config) {
415 nsight_aftermath_tracker.Initialize();
416
417 diagnostics_nv = {
418 .sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV,
419 .pNext = &features2,
420 .flags = VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV |
421 VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV |
422 VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV,
423 };
424 first_next = &diagnostics_nv;
425 }
426 logical = vk::Device::Create(physical, queue_cis, extensions, first_next, dld);
427
428 CollectTelemetryParameters();
429 CollectToolingInfo();
430
431 if (ext_extended_dynamic_state && driver_id == VK_DRIVER_ID_MESA_RADV) {
432 LOG_WARNING(
433 Render_Vulkan,
434 "Blacklisting RADV for VK_EXT_extended_dynamic state, likely due to a bug in yuzu");
435 ext_extended_dynamic_state = false;
436 }
437 if (ext_extended_dynamic_state && IsRDNA(properties.deviceName, driver_id)) {
438 // AMD's proprietary driver supports VK_EXT_extended_dynamic_state but on RDNA devices it
439 // seems to cause stability issues
440 LOG_WARNING(
441 Render_Vulkan,
442 "Blacklisting AMD proprietary on RDNA devices from VK_EXT_extended_dynamic_state");
443 ext_extended_dynamic_state = false;
444 }
445
446 graphics_queue = logical.GetQueue(graphics_family);
447 present_queue = logical.GetQueue(present_family);
448
449 use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue();
450}
451
452Device::~Device() = default;
453
454VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage,
455 FormatType format_type) const {
456 if (IsFormatSupported(wanted_format, wanted_usage, format_type)) {
457 return wanted_format;
458 }
459 // The wanted format is not supported by hardware, search for alternatives
460 const VkFormat* alternatives = GetFormatAlternatives(wanted_format);
461 if (alternatives == nullptr) {
462 UNREACHABLE_MSG("Format={} with usage={} and type={} has no defined alternatives and host "
463 "hardware does not support it",
464 wanted_format, wanted_usage, format_type);
465 return wanted_format;
466 }
467
468 std::size_t i = 0;
469 for (VkFormat alternative = *alternatives; alternative; alternative = alternatives[++i]) {
470 if (!IsFormatSupported(alternative, wanted_usage, format_type)) {
471 continue;
472 }
473 LOG_WARNING(Render_Vulkan,
474 "Emulating format={} with alternative format={} with usage={} and type={}",
475 wanted_format, alternative, wanted_usage, format_type);
476 return alternative;
477 }
478
479 // No alternatives found, panic
480 UNREACHABLE_MSG("Format={} with usage={} and type={} is not supported by the host hardware and "
481 "doesn't support any of the alternatives",
482 wanted_format, wanted_usage, format_type);
483 return wanted_format;
484}
485
486void Device::ReportLoss() const {
487 LOG_CRITICAL(Render_Vulkan, "Device loss occured!");
488
489 // Wait for the log to flush and for Nsight Aftermath to dump the results
490 std::this_thread::sleep_for(std::chrono::seconds{15});
491}
492
493void Device::SaveShader(const std::vector<u32>& spirv) const {
494 nsight_aftermath_tracker.SaveShader(spirv);
495}
496
497bool Device::IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const {
498 // Disable for now to avoid converting ASTC twice.
499 static constexpr std::array astc_formats = {
500 VK_FORMAT_ASTC_4x4_UNORM_BLOCK, VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
501 VK_FORMAT_ASTC_5x4_UNORM_BLOCK, VK_FORMAT_ASTC_5x4_SRGB_BLOCK,
502 VK_FORMAT_ASTC_5x5_UNORM_BLOCK, VK_FORMAT_ASTC_5x5_SRGB_BLOCK,
503 VK_FORMAT_ASTC_6x5_UNORM_BLOCK, VK_FORMAT_ASTC_6x5_SRGB_BLOCK,
504 VK_FORMAT_ASTC_6x6_UNORM_BLOCK, VK_FORMAT_ASTC_6x6_SRGB_BLOCK,
505 VK_FORMAT_ASTC_8x5_UNORM_BLOCK, VK_FORMAT_ASTC_8x5_SRGB_BLOCK,
506 VK_FORMAT_ASTC_8x6_UNORM_BLOCK, VK_FORMAT_ASTC_8x6_SRGB_BLOCK,
507 VK_FORMAT_ASTC_8x8_UNORM_BLOCK, VK_FORMAT_ASTC_8x8_SRGB_BLOCK,
508 VK_FORMAT_ASTC_10x5_UNORM_BLOCK, VK_FORMAT_ASTC_10x5_SRGB_BLOCK,
509 VK_FORMAT_ASTC_10x6_UNORM_BLOCK, VK_FORMAT_ASTC_10x6_SRGB_BLOCK,
510 VK_FORMAT_ASTC_10x8_UNORM_BLOCK, VK_FORMAT_ASTC_10x8_SRGB_BLOCK,
511 VK_FORMAT_ASTC_10x10_UNORM_BLOCK, VK_FORMAT_ASTC_10x10_SRGB_BLOCK,
512 VK_FORMAT_ASTC_12x10_UNORM_BLOCK, VK_FORMAT_ASTC_12x10_SRGB_BLOCK,
513 VK_FORMAT_ASTC_12x12_UNORM_BLOCK, VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
514 };
515 if (!features.textureCompressionASTC_LDR) {
516 return false;
517 }
518 const auto format_feature_usage{
519 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT |
520 VK_FORMAT_FEATURE_BLIT_DST_BIT | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
521 VK_FORMAT_FEATURE_TRANSFER_DST_BIT};
522 for (const auto format : astc_formats) {
523 const auto physical_format_properties{physical.GetFormatProperties(format)};
524 if ((physical_format_properties.optimalTilingFeatures & format_feature_usage) == 0) {
525 return false;
526 }
527 }
528 return true;
529}
530
531bool Device::TestDepthStencilBlits() const {
532 static constexpr VkFormatFeatureFlags required_features =
533 VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT;
534 const auto test_features = [](VkFormatProperties props) {
535 return (props.optimalTilingFeatures & required_features) == required_features;
536 };
537 return test_features(format_properties.at(VK_FORMAT_D32_SFLOAT_S8_UINT)) &&
538 test_features(format_properties.at(VK_FORMAT_D24_UNORM_S8_UINT));
539}
540
541bool Device::IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage,
542 FormatType format_type) const {
543 const auto it = format_properties.find(wanted_format);
544 if (it == format_properties.end()) {
545 UNIMPLEMENTED_MSG("Unimplemented format query={}", wanted_format);
546 return true;
547 }
548 const auto supported_usage = GetFormatFeatures(it->second, format_type);
549 return (supported_usage & wanted_usage) == wanted_usage;
550}
551
552void Device::CheckSuitability() const {
553 std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions;
554 for (const VkExtensionProperties& property : physical.EnumerateDeviceExtensionProperties()) {
555 for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
556 if (available_extensions[i]) {
557 continue;
558 }
559 const std::string_view name{property.extensionName};
560 available_extensions[i] = name == REQUIRED_EXTENSIONS[i];
561 }
562 }
563 for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
564 if (available_extensions[i]) {
565 continue;
566 }
567 LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]);
568 throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
569 }
570 struct LimitTuple {
571 u32 minimum;
572 u32 value;
573 const char* name;
574 };
575 const VkPhysicalDeviceLimits& limits{properties.limits};
576 const std::array limits_report{
577 LimitTuple{65536, limits.maxUniformBufferRange, "maxUniformBufferRange"},
578 LimitTuple{16, limits.maxViewports, "maxViewports"},
579 LimitTuple{8, limits.maxColorAttachments, "maxColorAttachments"},
580 LimitTuple{8, limits.maxClipDistances, "maxClipDistances"},
581 };
582 for (const auto& tuple : limits_report) {
583 if (tuple.value < tuple.minimum) {
584 LOG_ERROR(Render_Vulkan, "{} has to be {} or greater but it is {}", tuple.name,
585 tuple.minimum, tuple.value);
586 throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
587 }
588 }
589 const VkPhysicalDeviceFeatures features{physical.GetFeatures()};
590 const std::array feature_report{
591 std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),
592 std::make_pair(features.imageCubeArray, "imageCubeArray"),
593 std::make_pair(features.independentBlend, "independentBlend"),
594 std::make_pair(features.depthClamp, "depthClamp"),
595 std::make_pair(features.samplerAnisotropy, "samplerAnisotropy"),
596 std::make_pair(features.largePoints, "largePoints"),
597 std::make_pair(features.multiViewport, "multiViewport"),
598 std::make_pair(features.depthBiasClamp, "depthBiasClamp"),
599 std::make_pair(features.geometryShader, "geometryShader"),
600 std::make_pair(features.tessellationShader, "tessellationShader"),
601 std::make_pair(features.occlusionQueryPrecise, "occlusionQueryPrecise"),
602 std::make_pair(features.fragmentStoresAndAtomics, "fragmentStoresAndAtomics"),
603 std::make_pair(features.shaderImageGatherExtended, "shaderImageGatherExtended"),
604 std::make_pair(features.shaderStorageImageMultisample, "shaderStorageImageMultisample"),
605 std::make_pair(features.shaderStorageImageWriteWithoutFormat,
606 "shaderStorageImageWriteWithoutFormat"),
607 };
608 for (const auto& [is_supported, name] : feature_report) {
609 if (is_supported) {
610 continue;
611 }
612 LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name);
613 throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
614 }
615}
616
617std::vector<const char*> Device::LoadExtensions() {
618 std::vector<const char*> extensions;
619 extensions.reserve(7 + REQUIRED_EXTENSIONS.size());
620 extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end());
621
622 bool has_khr_shader_float16_int8{};
623 bool has_ext_subgroup_size_control{};
624 bool has_ext_transform_feedback{};
625 bool has_ext_custom_border_color{};
626 bool has_ext_extended_dynamic_state{};
627 bool has_ext_robustness2{};
628 for (const VkExtensionProperties& extension : physical.EnumerateDeviceExtensionProperties()) {
629 const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name,
630 bool push) {
631 if (extension.extensionName != std::string_view(name)) {
632 return;
633 }
634 if (push) {
635 extensions.push_back(name);
636 }
637 if (status) {
638 status->get() = true;
639 }
640 };
641 test(nv_viewport_swizzle, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME, true);
642 test(khr_uniform_buffer_standard_layout,
643 VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, true);
644 test(has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false);
645 test(ext_depth_range_unrestricted, VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true);
646 test(ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true);
647 test(ext_sampler_filter_minmax, VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME, true);
648 test(ext_shader_viewport_index_layer, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME,
649 true);
650 test(ext_tooling_info, VK_EXT_TOOLING_INFO_EXTENSION_NAME, true);
651 test(ext_shader_stencil_export, VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, true);
652 test(has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, false);
653 test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false);
654 test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false);
655 test(has_ext_robustness2, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, false);
656 test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false);
657 if (Settings::values.renderer_debug) {
658 test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME,
659 true);
660 }
661 }
662
663 VkPhysicalDeviceFeatures2KHR features;
664 features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
665
666 VkPhysicalDeviceProperties2KHR physical_properties;
667 physical_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
668
669 if (has_khr_shader_float16_int8) {
670 VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8_features;
671 float16_int8_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR;
672 float16_int8_features.pNext = nullptr;
673 features.pNext = &float16_int8_features;
674
675 physical.GetFeatures2KHR(features);
676 is_float16_supported = float16_int8_features.shaderFloat16;
677 extensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME);
678 }
679
680 if (has_ext_subgroup_size_control) {
681 VkPhysicalDeviceSubgroupSizeControlFeaturesEXT subgroup_features;
682 subgroup_features.sType =
683 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT;
684 subgroup_features.pNext = nullptr;
685 features.pNext = &subgroup_features;
686 physical.GetFeatures2KHR(features);
687
688 VkPhysicalDeviceSubgroupSizeControlPropertiesEXT subgroup_properties;
689 subgroup_properties.sType =
690 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT;
691 subgroup_properties.pNext = nullptr;
692 physical_properties.pNext = &subgroup_properties;
693 physical.GetProperties2KHR(physical_properties);
694
695 is_warp_potentially_bigger = subgroup_properties.maxSubgroupSize > GuestWarpSize;
696
697 if (subgroup_features.subgroupSizeControl &&
698 subgroup_properties.minSubgroupSize <= GuestWarpSize &&
699 subgroup_properties.maxSubgroupSize >= GuestWarpSize) {
700 extensions.push_back(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME);
701 guest_warp_stages = subgroup_properties.requiredSubgroupSizeStages;
702 }
703 } else {
704 is_warp_potentially_bigger = true;
705 }
706
707 if (has_ext_transform_feedback) {
708 VkPhysicalDeviceTransformFeedbackFeaturesEXT tfb_features;
709 tfb_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT;
710 tfb_features.pNext = nullptr;
711 features.pNext = &tfb_features;
712 physical.GetFeatures2KHR(features);
713
714 VkPhysicalDeviceTransformFeedbackPropertiesEXT tfb_properties;
715 tfb_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
716 tfb_properties.pNext = nullptr;
717 physical_properties.pNext = &tfb_properties;
718 physical.GetProperties2KHR(physical_properties);
719
720 if (tfb_features.transformFeedback && tfb_features.geometryStreams &&
721 tfb_properties.maxTransformFeedbackStreams >= 4 &&
722 tfb_properties.maxTransformFeedbackBuffers && tfb_properties.transformFeedbackQueries &&
723 tfb_properties.transformFeedbackDraw) {
724 extensions.push_back(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
725 ext_transform_feedback = true;
726 }
727 }
728
729 if (has_ext_custom_border_color) {
730 VkPhysicalDeviceCustomBorderColorFeaturesEXT border_features;
731 border_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT;
732 border_features.pNext = nullptr;
733 features.pNext = &border_features;
734 physical.GetFeatures2KHR(features);
735
736 if (border_features.customBorderColors && border_features.customBorderColorWithoutFormat) {
737 extensions.push_back(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
738 ext_custom_border_color = true;
739 }
740 }
741
742 if (has_ext_extended_dynamic_state) {
743 VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state;
744 dynamic_state.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT;
745 dynamic_state.pNext = nullptr;
746 features.pNext = &dynamic_state;
747 physical.GetFeatures2KHR(features);
748
749 if (dynamic_state.extendedDynamicState) {
750 extensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
751 ext_extended_dynamic_state = true;
752 }
753 }
754
755 if (has_ext_robustness2) {
756 VkPhysicalDeviceRobustness2FeaturesEXT robustness2;
757 robustness2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT;
758 robustness2.pNext = nullptr;
759 features.pNext = &robustness2;
760 physical.GetFeatures2KHR(features);
761 if (robustness2.nullDescriptor && robustness2.robustImageAccess2) {
762 extensions.push_back(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
763 ext_robustness2 = true;
764 }
765 }
766
767 return extensions;
768}
769
770void Device::SetupFamilies(VkSurfaceKHR surface) {
771 const std::vector queue_family_properties = physical.GetQueueFamilyProperties();
772 std::optional<u32> graphics;
773 std::optional<u32> present;
774 for (u32 index = 0; index < static_cast<u32>(queue_family_properties.size()); ++index) {
775 if (graphics && present) {
776 break;
777 }
778 const VkQueueFamilyProperties& queue_family = queue_family_properties[index];
779 if (queue_family.queueCount == 0) {
780 continue;
781 }
782 if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
783 graphics = index;
784 }
785 if (physical.GetSurfaceSupportKHR(index, surface)) {
786 present = index;
787 }
788 }
789 if (!graphics) {
790 LOG_ERROR(Render_Vulkan, "Device lacks a graphics queue");
791 throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
792 }
793 if (!present) {
794 LOG_ERROR(Render_Vulkan, "Device lacks a present queue");
795 throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
796 }
797 graphics_family = *graphics;
798 present_family = *present;
799}
800
801void Device::SetupFeatures() {
802 const auto supported_features{physical.GetFeatures()};
803 is_formatless_image_load_supported = supported_features.shaderStorageImageReadWithoutFormat;
804 is_blit_depth_stencil_supported = TestDepthStencilBlits();
805 is_optimal_astc_supported = IsOptimalAstcSupported(supported_features);
806}
807
808void Device::CollectTelemetryParameters() {
809 VkPhysicalDeviceDriverPropertiesKHR driver{
810 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR,
811 .pNext = nullptr,
812 .driverID = {},
813 .driverName = {},
814 .driverInfo = {},
815 .conformanceVersion = {},
816 };
817
818 VkPhysicalDeviceProperties2KHR device_properties{
819 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
820 .pNext = &driver,
821 .properties = {},
822 };
823 physical.GetProperties2KHR(device_properties);
824
825 driver_id = driver.driverID;
826 vendor_name = driver.driverName;
827
828 const std::vector extensions = physical.EnumerateDeviceExtensionProperties();
829 reported_extensions.reserve(std::size(extensions));
830 for (const auto& extension : extensions) {
831 reported_extensions.emplace_back(extension.extensionName);
832 }
833}
834
835void Device::CollectToolingInfo() {
836 if (!ext_tooling_info) {
837 return;
838 }
839 const auto vkGetPhysicalDeviceToolPropertiesEXT =
840 reinterpret_cast<PFN_vkGetPhysicalDeviceToolPropertiesEXT>(
841 dld.vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceToolPropertiesEXT"));
842 if (!vkGetPhysicalDeviceToolPropertiesEXT) {
843 return;
844 }
845 u32 tool_count = 0;
846 if (vkGetPhysicalDeviceToolPropertiesEXT(physical, &tool_count, nullptr) != VK_SUCCESS) {
847 return;
848 }
849 std::vector<VkPhysicalDeviceToolPropertiesEXT> tools(tool_count);
850 if (vkGetPhysicalDeviceToolPropertiesEXT(physical, &tool_count, tools.data()) != VK_SUCCESS) {
851 return;
852 }
853 for (const VkPhysicalDeviceToolPropertiesEXT& tool : tools) {
854 const std::string_view name = tool.name;
855 LOG_INFO(Render_Vulkan, "{}", name);
856 has_renderdoc = has_renderdoc || name == "RenderDoc";
857 has_nsight_graphics = has_nsight_graphics || name == "NVIDIA Nsight Graphics";
858 }
859}
860
861std::vector<VkDeviceQueueCreateInfo> Device::GetDeviceQueueCreateInfos() const {
862 static constexpr float QUEUE_PRIORITY = 1.0f;
863
864 std::unordered_set<u32> unique_queue_families{graphics_family, present_family};
865 std::vector<VkDeviceQueueCreateInfo> queue_cis;
866 queue_cis.reserve(unique_queue_families.size());
867
868 for (const u32 queue_family : unique_queue_families) {
869 auto& ci = queue_cis.emplace_back(VkDeviceQueueCreateInfo{
870 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
871 .pNext = nullptr,
872 .flags = 0,
873 .queueFamilyIndex = queue_family,
874 .queueCount = 1,
875 .pQueuePriorities = nullptr,
876 });
877 ci.pQueuePriorities = &QUEUE_PRIORITY;
878 }
879
880 return queue_cis;
881}
882
883} // namespace Vulkan
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
new file mode 100644
index 000000000..b2651e049
--- /dev/null
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -0,0 +1,306 @@
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/vulkan_common/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 Device final {
26public:
27 explicit Device(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface,
28 const vk::InstanceDispatch& dld);
29 ~Device();
30
31 /**
32 * Returns a format supported by the device for the passed requeriments.
33 * @param wanted_format The ideal format to be returned. It may not be the returned format.
34 * @param wanted_usage The usage that must be fulfilled even if the format is not supported.
35 * @param format_type Format type usage.
36 * @returns A format supported by the device.
37 */
38 VkFormat GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage,
39 FormatType format_type) const;
40
41 /// Reports a device loss.
42 void ReportLoss() const;
43
44 /// Reports a shader to Nsight Aftermath.
45 void SaveShader(const std::vector<u32>& spirv) const;
46
47 /// Returns the dispatch loader with direct function pointers of the device.
48 const vk::DeviceDispatch& GetDispatchLoader() const {
49 return dld;
50 }
51
52 /// Returns the logical device.
53 const vk::Device& GetLogical() const {
54 return logical;
55 }
56
57 /// Returns the physical device.
58 vk::PhysicalDevice GetPhysical() const {
59 return physical;
60 }
61
62 /// Returns the main graphics queue.
63 vk::Queue GetGraphicsQueue() const {
64 return graphics_queue;
65 }
66
67 /// Returns the main present queue.
68 vk::Queue GetPresentQueue() const {
69 return present_queue;
70 }
71
72 /// Returns main graphics queue family index.
73 u32 GetGraphicsFamily() const {
74 return graphics_family;
75 }
76
77 /// Returns main present queue family index.
78 u32 GetPresentFamily() const {
79 return present_family;
80 }
81
82 /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers.
83 u32 ApiVersion() const {
84 return properties.apiVersion;
85 }
86
87 /// Returns the current driver version provided in Vulkan-formatted version numbers.
88 u32 GetDriverVersion() const {
89 return properties.driverVersion;
90 }
91
92 /// Returns the device name.
93 std::string_view GetModelName() const {
94 return properties.deviceName;
95 }
96
97 /// Returns the driver ID.
98 VkDriverIdKHR GetDriverID() const {
99 return driver_id;
100 }
101
102 /// Returns uniform buffer alignment requeriment.
103 VkDeviceSize GetUniformBufferAlignment() const {
104 return properties.limits.minUniformBufferOffsetAlignment;
105 }
106
107 /// Returns storage alignment requeriment.
108 VkDeviceSize GetStorageBufferAlignment() const {
109 return properties.limits.minStorageBufferOffsetAlignment;
110 }
111
112 /// Returns the maximum range for storage buffers.
113 VkDeviceSize GetMaxStorageBufferRange() const {
114 return properties.limits.maxStorageBufferRange;
115 }
116
117 /// Returns the maximum size for push constants.
118 VkDeviceSize GetMaxPushConstantsSize() const {
119 return properties.limits.maxPushConstantsSize;
120 }
121
122 /// Returns the maximum size for shared memory.
123 u32 GetMaxComputeSharedMemorySize() const {
124 return properties.limits.maxComputeSharedMemorySize;
125 }
126
127 /// Returns true if ASTC is natively supported.
128 bool IsOptimalAstcSupported() const {
129 return is_optimal_astc_supported;
130 }
131
132 /// Returns true if the device supports float16 natively
133 bool IsFloat16Supported() const {
134 return is_float16_supported;
135 }
136
137 /// Returns true if the device warp size can potentially be bigger than guest's warp size.
138 bool IsWarpSizePotentiallyBiggerThanGuest() const {
139 return is_warp_potentially_bigger;
140 }
141
142 /// Returns true if the device can be forced to use the guest warp size.
143 bool IsGuestWarpSizeSupported(VkShaderStageFlagBits stage) const {
144 return guest_warp_stages & stage;
145 }
146
147 /// Returns true if formatless image load is supported.
148 bool IsFormatlessImageLoadSupported() const {
149 return is_formatless_image_load_supported;
150 }
151
152 /// Returns true when blitting from and to depth stencil images is supported.
153 bool IsBlitDepthStencilSupported() const {
154 return is_blit_depth_stencil_supported;
155 }
156
157 /// Returns true if the device supports VK_NV_viewport_swizzle.
158 bool IsNvViewportSwizzleSupported() const {
159 return nv_viewport_swizzle;
160 }
161
162 /// Returns true if the device supports VK_EXT_scalar_block_layout.
163 bool IsKhrUniformBufferStandardLayoutSupported() const {
164 return khr_uniform_buffer_standard_layout;
165 }
166
167 /// Returns true if the device supports VK_EXT_index_type_uint8.
168 bool IsExtIndexTypeUint8Supported() const {
169 return ext_index_type_uint8;
170 }
171
172 /// Returns true if the device supports VK_EXT_sampler_filter_minmax.
173 bool IsExtSamplerFilterMinmaxSupported() const {
174 return ext_sampler_filter_minmax;
175 }
176
177 /// Returns true if the device supports VK_EXT_depth_range_unrestricted.
178 bool IsExtDepthRangeUnrestrictedSupported() const {
179 return ext_depth_range_unrestricted;
180 }
181
182 /// Returns true if the device supports VK_EXT_shader_viewport_index_layer.
183 bool IsExtShaderViewportIndexLayerSupported() const {
184 return ext_shader_viewport_index_layer;
185 }
186
187 /// Returns true if the device supports VK_EXT_transform_feedback.
188 bool IsExtTransformFeedbackSupported() const {
189 return ext_transform_feedback;
190 }
191
192 /// Returns true if the device supports VK_EXT_custom_border_color.
193 bool IsExtCustomBorderColorSupported() const {
194 return ext_custom_border_color;
195 }
196
197 /// Returns true if the device supports VK_EXT_extended_dynamic_state.
198 bool IsExtExtendedDynamicStateSupported() const {
199 return ext_extended_dynamic_state;
200 }
201
202 /// Returns true if the device supports VK_EXT_shader_stencil_export.
203 bool IsExtShaderStencilExportSupported() const {
204 return ext_shader_stencil_export;
205 }
206
207 /// Returns true when a known debugging tool is attached.
208 bool HasDebuggingToolAttached() const {
209 return has_renderdoc || has_nsight_graphics;
210 }
211
212 /// Returns the vendor name reported from Vulkan.
213 std::string_view GetVendorName() const {
214 return vendor_name;
215 }
216
217 /// Returns the list of available extensions.
218 const std::vector<std::string>& GetAvailableExtensions() const {
219 return reported_extensions;
220 }
221
222 /// Returns true if the setting for async shader compilation is enabled.
223 bool UseAsynchronousShaders() const {
224 return use_asynchronous_shaders;
225 }
226
227private:
228 /// Checks if the physical device is suitable.
229 void CheckSuitability() const;
230
231 /// Loads extensions into a vector and stores available ones in this object.
232 std::vector<const char*> LoadExtensions();
233
234 /// Sets up queue families.
235 void SetupFamilies(VkSurfaceKHR surface);
236
237 /// Sets up device features.
238 void SetupFeatures();
239
240 /// Collects telemetry information from the device.
241 void CollectTelemetryParameters();
242
243 /// Collects information about attached tools.
244 void CollectToolingInfo();
245
246 /// Returns a list of queue initialization descriptors.
247 std::vector<VkDeviceQueueCreateInfo> GetDeviceQueueCreateInfos() const;
248
249 /// Returns true if ASTC textures are natively supported.
250 bool IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const;
251
252 /// Returns true if the device natively supports blitting depth stencil images.
253 bool TestDepthStencilBlits() const;
254
255 /// Returns true if a format is supported.
256 bool IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage,
257 FormatType format_type) const;
258
259 VkInstance instance; ///< Vulkan instance.
260 vk::DeviceDispatch dld; ///< Device function pointers.
261 vk::PhysicalDevice physical; ///< Physical device.
262 VkPhysicalDeviceProperties properties; ///< Device properties.
263 vk::Device logical; ///< Logical device.
264 vk::Queue graphics_queue; ///< Main graphics queue.
265 vk::Queue present_queue; ///< Main present queue.
266 u32 instance_version{}; ///< Vulkan onstance version.
267 u32 graphics_family{}; ///< Main graphics queue family index.
268 u32 present_family{}; ///< Main present queue family index.
269 VkDriverIdKHR driver_id{}; ///< Driver ID.
270 VkShaderStageFlags guest_warp_stages{}; ///< Stages where the guest warp size can be forced.ed
271 bool is_optimal_astc_supported{}; ///< Support for native ASTC.
272 bool is_float16_supported{}; ///< Support for float16 arithmetics.
273 bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest.
274 bool is_formatless_image_load_supported{}; ///< Support for shader image read without format.
275 bool is_blit_depth_stencil_supported{}; ///< Support for blitting from and to depth stencil.
276 bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle.
277 bool khr_uniform_buffer_standard_layout{}; ///< Support for std430 on UBOs.
278 bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8.
279 bool ext_sampler_filter_minmax{}; ///< Support for VK_EXT_sampler_filter_minmax.
280 bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted.
281 bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer.
282 bool ext_tooling_info{}; ///< Support for VK_EXT_tooling_info.
283 bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback.
284 bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color.
285 bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state.
286 bool ext_robustness2{}; ///< Support for VK_EXT_robustness2.
287 bool ext_shader_stencil_export{}; ///< Support for VK_EXT_shader_stencil_export.
288 bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config.
289 bool has_renderdoc{}; ///< Has RenderDoc attached
290 bool has_nsight_graphics{}; ///< Has Nsight Graphics attached
291
292 // Asynchronous Graphics Pipeline setting
293 bool use_asynchronous_shaders{}; ///< Setting to use asynchronous shaders/graphics pipeline
294
295 // Telemetry parameters
296 std::string vendor_name; ///< Device's driver name.
297 std::vector<std::string> reported_extensions; ///< Reported Vulkan extensions.
298
299 /// Format properties dictionary.
300 std::unordered_map<VkFormat, VkFormatProperties> format_properties;
301
302 /// Nsight Aftermath GPU crash tracker
303 NsightAftermathTracker nsight_aftermath_tracker;
304};
305
306} // namespace Vulkan