summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/input.h3
-rw-r--r--src/core/hid/emulated_controller.cpp10
-rw-r--r--src/input_common/helpers/stick_from_buttons.cpp17
-rw-r--r--src/input_common/main.cpp26
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate_program.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp4
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp19
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp2
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp1377
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h441
-rw-r--r--src/yuzu/main.cpp10
11 files changed, 715 insertions, 1196 deletions
diff --git a/src/common/input.h b/src/common/input.h
index fc14fd7bf..d27b1d772 100644
--- a/src/common/input.h
+++ b/src/common/input.h
@@ -292,9 +292,6 @@ class InputDevice {
292public: 292public:
293 virtual ~InputDevice() = default; 293 virtual ~InputDevice() = default;
294 294
295 // Request input device to update if necessary
296 virtual void SoftUpdate() {}
297
298 // Force input device to update data regardless of the current state 295 // Force input device to update data regardless of the current state
299 virtual void ForceUpdate() {} 296 virtual void ForceUpdate() {}
300 297
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 71364c323..7a01f3f4c 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -1434,16 +1434,6 @@ AnalogSticks EmulatedController::GetSticks() const {
1434 return {}; 1434 return {};
1435 } 1435 }
1436 1436
1437 // Some drivers like stick from buttons need constant refreshing
1438 for (auto& device : stick_devices) {
1439 if (!device) {
1440 continue;
1441 }
1442 lock.unlock();
1443 device->SoftUpdate();
1444 lock.lock();
1445 }
1446
1447 return controller.analog_stick_state; 1437 return controller.analog_stick_state;
1448} 1438}
1449 1439
diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp
index 82aa6ac2f..f3a0b3419 100644
--- a/src/input_common/helpers/stick_from_buttons.cpp
+++ b/src/input_common/helpers/stick_from_buttons.cpp
@@ -13,11 +13,11 @@ class Stick final : public Common::Input::InputDevice {
13public: 13public:
14 using Button = std::unique_ptr<Common::Input::InputDevice>; 14 using Button = std::unique_ptr<Common::Input::InputDevice>;
15 15
16 Stick(Button up_, Button down_, Button left_, Button right_, Button modifier_, 16 Stick(Button up_, Button down_, Button left_, Button right_, Button modifier_, Button updater_,
17 float modifier_scale_, float modifier_angle_) 17 float modifier_scale_, float modifier_angle_)
18 : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), 18 : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)),
19 right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_), 19 right(std::move(right_)), modifier(std::move(modifier_)), updater(std::move(updater_)),
20 modifier_angle(modifier_angle_) { 20 modifier_scale(modifier_scale_), modifier_angle(modifier_angle_) {
21 up->SetCallback({ 21 up->SetCallback({
22 .on_change = 22 .on_change =
23 [this](const Common::Input::CallbackStatus& callback_) { 23 [this](const Common::Input::CallbackStatus& callback_) {
@@ -48,6 +48,9 @@ public:
48 UpdateModButtonStatus(callback_); 48 UpdateModButtonStatus(callback_);
49 }, 49 },
50 }); 50 });
51 updater->SetCallback({
52 .on_change = [this](const Common::Input::CallbackStatus& callback_) { SoftUpdate(); },
53 });
51 last_x_axis_value = 0.0f; 54 last_x_axis_value = 0.0f;
52 last_y_axis_value = 0.0f; 55 last_y_axis_value = 0.0f;
53 } 56 }
@@ -248,7 +251,7 @@ public:
248 modifier->ForceUpdate(); 251 modifier->ForceUpdate();
249 } 252 }
250 253
251 void SoftUpdate() override { 254 void SoftUpdate() {
252 Common::Input::CallbackStatus status{ 255 Common::Input::CallbackStatus status{
253 .type = Common::Input::InputType::Stick, 256 .type = Common::Input::InputType::Stick,
254 .stick_status = GetStatus(), 257 .stick_status = GetStatus(),
@@ -308,6 +311,7 @@ private:
308 Button left; 311 Button left;
309 Button right; 312 Button right;
310 Button modifier; 313 Button modifier;
314 Button updater;
311 float modifier_scale{}; 315 float modifier_scale{};
312 float modifier_angle{}; 316 float modifier_angle{};
313 float angle{}; 317 float angle{};
@@ -331,11 +335,12 @@ std::unique_ptr<Common::Input::InputDevice> StickFromButton::Create(
331 auto left = Common::Input::CreateInputDeviceFromString(params.Get("left", null_engine)); 335 auto left = Common::Input::CreateInputDeviceFromString(params.Get("left", null_engine));
332 auto right = Common::Input::CreateInputDeviceFromString(params.Get("right", null_engine)); 336 auto right = Common::Input::CreateInputDeviceFromString(params.Get("right", null_engine));
333 auto modifier = Common::Input::CreateInputDeviceFromString(params.Get("modifier", null_engine)); 337 auto modifier = Common::Input::CreateInputDeviceFromString(params.Get("modifier", null_engine));
338 auto updater = Common::Input::CreateInputDeviceFromString("engine:updater,button:0");
334 auto modifier_scale = params.Get("modifier_scale", 0.5f); 339 auto modifier_scale = params.Get("modifier_scale", 0.5f);
335 auto modifier_angle = params.Get("modifier_angle", 5.5f); 340 auto modifier_angle = params.Get("modifier_angle", 5.5f);
336 return std::make_unique<Stick>(std::move(up), std::move(down), std::move(left), 341 return std::make_unique<Stick>(std::move(up), std::move(down), std::move(left),
337 std::move(right), std::move(modifier), modifier_scale, 342 std::move(right), std::move(modifier), std::move(updater),
338 modifier_angle); 343 modifier_scale, modifier_angle);
339} 344}
340 345
341} // namespace InputCommon 346} // namespace InputCommon
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 4dc92f482..e0b2131ed 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -28,6 +28,28 @@
28 28
29namespace InputCommon { 29namespace InputCommon {
30 30
31/// Dummy engine to get periodic updates
32class UpdateEngine final : public InputEngine {
33public:
34 explicit UpdateEngine(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
35 PreSetController(identifier);
36 }
37
38 void PumpEvents() {
39 SetButton(identifier, 0, last_state);
40 last_state = !last_state;
41 }
42
43private:
44 static constexpr PadIdentifier identifier = {
45 .guid = Common::UUID{},
46 .port = 0,
47 .pad = 0,
48 };
49
50 bool last_state{};
51};
52
31struct InputSubsystem::Impl { 53struct InputSubsystem::Impl {
32 template <typename Engine> 54 template <typename Engine>
33 void RegisterEngine(std::string name, std::shared_ptr<Engine>& engine) { 55 void RegisterEngine(std::string name, std::shared_ptr<Engine>& engine) {
@@ -45,6 +67,7 @@ struct InputSubsystem::Impl {
45 void Initialize() { 67 void Initialize() {
46 mapping_factory = std::make_shared<MappingFactory>(); 68 mapping_factory = std::make_shared<MappingFactory>();
47 69
70 RegisterEngine("updater", update_engine);
48 RegisterEngine("keyboard", keyboard); 71 RegisterEngine("keyboard", keyboard);
49 RegisterEngine("mouse", mouse); 72 RegisterEngine("mouse", mouse);
50 RegisterEngine("touch", touch_screen); 73 RegisterEngine("touch", touch_screen);
@@ -74,6 +97,7 @@ struct InputSubsystem::Impl {
74 } 97 }
75 98
76 void Shutdown() { 99 void Shutdown() {
100 UnregisterEngine(update_engine);
77 UnregisterEngine(keyboard); 101 UnregisterEngine(keyboard);
78 UnregisterEngine(mouse); 102 UnregisterEngine(mouse);
79 UnregisterEngine(touch_screen); 103 UnregisterEngine(touch_screen);
@@ -252,6 +276,7 @@ struct InputSubsystem::Impl {
252 } 276 }
253 277
254 void PumpEvents() const { 278 void PumpEvents() const {
279 update_engine->PumpEvents();
255#ifdef HAVE_SDL2 280#ifdef HAVE_SDL2
256 sdl->PumpEvents(); 281 sdl->PumpEvents();
257#endif 282#endif
@@ -263,6 +288,7 @@ struct InputSubsystem::Impl {
263 288
264 std::shared_ptr<MappingFactory> mapping_factory; 289 std::shared_ptr<MappingFactory> mapping_factory;
265 290
291 std::shared_ptr<UpdateEngine> update_engine;
266 std::shared_ptr<Keyboard> keyboard; 292 std::shared_ptr<Keyboard> keyboard;
267 std::shared_ptr<Mouse> mouse; 293 std::shared_ptr<Mouse> mouse;
268 std::shared_ptr<TouchScreen> touch_screen; 294 std::shared_ptr<TouchScreen> touch_screen;
diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp
index a3b99e24d..a42453e90 100644
--- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp
@@ -259,7 +259,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
259 program.is_geometry_passthrough = sph.common0.geometry_passthrough != 0; 259 program.is_geometry_passthrough = sph.common0.geometry_passthrough != 0;
260 if (program.is_geometry_passthrough) { 260 if (program.is_geometry_passthrough) {
261 const auto& mask{env.GpPassthroughMask()}; 261 const auto& mask{env.GpPassthroughMask()};
262 for (size_t i = 0; i < program.info.passthrough.mask.size(); ++i) { 262 for (size_t i = 0; i < mask.size() * 32; ++i) {
263 program.info.passthrough.mask[i] = ((mask[i / 32] >> (i % 32)) & 1) == 0; 263 program.info.passthrough.mask[i] = ((mask[i / 32] >> (i % 32)) & 1) == 0;
264 } 264 }
265 265
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 7d48af8e1..181857d9c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -139,6 +139,7 @@ void RasterizerOpenGL::LoadDiskResources(u64 title_id, std::stop_token stop_load
139void RasterizerOpenGL::Clear(u32 layer_count) { 139void RasterizerOpenGL::Clear(u32 layer_count) {
140 MICROPROFILE_SCOPE(OpenGL_Clears); 140 MICROPROFILE_SCOPE(OpenGL_Clears);
141 141
142 gpu_memory->FlushCaching();
142 const auto& regs = maxwell3d->regs; 143 const auto& regs = maxwell3d->regs;
143 bool use_color{}; 144 bool use_color{};
144 bool use_depth{}; 145 bool use_depth{};
@@ -207,6 +208,7 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) {
207 MICROPROFILE_SCOPE(OpenGL_Drawing); 208 MICROPROFILE_SCOPE(OpenGL_Drawing);
208 209
209 SCOPE_EXIT({ gpu.TickWork(); }); 210 SCOPE_EXIT({ gpu.TickWork(); });
211 gpu_memory->FlushCaching();
210 query_cache.UpdateCounters(); 212 query_cache.UpdateCounters();
211 213
212 GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()}; 214 GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()};
@@ -319,6 +321,7 @@ void RasterizerOpenGL::DrawIndirect() {
319} 321}
320 322
321void RasterizerOpenGL::DispatchCompute() { 323void RasterizerOpenGL::DispatchCompute() {
324 gpu_memory->FlushCaching();
322 ComputePipeline* const pipeline{shader_cache.CurrentComputePipeline()}; 325 ComputePipeline* const pipeline{shader_cache.CurrentComputePipeline()};
323 if (!pipeline) { 326 if (!pipeline) {
324 return; 327 return;
@@ -526,6 +529,7 @@ void RasterizerOpenGL::TickFrame() {
526} 529}
527 530
528bool RasterizerOpenGL::AccelerateConditionalRendering() { 531bool RasterizerOpenGL::AccelerateConditionalRendering() {
532 gpu_memory->FlushCaching();
529 if (Settings::IsGPULevelHigh()) { 533 if (Settings::IsGPULevelHigh()) {
530 // Reimplement Host conditional rendering. 534 // Reimplement Host conditional rendering.
531 return false; 535 return false;
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 8233c07d3..2a8d9e377 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -60,22 +60,9 @@ std::string GetDriverVersion(const Device& device) {
60 return GetReadableVersion(version); 60 return GetReadableVersion(version);
61} 61}
62 62
63std::string BuildCommaSeparatedExtensions(std::vector<std::string> available_extensions) { 63std::string BuildCommaSeparatedExtensions(
64 std::sort(std::begin(available_extensions), std::end(available_extensions)); 64 const std::set<std::string, std::less<>>& available_extensions) {
65 65 return fmt::format("{}", fmt::join(available_extensions, ","));
66 static constexpr std::size_t AverageExtensionSize = 64;
67 std::string separated_extensions;
68 separated_extensions.reserve(available_extensions.size() * AverageExtensionSize);
69
70 const auto end = std::end(available_extensions);
71 for (auto extension = std::begin(available_extensions); extension != end; ++extension) {
72 if (const bool is_last = extension + 1 == end; is_last) {
73 separated_extensions += *extension;
74 } else {
75 separated_extensions += fmt::format("{},", *extension);
76 }
77 }
78 return separated_extensions;
79} 66}
80 67
81} // Anonymous namespace 68} // Anonymous namespace
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index ed4a72166..b75b8eec6 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -270,6 +270,7 @@ void RasterizerVulkan::Clear(u32 layer_count) {
270 MICROPROFILE_SCOPE(Vulkan_Clearing); 270 MICROPROFILE_SCOPE(Vulkan_Clearing);
271 271
272 FlushWork(); 272 FlushWork();
273 gpu_memory->FlushCaching();
273 274
274 query_cache.UpdateCounters(); 275 query_cache.UpdateCounters();
275 276
@@ -628,6 +629,7 @@ void RasterizerVulkan::TickFrame() {
628} 629}
629 630
630bool RasterizerVulkan::AccelerateConditionalRendering() { 631bool RasterizerVulkan::AccelerateConditionalRendering() {
632 gpu_memory->FlushCaching();
631 if (Settings::IsGPULevelHigh()) { 633 if (Settings::IsGPULevelHigh()) {
632 // TODO(Blinkhawk): Reimplement Host conditional rendering. 634 // TODO(Blinkhawk): Reimplement Host conditional rendering.
633 return false; 635 return false;
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index fd1c5a683..1458ec4c8 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -74,30 +74,6 @@ enum class NvidiaArchitecture {
74 VoltaOrOlder, 74 VoltaOrOlder,
75}; 75};
76 76
77constexpr std::array REQUIRED_EXTENSIONS{
78 VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME,
79 VK_EXT_ROBUSTNESS_2_EXTENSION_NAME,
80#ifdef _WIN32
81 VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
82#endif
83#ifdef __unix__
84 VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
85#endif
86};
87
88constexpr std::array REQUIRED_EXTENSIONS_BEFORE_1_2{
89 VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
90 VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME,
91 VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
92 VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME,
93 VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME,
94 VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
95};
96
97constexpr std::array REQUIRED_EXTENSIONS_BEFORE_1_3{
98 VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME,
99};
100
101template <typename T> 77template <typename T>
102void SetNext(void**& next, T& data) { 78void SetNext(void**& next, T& data) {
103 *next = &data; 79 *next = &data;
@@ -286,24 +262,9 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::Physica
286 return format_properties; 262 return format_properties;
287} 263}
288 264
289std::vector<std::string> GetSupportedExtensions(vk::PhysicalDevice physical) {
290 const std::vector extensions = physical.EnumerateDeviceExtensionProperties();
291 std::vector<std::string> supported_extensions;
292 supported_extensions.reserve(extensions.size());
293 for (const auto& extension : extensions) {
294 supported_extensions.emplace_back(extension.extensionName);
295 }
296 return supported_extensions;
297}
298
299bool IsExtensionSupported(std::span<const std::string> supported_extensions,
300 std::string_view extension) {
301 return std::ranges::find(supported_extensions, extension) != supported_extensions.end();
302}
303
304NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical, 265NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
305 std::span<const std::string> exts) { 266 const std::set<std::string, std::less<>>& exts) {
306 if (IsExtensionSupported(exts, VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME)) { 267 if (exts.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME)) {
307 VkPhysicalDeviceFragmentShadingRatePropertiesKHR shading_rate_props{}; 268 VkPhysicalDeviceFragmentShadingRatePropertiesKHR shading_rate_props{};
308 shading_rate_props.sType = 269 shading_rate_props.sType =
309 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR; 270 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
@@ -316,423 +277,39 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
316 return NvidiaArchitecture::AmpereOrNewer; 277 return NvidiaArchitecture::AmpereOrNewer;
317 } 278 }
318 } 279 }
319 if (IsExtensionSupported(exts, VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME)) { 280 if (exts.contains(VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME)) {
320 return NvidiaArchitecture::Turing; 281 return NvidiaArchitecture::Turing;
321 } 282 }
322 return NvidiaArchitecture::VoltaOrOlder; 283 return NvidiaArchitecture::VoltaOrOlder;
323} 284}
285
286std::vector<const char*> ExtensionListForVulkan(
287 const std::set<std::string, std::less<>>& extensions) {
288 std::vector<const char*> output;
289 for (const auto& extension : extensions) {
290 output.push_back(extension.c_str());
291 }
292 return output;
293}
294
324} // Anonymous namespace 295} // Anonymous namespace
325 296
326Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface, 297Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface,
327 const vk::InstanceDispatch& dld_) 298 const vk::InstanceDispatch& dld_)
328 : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, 299 : instance{instance_}, dld{dld_}, physical{physical_},
329 instance_version{properties.apiVersion}, supported_extensions{GetSupportedExtensions(
330 physical)},
331 format_properties(GetFormatProperties(physical)) { 300 format_properties(GetFormatProperties(physical)) {
332 CheckSuitability(surface != nullptr); 301 if (!GetSuitability(surface != nullptr)) {
302 throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER);
303 }
333 SetupFamilies(surface); 304 SetupFamilies(surface);
334 SetupFeatures();
335 SetupProperties();
336
337 const auto queue_cis = GetDeviceQueueCreateInfos(); 305 const auto queue_cis = GetDeviceQueueCreateInfos();
338 const std::vector extensions = LoadExtensions(surface != nullptr);
339
340 VkPhysicalDeviceFeatures2 features2{
341 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
342 .pNext = nullptr,
343 .features{
344 .robustBufferAccess = true,
345 .fullDrawIndexUint32 = false,
346 .imageCubeArray = true,
347 .independentBlend = true,
348 .geometryShader = true,
349 .tessellationShader = true,
350 .sampleRateShading = true,
351 .dualSrcBlend = true,
352 .logicOp = true,
353 .multiDrawIndirect = true,
354 .drawIndirectFirstInstance = true,
355 .depthClamp = true,
356 .depthBiasClamp = true,
357 .fillModeNonSolid = true,
358 .depthBounds = is_depth_bounds_supported,
359 .wideLines = true,
360 .largePoints = true,
361 .alphaToOne = false,
362 .multiViewport = true,
363 .samplerAnisotropy = true,
364 .textureCompressionETC2 = false,
365 .textureCompressionASTC_LDR = is_optimal_astc_supported,
366 .textureCompressionBC = false,
367 .occlusionQueryPrecise = true,
368 .pipelineStatisticsQuery = false,
369 .vertexPipelineStoresAndAtomics = true,
370 .fragmentStoresAndAtomics = true,
371 .shaderTessellationAndGeometryPointSize = false,
372 .shaderImageGatherExtended = true,
373 .shaderStorageImageExtendedFormats = false,
374 .shaderStorageImageMultisample = is_shader_storage_image_multisample,
375 .shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported,
376 .shaderStorageImageWriteWithoutFormat = true,
377 .shaderUniformBufferArrayDynamicIndexing = false,
378 .shaderSampledImageArrayDynamicIndexing = false,
379 .shaderStorageBufferArrayDynamicIndexing = false,
380 .shaderStorageImageArrayDynamicIndexing = false,
381 .shaderClipDistance = true,
382 .shaderCullDistance = true,
383 .shaderFloat64 = is_shader_float64_supported,
384 .shaderInt64 = is_shader_int64_supported,
385 .shaderInt16 = is_shader_int16_supported,
386 .shaderResourceResidency = false,
387 .shaderResourceMinLod = false,
388 .sparseBinding = false,
389 .sparseResidencyBuffer = false,
390 .sparseResidencyImage2D = false,
391 .sparseResidencyImage3D = false,
392 .sparseResidency2Samples = false,
393 .sparseResidency4Samples = false,
394 .sparseResidency8Samples = false,
395 .sparseResidency16Samples = false,
396 .sparseResidencyAliased = false,
397 .variableMultisampleRate = false,
398 .inheritedQueries = false,
399 },
400 };
401 const void* first_next = &features2;
402 void** next = &features2.pNext;
403
404 VkPhysicalDeviceTimelineSemaphoreFeatures timeline_semaphore{
405 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES,
406 .pNext = nullptr,
407 .timelineSemaphore = true,
408 };
409 SetNext(next, timeline_semaphore);
410
411 VkPhysicalDevice16BitStorageFeatures bit16_storage{
412 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES,
413 .pNext = nullptr,
414 .storageBuffer16BitAccess = true,
415 .uniformAndStorageBuffer16BitAccess = true,
416 .storagePushConstant16 = false,
417 .storageInputOutput16 = false,
418 };
419 SetNext(next, bit16_storage);
420
421 VkPhysicalDevice8BitStorageFeatures bit8_storage{
422 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES,
423 .pNext = nullptr,
424 .storageBuffer8BitAccess = true,
425 .uniformAndStorageBuffer8BitAccess = true,
426 .storagePushConstant8 = false,
427 };
428 SetNext(next, bit8_storage);
429
430 VkPhysicalDeviceRobustness2FeaturesEXT robustness2{
431 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT,
432 .pNext = nullptr,
433 .robustBufferAccess2 = true,
434 .robustImageAccess2 = true,
435 .nullDescriptor = true,
436 };
437 SetNext(next, robustness2);
438
439 VkPhysicalDeviceHostQueryResetFeatures host_query_reset{
440 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES,
441 .pNext = nullptr,
442 .hostQueryReset = true,
443 };
444 SetNext(next, host_query_reset);
445
446 VkPhysicalDeviceVariablePointerFeatures variable_pointers{
447 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES,
448 .pNext = nullptr,
449 .variablePointersStorageBuffer = VK_TRUE,
450 .variablePointers = VK_TRUE,
451 };
452 SetNext(next, variable_pointers);
453
454 VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures demote{
455 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES,
456 .pNext = nullptr,
457 .shaderDemoteToHelperInvocation = true,
458 };
459 SetNext(next, demote);
460
461 VkPhysicalDeviceShaderDrawParametersFeatures draw_parameters{
462 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES,
463 .pNext = nullptr,
464 .shaderDrawParameters = true,
465 };
466 SetNext(next, draw_parameters);
467
468 VkPhysicalDeviceShaderFloat16Int8Features float16_int8;
469 if (is_int8_supported || is_float16_supported) {
470 float16_int8 = {
471 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES,
472 .pNext = nullptr,
473 .shaderFloat16 = is_float16_supported,
474 .shaderInt8 = is_int8_supported,
475 };
476 SetNext(next, float16_int8);
477 }
478 if (!is_float16_supported) {
479 LOG_INFO(Render_Vulkan, "Device doesn't support float16 natively");
480 }
481 if (!is_int8_supported) {
482 LOG_INFO(Render_Vulkan, "Device doesn't support int8 natively");
483 }
484
485 if (!nv_viewport_swizzle) {
486 LOG_INFO(Render_Vulkan, "Device doesn't support viewport swizzles");
487 }
488
489 if (!nv_viewport_array2) {
490 LOG_INFO(Render_Vulkan, "Device doesn't support viewport masks");
491 }
492
493 if (!nv_geometry_shader_passthrough) {
494 LOG_INFO(Render_Vulkan, "Device doesn't support passthrough geometry shaders");
495 }
496
497 VkPhysicalDeviceUniformBufferStandardLayoutFeatures std430_layout;
498 if (khr_uniform_buffer_standard_layout) {
499 std430_layout = {
500 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES,
501 .pNext = nullptr,
502 .uniformBufferStandardLayout = true,
503 };
504 SetNext(next, std430_layout);
505 } else {
506 LOG_INFO(Render_Vulkan, "Device doesn't support packed UBOs");
507 }
508
509 VkPhysicalDeviceIndexTypeUint8FeaturesEXT index_type_uint8;
510 if (ext_index_type_uint8) {
511 index_type_uint8 = {
512 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT,
513 .pNext = nullptr,
514 .indexTypeUint8 = true,
515 };
516 SetNext(next, index_type_uint8);
517 } else {
518 LOG_INFO(Render_Vulkan, "Device doesn't support uint8 indexes");
519 }
520
521 VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT primitive_topology_list_restart;
522 if (is_topology_list_restart_supported || is_patch_list_restart_supported) {
523 primitive_topology_list_restart = {
524 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT,
525 .pNext = nullptr,
526 .primitiveTopologyListRestart = is_topology_list_restart_supported,
527 .primitiveTopologyPatchListRestart = is_patch_list_restart_supported,
528 };
529 SetNext(next, primitive_topology_list_restart);
530 } else {
531 LOG_INFO(Render_Vulkan, "Device doesn't support list topology primitive restart");
532 }
533
534 VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback;
535 if (ext_transform_feedback) {
536 transform_feedback = {
537 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT,
538 .pNext = nullptr,
539 .transformFeedback = true,
540 .geometryStreams = true,
541 };
542 SetNext(next, transform_feedback);
543 } else {
544 LOG_INFO(Render_Vulkan, "Device doesn't support transform feedbacks");
545 }
546
547 VkPhysicalDeviceCustomBorderColorFeaturesEXT custom_border;
548 if (ext_custom_border_color) {
549 custom_border = {
550 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT,
551 .pNext = nullptr,
552 .customBorderColors = VK_TRUE,
553 .customBorderColorWithoutFormat = VK_TRUE,
554 };
555 SetNext(next, custom_border);
556 } else {
557 LOG_INFO(Render_Vulkan, "Device doesn't support custom border colors");
558 }
559
560 VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state;
561 if (ext_extended_dynamic_state) {
562 dynamic_state = {
563 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT,
564 .pNext = nullptr,
565 .extendedDynamicState = VK_TRUE,
566 };
567 SetNext(next, dynamic_state);
568 } else {
569 LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state");
570 }
571
572 VkPhysicalDeviceExtendedDynamicState2FeaturesEXT dynamic_state_2;
573 if (ext_extended_dynamic_state_2) {
574 dynamic_state_2 = {
575 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT,
576 .pNext = nullptr,
577 .extendedDynamicState2 = VK_TRUE,
578 .extendedDynamicState2LogicOp = ext_extended_dynamic_state_2_extra ? VK_TRUE : VK_FALSE,
579 .extendedDynamicState2PatchControlPoints = VK_FALSE,
580 };
581 SetNext(next, dynamic_state_2);
582 } else {
583 LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state 2");
584 }
585 306
586 VkPhysicalDeviceExtendedDynamicState3FeaturesEXT dynamic_state_3; 307 // GetSuitability has already configured the linked list of features for us.
587 if (ext_extended_dynamic_state_3) { 308 // Reuse it here.
588 dynamic_state_3 = { 309 const void* first_next = &features2;
589 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT,
590 .pNext = nullptr,
591 .extendedDynamicState3TessellationDomainOrigin = VK_FALSE,
592 .extendedDynamicState3DepthClampEnable =
593 ext_extended_dynamic_state_3_enables ? VK_TRUE : VK_FALSE,
594 .extendedDynamicState3PolygonMode = VK_FALSE,
595 .extendedDynamicState3RasterizationSamples = VK_FALSE,
596 .extendedDynamicState3SampleMask = VK_FALSE,
597 .extendedDynamicState3AlphaToCoverageEnable = VK_FALSE,
598 .extendedDynamicState3AlphaToOneEnable = VK_FALSE,
599 .extendedDynamicState3LogicOpEnable =
600 ext_extended_dynamic_state_3_enables ? VK_TRUE : VK_FALSE,
601 .extendedDynamicState3ColorBlendEnable =
602 ext_extended_dynamic_state_3_blend ? VK_TRUE : VK_FALSE,
603 .extendedDynamicState3ColorBlendEquation =
604 ext_extended_dynamic_state_3_blend ? VK_TRUE : VK_FALSE,
605 .extendedDynamicState3ColorWriteMask =
606 ext_extended_dynamic_state_3_blend ? VK_TRUE : VK_FALSE,
607 .extendedDynamicState3RasterizationStream = VK_FALSE,
608 .extendedDynamicState3ConservativeRasterizationMode = VK_FALSE,
609 .extendedDynamicState3ExtraPrimitiveOverestimationSize = VK_FALSE,
610 .extendedDynamicState3DepthClipEnable = VK_FALSE,
611 .extendedDynamicState3SampleLocationsEnable = VK_FALSE,
612 .extendedDynamicState3ColorBlendAdvanced = VK_FALSE,
613 .extendedDynamicState3ProvokingVertexMode = VK_FALSE,
614 .extendedDynamicState3LineRasterizationMode = VK_FALSE,
615 .extendedDynamicState3LineStippleEnable = VK_FALSE,
616 .extendedDynamicState3DepthClipNegativeOneToOne = VK_FALSE,
617 .extendedDynamicState3ViewportWScalingEnable = VK_FALSE,
618 .extendedDynamicState3ViewportSwizzle = VK_FALSE,
619 .extendedDynamicState3CoverageToColorEnable = VK_FALSE,
620 .extendedDynamicState3CoverageToColorLocation = VK_FALSE,
621 .extendedDynamicState3CoverageModulationMode = VK_FALSE,
622 .extendedDynamicState3CoverageModulationTableEnable = VK_FALSE,
623 .extendedDynamicState3CoverageModulationTable = VK_FALSE,
624 .extendedDynamicState3CoverageReductionMode = VK_FALSE,
625 .extendedDynamicState3RepresentativeFragmentTestEnable = VK_FALSE,
626 .extendedDynamicState3ShadingRateImageEnable = VK_FALSE,
627 };
628 SetNext(next, dynamic_state_3);
629 } else {
630 LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state 3");
631 }
632
633 VkPhysicalDeviceLineRasterizationFeaturesEXT line_raster;
634 if (ext_line_rasterization) {
635 line_raster = {
636 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT,
637 .pNext = nullptr,
638 .rectangularLines = VK_TRUE,
639 .bresenhamLines = VK_FALSE,
640 .smoothLines = VK_TRUE,
641 .stippledRectangularLines = VK_FALSE,
642 .stippledBresenhamLines = VK_FALSE,
643 .stippledSmoothLines = VK_FALSE,
644 };
645 SetNext(next, line_raster);
646 } else {
647 LOG_INFO(Render_Vulkan, "Device doesn't support smooth lines");
648 }
649
650 if (!ext_conservative_rasterization) {
651 LOG_INFO(Render_Vulkan, "Device doesn't support conservative rasterization");
652 }
653
654 VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex;
655 if (ext_provoking_vertex) {
656 provoking_vertex = {
657 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT,
658 .pNext = nullptr,
659 .provokingVertexLast = VK_TRUE,
660 .transformFeedbackPreservesProvokingVertex = VK_TRUE,
661 };
662 SetNext(next, provoking_vertex);
663 } else {
664 LOG_INFO(Render_Vulkan, "Device doesn't support provoking vertex last");
665 }
666
667 VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT vertex_input_dynamic;
668 if (ext_vertex_input_dynamic_state) {
669 vertex_input_dynamic = {
670 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT,
671 .pNext = nullptr,
672 .vertexInputDynamicState = VK_TRUE,
673 };
674 SetNext(next, vertex_input_dynamic);
675 } else {
676 LOG_INFO(Render_Vulkan, "Device doesn't support vertex input dynamic state");
677 }
678
679 VkPhysicalDeviceShaderAtomicInt64Features atomic_int64;
680 if (ext_shader_atomic_int64) {
681 atomic_int64 = {
682 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES,
683 .pNext = nullptr,
684 .shaderBufferInt64Atomics = VK_TRUE,
685 .shaderSharedInt64Atomics = VK_TRUE,
686 };
687 SetNext(next, atomic_int64);
688 }
689
690 VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR workgroup_layout;
691 if (khr_workgroup_memory_explicit_layout && is_shader_int16_supported) {
692 workgroup_layout = {
693 .sType =
694 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR,
695 .pNext = nullptr,
696 .workgroupMemoryExplicitLayout = VK_TRUE,
697 .workgroupMemoryExplicitLayoutScalarBlockLayout = VK_TRUE,
698 .workgroupMemoryExplicitLayout8BitAccess = VK_TRUE,
699 .workgroupMemoryExplicitLayout16BitAccess = VK_TRUE,
700 };
701 SetNext(next, workgroup_layout);
702 } else if (khr_workgroup_memory_explicit_layout) {
703 // TODO(lat9nq): Find a proper fix for this
704 LOG_WARNING(Render_Vulkan, "Disabling VK_KHR_workgroup_memory_explicit_layout due to a "
705 "yuzu bug when host driver does not support 16-bit integers");
706 khr_workgroup_memory_explicit_layout = false;
707 }
708
709 VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR executable_properties;
710 if (khr_pipeline_executable_properties) {
711 LOG_INFO(Render_Vulkan, "Enabling shader feedback, expect slower shader build times");
712 executable_properties = {
713 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR,
714 .pNext = nullptr,
715 .pipelineExecutableInfo = VK_TRUE,
716 };
717 SetNext(next, executable_properties);
718 }
719
720 if (!ext_depth_range_unrestricted) {
721 LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted");
722 }
723
724 VkPhysicalDeviceDepthClipControlFeaturesEXT depth_clip_control_features;
725 if (ext_depth_clip_control) {
726 depth_clip_control_features = {
727 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT,
728 .pNext = nullptr,
729 .depthClipControl = VK_TRUE,
730 };
731 SetNext(next, depth_clip_control_features);
732 }
733 310
734 VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv; 311 VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv{};
735 if (Settings::values.enable_nsight_aftermath && nv_device_diagnostics_config) { 312 if (Settings::values.enable_nsight_aftermath && extensions.device_diagnostics_config) {
736 nsight_aftermath_tracker = std::make_unique<NsightAftermathTracker>(); 313 nsight_aftermath_tracker = std::make_unique<NsightAftermathTracker>();
737 314
738 diagnostics_nv = { 315 diagnostics_nv = {
@@ -744,33 +321,48 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
744 }; 321 };
745 first_next = &diagnostics_nv; 322 first_next = &diagnostics_nv;
746 } 323 }
747 logical = vk::Device::Create(physical, queue_cis, extensions, first_next, dld);
748 324
749 is_integrated = properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU; 325 is_blit_depth_stencil_supported = TestDepthStencilBlits();
750 is_virtual = properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU; 326 is_optimal_astc_supported = ComputeIsOptimalAstcSupported();
751 is_non_gpu = properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_OTHER || 327 is_warp_potentially_bigger = !extensions.subgroup_size_control ||
752 properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU; 328 properties.subgroup_size_control.maxSubgroupSize > GuestWarpSize;
329
330 is_integrated = properties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
331 is_virtual = properties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU;
332 is_non_gpu = properties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_OTHER ||
333 properties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU;
334
335 supports_d24_depth =
336 IsFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT,
337 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, FormatType::Optimal);
753 338
754 CollectPhysicalMemoryInfo(); 339 CollectPhysicalMemoryInfo();
755 CollectTelemetryParameters();
756 CollectToolingInfo(); 340 CollectToolingInfo();
757 341
758 if (driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR) { 342 const VkDriverId driver_id = properties.driver.driverID;
759 const u32 nv_major_version = (properties.driverVersion >> 22) & 0x3ff; 343 const bool is_radv = driver_id == VK_DRIVER_ID_MESA_RADV;
344 const bool is_amd_driver =
345 driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE;
346 const bool is_amd = is_amd_driver || is_radv;
347 const bool is_intel_windows = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS;
348 const bool is_intel_anv = driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA;
349 const bool is_nvidia = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY;
760 350
351 if (is_nvidia) {
352 const u32 nv_major_version = (properties.properties.driverVersion >> 22) & 0x3ff;
761 const auto arch = GetNvidiaArchitecture(physical, supported_extensions); 353 const auto arch = GetNvidiaArchitecture(physical, supported_extensions);
762 switch (arch) { 354 switch (arch) {
763 case NvidiaArchitecture::AmpereOrNewer: 355 case NvidiaArchitecture::AmpereOrNewer:
764 LOG_WARNING(Render_Vulkan, "Blacklisting Ampere devices from float16 math"); 356 LOG_WARNING(Render_Vulkan, "Ampere and newer have broken float16 math");
765 is_float16_supported = false; 357 features.shader_float16_int8.shaderFloat16 = false;
766 break; 358 break;
767 case NvidiaArchitecture::Turing: 359 case NvidiaArchitecture::Turing:
768 break; 360 break;
769 case NvidiaArchitecture::VoltaOrOlder: 361 case NvidiaArchitecture::VoltaOrOlder:
770 if (nv_major_version < 527) { 362 if (nv_major_version < 527) {
771 LOG_WARNING(Render_Vulkan, 363 LOG_WARNING(Render_Vulkan, "Volta and older have broken VK_KHR_push_descriptor");
772 "Blacklisting Volta and older from VK_KHR_push_descriptor"); 364 extensions.push_descriptor = false;
773 khr_push_descriptor = false; 365 loaded_extensions.erase(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
774 } 366 }
775 break; 367 break;
776 } 368 }
@@ -779,75 +371,75 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
779 cant_blit_msaa = true; 371 cant_blit_msaa = true;
780 } 372 }
781 } 373 }
782 const bool is_radv = driver_id == VK_DRIVER_ID_MESA_RADV; 374 if (extensions.extended_dynamic_state && is_radv) {
783 if (ext_extended_dynamic_state && is_radv) {
784 // Mask driver version variant 375 // Mask driver version variant
785 const u32 version = (properties.driverVersion << 3) >> 3; 376 const u32 version = (properties.properties.driverVersion << 3) >> 3;
786 if (version < VK_MAKE_API_VERSION(0, 21, 2, 0)) { 377 if (version < VK_MAKE_API_VERSION(0, 21, 2, 0)) {
787 LOG_WARNING(Render_Vulkan, 378 LOG_WARNING(Render_Vulkan,
788 "RADV versions older than 21.2 have broken VK_EXT_extended_dynamic_state"); 379 "RADV versions older than 21.2 have broken VK_EXT_extended_dynamic_state");
789 ext_extended_dynamic_state = false; 380 extensions.extended_dynamic_state = false;
381 loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
790 } 382 }
791 } 383 }
792 if (ext_vertex_input_dynamic_state && is_radv) { 384 if (extensions.extended_dynamic_state2 && is_radv) {
385 const u32 version = (properties.properties.driverVersion << 3) >> 3;
386 if (version < VK_MAKE_API_VERSION(0, 22, 3, 1)) {
387 LOG_WARNING(
388 Render_Vulkan,
389 "RADV versions older than 22.3.1 have broken VK_EXT_extended_dynamic_state2");
390 features.extended_dynamic_state2.extendedDynamicState2 = false;
391 features.extended_dynamic_state2.extendedDynamicState2LogicOp = false;
392 features.extended_dynamic_state2.extendedDynamicState2PatchControlPoints = false;
393 extensions.extended_dynamic_state2 = false;
394 loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
395 }
396 }
397 if (extensions.vertex_input_dynamic_state && is_radv) {
793 // TODO(ameerj): Blacklist only offending driver versions 398 // TODO(ameerj): Blacklist only offending driver versions
794 // TODO(ameerj): Confirm if RDNA1 is affected 399 // TODO(ameerj): Confirm if RDNA1 is affected
795 const bool is_rdna2 = 400 const bool is_rdna2 =
796 IsExtensionSupported(supported_extensions, VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME); 401 supported_extensions.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
797 if (is_rdna2) { 402 if (is_rdna2) {
798 LOG_WARNING(Render_Vulkan, 403 LOG_WARNING(Render_Vulkan,
799 "RADV has broken VK_EXT_vertex_input_dynamic_state on RDNA2 hardware"); 404 "RADV has broken VK_EXT_vertex_input_dynamic_state on RDNA2 hardware");
800 ext_vertex_input_dynamic_state = false; 405 extensions.vertex_input_dynamic_state = false;
406 loaded_extensions.erase(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
801 } 407 }
802 } 408 }
803 if (ext_extended_dynamic_state_2 && is_radv) {
804 const u32 version = (properties.driverVersion << 3) >> 3;
805 if (version < VK_MAKE_API_VERSION(0, 22, 3, 1)) {
806 LOG_WARNING(
807 Render_Vulkan,
808 "RADV versions older than 22.3.1 have broken VK_EXT_extended_dynamic_state2");
809 ext_extended_dynamic_state_2 = false;
810 ext_extended_dynamic_state_2_extra = false;
811 }
812 }
813 sets_per_pool = 64;
814 409
815 const bool is_amd = 410 sets_per_pool = 64;
816 driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE; 411 if (is_amd_driver) {
817 if (is_amd) {
818 // AMD drivers need a higher amount of Sets per Pool in certain circunstances like in XC2. 412 // AMD drivers need a higher amount of Sets per Pool in certain circunstances like in XC2.
819 sets_per_pool = 96; 413 sets_per_pool = 96;
820 // Disable VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT on AMD GCN4 and lower as it is broken. 414 // Disable VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT on AMD GCN4 and lower as it is broken.
821 if (!is_float16_supported) { 415 if (!features.shader_float16_int8.shaderFloat16) {
822 LOG_WARNING( 416 LOG_WARNING(Render_Vulkan,
823 Render_Vulkan, 417 "AMD GCN4 and earlier have broken VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT");
824 "AMD GCN4 and earlier do not properly support VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT");
825 has_broken_cube_compatibility = true; 418 has_broken_cube_compatibility = true;
826 } 419 }
827 } 420 }
828 const bool is_amd_or_radv = is_amd || is_radv; 421 if (extensions.sampler_filter_minmax && is_amd) {
829 if (ext_sampler_filter_minmax && is_amd_or_radv) {
830 // Disable ext_sampler_filter_minmax on AMD GCN4 and lower as it is broken. 422 // Disable ext_sampler_filter_minmax on AMD GCN4 and lower as it is broken.
831 if (!is_float16_supported) { 423 if (!features.shader_float16_int8.shaderFloat16) {
832 LOG_WARNING(Render_Vulkan, 424 LOG_WARNING(Render_Vulkan,
833 "Blacklisting AMD GCN4 and earlier for VK_EXT_sampler_filter_minmax"); 425 "AMD GCN4 and earlier have broken VK_EXT_sampler_filter_minmax");
834 ext_sampler_filter_minmax = false; 426 extensions.sampler_filter_minmax = false;
427 loaded_extensions.erase(VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME);
835 } 428 }
836 } 429 }
837 430
838 const bool is_intel_windows = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS; 431 if (extensions.vertex_input_dynamic_state && is_intel_windows) {
839 const bool is_intel_anv = driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA; 432 const u32 version = (properties.properties.driverVersion << 3) >> 3;
840 if (ext_vertex_input_dynamic_state && is_intel_windows) {
841 const u32 version = (properties.driverVersion << 3) >> 3;
842 if (version < VK_MAKE_API_VERSION(27, 20, 100, 0)) { 433 if (version < VK_MAKE_API_VERSION(27, 20, 100, 0)) {
843 LOG_WARNING(Render_Vulkan, "Blacklisting Intel for VK_EXT_vertex_input_dynamic_state"); 434 LOG_WARNING(Render_Vulkan, "Intel has broken VK_EXT_vertex_input_dynamic_state");
844 ext_vertex_input_dynamic_state = false; 435 extensions.vertex_input_dynamic_state = false;
436 loaded_extensions.erase(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
845 } 437 }
846 } 438 }
847 if (is_float16_supported && is_intel_windows) { 439 if (features.shader_float16_int8.shaderFloat16 && is_intel_windows) {
848 // Intel's compiler crashes when using fp16 on Astral Chain, disable it for the time being. 440 // Intel's compiler crashes when using fp16 on Astral Chain, disable it for the time being.
849 LOG_WARNING(Render_Vulkan, "Blacklisting Intel proprietary from float16 math"); 441 LOG_WARNING(Render_Vulkan, "Intel has broken float16 math");
850 is_float16_supported = false; 442 features.shader_float16_int8.shaderFloat16 = false;
851 } 443 }
852 if (is_intel_windows) { 444 if (is_intel_windows) {
853 LOG_WARNING(Render_Vulkan, "Intel proprietary drivers do not support MSAA image blits"); 445 LOG_WARNING(Render_Vulkan, "Intel proprietary drivers do not support MSAA image blits");
@@ -858,9 +450,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
858 must_emulate_bgr565 = true; 450 must_emulate_bgr565 = true;
859 } 451 }
860 452
861 supports_d24_depth = 453 logical = vk::Device::Create(physical, queue_cis, ExtensionListForVulkan(loaded_extensions),
862 IsFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT, 454 first_next, dld);
863 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, FormatType::Optimal);
864 455
865 graphics_queue = logical.GetQueue(graphics_family); 456 graphics_queue = logical.GetQueue(graphics_family);
866 present_queue = logical.GetQueue(present_family); 457 present_queue = logical.GetQueue(present_family);
@@ -915,7 +506,7 @@ void Device::SaveShader(std::span<const u32> spirv) const {
915 } 506 }
916} 507}
917 508
918bool Device::IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const { 509bool Device::ComputeIsOptimalAstcSupported() const {
919 // Disable for now to avoid converting ASTC twice. 510 // Disable for now to avoid converting ASTC twice.
920 static constexpr std::array astc_formats = { 511 static constexpr std::array astc_formats = {
921 VK_FORMAT_ASTC_4x4_UNORM_BLOCK, VK_FORMAT_ASTC_4x4_SRGB_BLOCK, 512 VK_FORMAT_ASTC_4x4_UNORM_BLOCK, VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
@@ -933,7 +524,7 @@ bool Device::IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) co
933 VK_FORMAT_ASTC_12x10_UNORM_BLOCK, VK_FORMAT_ASTC_12x10_SRGB_BLOCK, 524 VK_FORMAT_ASTC_12x10_UNORM_BLOCK, VK_FORMAT_ASTC_12x10_SRGB_BLOCK,
934 VK_FORMAT_ASTC_12x12_UNORM_BLOCK, VK_FORMAT_ASTC_12x12_SRGB_BLOCK, 525 VK_FORMAT_ASTC_12x12_UNORM_BLOCK, VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
935 }; 526 };
936 if (!features.textureCompressionASTC_LDR) { 527 if (!features.features.textureCompressionASTC_LDR) {
937 return false; 528 return false;
938 } 529 }
939 const auto format_feature_usage{ 530 const auto format_feature_usage{
@@ -971,7 +562,7 @@ bool Device::IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags want
971} 562}
972 563
973std::string Device::GetDriverName() const { 564std::string Device::GetDriverName() const {
974 switch (driver_id) { 565 switch (properties.driver.driverID) {
975 case VK_DRIVER_ID_AMD_PROPRIETARY: 566 case VK_DRIVER_ID_AMD_PROPRIETARY:
976 return "AMD"; 567 return "AMD";
977 case VK_DRIVER_ID_AMD_OPEN_SOURCE: 568 case VK_DRIVER_ID_AMD_OPEN_SOURCE:
@@ -987,522 +578,336 @@ std::string Device::GetDriverName() const {
987 case VK_DRIVER_ID_MESA_LLVMPIPE: 578 case VK_DRIVER_ID_MESA_LLVMPIPE:
988 return "LAVAPIPE"; 579 return "LAVAPIPE";
989 default: 580 default:
990 return vendor_name; 581 return properties.driver.driverName;
991 } 582 }
992} 583}
993 584
994bool Device::ShouldBoostClocks() const { 585bool Device::ShouldBoostClocks() const {
586 const auto driver_id = properties.driver.driverID;
587 const auto vendor_id = properties.properties.vendorID;
588 const auto device_id = properties.properties.deviceID;
589
995 const bool validated_driver = 590 const bool validated_driver =
996 driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE || 591 driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE ||
997 driver_id == VK_DRIVER_ID_MESA_RADV || driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY || 592 driver_id == VK_DRIVER_ID_MESA_RADV || driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY ||
998 driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS || 593 driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS ||
999 driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA; 594 driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA;
1000 595
1001 const bool is_steam_deck = properties.vendorID == 0x1002 && properties.deviceID == 0x163F; 596 const bool is_steam_deck = vendor_id == 0x1002 && device_id == 0x163F;
1002 597
1003 return validated_driver && !is_steam_deck; 598 return validated_driver && !is_steam_deck;
1004} 599}
1005 600
1006static std::vector<const char*> ExtensionsRequiredForInstanceVersion(u32 available_version) { 601bool Device::GetSuitability(bool requires_swapchain) {
1007 std::vector<const char*> extensions{REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()}; 602 // Assume we will be suitable.
603 bool suitable = true;
1008 604
1009 if (available_version < VK_API_VERSION_1_2) { 605 // Configure properties.
1010 extensions.insert(extensions.end(), REQUIRED_EXTENSIONS_BEFORE_1_2.begin(), 606 properties.properties = physical.GetProperties();
1011 REQUIRED_EXTENSIONS_BEFORE_1_2.end());
1012 }
1013
1014 if (available_version < VK_API_VERSION_1_3) {
1015 extensions.insert(extensions.end(), REQUIRED_EXTENSIONS_BEFORE_1_3.begin(),
1016 REQUIRED_EXTENSIONS_BEFORE_1_3.end());
1017 }
1018
1019 return extensions;
1020}
1021 607
1022void Device::CheckSuitability(bool requires_swapchain) const { 608 // Set instance version.
1023 std::vector<const char*> required_extensions = 609 instance_version = properties.properties.apiVersion;
1024 ExtensionsRequiredForInstanceVersion(instance_version);
1025 std::vector<const char*> available_extensions;
1026 610
1027 if (requires_swapchain) { 611 // Minimum of API version 1.1 is required. (This is well-supported.)
1028 required_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); 612 ASSERT(instance_version >= VK_API_VERSION_1_1);
1029 }
1030 613
614 // Get available extensions.
1031 auto extension_properties = physical.EnumerateDeviceExtensionProperties(); 615 auto extension_properties = physical.EnumerateDeviceExtensionProperties();
1032 616
617 // Get the set of supported extensions.
618 supported_extensions.clear();
1033 for (const VkExtensionProperties& property : extension_properties) { 619 for (const VkExtensionProperties& property : extension_properties) {
1034 available_extensions.push_back(property.extensionName); 620 supported_extensions.insert(property.extensionName);
1035 } 621 }
1036 622
1037 bool has_all_required_extensions = true; 623 // Generate list of extensions to load.
1038 for (const char* requirement_name : required_extensions) { 624 loaded_extensions.clear();
1039 const bool found =
1040 std::ranges::any_of(available_extensions, [&](const char* extension_name) {
1041 return std::strcmp(requirement_name, extension_name) == 0;
1042 });
1043 625
1044 if (!found) { 626#define EXTENSION(prefix, macro_name, var_name) \
1045 LOG_ERROR(Render_Vulkan, "Missing required extension: {}", requirement_name); 627 if (supported_extensions.contains(VK_##prefix##_##macro_name##_EXTENSION_NAME)) { \
1046 has_all_required_extensions = false; 628 loaded_extensions.insert(VK_##prefix##_##macro_name##_EXTENSION_NAME); \
1047 } 629 extensions.var_name = true; \
1048 } 630 }
1049 631#define FEATURE_EXTENSION(prefix, struct_name, macro_name, var_name) \
1050 if (!has_all_required_extensions) { 632 if (supported_extensions.contains(VK_##prefix##_##macro_name##_EXTENSION_NAME)) { \
1051 throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); 633 loaded_extensions.insert(VK_##prefix##_##macro_name##_EXTENSION_NAME); \
634 extensions.var_name = true; \
1052 } 635 }
1053 636
1054 struct LimitTuple { 637 if (instance_version < VK_API_VERSION_1_2) {
1055 u32 minimum; 638 FOR_EACH_VK_FEATURE_1_2(FEATURE_EXTENSION);
1056 u32 value; 639 }
1057 const char* name; 640 if (instance_version < VK_API_VERSION_1_3) {
1058 }; 641 FOR_EACH_VK_FEATURE_1_3(FEATURE_EXTENSION);
1059 const VkPhysicalDeviceLimits& limits{properties.limits};
1060 const std::array limits_report{
1061 LimitTuple{65536, limits.maxUniformBufferRange, "maxUniformBufferRange"},
1062 LimitTuple{16, limits.maxViewports, "maxViewports"},
1063 LimitTuple{8, limits.maxColorAttachments, "maxColorAttachments"},
1064 LimitTuple{8, limits.maxClipDistances, "maxClipDistances"},
1065 };
1066 for (const auto& tuple : limits_report) {
1067 if (tuple.value < tuple.minimum) {
1068 LOG_ERROR(Render_Vulkan, "{} has to be {} or greater but it is {}", tuple.name,
1069 tuple.minimum, tuple.value);
1070 throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
1071 }
1072 } 642 }
1073 VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures demote{};
1074 demote.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES;
1075 demote.pNext = nullptr;
1076 643
1077 VkPhysicalDeviceVariablePointerFeatures variable_pointers{}; 644 FOR_EACH_VK_FEATURE_EXT(FEATURE_EXTENSION);
1078 variable_pointers.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES; 645 FOR_EACH_VK_EXTENSION(EXTENSION);
1079 variable_pointers.pNext = &demote; 646#ifdef _WIN32
647 FOR_EACH_VK_EXTENSION_WIN32(EXTENSION);
648#endif
1080 649
1081 VkPhysicalDeviceRobustness2FeaturesEXT robustness2{}; 650#undef FEATURE_EXTENSION
1082 robustness2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT; 651#undef EXTENSION
1083 robustness2.pNext = &variable_pointers;
1084 652
1085 VkPhysicalDeviceTimelineSemaphoreFeatures timeline_semaphore{}; 653 // Some extensions are mandatory. Check those.
1086 timeline_semaphore.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; 654#define CHECK_EXTENSION(extension_name) \
1087 timeline_semaphore.pNext = &robustness2; 655 if (!loaded_extensions.contains(extension_name)) { \
656 LOG_ERROR(Render_Vulkan, "Missing required extension {}", extension_name); \
657 suitable = false; \
658 }
1088 659
1089 VkPhysicalDevice16BitStorageFeatures bit16_storage{}; 660#define LOG_EXTENSION(extension_name) \
1090 bit16_storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; 661 if (!loaded_extensions.contains(extension_name)) { \
1091 bit16_storage.pNext = &timeline_semaphore; 662 LOG_INFO(Render_Vulkan, "Device doesn't support extension {}", extension_name); \
663 }
1092 664
1093 VkPhysicalDevice8BitStorageFeatures bit8_storage{}; 665 FOR_EACH_VK_RECOMMENDED_EXTENSION(LOG_EXTENSION);
1094 bit8_storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES; 666 FOR_EACH_VK_MANDATORY_EXTENSION(CHECK_EXTENSION);
1095 bit8_storage.pNext = &bit16_storage; 667#ifdef _WIN32
668 FOR_EACH_VK_MANDATORY_EXTENSION_WIN32(CHECK_EXTENSION);
669#else
670 FOR_EACH_VK_MANDATORY_EXTENSION_GENERIC(CHECK_EXTENSION);
671#endif
1096 672
1097 VkPhysicalDeviceHostQueryResetFeatures host_query_reset{}; 673 if (requires_swapchain) {
1098 host_query_reset.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES; 674 CHECK_EXTENSION(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
1099 host_query_reset.pNext = &bit8_storage; 675 }
1100 676
1101 VkPhysicalDeviceShaderDrawParametersFeatures draw_parameters{}; 677#undef LOG_EXTENSION
1102 draw_parameters.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES; 678#undef CHECK_EXTENSION
1103 draw_parameters.pNext = &host_query_reset;
1104 679
1105 VkPhysicalDeviceFeatures2 features2{}; 680 // Generate the linked list of features to test.
1106 features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; 681 features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
1107 features2.pNext = &draw_parameters;
1108 682
1109 physical.GetFeatures2(features2); 683 // Set next pointer.
684 void** next = &features2.pNext;
1110 685
1111 const VkPhysicalDeviceFeatures& features{features2.features}; 686 // Test all features we know about. If the feature is not available in core at our
1112 std::array feature_report{ 687 // current API version, and was not enabled by an extension, skip testing the feature.
1113 std::make_pair(features.robustBufferAccess, "robustBufferAccess"), 688 // We set the structure sType explicitly here as it is zeroed by the constructor.
1114 std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"), 689#define FEATURE(prefix, struct_name, macro_name, var_name) \
1115 std::make_pair(features.imageCubeArray, "imageCubeArray"), 690 features.var_name.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_##macro_name##_FEATURES; \
1116 std::make_pair(features.independentBlend, "independentBlend"), 691 SetNext(next, features.var_name);
1117 std::make_pair(features.multiDrawIndirect, "multiDrawIndirect"),
1118 std::make_pair(features.drawIndirectFirstInstance, "drawIndirectFirstInstance"),
1119 std::make_pair(features.depthClamp, "depthClamp"),
1120 std::make_pair(features.samplerAnisotropy, "samplerAnisotropy"),
1121 std::make_pair(features.largePoints, "largePoints"),
1122 std::make_pair(features.multiViewport, "multiViewport"),
1123 std::make_pair(features.depthBiasClamp, "depthBiasClamp"),
1124 std::make_pair(features.fillModeNonSolid, "fillModeNonSolid"),
1125 std::make_pair(features.wideLines, "wideLines"),
1126 std::make_pair(features.geometryShader, "geometryShader"),
1127 std::make_pair(features.tessellationShader, "tessellationShader"),
1128 std::make_pair(features.sampleRateShading, "sampleRateShading"),
1129 std::make_pair(features.dualSrcBlend, "dualSrcBlend"),
1130 std::make_pair(features.logicOp, "logicOp"),
1131 std::make_pair(features.occlusionQueryPrecise, "occlusionQueryPrecise"),
1132 std::make_pair(features.fragmentStoresAndAtomics, "fragmentStoresAndAtomics"),
1133 std::make_pair(features.shaderImageGatherExtended, "shaderImageGatherExtended"),
1134 std::make_pair(features.shaderStorageImageWriteWithoutFormat,
1135 "shaderStorageImageWriteWithoutFormat"),
1136 std::make_pair(features.shaderClipDistance, "shaderClipDistance"),
1137 std::make_pair(features.shaderCullDistance, "shaderCullDistance"),
1138 std::make_pair(variable_pointers.variablePointers, "variablePointers"),
1139 std::make_pair(variable_pointers.variablePointersStorageBuffer,
1140 "variablePointersStorageBuffer"),
1141 std::make_pair(robustness2.robustBufferAccess2, "robustBufferAccess2"),
1142 std::make_pair(robustness2.robustImageAccess2, "robustImageAccess2"),
1143 std::make_pair(robustness2.nullDescriptor, "nullDescriptor"),
1144 std::make_pair(demote.shaderDemoteToHelperInvocation, "shaderDemoteToHelperInvocation"),
1145 std::make_pair(timeline_semaphore.timelineSemaphore, "timelineSemaphore"),
1146 std::make_pair(bit16_storage.storageBuffer16BitAccess, "storageBuffer16BitAccess"),
1147 std::make_pair(bit16_storage.uniformAndStorageBuffer16BitAccess,
1148 "uniformAndStorageBuffer16BitAccess"),
1149 std::make_pair(bit8_storage.storageBuffer8BitAccess, "storageBuffer8BitAccess"),
1150 std::make_pair(bit8_storage.uniformAndStorageBuffer8BitAccess,
1151 "uniformAndStorageBuffer8BitAccess"),
1152 std::make_pair(host_query_reset.hostQueryReset, "hostQueryReset"),
1153 std::make_pair(draw_parameters.shaderDrawParameters, "shaderDrawParameters"),
1154 };
1155 692
1156 bool has_all_required_features = true; 693#define EXT_FEATURE(prefix, struct_name, macro_name, var_name) \
1157 for (const auto& [is_supported, name] : feature_report) { 694 if (extensions.var_name) { \
1158 if (!is_supported) { 695 features.var_name.sType = \
1159 LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name); 696 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_##macro_name##_FEATURES_##prefix; \
1160 has_all_required_features = false; 697 SetNext(next, features.var_name); \
1161 }
1162 } 698 }
1163 699
1164 if (!has_all_required_features) { 700 FOR_EACH_VK_FEATURE_1_1(FEATURE);
1165 throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT); 701 FOR_EACH_VK_FEATURE_EXT(EXT_FEATURE);
702 if (instance_version >= VK_API_VERSION_1_2) {
703 FOR_EACH_VK_FEATURE_1_2(FEATURE);
704 } else {
705 FOR_EACH_VK_FEATURE_1_2(EXT_FEATURE);
1166 } 706 }
1167} 707 if (instance_version >= VK_API_VERSION_1_3) {
1168 708 FOR_EACH_VK_FEATURE_1_3(FEATURE);
1169std::vector<const char*> Device::LoadExtensions(bool requires_surface) { 709 } else {
1170 std::vector<const char*> extensions = ExtensionsRequiredForInstanceVersion(instance_version); 710 FOR_EACH_VK_FEATURE_1_3(EXT_FEATURE);
1171 if (requires_surface) {
1172 extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
1173 } 711 }
1174 712
1175 bool has_khr_shader_float16_int8{}; 713#undef EXT_FEATURE
1176 bool has_khr_workgroup_memory_explicit_layout{}; 714#undef FEATURE
1177 bool has_khr_pipeline_executable_properties{};
1178 bool has_khr_image_format_list{};
1179 bool has_khr_swapchain_mutable_format{};
1180 bool has_ext_subgroup_size_control{};
1181 bool has_ext_transform_feedback{};
1182 bool has_ext_custom_border_color{};
1183 bool has_ext_extended_dynamic_state{};
1184 bool has_ext_extended_dynamic_state_2{};
1185 bool has_ext_extended_dynamic_state_3{};
1186 bool has_ext_shader_atomic_int64{};
1187 bool has_ext_provoking_vertex{};
1188 bool has_ext_vertex_input_dynamic_state{};
1189 bool has_ext_line_rasterization{};
1190 bool has_ext_primitive_topology_list_restart{};
1191 bool has_ext_depth_clip_control{};
1192 for (const std::string& extension : supported_extensions) {
1193 const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name,
1194 bool push) {
1195 if (extension != name) {
1196 return;
1197 }
1198 if (push) {
1199 extensions.push_back(name);
1200 }
1201 if (status) {
1202 status->get() = true;
1203 }
1204 };
1205 test(nv_viewport_swizzle, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME, true);
1206 test(nv_viewport_array2, VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME, true);
1207 test(nv_geometry_shader_passthrough, VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME,
1208 true);
1209 test(khr_uniform_buffer_standard_layout,
1210 VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, true);
1211 test(khr_spirv_1_4, VK_KHR_SPIRV_1_4_EXTENSION_NAME, true);
1212 test(khr_push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, true);
1213 test(has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false);
1214 test(khr_draw_indirect_count, VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME, true);
1215 test(ext_depth_range_unrestricted, VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true);
1216 test(ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true);
1217 test(has_ext_primitive_topology_list_restart,
1218 VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME, true);
1219 test(ext_sampler_filter_minmax, VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME, true);
1220 test(ext_shader_viewport_index_layer, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME,
1221 true);
1222 test(ext_tooling_info, VK_EXT_TOOLING_INFO_EXTENSION_NAME, true);
1223 test(ext_shader_stencil_export, VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, true);
1224 test(ext_conservative_rasterization, VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME,
1225 true);
1226 test(has_ext_depth_clip_control, VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME, false);
1227 test(has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, false);
1228 test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false);
1229 test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false);
1230 test(has_ext_extended_dynamic_state_2, VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME,
1231 false);
1232 test(has_ext_extended_dynamic_state_3, VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME,
1233 false);
1234 test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, true);
1235 test(has_ext_provoking_vertex, VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, false);
1236 test(has_ext_vertex_input_dynamic_state, VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME,
1237 false);
1238 test(has_ext_shader_atomic_int64, VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME, false);
1239 test(has_khr_workgroup_memory_explicit_layout,
1240 VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME, false);
1241 test(has_khr_image_format_list, VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, false);
1242 test(has_khr_swapchain_mutable_format, VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME,
1243 false);
1244 test(has_ext_line_rasterization, VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, false);
1245 test(ext_memory_budget, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, true);
1246 if (Settings::values.enable_nsight_aftermath) {
1247 test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME,
1248 true);
1249 }
1250 if (Settings::values.renderer_shader_feedback) {
1251 test(has_khr_pipeline_executable_properties,
1252 VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME, false);
1253 }
1254 }
1255 VkPhysicalDeviceFeatures2 features{};
1256 features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
1257
1258 VkPhysicalDeviceProperties2 physical_properties{};
1259 physical_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1260
1261 if (has_khr_shader_float16_int8) {
1262 VkPhysicalDeviceShaderFloat16Int8Features float16_int8_features;
1263 float16_int8_features.sType =
1264 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES;
1265 float16_int8_features.pNext = nullptr;
1266 features.pNext = &float16_int8_features;
1267
1268 physical.GetFeatures2(features);
1269 is_float16_supported = float16_int8_features.shaderFloat16;
1270 is_int8_supported = float16_int8_features.shaderInt8;
1271 extensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME);
1272 }
1273 if (has_ext_subgroup_size_control) {
1274 VkPhysicalDeviceSubgroupSizeControlFeatures subgroup_features;
1275 subgroup_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES;
1276 subgroup_features.pNext = nullptr;
1277 features.pNext = &subgroup_features;
1278 physical.GetFeatures2(features);
1279
1280 VkPhysicalDeviceSubgroupSizeControlProperties subgroup_properties;
1281 subgroup_properties.sType =
1282 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES;
1283 subgroup_properties.pNext = nullptr;
1284 physical_properties.pNext = &subgroup_properties;
1285 physical.GetProperties2(physical_properties);
1286 715
1287 is_warp_potentially_bigger = subgroup_properties.maxSubgroupSize > GuestWarpSize; 716 // Perform the feature test.
717 physical.GetFeatures2(features2);
718 features.features = features2.features;
1288 719
1289 if (subgroup_features.subgroupSizeControl && 720 // Some features are mandatory. Check those.
1290 subgroup_properties.minSubgroupSize <= GuestWarpSize && 721#define CHECK_FEATURE(feature, name) \
1291 subgroup_properties.maxSubgroupSize >= GuestWarpSize) { 722 if (!features.feature.name) { \
1292 extensions.push_back(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME); 723 LOG_ERROR(Render_Vulkan, "Missing required feature {}", #name); \
1293 guest_warp_stages = subgroup_properties.requiredSubgroupSizeStages; 724 suitable = false; \
1294 ext_subgroup_size_control = true;
1295 }
1296 } else {
1297 is_warp_potentially_bigger = true;
1298 }
1299 if (has_ext_provoking_vertex) {
1300 VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex;
1301 provoking_vertex.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT;
1302 provoking_vertex.pNext = nullptr;
1303 features.pNext = &provoking_vertex;
1304 physical.GetFeatures2(features);
1305
1306 if (provoking_vertex.provokingVertexLast &&
1307 provoking_vertex.transformFeedbackPreservesProvokingVertex) {
1308 extensions.push_back(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME);
1309 ext_provoking_vertex = true;
1310 }
1311 } 725 }
1312 if (has_ext_vertex_input_dynamic_state) {
1313 VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT vertex_input;
1314 vertex_input.sType =
1315 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT;
1316 vertex_input.pNext = nullptr;
1317 features.pNext = &vertex_input;
1318 physical.GetFeatures2(features);
1319
1320 if (vertex_input.vertexInputDynamicState) {
1321 extensions.push_back(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
1322 ext_vertex_input_dynamic_state = true;
1323 }
1324 }
1325 if (has_ext_shader_atomic_int64) {
1326 VkPhysicalDeviceShaderAtomicInt64Features atomic_int64;
1327 atomic_int64.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES;
1328 atomic_int64.pNext = nullptr;
1329 features.pNext = &atomic_int64;
1330 physical.GetFeatures2(features);
1331
1332 if (atomic_int64.shaderBufferInt64Atomics && atomic_int64.shaderSharedInt64Atomics) {
1333 extensions.push_back(VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME);
1334 ext_shader_atomic_int64 = true;
1335 }
1336 }
1337 if (has_ext_transform_feedback) {
1338 VkPhysicalDeviceTransformFeedbackFeaturesEXT tfb_features;
1339 tfb_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT;
1340 tfb_features.pNext = nullptr;
1341 features.pNext = &tfb_features;
1342 physical.GetFeatures2(features);
1343
1344 VkPhysicalDeviceTransformFeedbackPropertiesEXT tfb_properties;
1345 tfb_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
1346 tfb_properties.pNext = nullptr;
1347 physical_properties.pNext = &tfb_properties;
1348 physical.GetProperties2(physical_properties);
1349 726
1350 if (tfb_features.transformFeedback && tfb_features.geometryStreams && 727#define LOG_FEATURE(feature, name) \
1351 tfb_properties.maxTransformFeedbackStreams >= 4 && 728 if (!features.feature.name) { \
1352 tfb_properties.maxTransformFeedbackBuffers && tfb_properties.transformFeedbackQueries && 729 LOG_INFO(Render_Vulkan, "Device doesn't support feature {}", #name); \
1353 tfb_properties.transformFeedbackDraw) {
1354 extensions.push_back(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
1355 ext_transform_feedback = true;
1356 }
1357 }
1358 if (has_ext_custom_border_color) {
1359 VkPhysicalDeviceCustomBorderColorFeaturesEXT border_features;
1360 border_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT;
1361 border_features.pNext = nullptr;
1362 features.pNext = &border_features;
1363 physical.GetFeatures2(features);
1364
1365 if (border_features.customBorderColors && border_features.customBorderColorWithoutFormat) {
1366 extensions.push_back(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
1367 ext_custom_border_color = true;
1368 }
1369 }
1370 if (has_ext_extended_dynamic_state) {
1371 VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extended_dynamic_state;
1372 extended_dynamic_state.sType =
1373 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT;
1374 extended_dynamic_state.pNext = nullptr;
1375 features.pNext = &extended_dynamic_state;
1376 physical.GetFeatures2(features);
1377
1378 if (extended_dynamic_state.extendedDynamicState) {
1379 extensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
1380 ext_extended_dynamic_state = true;
1381 }
1382 }
1383 if (has_ext_extended_dynamic_state_2) {
1384 VkPhysicalDeviceExtendedDynamicState2FeaturesEXT extended_dynamic_state_2;
1385 extended_dynamic_state_2.sType =
1386 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT;
1387 extended_dynamic_state_2.pNext = nullptr;
1388 features.pNext = &extended_dynamic_state_2;
1389 physical.GetFeatures2(features);
1390
1391 if (extended_dynamic_state_2.extendedDynamicState2) {
1392 extensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
1393 ext_extended_dynamic_state_2 = true;
1394 ext_extended_dynamic_state_2_extra =
1395 extended_dynamic_state_2.extendedDynamicState2LogicOp;
1396 }
1397 } 730 }
1398 if (has_ext_extended_dynamic_state_3) { 731
1399 VkPhysicalDeviceExtendedDynamicState3FeaturesEXT extended_dynamic_state_3; 732 FOR_EACH_VK_RECOMMENDED_FEATURE(LOG_FEATURE);
1400 extended_dynamic_state_3.sType = 733 FOR_EACH_VK_MANDATORY_FEATURE(CHECK_FEATURE);
1401 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT; 734
1402 extended_dynamic_state_3.pNext = nullptr; 735#undef LOG_FEATURE
1403 features.pNext = &extended_dynamic_state_3; 736#undef CHECK_FEATURE
1404 physical.GetFeatures2(features); 737
1405 738 // Generate linked list of properties.
1406 ext_extended_dynamic_state_3_blend = 739 properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1407 extended_dynamic_state_3.extendedDynamicState3ColorBlendEnable && 740
1408 extended_dynamic_state_3.extendedDynamicState3ColorBlendEquation && 741 // Set next pointer.
1409 extended_dynamic_state_3.extendedDynamicState3ColorWriteMask; 742 next = &properties2.pNext;
1410 743
1411 ext_extended_dynamic_state_3_enables = 744 // Get driver info.
1412 extended_dynamic_state_3.extendedDynamicState3DepthClampEnable && 745 properties.driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
1413 extended_dynamic_state_3.extendedDynamicState3LogicOpEnable; 746 SetNext(next, properties.driver);
1414 747
1415 ext_extended_dynamic_state_3 = 748 // Retrieve relevant extension properties.
1416 ext_extended_dynamic_state_3_blend || ext_extended_dynamic_state_3_enables; 749 if (extensions.shader_float_controls) {
1417 if (ext_extended_dynamic_state_3) { 750 properties.float_controls.sType =
1418 extensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); 751 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES;
1419 } 752 SetNext(next, properties.float_controls);
1420 } 753 }
1421 if (has_ext_line_rasterization) { 754 if (extensions.push_descriptor) {
1422 VkPhysicalDeviceLineRasterizationFeaturesEXT line_raster; 755 properties.push_descriptor.sType =
1423 line_raster.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT; 756 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR;
1424 line_raster.pNext = nullptr; 757 SetNext(next, properties.push_descriptor);
1425 features.pNext = &line_raster;
1426 physical.GetFeatures2(features);
1427 if (line_raster.rectangularLines && line_raster.smoothLines) {
1428 extensions.push_back(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME);
1429 ext_line_rasterization = true;
1430 }
1431 } 758 }
1432 if (has_ext_depth_clip_control) { 759 if (extensions.subgroup_size_control) {
1433 VkPhysicalDeviceDepthClipControlFeaturesEXT depth_clip_control_features; 760 properties.subgroup_size_control.sType =
1434 depth_clip_control_features.sType = 761 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES;
1435 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT; 762 SetNext(next, properties.subgroup_size_control);
1436 depth_clip_control_features.pNext = nullptr;
1437 features.pNext = &depth_clip_control_features;
1438 physical.GetFeatures2(features);
1439
1440 if (depth_clip_control_features.depthClipControl) {
1441 extensions.push_back(VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME);
1442 ext_depth_clip_control = true;
1443 }
1444 } 763 }
1445 if (has_khr_workgroup_memory_explicit_layout) { 764 if (extensions.transform_feedback) {
1446 VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR layout; 765 properties.transform_feedback.sType =
1447 layout.sType = 766 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
1448 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR; 767 SetNext(next, properties.transform_feedback);
1449 layout.pNext = nullptr;
1450 features.pNext = &layout;
1451 physical.GetFeatures2(features);
1452
1453 if (layout.workgroupMemoryExplicitLayout &&
1454 layout.workgroupMemoryExplicitLayout8BitAccess &&
1455 layout.workgroupMemoryExplicitLayout16BitAccess &&
1456 layout.workgroupMemoryExplicitLayoutScalarBlockLayout) {
1457 extensions.push_back(VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME);
1458 khr_workgroup_memory_explicit_layout = true;
1459 }
1460 } 768 }
1461 if (has_khr_pipeline_executable_properties) { 769
1462 VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR executable_properties; 770 // Perform the property fetch.
1463 executable_properties.sType = 771 physical.GetProperties2(properties2);
1464 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR; 772 properties.properties = properties2.properties;
1465 executable_properties.pNext = nullptr; 773
1466 features.pNext = &executable_properties; 774 // Unload extensions if feature support is insufficient.
1467 physical.GetFeatures2(features); 775 RemoveUnsuitableExtensions();
1468 776
1469 if (executable_properties.pipelineExecutableInfo) { 777 // Check limits.
1470 extensions.push_back(VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME); 778 struct Limit {
1471 khr_pipeline_executable_properties = true; 779 u32 minimum;
780 u32 value;
781 const char* name;
782 };
783
784 const VkPhysicalDeviceLimits& limits{properties.properties.limits};
785 const std::array limits_report{
786 Limit{65536, limits.maxUniformBufferRange, "maxUniformBufferRange"},
787 Limit{16, limits.maxViewports, "maxViewports"},
788 Limit{8, limits.maxColorAttachments, "maxColorAttachments"},
789 Limit{8, limits.maxClipDistances, "maxClipDistances"},
790 };
791
792 for (const auto& [min, value, name] : limits_report) {
793 if (value < min) {
794 LOG_ERROR(Render_Vulkan, "{} has to be {} or greater but it is {}", name, min, value);
795 suitable = false;
1472 } 796 }
1473 } 797 }
1474 if (has_ext_primitive_topology_list_restart) {
1475 VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT primitive_topology_list_restart{};
1476 primitive_topology_list_restart.sType =
1477 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT;
1478 primitive_topology_list_restart.pNext = nullptr;
1479 features.pNext = &primitive_topology_list_restart;
1480 physical.GetFeatures2(features);
1481
1482 is_topology_list_restart_supported =
1483 primitive_topology_list_restart.primitiveTopologyListRestart;
1484 is_patch_list_restart_supported =
1485 primitive_topology_list_restart.primitiveTopologyPatchListRestart;
1486 }
1487 if (requires_surface && has_khr_image_format_list && has_khr_swapchain_mutable_format) {
1488 extensions.push_back(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME);
1489 extensions.push_back(VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME);
1490 khr_swapchain_mutable_format = true;
1491 }
1492 if (khr_push_descriptor) {
1493 VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor;
1494 push_descriptor.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR;
1495 push_descriptor.pNext = nullptr;
1496 798
1497 physical_properties.pNext = &push_descriptor; 799 // Return whether we were suitable.
1498 physical.GetProperties2(physical_properties); 800 return suitable;
801}
1499 802
1500 max_push_descriptors = push_descriptor.maxPushDescriptors; 803void Device::RemoveExtensionIfUnsuitable(bool is_suitable, const std::string& extension_name) {
804 if (loaded_extensions.contains(extension_name) && !is_suitable) {
805 LOG_WARNING(Render_Vulkan, "Removing unsuitable extension {}", extension_name);
806 loaded_extensions.erase(extension_name);
1501 } 807 }
808}
1502 809
1503 has_null_descriptor = true; 810void Device::RemoveUnsuitableExtensions() {
1504 811 // VK_EXT_custom_border_color
1505 return extensions; 812 extensions.custom_border_color = features.custom_border_color.customBorderColors &&
813 features.custom_border_color.customBorderColorWithoutFormat;
814 RemoveExtensionIfUnsuitable(extensions.custom_border_color,
815 VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
816
817 // VK_EXT_depth_clip_control
818 extensions.depth_clip_control = features.depth_clip_control.depthClipControl;
819 RemoveExtensionIfUnsuitable(extensions.depth_clip_control,
820 VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME);
821
822 // VK_EXT_extended_dynamic_state
823 extensions.extended_dynamic_state = features.extended_dynamic_state.extendedDynamicState;
824 RemoveExtensionIfUnsuitable(extensions.extended_dynamic_state,
825 VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
826
827 // VK_EXT_extended_dynamic_state2
828 extensions.extended_dynamic_state2 = features.extended_dynamic_state2.extendedDynamicState2;
829 RemoveExtensionIfUnsuitable(extensions.extended_dynamic_state2,
830 VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
831
832 // VK_EXT_extended_dynamic_state3
833 dynamic_state3_blending =
834 features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable &&
835 features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation &&
836 features.extended_dynamic_state3.extendedDynamicState3ColorWriteMask;
837 dynamic_state3_enables =
838 features.extended_dynamic_state3.extendedDynamicState3DepthClampEnable &&
839 features.extended_dynamic_state3.extendedDynamicState3LogicOpEnable;
840
841 extensions.extended_dynamic_state3 = dynamic_state3_blending || dynamic_state3_enables;
842 dynamic_state3_blending = dynamic_state3_blending && extensions.extended_dynamic_state3;
843 dynamic_state3_enables = dynamic_state3_enables && extensions.extended_dynamic_state3;
844 RemoveExtensionIfUnsuitable(extensions.extended_dynamic_state3,
845 VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
846
847 // VK_EXT_provoking_vertex
848 extensions.provoking_vertex =
849 features.provoking_vertex.provokingVertexLast &&
850 features.provoking_vertex.transformFeedbackPreservesProvokingVertex;
851 RemoveExtensionIfUnsuitable(extensions.provoking_vertex,
852 VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME);
853
854 // VK_KHR_shader_atomic_int64
855 extensions.shader_atomic_int64 = features.shader_atomic_int64.shaderBufferInt64Atomics &&
856 features.shader_atomic_int64.shaderSharedInt64Atomics;
857 RemoveExtensionIfUnsuitable(extensions.shader_atomic_int64,
858 VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME);
859
860 // VK_EXT_shader_demote_to_helper_invocation
861 extensions.shader_demote_to_helper_invocation =
862 features.shader_demote_to_helper_invocation.shaderDemoteToHelperInvocation;
863 RemoveExtensionIfUnsuitable(extensions.shader_demote_to_helper_invocation,
864 VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME);
865
866 // VK_EXT_subgroup_size_control
867 extensions.subgroup_size_control =
868 features.subgroup_size_control.subgroupSizeControl &&
869 properties.subgroup_size_control.minSubgroupSize <= GuestWarpSize &&
870 properties.subgroup_size_control.maxSubgroupSize >= GuestWarpSize;
871 RemoveExtensionIfUnsuitable(extensions.subgroup_size_control,
872 VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME);
873
874 // VK_EXT_transform_feedback
875 extensions.transform_feedback =
876 features.transform_feedback.transformFeedback &&
877 features.transform_feedback.geometryStreams &&
878 properties.transform_feedback.maxTransformFeedbackStreams >= 4 &&
879 properties.transform_feedback.maxTransformFeedbackBuffers > 0 &&
880 properties.transform_feedback.transformFeedbackQueries &&
881 properties.transform_feedback.transformFeedbackDraw;
882 RemoveExtensionIfUnsuitable(extensions.transform_feedback,
883 VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
884
885 // VK_EXT_vertex_input_dynamic_state
886 extensions.vertex_input_dynamic_state =
887 features.vertex_input_dynamic_state.vertexInputDynamicState;
888 RemoveExtensionIfUnsuitable(extensions.vertex_input_dynamic_state,
889 VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
890
891 // VK_KHR_pipeline_executable_properties
892 if (Settings::values.renderer_shader_feedback.GetValue()) {
893 extensions.pipeline_executable_properties =
894 features.pipeline_executable_properties.pipelineExecutableInfo;
895 RemoveExtensionIfUnsuitable(extensions.pipeline_executable_properties,
896 VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME);
897 } else {
898 extensions.pipeline_executable_properties = false;
899 loaded_extensions.erase(VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME);
900 }
901
902 // VK_KHR_workgroup_memory_explicit_layout
903 extensions.workgroup_memory_explicit_layout =
904 features.features.shaderInt16 &&
905 features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayout &&
906 features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayout8BitAccess &&
907 features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayout16BitAccess &&
908 features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayoutScalarBlockLayout;
909 RemoveExtensionIfUnsuitable(extensions.workgroup_memory_explicit_layout,
910 VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME);
1506} 911}
1507 912
1508void Device::SetupFamilies(VkSurfaceKHR surface) { 913void Device::SetupFamilies(VkSurfaceKHR surface) {
@@ -1540,53 +945,6 @@ void Device::SetupFamilies(VkSurfaceKHR surface) {
1540 } 945 }
1541} 946}
1542 947
1543void Device::SetupFeatures() {
1544 const VkPhysicalDeviceFeatures features{physical.GetFeatures()};
1545 is_depth_bounds_supported = features.depthBounds;
1546 is_formatless_image_load_supported = features.shaderStorageImageReadWithoutFormat;
1547 is_shader_float64_supported = features.shaderFloat64;
1548 is_shader_int64_supported = features.shaderInt64;
1549 is_shader_int16_supported = features.shaderInt16;
1550 is_shader_storage_image_multisample = features.shaderStorageImageMultisample;
1551 is_blit_depth_stencil_supported = TestDepthStencilBlits();
1552 is_optimal_astc_supported = IsOptimalAstcSupported(features);
1553
1554 const VkPhysicalDeviceLimits& limits{properties.limits};
1555 max_vertex_input_attributes = limits.maxVertexInputAttributes;
1556 max_vertex_input_bindings = limits.maxVertexInputBindings;
1557}
1558
1559void Device::SetupProperties() {
1560 float_controls.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES;
1561
1562 VkPhysicalDeviceProperties2KHR properties2{};
1563 properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1564 properties2.pNext = &float_controls;
1565
1566 physical.GetProperties2(properties2);
1567}
1568
1569void Device::CollectTelemetryParameters() {
1570 VkPhysicalDeviceDriverProperties driver{
1571 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES,
1572 .pNext = nullptr,
1573 .driverID = {},
1574 .driverName = {},
1575 .driverInfo = {},
1576 .conformanceVersion = {},
1577 };
1578
1579 VkPhysicalDeviceProperties2 device_properties{
1580 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
1581 .pNext = &driver,
1582 .properties = {},
1583 };
1584 physical.GetProperties2(device_properties);
1585
1586 driver_id = driver.driverID;
1587 vendor_name = driver.driverName;
1588}
1589
1590u64 Device::GetDeviceMemoryUsage() const { 948u64 Device::GetDeviceMemoryUsage() const {
1591 VkPhysicalDeviceMemoryBudgetPropertiesEXT budget; 949 VkPhysicalDeviceMemoryBudgetPropertiesEXT budget;
1592 budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; 950 budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
@@ -1602,7 +960,8 @@ u64 Device::GetDeviceMemoryUsage() const {
1602void Device::CollectPhysicalMemoryInfo() { 960void Device::CollectPhysicalMemoryInfo() {
1603 VkPhysicalDeviceMemoryBudgetPropertiesEXT budget{}; 961 VkPhysicalDeviceMemoryBudgetPropertiesEXT budget{};
1604 budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; 962 budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
1605 const auto mem_info = physical.GetMemoryProperties(ext_memory_budget ? &budget : nullptr); 963 const auto mem_info =
964 physical.GetMemoryProperties(extensions.memory_budget ? &budget : nullptr);
1606 const auto& mem_properties = mem_info.memoryProperties; 965 const auto& mem_properties = mem_info.memoryProperties;
1607 const size_t num_properties = mem_properties.memoryHeapCount; 966 const size_t num_properties = mem_properties.memoryHeapCount;
1608 device_access_memory = 0; 967 device_access_memory = 0;
@@ -1618,7 +977,7 @@ void Device::CollectPhysicalMemoryInfo() {
1618 if (is_heap_local) { 977 if (is_heap_local) {
1619 local_memory += mem_properties.memoryHeaps[element].size; 978 local_memory += mem_properties.memoryHeaps[element].size;
1620 } 979 }
1621 if (ext_memory_budget) { 980 if (extensions.memory_budget) {
1622 device_initial_usage += budget.heapUsage[element]; 981 device_initial_usage += budget.heapUsage[element];
1623 device_access_memory += budget.heapBudget[element]; 982 device_access_memory += budget.heapBudget[element];
1624 continue; 983 continue;
@@ -1634,7 +993,7 @@ void Device::CollectPhysicalMemoryInfo() {
1634} 993}
1635 994
1636void Device::CollectToolingInfo() { 995void Device::CollectToolingInfo() {
1637 if (!ext_tooling_info) { 996 if (!extensions.tooling_info) {
1638 return; 997 return;
1639 } 998 }
1640 auto tools{physical.GetPhysicalDeviceToolProperties()}; 999 auto tools{physical.GetPhysicalDeviceToolProperties()};
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index 4bc267163..4cfb20bc2 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -3,6 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <set>
6#include <span> 7#include <span>
7#include <string> 8#include <string>
8#include <unordered_map> 9#include <unordered_map>
@@ -11,6 +12,155 @@
11#include "common/common_types.h" 12#include "common/common_types.h"
12#include "video_core/vulkan_common/vulkan_wrapper.h" 13#include "video_core/vulkan_common/vulkan_wrapper.h"
13 14
15// Define all features which may be used by the implementation here.
16// Vulkan version in the macro describes the minimum version required for feature availability.
17// If the Vulkan version is lower than the required version, the named extension is required.
18#define FOR_EACH_VK_FEATURE_1_1(FEATURE) \
19 FEATURE(EXT, SubgroupSizeControl, SUBGROUP_SIZE_CONTROL, subgroup_size_control) \
20 FEATURE(KHR, 16BitStorage, 16BIT_STORAGE, bit16_storage) \
21 FEATURE(KHR, ShaderAtomicInt64, SHADER_ATOMIC_INT64, shader_atomic_int64) \
22 FEATURE(KHR, ShaderDrawParameters, SHADER_DRAW_PARAMETERS, shader_draw_parameters) \
23 FEATURE(KHR, ShaderFloat16Int8, SHADER_FLOAT16_INT8, shader_float16_int8) \
24 FEATURE(KHR, UniformBufferStandardLayout, UNIFORM_BUFFER_STANDARD_LAYOUT, \
25 uniform_buffer_standard_layout) \
26 FEATURE(KHR, VariablePointer, VARIABLE_POINTERS, variable_pointer)
27
28#define FOR_EACH_VK_FEATURE_1_2(FEATURE) \
29 FEATURE(EXT, HostQueryReset, HOST_QUERY_RESET, host_query_reset) \
30 FEATURE(KHR, 8BitStorage, 8BIT_STORAGE, bit8_storage) \
31 FEATURE(KHR, TimelineSemaphore, TIMELINE_SEMAPHORE, timeline_semaphore)
32
33#define FOR_EACH_VK_FEATURE_1_3(FEATURE) \
34 FEATURE(EXT, ShaderDemoteToHelperInvocation, SHADER_DEMOTE_TO_HELPER_INVOCATION, \
35 shader_demote_to_helper_invocation)
36
37// Define all features which may be used by the implementation and require an extension here.
38#define FOR_EACH_VK_FEATURE_EXT(FEATURE) \
39 FEATURE(EXT, CustomBorderColor, CUSTOM_BORDER_COLOR, custom_border_color) \
40 FEATURE(EXT, DepthClipControl, DEPTH_CLIP_CONTROL, depth_clip_control) \
41 FEATURE(EXT, ExtendedDynamicState, EXTENDED_DYNAMIC_STATE, extended_dynamic_state) \
42 FEATURE(EXT, ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, extended_dynamic_state2) \
43 FEATURE(EXT, ExtendedDynamicState3, EXTENDED_DYNAMIC_STATE_3, extended_dynamic_state3) \
44 FEATURE(EXT, IndexTypeUint8, INDEX_TYPE_UINT8, index_type_uint8) \
45 FEATURE(EXT, LineRasterization, LINE_RASTERIZATION, line_rasterization) \
46 FEATURE(EXT, PrimitiveTopologyListRestart, PRIMITIVE_TOPOLOGY_LIST_RESTART, \
47 primitive_topology_list_restart) \
48 FEATURE(EXT, ProvokingVertex, PROVOKING_VERTEX, provoking_vertex) \
49 FEATURE(EXT, Robustness2, ROBUSTNESS_2, robustness2) \
50 FEATURE(EXT, TransformFeedback, TRANSFORM_FEEDBACK, transform_feedback) \
51 FEATURE(EXT, VertexInputDynamicState, VERTEX_INPUT_DYNAMIC_STATE, vertex_input_dynamic_state) \
52 FEATURE(KHR, PipelineExecutableProperties, PIPELINE_EXECUTABLE_PROPERTIES, \
53 pipeline_executable_properties) \
54 FEATURE(KHR, WorkgroupMemoryExplicitLayout, WORKGROUP_MEMORY_EXPLICIT_LAYOUT, \
55 workgroup_memory_explicit_layout)
56
57// Define miscellaneous extensions which may be used by the implementation here.
58#define FOR_EACH_VK_EXTENSION(EXTENSION) \
59 EXTENSION(EXT, CONSERVATIVE_RASTERIZATION, conservative_rasterization) \
60 EXTENSION(EXT, DEPTH_RANGE_UNRESTRICTED, depth_range_unrestricted) \
61 EXTENSION(EXT, MEMORY_BUDGET, memory_budget) \
62 EXTENSION(EXT, ROBUSTNESS_2, robustness_2) \
63 EXTENSION(EXT, SAMPLER_FILTER_MINMAX, sampler_filter_minmax) \
64 EXTENSION(EXT, SHADER_STENCIL_EXPORT, shader_stencil_export) \
65 EXTENSION(EXT, SHADER_VIEWPORT_INDEX_LAYER, shader_viewport_index_layer) \
66 EXTENSION(EXT, TOOLING_INFO, tooling_info) \
67 EXTENSION(EXT, VERTEX_ATTRIBUTE_DIVISOR, vertex_attribute_divisor) \
68 EXTENSION(KHR, DRIVER_PROPERTIES, driver_properties) \
69 EXTENSION(KHR, EXTERNAL_MEMORY_FD, external_memory_fd) \
70 EXTENSION(KHR, PUSH_DESCRIPTOR, push_descriptor) \
71 EXTENSION(KHR, SAMPLER_MIRROR_CLAMP_TO_EDGE, sampler_mirror_clamp_to_edge) \
72 EXTENSION(KHR, SHADER_FLOAT_CONTROLS, shader_float_controls) \
73 EXTENSION(KHR, SPIRV_1_4, spirv_1_4) \
74 EXTENSION(KHR, SWAPCHAIN, swapchain) \
75 EXTENSION(KHR, SWAPCHAIN_MUTABLE_FORMAT, swapchain_mutable_format) \
76 EXTENSION(NV, DEVICE_DIAGNOSTICS_CONFIG, device_diagnostics_config) \
77 EXTENSION(NV, GEOMETRY_SHADER_PASSTHROUGH, geometry_shader_passthrough) \
78 EXTENSION(NV, VIEWPORT_ARRAY2, viewport_array2) \
79 EXTENSION(NV, VIEWPORT_SWIZZLE, viewport_swizzle)
80
81#define FOR_EACH_VK_EXTENSION_WIN32(EXTENSION) \
82 EXTENSION(KHR, EXTERNAL_MEMORY_WIN32, external_memory_win32)
83
84// Define extensions which must be supported.
85#define FOR_EACH_VK_MANDATORY_EXTENSION(EXTENSION_NAME) \
86 EXTENSION_NAME(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME) \
87 EXTENSION_NAME(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME) \
88 EXTENSION_NAME(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME) \
89 EXTENSION_NAME(VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME) \
90 EXTENSION_NAME(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME)
91
92#define FOR_EACH_VK_MANDATORY_EXTENSION_GENERIC(EXTENSION_NAME) \
93 EXTENSION_NAME(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME)
94
95#define FOR_EACH_VK_MANDATORY_EXTENSION_WIN32(EXTENSION_NAME) \
96 EXTENSION_NAME(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME)
97
98// Define extensions where the absence of the extension may result in a degraded experience.
99#define FOR_EACH_VK_RECOMMENDED_EXTENSION(EXTENSION_NAME) \
100 EXTENSION_NAME(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME) \
101 EXTENSION_NAME(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME) \
102 EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) \
103 EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME) \
104 EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME) \
105 EXTENSION_NAME(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME) \
106 EXTENSION_NAME(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME) \
107 EXTENSION_NAME(VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME) \
108 EXTENSION_NAME(VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME) \
109 EXTENSION_NAME(VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME)
110
111// Define features which must be supported.
112#define FOR_EACH_VK_MANDATORY_FEATURE(FEATURE_NAME) \
113 FEATURE_NAME(bit16_storage, storageBuffer16BitAccess) \
114 FEATURE_NAME(bit16_storage, uniformAndStorageBuffer16BitAccess) \
115 FEATURE_NAME(bit8_storage, storageBuffer8BitAccess) \
116 FEATURE_NAME(bit8_storage, uniformAndStorageBuffer8BitAccess) \
117 FEATURE_NAME(features, depthBiasClamp) \
118 FEATURE_NAME(features, depthClamp) \
119 FEATURE_NAME(features, drawIndirectFirstInstance) \
120 FEATURE_NAME(features, dualSrcBlend) \
121 FEATURE_NAME(features, fillModeNonSolid) \
122 FEATURE_NAME(features, fragmentStoresAndAtomics) \
123 FEATURE_NAME(features, geometryShader) \
124 FEATURE_NAME(features, imageCubeArray) \
125 FEATURE_NAME(features, independentBlend) \
126 FEATURE_NAME(features, largePoints) \
127 FEATURE_NAME(features, logicOp) \
128 FEATURE_NAME(features, multiDrawIndirect) \
129 FEATURE_NAME(features, multiViewport) \
130 FEATURE_NAME(features, occlusionQueryPrecise) \
131 FEATURE_NAME(features, robustBufferAccess) \
132 FEATURE_NAME(features, samplerAnisotropy) \
133 FEATURE_NAME(features, sampleRateShading) \
134 FEATURE_NAME(features, shaderClipDistance) \
135 FEATURE_NAME(features, shaderCullDistance) \
136 FEATURE_NAME(features, shaderImageGatherExtended) \
137 FEATURE_NAME(features, shaderStorageImageWriteWithoutFormat) \
138 FEATURE_NAME(features, tessellationShader) \
139 FEATURE_NAME(features, vertexPipelineStoresAndAtomics) \
140 FEATURE_NAME(features, wideLines) \
141 FEATURE_NAME(host_query_reset, hostQueryReset) \
142 FEATURE_NAME(robustness2, nullDescriptor) \
143 FEATURE_NAME(robustness2, robustBufferAccess2) \
144 FEATURE_NAME(robustness2, robustImageAccess2) \
145 FEATURE_NAME(shader_demote_to_helper_invocation, shaderDemoteToHelperInvocation) \
146 FEATURE_NAME(shader_draw_parameters, shaderDrawParameters) \
147 FEATURE_NAME(timeline_semaphore, timelineSemaphore) \
148 FEATURE_NAME(variable_pointer, variablePointers) \
149 FEATURE_NAME(variable_pointer, variablePointersStorageBuffer)
150
151// Define features where the absence of the feature may result in a degraded experience.
152#define FOR_EACH_VK_RECOMMENDED_FEATURE(FEATURE_NAME) \
153 FEATURE_NAME(custom_border_color, customBorderColors) \
154 FEATURE_NAME(extended_dynamic_state, extendedDynamicState) \
155 FEATURE_NAME(index_type_uint8, indexTypeUint8) \
156 FEATURE_NAME(primitive_topology_list_restart, primitiveTopologyListRestart) \
157 FEATURE_NAME(provoking_vertex, provokingVertexLast) \
158 FEATURE_NAME(shader_float16_int8, shaderFloat16) \
159 FEATURE_NAME(shader_float16_int8, shaderInt8) \
160 FEATURE_NAME(transform_feedback, transformFeedback) \
161 FEATURE_NAME(uniform_buffer_standard_layout, uniformBufferStandardLayout) \
162 FEATURE_NAME(vertex_input_dynamic_state, vertexInputDynamicState)
163
14namespace Vulkan { 164namespace Vulkan {
15 165
16class NsightAftermathTracker; 166class NsightAftermathTracker;
@@ -88,69 +238,69 @@ public:
88 238
89 /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers. 239 /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers.
90 u32 ApiVersion() const { 240 u32 ApiVersion() const {
91 return properties.apiVersion; 241 return properties.properties.apiVersion;
92 } 242 }
93 243
94 /// Returns the current driver version provided in Vulkan-formatted version numbers. 244 /// Returns the current driver version provided in Vulkan-formatted version numbers.
95 u32 GetDriverVersion() const { 245 u32 GetDriverVersion() const {
96 return properties.driverVersion; 246 return properties.properties.driverVersion;
97 } 247 }
98 248
99 /// Returns the device name. 249 /// Returns the device name.
100 std::string_view GetModelName() const { 250 std::string_view GetModelName() const {
101 return properties.deviceName; 251 return properties.properties.deviceName;
102 } 252 }
103 253
104 /// Returns the driver ID. 254 /// Returns the driver ID.
105 VkDriverIdKHR GetDriverID() const { 255 VkDriverIdKHR GetDriverID() const {
106 return driver_id; 256 return properties.driver.driverID;
107 } 257 }
108 258
109 bool ShouldBoostClocks() const; 259 bool ShouldBoostClocks() const;
110 260
111 /// Returns uniform buffer alignment requeriment. 261 /// Returns uniform buffer alignment requeriment.
112 VkDeviceSize GetUniformBufferAlignment() const { 262 VkDeviceSize GetUniformBufferAlignment() const {
113 return properties.limits.minUniformBufferOffsetAlignment; 263 return properties.properties.limits.minUniformBufferOffsetAlignment;
114 } 264 }
115 265
116 /// Returns storage alignment requeriment. 266 /// Returns storage alignment requeriment.
117 VkDeviceSize GetStorageBufferAlignment() const { 267 VkDeviceSize GetStorageBufferAlignment() const {
118 return properties.limits.minStorageBufferOffsetAlignment; 268 return properties.properties.limits.minStorageBufferOffsetAlignment;
119 } 269 }
120 270
121 /// Returns the maximum range for storage buffers. 271 /// Returns the maximum range for storage buffers.
122 VkDeviceSize GetMaxStorageBufferRange() const { 272 VkDeviceSize GetMaxStorageBufferRange() const {
123 return properties.limits.maxStorageBufferRange; 273 return properties.properties.limits.maxStorageBufferRange;
124 } 274 }
125 275
126 /// Returns the maximum size for push constants. 276 /// Returns the maximum size for push constants.
127 VkDeviceSize GetMaxPushConstantsSize() const { 277 VkDeviceSize GetMaxPushConstantsSize() const {
128 return properties.limits.maxPushConstantsSize; 278 return properties.properties.limits.maxPushConstantsSize;
129 } 279 }
130 280
131 /// Returns the maximum size for shared memory. 281 /// Returns the maximum size for shared memory.
132 u32 GetMaxComputeSharedMemorySize() const { 282 u32 GetMaxComputeSharedMemorySize() const {
133 return properties.limits.maxComputeSharedMemorySize; 283 return properties.properties.limits.maxComputeSharedMemorySize;
134 } 284 }
135 285
136 /// Returns float control properties of the device. 286 /// Returns float control properties of the device.
137 const VkPhysicalDeviceFloatControlsPropertiesKHR& FloatControlProperties() const { 287 const VkPhysicalDeviceFloatControlsPropertiesKHR& FloatControlProperties() const {
138 return float_controls; 288 return properties.float_controls;
139 } 289 }
140 290
141 /// Returns true if ASTC is natively supported. 291 /// Returns true if ASTC is natively supported.
142 bool IsOptimalAstcSupported() const { 292 bool IsOptimalAstcSupported() const {
143 return is_optimal_astc_supported; 293 return features.features.textureCompressionASTC_LDR;
144 } 294 }
145 295
146 /// Returns true if the device supports float16 natively. 296 /// Returns true if the device supports float16 natively.
147 bool IsFloat16Supported() const { 297 bool IsFloat16Supported() const {
148 return is_float16_supported; 298 return features.shader_float16_int8.shaderFloat16;
149 } 299 }
150 300
151 /// Returns true if the device supports int8 natively. 301 /// Returns true if the device supports int8 natively.
152 bool IsInt8Supported() const { 302 bool IsInt8Supported() const {
153 return is_int8_supported; 303 return features.shader_float16_int8.shaderInt8;
154 } 304 }
155 305
156 /// Returns true if the device warp size can potentially be bigger than guest's warp size. 306 /// Returns true if the device warp size can potentially be bigger than guest's warp size.
@@ -160,32 +310,32 @@ public:
160 310
161 /// Returns true if the device can be forced to use the guest warp size. 311 /// Returns true if the device can be forced to use the guest warp size.
162 bool IsGuestWarpSizeSupported(VkShaderStageFlagBits stage) const { 312 bool IsGuestWarpSizeSupported(VkShaderStageFlagBits stage) const {
163 return guest_warp_stages & stage; 313 return properties.subgroup_size_control.requiredSubgroupSizeStages & stage;
164 } 314 }
165 315
166 /// Returns the maximum number of push descriptors. 316 /// Returns the maximum number of push descriptors.
167 u32 MaxPushDescriptors() const { 317 u32 MaxPushDescriptors() const {
168 return max_push_descriptors; 318 return properties.push_descriptor.maxPushDescriptors;
169 } 319 }
170 320
171 /// Returns true if formatless image load is supported. 321 /// Returns true if formatless image load is supported.
172 bool IsFormatlessImageLoadSupported() const { 322 bool IsFormatlessImageLoadSupported() const {
173 return is_formatless_image_load_supported; 323 return features.features.shaderStorageImageReadWithoutFormat;
174 } 324 }
175 325
176 /// Returns true if shader int64 is supported. 326 /// Returns true if shader int64 is supported.
177 bool IsShaderInt64Supported() const { 327 bool IsShaderInt64Supported() const {
178 return is_shader_int64_supported; 328 return features.features.shaderInt64;
179 } 329 }
180 330
181 /// Returns true if shader int16 is supported. 331 /// Returns true if shader int16 is supported.
182 bool IsShaderInt16Supported() const { 332 bool IsShaderInt16Supported() const {
183 return is_shader_int16_supported; 333 return features.features.shaderInt16;
184 } 334 }
185 335
186 // Returns true if depth bounds is supported. 336 // Returns true if depth bounds is supported.
187 bool IsDepthBoundsSupported() const { 337 bool IsDepthBoundsSupported() const {
188 return is_depth_bounds_supported; 338 return features.features.depthBounds;
189 } 339 }
190 340
191 /// Returns true when blitting from and to depth stencil images is supported. 341 /// Returns true when blitting from and to depth stencil images is supported.
@@ -195,151 +345,151 @@ public:
195 345
196 /// Returns true if the device supports VK_NV_viewport_swizzle. 346 /// Returns true if the device supports VK_NV_viewport_swizzle.
197 bool IsNvViewportSwizzleSupported() const { 347 bool IsNvViewportSwizzleSupported() const {
198 return nv_viewport_swizzle; 348 return extensions.viewport_swizzle;
199 } 349 }
200 350
201 /// Returns true if the device supports VK_NV_viewport_array2. 351 /// Returns true if the device supports VK_NV_viewport_array2.
202 bool IsNvViewportArray2Supported() const { 352 bool IsNvViewportArray2Supported() const {
203 return nv_viewport_array2; 353 return extensions.viewport_array2;
204 } 354 }
205 355
206 /// Returns true if the device supports VK_NV_geometry_shader_passthrough. 356 /// Returns true if the device supports VK_NV_geometry_shader_passthrough.
207 bool IsNvGeometryShaderPassthroughSupported() const { 357 bool IsNvGeometryShaderPassthroughSupported() const {
208 return nv_geometry_shader_passthrough; 358 return extensions.geometry_shader_passthrough;
209 } 359 }
210 360
211 /// Returns true if the device supports VK_KHR_uniform_buffer_standard_layout. 361 /// Returns true if the device supports VK_KHR_uniform_buffer_standard_layout.
212 bool IsKhrUniformBufferStandardLayoutSupported() const { 362 bool IsKhrUniformBufferStandardLayoutSupported() const {
213 return khr_uniform_buffer_standard_layout; 363 return extensions.uniform_buffer_standard_layout;
214 } 364 }
215 365
216 /// Returns true if the device supports VK_KHR_push_descriptor. 366 /// Returns true if the device supports VK_KHR_push_descriptor.
217 bool IsKhrPushDescriptorSupported() const { 367 bool IsKhrPushDescriptorSupported() const {
218 return khr_push_descriptor; 368 return extensions.push_descriptor;
219 } 369 }
220 370
221 /// Returns true if VK_KHR_pipeline_executable_properties is enabled. 371 /// Returns true if VK_KHR_pipeline_executable_properties is enabled.
222 bool IsKhrPipelineExecutablePropertiesEnabled() const { 372 bool IsKhrPipelineExecutablePropertiesEnabled() const {
223 return khr_pipeline_executable_properties; 373 return extensions.pipeline_executable_properties;
224 } 374 }
225 375
226 /// Returns true if VK_KHR_swapchain_mutable_format is enabled. 376 /// Returns true if VK_KHR_swapchain_mutable_format is enabled.
227 bool IsKhrSwapchainMutableFormatEnabled() const { 377 bool IsKhrSwapchainMutableFormatEnabled() const {
228 return khr_swapchain_mutable_format; 378 return extensions.swapchain_mutable_format;
229 } 379 }
230 380
231 /// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout. 381 /// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout.
232 bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const { 382 bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const {
233 return khr_workgroup_memory_explicit_layout; 383 return extensions.workgroup_memory_explicit_layout;
234 } 384 }
235 385
236 /// Returns true if the device supports VK_EXT_primitive_topology_list_restart. 386 /// Returns true if the device supports VK_EXT_primitive_topology_list_restart.
237 bool IsTopologyListPrimitiveRestartSupported() const { 387 bool IsTopologyListPrimitiveRestartSupported() const {
238 return is_topology_list_restart_supported; 388 return features.primitive_topology_list_restart.primitiveTopologyListRestart;
239 } 389 }
240 390
241 /// Returns true if the device supports VK_EXT_primitive_topology_list_restart. 391 /// Returns true if the device supports VK_EXT_primitive_topology_list_restart.
242 bool IsPatchListPrimitiveRestartSupported() const { 392 bool IsPatchListPrimitiveRestartSupported() const {
243 return is_patch_list_restart_supported; 393 return features.primitive_topology_list_restart.primitiveTopologyPatchListRestart;
244 } 394 }
245 395
246 /// Returns true if the device supports VK_EXT_index_type_uint8. 396 /// Returns true if the device supports VK_EXT_index_type_uint8.
247 bool IsExtIndexTypeUint8Supported() const { 397 bool IsExtIndexTypeUint8Supported() const {
248 return ext_index_type_uint8; 398 return extensions.index_type_uint8;
249 } 399 }
250 400
251 /// Returns true if the device supports VK_EXT_sampler_filter_minmax. 401 /// Returns true if the device supports VK_EXT_sampler_filter_minmax.
252 bool IsExtSamplerFilterMinmaxSupported() const { 402 bool IsExtSamplerFilterMinmaxSupported() const {
253 return ext_sampler_filter_minmax; 403 return extensions.sampler_filter_minmax;
254 } 404 }
255 405
256 /// Returns true if the device supports VK_EXT_depth_range_unrestricted. 406 /// Returns true if the device supports VK_EXT_depth_range_unrestricted.
257 bool IsExtDepthRangeUnrestrictedSupported() const { 407 bool IsExtDepthRangeUnrestrictedSupported() const {
258 return ext_depth_range_unrestricted; 408 return extensions.depth_range_unrestricted;
259 } 409 }
260 410
261 /// Returns true if the device supports VK_EXT_depth_clip_control. 411 /// Returns true if the device supports VK_EXT_depth_clip_control.
262 bool IsExtDepthClipControlSupported() const { 412 bool IsExtDepthClipControlSupported() const {
263 return ext_depth_clip_control; 413 return extensions.depth_clip_control;
264 } 414 }
265 415
266 /// Returns true if the device supports VK_EXT_shader_viewport_index_layer. 416 /// Returns true if the device supports VK_EXT_shader_viewport_index_layer.
267 bool IsExtShaderViewportIndexLayerSupported() const { 417 bool IsExtShaderViewportIndexLayerSupported() const {
268 return ext_shader_viewport_index_layer; 418 return extensions.shader_viewport_index_layer;
269 } 419 }
270 420
271 /// Returns true if the device supports VK_EXT_subgroup_size_control. 421 /// Returns true if the device supports VK_EXT_subgroup_size_control.
272 bool IsExtSubgroupSizeControlSupported() const { 422 bool IsExtSubgroupSizeControlSupported() const {
273 return ext_subgroup_size_control; 423 return extensions.subgroup_size_control;
274 } 424 }
275 425
276 /// Returns true if the device supports VK_EXT_transform_feedback. 426 /// Returns true if the device supports VK_EXT_transform_feedback.
277 bool IsExtTransformFeedbackSupported() const { 427 bool IsExtTransformFeedbackSupported() const {
278 return ext_transform_feedback; 428 return extensions.transform_feedback;
279 } 429 }
280 430
281 /// Returns true if the device supports VK_EXT_custom_border_color. 431 /// Returns true if the device supports VK_EXT_custom_border_color.
282 bool IsExtCustomBorderColorSupported() const { 432 bool IsExtCustomBorderColorSupported() const {
283 return ext_custom_border_color; 433 return extensions.custom_border_color;
284 } 434 }
285 435
286 /// Returns true if the device supports VK_EXT_extended_dynamic_state. 436 /// Returns true if the device supports VK_EXT_extended_dynamic_state.
287 bool IsExtExtendedDynamicStateSupported() const { 437 bool IsExtExtendedDynamicStateSupported() const {
288 return ext_extended_dynamic_state; 438 return extensions.extended_dynamic_state;
289 } 439 }
290 440
291 /// Returns true if the device supports VK_EXT_extended_dynamic_state2. 441 /// Returns true if the device supports VK_EXT_extended_dynamic_state2.
292 bool IsExtExtendedDynamicState2Supported() const { 442 bool IsExtExtendedDynamicState2Supported() const {
293 return ext_extended_dynamic_state_2; 443 return extensions.extended_dynamic_state2;
294 } 444 }
295 445
296 bool IsExtExtendedDynamicState2ExtrasSupported() const { 446 bool IsExtExtendedDynamicState2ExtrasSupported() const {
297 return ext_extended_dynamic_state_2_extra; 447 return features.extended_dynamic_state2.extendedDynamicState2LogicOp;
298 } 448 }
299 449
300 /// Returns true if the device supports VK_EXT_extended_dynamic_state3. 450 /// Returns true if the device supports VK_EXT_extended_dynamic_state3.
301 bool IsExtExtendedDynamicState3Supported() const { 451 bool IsExtExtendedDynamicState3Supported() const {
302 return ext_extended_dynamic_state_3; 452 return extensions.extended_dynamic_state3;
303 } 453 }
304 454
305 /// Returns true if the device supports VK_EXT_extended_dynamic_state3. 455 /// Returns true if the device supports VK_EXT_extended_dynamic_state3.
306 bool IsExtExtendedDynamicState3BlendingSupported() const { 456 bool IsExtExtendedDynamicState3BlendingSupported() const {
307 return ext_extended_dynamic_state_3_blend; 457 return dynamic_state3_blending;
308 } 458 }
309 459
310 /// Returns true if the device supports VK_EXT_extended_dynamic_state3. 460 /// Returns true if the device supports VK_EXT_extended_dynamic_state3.
311 bool IsExtExtendedDynamicState3EnablesSupported() const { 461 bool IsExtExtendedDynamicState3EnablesSupported() const {
312 return ext_extended_dynamic_state_3_enables; 462 return dynamic_state3_enables;
313 } 463 }
314 464
315 /// Returns true if the device supports VK_EXT_line_rasterization. 465 /// Returns true if the device supports VK_EXT_line_rasterization.
316 bool IsExtLineRasterizationSupported() const { 466 bool IsExtLineRasterizationSupported() const {
317 return ext_line_rasterization; 467 return extensions.line_rasterization;
318 } 468 }
319 469
320 /// Returns true if the device supports VK_EXT_vertex_input_dynamic_state. 470 /// Returns true if the device supports VK_EXT_vertex_input_dynamic_state.
321 bool IsExtVertexInputDynamicStateSupported() const { 471 bool IsExtVertexInputDynamicStateSupported() const {
322 return ext_vertex_input_dynamic_state; 472 return extensions.vertex_input_dynamic_state;
323 } 473 }
324 474
325 /// Returns true if the device supports VK_EXT_shader_stencil_export. 475 /// Returns true if the device supports VK_EXT_shader_stencil_export.
326 bool IsExtShaderStencilExportSupported() const { 476 bool IsExtShaderStencilExportSupported() const {
327 return ext_shader_stencil_export; 477 return extensions.shader_stencil_export;
328 } 478 }
329 479
330 /// Returns true if the device supports VK_EXT_conservative_rasterization. 480 /// Returns true if the device supports VK_EXT_conservative_rasterization.
331 bool IsExtConservativeRasterizationSupported() const { 481 bool IsExtConservativeRasterizationSupported() const {
332 return ext_conservative_rasterization; 482 return extensions.conservative_rasterization;
333 } 483 }
334 484
335 /// Returns true if the device supports VK_EXT_provoking_vertex. 485 /// Returns true if the device supports VK_EXT_provoking_vertex.
336 bool IsExtProvokingVertexSupported() const { 486 bool IsExtProvokingVertexSupported() const {
337 return ext_provoking_vertex; 487 return extensions.provoking_vertex;
338 } 488 }
339 489
340 /// Returns true if the device supports VK_KHR_shader_atomic_int64. 490 /// Returns true if the device supports VK_KHR_shader_atomic_int64.
341 bool IsExtShaderAtomicInt64Supported() const { 491 bool IsExtShaderAtomicInt64Supported() const {
342 return ext_shader_atomic_int64; 492 return extensions.shader_atomic_int64;
343 } 493 }
344 494
345 /// Returns the minimum supported version of SPIR-V. 495 /// Returns the minimum supported version of SPIR-V.
@@ -347,7 +497,7 @@ public:
347 if (instance_version >= VK_API_VERSION_1_3) { 497 if (instance_version >= VK_API_VERSION_1_3) {
348 return 0x00010600U; 498 return 0x00010600U;
349 } 499 }
350 if (khr_spirv_1_4) { 500 if (extensions.spirv_1_4) {
351 return 0x00010400U; 501 return 0x00010400U;
352 } 502 }
353 return 0x00010000U; 503 return 0x00010000U;
@@ -365,11 +515,11 @@ public:
365 515
366 /// Returns the vendor name reported from Vulkan. 516 /// Returns the vendor name reported from Vulkan.
367 std::string_view GetVendorName() const { 517 std::string_view GetVendorName() const {
368 return vendor_name; 518 return properties.driver.driverName;
369 } 519 }
370 520
371 /// Returns the list of available extensions. 521 /// Returns the list of available extensions.
372 const std::vector<std::string>& GetAvailableExtensions() const { 522 const std::set<std::string, std::less<>>& GetAvailableExtensions() const {
373 return supported_extensions; 523 return supported_extensions;
374 } 524 }
375 525
@@ -378,7 +528,7 @@ public:
378 } 528 }
379 529
380 bool CanReportMemoryUsage() const { 530 bool CanReportMemoryUsage() const {
381 return ext_memory_budget; 531 return extensions.memory_budget;
382 } 532 }
383 533
384 u64 GetDeviceMemoryUsage() const; 534 u64 GetDeviceMemoryUsage() const;
@@ -400,36 +550,29 @@ public:
400 } 550 }
401 551
402 bool HasNullDescriptor() const { 552 bool HasNullDescriptor() const {
403 return has_null_descriptor; 553 return features.robustness2.nullDescriptor;
404 } 554 }
405 555
406 u32 GetMaxVertexInputAttributes() const { 556 u32 GetMaxVertexInputAttributes() const {
407 return max_vertex_input_attributes; 557 return properties.properties.limits.maxVertexInputAttributes;
408 } 558 }
409 559
410 u32 GetMaxVertexInputBindings() const { 560 u32 GetMaxVertexInputBindings() const {
411 return max_vertex_input_bindings; 561 return properties.properties.limits.maxVertexInputBindings;
412 } 562 }
413 563
414private: 564private:
415 /// Checks if the physical device is suitable. 565 /// Checks if the physical device is suitable and configures the object state
416 void CheckSuitability(bool requires_swapchain) const; 566 /// with all necessary info about its properties.
567 bool GetSuitability(bool requires_swapchain);
417 568
418 /// Loads extensions into a vector and stores available ones in this object. 569 // Remove extensions which have incomplete feature support.
419 std::vector<const char*> LoadExtensions(bool requires_surface); 570 void RemoveUnsuitableExtensions();
571 void RemoveExtensionIfUnsuitable(bool is_suitable, const std::string& extension_name);
420 572
421 /// Sets up queue families. 573 /// Sets up queue families.
422 void SetupFamilies(VkSurfaceKHR surface); 574 void SetupFamilies(VkSurfaceKHR surface);
423 575
424 /// Sets up device features.
425 void SetupFeatures();
426
427 /// Sets up device properties.
428 void SetupProperties();
429
430 /// Collects telemetry information from the device.
431 void CollectTelemetryParameters();
432
433 /// Collects information about attached tools. 576 /// Collects information about attached tools.
434 void CollectToolingInfo(); 577 void CollectToolingInfo();
435 578
@@ -440,91 +583,93 @@ private:
440 std::vector<VkDeviceQueueCreateInfo> GetDeviceQueueCreateInfos() const; 583 std::vector<VkDeviceQueueCreateInfo> GetDeviceQueueCreateInfos() const;
441 584
442 /// Returns true if ASTC textures are natively supported. 585 /// Returns true if ASTC textures are natively supported.
443 bool IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const; 586 bool ComputeIsOptimalAstcSupported() const;
444 587
445 /// Returns true if the device natively supports blitting depth stencil images. 588 /// Returns true if the device natively supports blitting depth stencil images.
446 bool TestDepthStencilBlits() const; 589 bool TestDepthStencilBlits() const;
447 590
448 VkInstance instance; ///< Vulkan instance. 591private:
449 vk::DeviceDispatch dld; ///< Device function pointers. 592 VkInstance instance; ///< Vulkan instance.
450 vk::PhysicalDevice physical; ///< Physical device. 593 vk::DeviceDispatch dld; ///< Device function pointers.
451 VkPhysicalDeviceProperties properties; ///< Device properties. 594 vk::PhysicalDevice physical; ///< Physical device.
452 VkPhysicalDeviceFloatControlsPropertiesKHR float_controls{}; ///< Float control properties. 595 vk::Device logical; ///< Logical device.
453 vk::Device logical; ///< Logical device. 596 vk::Queue graphics_queue; ///< Main graphics queue.
454 vk::Queue graphics_queue; ///< Main graphics queue. 597 vk::Queue present_queue; ///< Main present queue.
455 vk::Queue present_queue; ///< Main present queue. 598 u32 instance_version{}; ///< Vulkan instance version.
456 u32 instance_version{}; ///< Vulkan onstance version. 599 u32 graphics_family{}; ///< Main graphics queue family index.
457 u32 graphics_family{}; ///< Main graphics queue family index. 600 u32 present_family{}; ///< Main present queue family index.
458 u32 present_family{}; ///< Main present queue family index. 601
459 VkDriverIdKHR driver_id{}; ///< Driver ID. 602 struct Extensions {
460 VkShaderStageFlags guest_warp_stages{}; ///< Stages where the guest warp size can be forced. 603#define EXTENSION(prefix, macro_name, var_name) bool var_name{};
461 u64 device_access_memory{}; ///< Total size of device local memory in bytes. 604#define FEATURE(prefix, struct_name, macro_name, var_name) bool var_name{};
462 u32 max_push_descriptors{}; ///< Maximum number of push descriptors 605
463 u32 sets_per_pool{}; ///< Sets per Description Pool 606 FOR_EACH_VK_FEATURE_1_1(FEATURE);
464 bool is_optimal_astc_supported{}; ///< Support for native ASTC. 607 FOR_EACH_VK_FEATURE_1_2(FEATURE);
465 bool is_float16_supported{}; ///< Support for float16 arithmetic. 608 FOR_EACH_VK_FEATURE_1_3(FEATURE);
466 bool is_int8_supported{}; ///< Support for int8 arithmetic. 609 FOR_EACH_VK_FEATURE_EXT(FEATURE);
467 bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest. 610 FOR_EACH_VK_EXTENSION(EXTENSION);
468 bool is_formatless_image_load_supported{}; ///< Support for shader image read without format. 611 FOR_EACH_VK_EXTENSION_WIN32(EXTENSION);
469 bool is_depth_bounds_supported{}; ///< Support for depth bounds. 612
470 bool is_shader_float64_supported{}; ///< Support for float64. 613#undef EXTENSION
471 bool is_shader_int64_supported{}; ///< Support for int64. 614#undef FEATURE
472 bool is_shader_int16_supported{}; ///< Support for int16. 615 };
473 bool is_shader_storage_image_multisample{}; ///< Support for image operations on MSAA images. 616
474 bool is_blit_depth_stencil_supported{}; ///< Support for blitting from and to depth stencil. 617 struct Features {
475 bool is_topology_list_restart_supported{}; ///< Support for primitive restart with list 618#define FEATURE_CORE(prefix, struct_name, macro_name, var_name) \
476 ///< topologies. 619 VkPhysicalDevice##struct_name##Features var_name{};
477 bool is_patch_list_restart_supported{}; ///< Support for primitive restart with list patch. 620#define FEATURE_EXT(prefix, struct_name, macro_name, var_name) \
478 bool is_integrated{}; ///< Is GPU an iGPU. 621 VkPhysicalDevice##struct_name##Features##prefix var_name{};
479 bool is_virtual{}; ///< Is GPU a virtual GPU. 622
480 bool is_non_gpu{}; ///< Is SoftwareRasterizer, FPGA, non-GPU device. 623 FOR_EACH_VK_FEATURE_1_1(FEATURE_CORE);
481 bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle. 624 FOR_EACH_VK_FEATURE_1_2(FEATURE_CORE);
482 bool nv_viewport_array2{}; ///< Support for VK_NV_viewport_array2. 625 FOR_EACH_VK_FEATURE_1_3(FEATURE_CORE);
483 bool nv_geometry_shader_passthrough{}; ///< Support for VK_NV_geometry_shader_passthrough. 626 FOR_EACH_VK_FEATURE_EXT(FEATURE_EXT);
484 bool khr_draw_indirect_count{}; ///< Support for VK_KHR_draw_indirect_count. 627
485 bool khr_uniform_buffer_standard_layout{}; ///< Support for scalar uniform buffer layouts. 628#undef FEATURE_CORE
486 bool khr_spirv_1_4{}; ///< Support for VK_KHR_spirv_1_4. 629#undef FEATURE_EXT
487 bool khr_workgroup_memory_explicit_layout{}; ///< Support for explicit workgroup layouts. 630
488 bool khr_push_descriptor{}; ///< Support for VK_KHR_push_descritor. 631 VkPhysicalDeviceFeatures features{};
489 bool khr_pipeline_executable_properties{}; ///< Support for executable properties. 632 };
490 bool khr_swapchain_mutable_format{}; ///< Support for VK_KHR_swapchain_mutable_format. 633
491 bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8. 634 struct Properties {
492 bool ext_sampler_filter_minmax{}; ///< Support for VK_EXT_sampler_filter_minmax. 635 VkPhysicalDeviceDriverProperties driver{};
493 bool ext_depth_clip_control{}; ///< Support for VK_EXT_depth_clip_control 636 VkPhysicalDeviceFloatControlsProperties float_controls{};
494 bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted. 637 VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor{};
495 bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer. 638 VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};
496 bool ext_tooling_info{}; ///< Support for VK_EXT_tooling_info. 639 VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback{};
497 bool ext_subgroup_size_control{}; ///< Support for VK_EXT_subgroup_size_control. 640
498 bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback. 641 VkPhysicalDeviceProperties properties{};
499 bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color. 642 };
500 bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state. 643
501 bool ext_extended_dynamic_state_2{}; ///< Support for VK_EXT_extended_dynamic_state2. 644 Extensions extensions{};
502 bool ext_extended_dynamic_state_2_extra{}; ///< Support for VK_EXT_extended_dynamic_state2. 645 Features features{};
503 bool ext_extended_dynamic_state_3{}; ///< Support for VK_EXT_extended_dynamic_state3. 646 Properties properties{};
504 bool ext_extended_dynamic_state_3_blend{}; ///< Support for VK_EXT_extended_dynamic_state3. 647
505 bool ext_extended_dynamic_state_3_enables{}; ///< Support for VK_EXT_extended_dynamic_state3. 648 VkPhysicalDeviceFeatures2 features2{};
506 bool ext_line_rasterization{}; ///< Support for VK_EXT_line_rasterization. 649 VkPhysicalDeviceProperties2 properties2{};
507 bool ext_vertex_input_dynamic_state{}; ///< Support for VK_EXT_vertex_input_dynamic_state. 650
508 bool ext_shader_stencil_export{}; ///< Support for VK_EXT_shader_stencil_export. 651 // Misc features
509 bool ext_shader_atomic_int64{}; ///< Support for VK_KHR_shader_atomic_int64. 652 bool is_optimal_astc_supported{}; ///< Support for all guest ASTC formats.
510 bool ext_conservative_rasterization{}; ///< Support for VK_EXT_conservative_rasterization. 653 bool is_blit_depth_stencil_supported{}; ///< Support for blitting from and to depth stencil.
511 bool ext_provoking_vertex{}; ///< Support for VK_EXT_provoking_vertex. 654 bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest.
512 bool ext_memory_budget{}; ///< Support for VK_EXT_memory_budget. 655 bool is_integrated{}; ///< Is GPU an iGPU.
513 bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config. 656 bool is_virtual{}; ///< Is GPU a virtual GPU.
514 bool has_broken_cube_compatibility{}; ///< Has broken cube compatiblity bit 657 bool is_non_gpu{}; ///< Is SoftwareRasterizer, FPGA, non-GPU device.
515 bool has_renderdoc{}; ///< Has RenderDoc attached 658 bool has_broken_cube_compatibility{}; ///< Has broken cube compatiblity bit
516 bool has_nsight_graphics{}; ///< Has Nsight Graphics attached 659 bool has_renderdoc{}; ///< Has RenderDoc attached
517 bool supports_d24_depth{}; ///< Supports D24 depth buffers. 660 bool has_nsight_graphics{}; ///< Has Nsight Graphics attached
518 bool cant_blit_msaa{}; ///< Does not support MSAA<->MSAA blitting. 661 bool supports_d24_depth{}; ///< Supports D24 depth buffers.
519 bool must_emulate_bgr565{}; ///< Emulates BGR565 by swizzling RGB565 format. 662 bool cant_blit_msaa{}; ///< Does not support MSAA<->MSAA blitting.
520 bool has_null_descriptor{}; ///< Has support for null descriptors. 663 bool must_emulate_bgr565{}; ///< Emulates BGR565 by swizzling RGB565 format.
521 u32 max_vertex_input_attributes{}; ///< Max vertex input attributes in pipeline 664 bool dynamic_state3_blending{}; ///< Has all blending features of dynamic_state3.
522 u32 max_vertex_input_bindings{}; ///< Max vertex input buffers in pipeline 665 bool dynamic_state3_enables{}; ///< Has all enables features of dynamic_state3.
666 u64 device_access_memory{}; ///< Total size of device local memory in bytes.
667 u32 sets_per_pool{}; ///< Sets per Description Pool
523 668
524 // Telemetry parameters 669 // Telemetry parameters
525 std::string vendor_name; ///< Device's driver name. 670 std::set<std::string, std::less<>> supported_extensions; ///< Reported Vulkan extensions.
526 std::vector<std::string> supported_extensions; ///< Reported Vulkan extensions. 671 std::set<std::string, std::less<>> loaded_extensions; ///< Loaded Vulkan extensions.
527 std::vector<size_t> valid_heap_memory; ///< Heaps used. 672 std::vector<size_t> valid_heap_memory; ///< Heaps used.
528 673
529 /// Format properties dictionary. 674 /// Format properties dictionary.
530 std::unordered_map<VkFormat, VkFormatProperties> format_properties; 675 std::unordered_map<VkFormat, VkFormatProperties> format_properties;
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index c55f81c2f..2ea3b7d59 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1839,9 +1839,11 @@ void GMainWindow::OnEmulationStopTimeExpired() {
1839 1839
1840void GMainWindow::OnEmulationStopped() { 1840void GMainWindow::OnEmulationStopped() {
1841 shutdown_timer.stop(); 1841 shutdown_timer.stop();
1842 emu_thread->disconnect(); 1842 if (emu_thread) {
1843 emu_thread->wait(); 1843 emu_thread->disconnect();
1844 emu_thread = nullptr; 1844 emu_thread->wait();
1845 emu_thread.reset();
1846 }
1845 1847
1846 if (shutdown_dialog) { 1848 if (shutdown_dialog) {
1847 shutdown_dialog->deleteLater(); 1849 shutdown_dialog->deleteLater();
@@ -3029,6 +3031,8 @@ void GMainWindow::OnStopGame() {
3029 3031
3030 if (OnShutdownBegin()) { 3032 if (OnShutdownBegin()) {
3031 OnShutdownBeginDialog(); 3033 OnShutdownBeginDialog();
3034 } else {
3035 OnEmulationStopped();
3032 } 3036 }
3033} 3037}
3034 3038