diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 52855120c1..067cafb85e 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) {
     return GetReadableVersion(version);
 }
 
-std::string BuildCommaSeparatedExtensions(std::vector<std::string> available_extensions) {
-    std::sort(std::begin(available_extensions), std::end(available_extensions));
-
-    static constexpr std::size_t AverageExtensionSize = 64;
-    std::string separated_extensions;
-    separated_extensions.reserve(available_extensions.size() * AverageExtensionSize);
-
-    const auto end = std::end(available_extensions);
-    for (auto extension = std::begin(available_extensions); extension != end; ++extension) {
-        if (const bool is_last = extension + 1 == end; is_last) {
-            separated_extensions += *extension;
-        } else {
-            separated_extensions += fmt::format("{},", *extension);
-        }
-    }
-    return separated_extensions;
+std::string BuildCommaSeparatedExtensions(
+    const std::set<std::string, std::less<>>& available_extensions) {
+    return fmt::format("{}", fmt::join(available_extensions, ","));
 }
 
 } // Anonymous namespace
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index fd1c5a683e..1458ec4c8b 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 {
     VoltaOrOlder,
 };
 
-constexpr std::array REQUIRED_EXTENSIONS{
-    VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME,
-    VK_EXT_ROBUSTNESS_2_EXTENSION_NAME,
-#ifdef _WIN32
-    VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
-#endif
-#ifdef __unix__
-    VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
-#endif
-};
-
-constexpr std::array REQUIRED_EXTENSIONS_BEFORE_1_2{
-    VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
-    VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME,
-    VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
-    VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME,
-    VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME,
-    VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
-};
-
-constexpr std::array REQUIRED_EXTENSIONS_BEFORE_1_3{
-    VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME,
-};
-
 template <typename T>
 void SetNext(void**& next, T& data) {
     *next = &data;
@@ -286,24 +262,9 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::Physica
     return format_properties;
 }
 
-std::vector<std::string> GetSupportedExtensions(vk::PhysicalDevice physical) {
-    const std::vector extensions = physical.EnumerateDeviceExtensionProperties();
-    std::vector<std::string> supported_extensions;
-    supported_extensions.reserve(extensions.size());
-    for (const auto& extension : extensions) {
-        supported_extensions.emplace_back(extension.extensionName);
-    }
-    return supported_extensions;
-}
-
-bool IsExtensionSupported(std::span<const std::string> supported_extensions,
-                          std::string_view extension) {
-    return std::ranges::find(supported_extensions, extension) != supported_extensions.end();
-}
-
 NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
-                                         std::span<const std::string> exts) {
-    if (IsExtensionSupported(exts, VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME)) {
+                                         const std::set<std::string, std::less<>>& exts) {
+    if (exts.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME)) {
         VkPhysicalDeviceFragmentShadingRatePropertiesKHR shading_rate_props{};
         shading_rate_props.sType =
             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
@@ -316,423 +277,39 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
             return NvidiaArchitecture::AmpereOrNewer;
         }
     }
-    if (IsExtensionSupported(exts, VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME)) {
+    if (exts.contains(VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME)) {
         return NvidiaArchitecture::Turing;
     }
     return NvidiaArchitecture::VoltaOrOlder;
 }
+
+std::vector<const char*> ExtensionListForVulkan(
+    const std::set<std::string, std::less<>>& extensions) {
+    std::vector<const char*> output;
+    for (const auto& extension : extensions) {
+        output.push_back(extension.c_str());
+    }
+    return output;
+}
+
 } // Anonymous namespace
 
 Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface,
                const vk::InstanceDispatch& dld_)
-    : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()},
-      instance_version{properties.apiVersion}, supported_extensions{GetSupportedExtensions(
-                                                   physical)},
+    : instance{instance_}, dld{dld_}, physical{physical_},
       format_properties(GetFormatProperties(physical)) {
-    CheckSuitability(surface != nullptr);
+    if (!GetSuitability(surface != nullptr)) {
+        throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER);
+    }
     SetupFamilies(surface);
-    SetupFeatures();
-    SetupProperties();
-
     const auto queue_cis = GetDeviceQueueCreateInfos();
-    const std::vector extensions = LoadExtensions(surface != nullptr);
 
-    VkPhysicalDeviceFeatures2 features2{
-        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
-        .pNext = nullptr,
-        .features{
-            .robustBufferAccess = true,
-            .fullDrawIndexUint32 = false,
-            .imageCubeArray = true,
-            .independentBlend = true,
-            .geometryShader = true,
-            .tessellationShader = true,
-            .sampleRateShading = true,
-            .dualSrcBlend = true,
-            .logicOp = true,
-            .multiDrawIndirect = true,
-            .drawIndirectFirstInstance = true,
-            .depthClamp = true,
-            .depthBiasClamp = true,
-            .fillModeNonSolid = true,
-            .depthBounds = is_depth_bounds_supported,
-            .wideLines = true,
-            .largePoints = true,
-            .alphaToOne = false,
-            .multiViewport = true,
-            .samplerAnisotropy = true,
-            .textureCompressionETC2 = false,
-            .textureCompressionASTC_LDR = is_optimal_astc_supported,
-            .textureCompressionBC = false,
-            .occlusionQueryPrecise = true,
-            .pipelineStatisticsQuery = false,
-            .vertexPipelineStoresAndAtomics = true,
-            .fragmentStoresAndAtomics = true,
-            .shaderTessellationAndGeometryPointSize = false,
-            .shaderImageGatherExtended = true,
-            .shaderStorageImageExtendedFormats = false,
-            .shaderStorageImageMultisample = is_shader_storage_image_multisample,
-            .shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported,
-            .shaderStorageImageWriteWithoutFormat = true,
-            .shaderUniformBufferArrayDynamicIndexing = false,
-            .shaderSampledImageArrayDynamicIndexing = false,
-            .shaderStorageBufferArrayDynamicIndexing = false,
-            .shaderStorageImageArrayDynamicIndexing = false,
-            .shaderClipDistance = true,
-            .shaderCullDistance = true,
-            .shaderFloat64 = is_shader_float64_supported,
-            .shaderInt64 = is_shader_int64_supported,
-            .shaderInt16 = is_shader_int16_supported,
-            .shaderResourceResidency = false,
-            .shaderResourceMinLod = false,
-            .sparseBinding = false,
-            .sparseResidencyBuffer = false,
-            .sparseResidencyImage2D = false,
-            .sparseResidencyImage3D = false,
-            .sparseResidency2Samples = false,
-            .sparseResidency4Samples = false,
-            .sparseResidency8Samples = false,
-            .sparseResidency16Samples = false,
-            .sparseResidencyAliased = false,
-            .variableMultisampleRate = false,
-            .inheritedQueries = false,
-        },
-    };
+    // GetSuitability has already configured the linked list of features for us.
+    // Reuse it here.
     const void* first_next = &features2;
-    void** next = &features2.pNext;
 
-    VkPhysicalDeviceTimelineSemaphoreFeatures timeline_semaphore{
-        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES,
-        .pNext = nullptr,
-        .timelineSemaphore = true,
-    };
-    SetNext(next, timeline_semaphore);
-
-    VkPhysicalDevice16BitStorageFeatures bit16_storage{
-        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES,
-        .pNext = nullptr,
-        .storageBuffer16BitAccess = true,
-        .uniformAndStorageBuffer16BitAccess = true,
-        .storagePushConstant16 = false,
-        .storageInputOutput16 = false,
-    };
-    SetNext(next, bit16_storage);
-
-    VkPhysicalDevice8BitStorageFeatures bit8_storage{
-        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES,
-        .pNext = nullptr,
-        .storageBuffer8BitAccess = true,
-        .uniformAndStorageBuffer8BitAccess = true,
-        .storagePushConstant8 = false,
-    };
-    SetNext(next, bit8_storage);
-
-    VkPhysicalDeviceRobustness2FeaturesEXT robustness2{
-        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT,
-        .pNext = nullptr,
-        .robustBufferAccess2 = true,
-        .robustImageAccess2 = true,
-        .nullDescriptor = true,
-    };
-    SetNext(next, robustness2);
-
-    VkPhysicalDeviceHostQueryResetFeatures host_query_reset{
-        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES,
-        .pNext = nullptr,
-        .hostQueryReset = true,
-    };
-    SetNext(next, host_query_reset);
-
-    VkPhysicalDeviceVariablePointerFeatures variable_pointers{
-        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES,
-        .pNext = nullptr,
-        .variablePointersStorageBuffer = VK_TRUE,
-        .variablePointers = VK_TRUE,
-    };
-    SetNext(next, variable_pointers);
-
-    VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures demote{
-        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES,
-        .pNext = nullptr,
-        .shaderDemoteToHelperInvocation = true,
-    };
-    SetNext(next, demote);
-
-    VkPhysicalDeviceShaderDrawParametersFeatures draw_parameters{
-        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES,
-        .pNext = nullptr,
-        .shaderDrawParameters = true,
-    };
-    SetNext(next, draw_parameters);
-
-    VkPhysicalDeviceShaderFloat16Int8Features float16_int8;
-    if (is_int8_supported || is_float16_supported) {
-        float16_int8 = {
-            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES,
-            .pNext = nullptr,
-            .shaderFloat16 = is_float16_supported,
-            .shaderInt8 = is_int8_supported,
-        };
-        SetNext(next, float16_int8);
-    }
-    if (!is_float16_supported) {
-        LOG_INFO(Render_Vulkan, "Device doesn't support float16 natively");
-    }
-    if (!is_int8_supported) {
-        LOG_INFO(Render_Vulkan, "Device doesn't support int8 natively");
-    }
-
-    if (!nv_viewport_swizzle) {
-        LOG_INFO(Render_Vulkan, "Device doesn't support viewport swizzles");
-    }
-
-    if (!nv_viewport_array2) {
-        LOG_INFO(Render_Vulkan, "Device doesn't support viewport masks");
-    }
-
-    if (!nv_geometry_shader_passthrough) {
-        LOG_INFO(Render_Vulkan, "Device doesn't support passthrough geometry shaders");
-    }
-
-    VkPhysicalDeviceUniformBufferStandardLayoutFeatures std430_layout;
-    if (khr_uniform_buffer_standard_layout) {
-        std430_layout = {
-            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES,
-            .pNext = nullptr,
-            .uniformBufferStandardLayout = true,
-        };
-        SetNext(next, std430_layout);
-    } else {
-        LOG_INFO(Render_Vulkan, "Device doesn't support packed UBOs");
-    }
-
-    VkPhysicalDeviceIndexTypeUint8FeaturesEXT index_type_uint8;
-    if (ext_index_type_uint8) {
-        index_type_uint8 = {
-            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT,
-            .pNext = nullptr,
-            .indexTypeUint8 = true,
-        };
-        SetNext(next, index_type_uint8);
-    } else {
-        LOG_INFO(Render_Vulkan, "Device doesn't support uint8 indexes");
-    }
-
-    VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT primitive_topology_list_restart;
-    if (is_topology_list_restart_supported || is_patch_list_restart_supported) {
-        primitive_topology_list_restart = {
-            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT,
-            .pNext = nullptr,
-            .primitiveTopologyListRestart = is_topology_list_restart_supported,
-            .primitiveTopologyPatchListRestart = is_patch_list_restart_supported,
-        };
-        SetNext(next, primitive_topology_list_restart);
-    } else {
-        LOG_INFO(Render_Vulkan, "Device doesn't support list topology primitive restart");
-    }
-
-    VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback;
-    if (ext_transform_feedback) {
-        transform_feedback = {
-            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT,
-            .pNext = nullptr,
-            .transformFeedback = true,
-            .geometryStreams = true,
-        };
-        SetNext(next, transform_feedback);
-    } else {
-        LOG_INFO(Render_Vulkan, "Device doesn't support transform feedbacks");
-    }
-
-    VkPhysicalDeviceCustomBorderColorFeaturesEXT custom_border;
-    if (ext_custom_border_color) {
-        custom_border = {
-            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT,
-            .pNext = nullptr,
-            .customBorderColors = VK_TRUE,
-            .customBorderColorWithoutFormat = VK_TRUE,
-        };
-        SetNext(next, custom_border);
-    } else {
-        LOG_INFO(Render_Vulkan, "Device doesn't support custom border colors");
-    }
-
-    VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state;
-    if (ext_extended_dynamic_state) {
-        dynamic_state = {
-            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT,
-            .pNext = nullptr,
-            .extendedDynamicState = VK_TRUE,
-        };
-        SetNext(next, dynamic_state);
-    } else {
-        LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state");
-    }
-
-    VkPhysicalDeviceExtendedDynamicState2FeaturesEXT dynamic_state_2;
-    if (ext_extended_dynamic_state_2) {
-        dynamic_state_2 = {
-            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT,
-            .pNext = nullptr,
-            .extendedDynamicState2 = VK_TRUE,
-            .extendedDynamicState2LogicOp = ext_extended_dynamic_state_2_extra ? VK_TRUE : VK_FALSE,
-            .extendedDynamicState2PatchControlPoints = VK_FALSE,
-        };
-        SetNext(next, dynamic_state_2);
-    } else {
-        LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state 2");
-    }
-
-    VkPhysicalDeviceExtendedDynamicState3FeaturesEXT dynamic_state_3;
-    if (ext_extended_dynamic_state_3) {
-        dynamic_state_3 = {
-            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT,
-            .pNext = nullptr,
-            .extendedDynamicState3TessellationDomainOrigin = VK_FALSE,
-            .extendedDynamicState3DepthClampEnable =
-                ext_extended_dynamic_state_3_enables ? VK_TRUE : VK_FALSE,
-            .extendedDynamicState3PolygonMode = VK_FALSE,
-            .extendedDynamicState3RasterizationSamples = VK_FALSE,
-            .extendedDynamicState3SampleMask = VK_FALSE,
-            .extendedDynamicState3AlphaToCoverageEnable = VK_FALSE,
-            .extendedDynamicState3AlphaToOneEnable = VK_FALSE,
-            .extendedDynamicState3LogicOpEnable =
-                ext_extended_dynamic_state_3_enables ? VK_TRUE : VK_FALSE,
-            .extendedDynamicState3ColorBlendEnable =
-                ext_extended_dynamic_state_3_blend ? VK_TRUE : VK_FALSE,
-            .extendedDynamicState3ColorBlendEquation =
-                ext_extended_dynamic_state_3_blend ? VK_TRUE : VK_FALSE,
-            .extendedDynamicState3ColorWriteMask =
-                ext_extended_dynamic_state_3_blend ? VK_TRUE : VK_FALSE,
-            .extendedDynamicState3RasterizationStream = VK_FALSE,
-            .extendedDynamicState3ConservativeRasterizationMode = VK_FALSE,
-            .extendedDynamicState3ExtraPrimitiveOverestimationSize = VK_FALSE,
-            .extendedDynamicState3DepthClipEnable = VK_FALSE,
-            .extendedDynamicState3SampleLocationsEnable = VK_FALSE,
-            .extendedDynamicState3ColorBlendAdvanced = VK_FALSE,
-            .extendedDynamicState3ProvokingVertexMode = VK_FALSE,
-            .extendedDynamicState3LineRasterizationMode = VK_FALSE,
-            .extendedDynamicState3LineStippleEnable = VK_FALSE,
-            .extendedDynamicState3DepthClipNegativeOneToOne = VK_FALSE,
-            .extendedDynamicState3ViewportWScalingEnable = VK_FALSE,
-            .extendedDynamicState3ViewportSwizzle = VK_FALSE,
-            .extendedDynamicState3CoverageToColorEnable = VK_FALSE,
-            .extendedDynamicState3CoverageToColorLocation = VK_FALSE,
-            .extendedDynamicState3CoverageModulationMode = VK_FALSE,
-            .extendedDynamicState3CoverageModulationTableEnable = VK_FALSE,
-            .extendedDynamicState3CoverageModulationTable = VK_FALSE,
-            .extendedDynamicState3CoverageReductionMode = VK_FALSE,
-            .extendedDynamicState3RepresentativeFragmentTestEnable = VK_FALSE,
-            .extendedDynamicState3ShadingRateImageEnable = VK_FALSE,
-        };
-        SetNext(next, dynamic_state_3);
-    } else {
-        LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state 3");
-    }
-
-    VkPhysicalDeviceLineRasterizationFeaturesEXT line_raster;
-    if (ext_line_rasterization) {
-        line_raster = {
-            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT,
-            .pNext = nullptr,
-            .rectangularLines = VK_TRUE,
-            .bresenhamLines = VK_FALSE,
-            .smoothLines = VK_TRUE,
-            .stippledRectangularLines = VK_FALSE,
-            .stippledBresenhamLines = VK_FALSE,
-            .stippledSmoothLines = VK_FALSE,
-        };
-        SetNext(next, line_raster);
-    } else {
-        LOG_INFO(Render_Vulkan, "Device doesn't support smooth lines");
-    }
-
-    if (!ext_conservative_rasterization) {
-        LOG_INFO(Render_Vulkan, "Device doesn't support conservative rasterization");
-    }
-
-    VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex;
-    if (ext_provoking_vertex) {
-        provoking_vertex = {
-            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT,
-            .pNext = nullptr,
-            .provokingVertexLast = VK_TRUE,
-            .transformFeedbackPreservesProvokingVertex = VK_TRUE,
-        };
-        SetNext(next, provoking_vertex);
-    } else {
-        LOG_INFO(Render_Vulkan, "Device doesn't support provoking vertex last");
-    }
-
-    VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT vertex_input_dynamic;
-    if (ext_vertex_input_dynamic_state) {
-        vertex_input_dynamic = {
-            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT,
-            .pNext = nullptr,
-            .vertexInputDynamicState = VK_TRUE,
-        };
-        SetNext(next, vertex_input_dynamic);
-    } else {
-        LOG_INFO(Render_Vulkan, "Device doesn't support vertex input dynamic state");
-    }
-
-    VkPhysicalDeviceShaderAtomicInt64Features atomic_int64;
-    if (ext_shader_atomic_int64) {
-        atomic_int64 = {
-            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES,
-            .pNext = nullptr,
-            .shaderBufferInt64Atomics = VK_TRUE,
-            .shaderSharedInt64Atomics = VK_TRUE,
-        };
-        SetNext(next, atomic_int64);
-    }
-
-    VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR workgroup_layout;
-    if (khr_workgroup_memory_explicit_layout && is_shader_int16_supported) {
-        workgroup_layout = {
-            .sType =
-                VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR,
-            .pNext = nullptr,
-            .workgroupMemoryExplicitLayout = VK_TRUE,
-            .workgroupMemoryExplicitLayoutScalarBlockLayout = VK_TRUE,
-            .workgroupMemoryExplicitLayout8BitAccess = VK_TRUE,
-            .workgroupMemoryExplicitLayout16BitAccess = VK_TRUE,
-        };
-        SetNext(next, workgroup_layout);
-    } else if (khr_workgroup_memory_explicit_layout) {
-        // TODO(lat9nq): Find a proper fix for this
-        LOG_WARNING(Render_Vulkan, "Disabling VK_KHR_workgroup_memory_explicit_layout due to a "
-                                   "yuzu bug when host driver does not support 16-bit integers");
-        khr_workgroup_memory_explicit_layout = false;
-    }
-
-    VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR executable_properties;
-    if (khr_pipeline_executable_properties) {
-        LOG_INFO(Render_Vulkan, "Enabling shader feedback, expect slower shader build times");
-        executable_properties = {
-            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR,
-            .pNext = nullptr,
-            .pipelineExecutableInfo = VK_TRUE,
-        };
-        SetNext(next, executable_properties);
-    }
-
-    if (!ext_depth_range_unrestricted) {
-        LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted");
-    }
-
-    VkPhysicalDeviceDepthClipControlFeaturesEXT depth_clip_control_features;
-    if (ext_depth_clip_control) {
-        depth_clip_control_features = {
-            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT,
-            .pNext = nullptr,
-            .depthClipControl = VK_TRUE,
-        };
-        SetNext(next, depth_clip_control_features);
-    }
-
-    VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv;
-    if (Settings::values.enable_nsight_aftermath && nv_device_diagnostics_config) {
+    VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv{};
+    if (Settings::values.enable_nsight_aftermath && extensions.device_diagnostics_config) {
         nsight_aftermath_tracker = std::make_unique<NsightAftermathTracker>();
 
         diagnostics_nv = {
@@ -744,33 +321,48 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
         };
         first_next = &diagnostics_nv;
     }
-    logical = vk::Device::Create(physical, queue_cis, extensions, first_next, dld);
 
-    is_integrated = properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
-    is_virtual = properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU;
-    is_non_gpu = properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_OTHER ||
-                 properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU;
+    is_blit_depth_stencil_supported = TestDepthStencilBlits();
+    is_optimal_astc_supported = ComputeIsOptimalAstcSupported();
+    is_warp_potentially_bigger = !extensions.subgroup_size_control ||
+                                 properties.subgroup_size_control.maxSubgroupSize > GuestWarpSize;
+
+    is_integrated = properties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
+    is_virtual = properties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU;
+    is_non_gpu = properties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_OTHER ||
+                 properties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU;
+
+    supports_d24_depth =
+        IsFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT,
+                          VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, FormatType::Optimal);
 
     CollectPhysicalMemoryInfo();
-    CollectTelemetryParameters();
     CollectToolingInfo();
 
-    if (driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR) {
-        const u32 nv_major_version = (properties.driverVersion >> 22) & 0x3ff;
+    const VkDriverId driver_id = properties.driver.driverID;
+    const bool is_radv = driver_id == VK_DRIVER_ID_MESA_RADV;
+    const bool is_amd_driver =
+        driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE;
+    const bool is_amd = is_amd_driver || is_radv;
+    const bool is_intel_windows = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS;
+    const bool is_intel_anv = driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA;
+    const bool is_nvidia = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY;
 
+    if (is_nvidia) {
+        const u32 nv_major_version = (properties.properties.driverVersion >> 22) & 0x3ff;
         const auto arch = GetNvidiaArchitecture(physical, supported_extensions);
         switch (arch) {
         case NvidiaArchitecture::AmpereOrNewer:
-            LOG_WARNING(Render_Vulkan, "Blacklisting Ampere devices from float16 math");
-            is_float16_supported = false;
+            LOG_WARNING(Render_Vulkan, "Ampere and newer have broken float16 math");
+            features.shader_float16_int8.shaderFloat16 = false;
             break;
         case NvidiaArchitecture::Turing:
             break;
         case NvidiaArchitecture::VoltaOrOlder:
             if (nv_major_version < 527) {
-                LOG_WARNING(Render_Vulkan,
-                            "Blacklisting Volta and older from VK_KHR_push_descriptor");
-                khr_push_descriptor = false;
+                LOG_WARNING(Render_Vulkan, "Volta and older have broken VK_KHR_push_descriptor");
+                extensions.push_descriptor = false;
+                loaded_extensions.erase(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
             }
             break;
         }
@@ -779,75 +371,75 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
             cant_blit_msaa = true;
         }
     }
-    const bool is_radv = driver_id == VK_DRIVER_ID_MESA_RADV;
-    if (ext_extended_dynamic_state && is_radv) {
+    if (extensions.extended_dynamic_state && is_radv) {
         // Mask driver version variant
-        const u32 version = (properties.driverVersion << 3) >> 3;
+        const u32 version = (properties.properties.driverVersion << 3) >> 3;
         if (version < VK_MAKE_API_VERSION(0, 21, 2, 0)) {
             LOG_WARNING(Render_Vulkan,
                         "RADV versions older than 21.2 have broken VK_EXT_extended_dynamic_state");
-            ext_extended_dynamic_state = false;
+            extensions.extended_dynamic_state = false;
+            loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
         }
     }
-    if (ext_vertex_input_dynamic_state && is_radv) {
-        // TODO(ameerj): Blacklist only offending driver versions
-        // TODO(ameerj): Confirm if RDNA1 is affected
-        const bool is_rdna2 =
-            IsExtensionSupported(supported_extensions, VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
-        if (is_rdna2) {
-            LOG_WARNING(Render_Vulkan,
-                        "RADV has broken VK_EXT_vertex_input_dynamic_state on RDNA2 hardware");
-            ext_vertex_input_dynamic_state = false;
-        }
-    }
-    if (ext_extended_dynamic_state_2 && is_radv) {
-        const u32 version = (properties.driverVersion << 3) >> 3;
+    if (extensions.extended_dynamic_state2 && is_radv) {
+        const u32 version = (properties.properties.driverVersion << 3) >> 3;
         if (version < VK_MAKE_API_VERSION(0, 22, 3, 1)) {
             LOG_WARNING(
                 Render_Vulkan,
                 "RADV versions older than 22.3.1 have broken VK_EXT_extended_dynamic_state2");
-            ext_extended_dynamic_state_2 = false;
-            ext_extended_dynamic_state_2_extra = false;
+            features.extended_dynamic_state2.extendedDynamicState2 = false;
+            features.extended_dynamic_state2.extendedDynamicState2LogicOp = false;
+            features.extended_dynamic_state2.extendedDynamicState2PatchControlPoints = false;
+            extensions.extended_dynamic_state2 = false;
+            loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
+        }
+    }
+    if (extensions.vertex_input_dynamic_state && is_radv) {
+        // TODO(ameerj): Blacklist only offending driver versions
+        // TODO(ameerj): Confirm if RDNA1 is affected
+        const bool is_rdna2 =
+            supported_extensions.contains(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
+        if (is_rdna2) {
+            LOG_WARNING(Render_Vulkan,
+                        "RADV has broken VK_EXT_vertex_input_dynamic_state on RDNA2 hardware");
+            extensions.vertex_input_dynamic_state = false;
+            loaded_extensions.erase(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
         }
     }
-    sets_per_pool = 64;
 
-    const bool is_amd =
-        driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE;
-    if (is_amd) {
+    sets_per_pool = 64;
+    if (is_amd_driver) {
         // AMD drivers need a higher amount of Sets per Pool in certain circunstances like in XC2.
         sets_per_pool = 96;
         // Disable VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT on AMD GCN4 and lower as it is broken.
-        if (!is_float16_supported) {
-            LOG_WARNING(
-                Render_Vulkan,
-                "AMD GCN4 and earlier do not properly support VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT");
+        if (!features.shader_float16_int8.shaderFloat16) {
+            LOG_WARNING(Render_Vulkan,
+                        "AMD GCN4 and earlier have broken VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT");
             has_broken_cube_compatibility = true;
         }
     }
-    const bool is_amd_or_radv = is_amd || is_radv;
-    if (ext_sampler_filter_minmax && is_amd_or_radv) {
+    if (extensions.sampler_filter_minmax && is_amd) {
         // Disable ext_sampler_filter_minmax on AMD GCN4 and lower as it is broken.
-        if (!is_float16_supported) {
+        if (!features.shader_float16_int8.shaderFloat16) {
             LOG_WARNING(Render_Vulkan,
-                        "Blacklisting AMD GCN4 and earlier for VK_EXT_sampler_filter_minmax");
-            ext_sampler_filter_minmax = false;
+                        "AMD GCN4 and earlier have broken VK_EXT_sampler_filter_minmax");
+            extensions.sampler_filter_minmax = false;
+            loaded_extensions.erase(VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME);
         }
     }
 
-    const bool is_intel_windows = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS;
-    const bool is_intel_anv = driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA;
-    if (ext_vertex_input_dynamic_state && is_intel_windows) {
-        const u32 version = (properties.driverVersion << 3) >> 3;
+    if (extensions.vertex_input_dynamic_state && is_intel_windows) {
+        const u32 version = (properties.properties.driverVersion << 3) >> 3;
         if (version < VK_MAKE_API_VERSION(27, 20, 100, 0)) {
-            LOG_WARNING(Render_Vulkan, "Blacklisting Intel for VK_EXT_vertex_input_dynamic_state");
-            ext_vertex_input_dynamic_state = false;
+            LOG_WARNING(Render_Vulkan, "Intel has broken VK_EXT_vertex_input_dynamic_state");
+            extensions.vertex_input_dynamic_state = false;
+            loaded_extensions.erase(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
         }
     }
-    if (is_float16_supported && is_intel_windows) {
+    if (features.shader_float16_int8.shaderFloat16 && is_intel_windows) {
         // Intel's compiler crashes when using fp16 on Astral Chain, disable it for the time being.
-        LOG_WARNING(Render_Vulkan, "Blacklisting Intel proprietary from float16 math");
-        is_float16_supported = false;
+        LOG_WARNING(Render_Vulkan, "Intel has broken float16 math");
+        features.shader_float16_int8.shaderFloat16 = false;
     }
     if (is_intel_windows) {
         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
         must_emulate_bgr565 = true;
     }
 
-    supports_d24_depth =
-        IsFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT,
-                          VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, FormatType::Optimal);
+    logical = vk::Device::Create(physical, queue_cis, ExtensionListForVulkan(loaded_extensions),
+                                 first_next, dld);
 
     graphics_queue = logical.GetQueue(graphics_family);
     present_queue = logical.GetQueue(present_family);
@@ -915,7 +506,7 @@ void Device::SaveShader(std::span<const u32> spirv) const {
     }
 }
 
-bool Device::IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const {
+bool Device::ComputeIsOptimalAstcSupported() const {
     // Disable for now to avoid converting ASTC twice.
     static constexpr std::array astc_formats = {
         VK_FORMAT_ASTC_4x4_UNORM_BLOCK,   VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
@@ -933,7 +524,7 @@ bool Device::IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) co
         VK_FORMAT_ASTC_12x10_UNORM_BLOCK, VK_FORMAT_ASTC_12x10_SRGB_BLOCK,
         VK_FORMAT_ASTC_12x12_UNORM_BLOCK, VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
     };
-    if (!features.textureCompressionASTC_LDR) {
+    if (!features.features.textureCompressionASTC_LDR) {
         return false;
     }
     const auto format_feature_usage{
@@ -971,7 +562,7 @@ bool Device::IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags want
 }
 
 std::string Device::GetDriverName() const {
-    switch (driver_id) {
+    switch (properties.driver.driverID) {
     case VK_DRIVER_ID_AMD_PROPRIETARY:
         return "AMD";
     case VK_DRIVER_ID_AMD_OPEN_SOURCE:
@@ -987,522 +578,336 @@ std::string Device::GetDriverName() const {
     case VK_DRIVER_ID_MESA_LLVMPIPE:
         return "LAVAPIPE";
     default:
-        return vendor_name;
+        return properties.driver.driverName;
     }
 }
 
 bool Device::ShouldBoostClocks() const {
+    const auto driver_id = properties.driver.driverID;
+    const auto vendor_id = properties.properties.vendorID;
+    const auto device_id = properties.properties.deviceID;
+
     const bool validated_driver =
         driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE ||
         driver_id == VK_DRIVER_ID_MESA_RADV || driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY ||
         driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS ||
         driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA;
 
-    const bool is_steam_deck = properties.vendorID == 0x1002 && properties.deviceID == 0x163F;
+    const bool is_steam_deck = vendor_id == 0x1002 && device_id == 0x163F;
 
     return validated_driver && !is_steam_deck;
 }
 
-static std::vector<const char*> ExtensionsRequiredForInstanceVersion(u32 available_version) {
-    std::vector<const char*> extensions{REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()};
+bool Device::GetSuitability(bool requires_swapchain) {
+    // Assume we will be suitable.
+    bool suitable = true;
 
-    if (available_version < VK_API_VERSION_1_2) {
-        extensions.insert(extensions.end(), REQUIRED_EXTENSIONS_BEFORE_1_2.begin(),
-                          REQUIRED_EXTENSIONS_BEFORE_1_2.end());
-    }
+    // Configure properties.
+    properties.properties = physical.GetProperties();
 
-    if (available_version < VK_API_VERSION_1_3) {
-        extensions.insert(extensions.end(), REQUIRED_EXTENSIONS_BEFORE_1_3.begin(),
-                          REQUIRED_EXTENSIONS_BEFORE_1_3.end());
-    }
+    // Set instance version.
+    instance_version = properties.properties.apiVersion;
 
-    return extensions;
-}
-
-void Device::CheckSuitability(bool requires_swapchain) const {
-    std::vector<const char*> required_extensions =
-        ExtensionsRequiredForInstanceVersion(instance_version);
-    std::vector<const char*> available_extensions;
-
-    if (requires_swapchain) {
-        required_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
-    }
+    // Minimum of API version 1.1 is required. (This is well-supported.)
+    ASSERT(instance_version >= VK_API_VERSION_1_1);
 
+    // Get available extensions.
     auto extension_properties = physical.EnumerateDeviceExtensionProperties();
 
+    // Get the set of supported extensions.
+    supported_extensions.clear();
     for (const VkExtensionProperties& property : extension_properties) {
-        available_extensions.push_back(property.extensionName);
+        supported_extensions.insert(property.extensionName);
     }
 
-    bool has_all_required_extensions = true;
-    for (const char* requirement_name : required_extensions) {
-        const bool found =
-            std::ranges::any_of(available_extensions, [&](const char* extension_name) {
-                return std::strcmp(requirement_name, extension_name) == 0;
-            });
+    // Generate list of extensions to load.
+    loaded_extensions.clear();
 
-        if (!found) {
-            LOG_ERROR(Render_Vulkan, "Missing required extension: {}", requirement_name);
-            has_all_required_extensions = false;
-        }
+#define EXTENSION(prefix, macro_name, var_name)                                                    \
+    if (supported_extensions.contains(VK_##prefix##_##macro_name##_EXTENSION_NAME)) {              \
+        loaded_extensions.insert(VK_##prefix##_##macro_name##_EXTENSION_NAME);                     \
+        extensions.var_name = true;                                                                \
+    }
+#define FEATURE_EXTENSION(prefix, struct_name, macro_name, var_name)                               \
+    if (supported_extensions.contains(VK_##prefix##_##macro_name##_EXTENSION_NAME)) {              \
+        loaded_extensions.insert(VK_##prefix##_##macro_name##_EXTENSION_NAME);                     \
+        extensions.var_name = true;                                                                \
     }
 
-    if (!has_all_required_extensions) {
-        throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
+    if (instance_version < VK_API_VERSION_1_2) {
+        FOR_EACH_VK_FEATURE_1_2(FEATURE_EXTENSION);
+    }
+    if (instance_version < VK_API_VERSION_1_3) {
+        FOR_EACH_VK_FEATURE_1_3(FEATURE_EXTENSION);
     }
 
-    struct LimitTuple {
+    FOR_EACH_VK_FEATURE_EXT(FEATURE_EXTENSION);
+    FOR_EACH_VK_EXTENSION(EXTENSION);
+#ifdef _WIN32
+    FOR_EACH_VK_EXTENSION_WIN32(EXTENSION);
+#endif
+
+#undef FEATURE_EXTENSION
+#undef EXTENSION
+
+    // Some extensions are mandatory. Check those.
+#define CHECK_EXTENSION(extension_name)                                                            \
+    if (!loaded_extensions.contains(extension_name)) {                                             \
+        LOG_ERROR(Render_Vulkan, "Missing required extension {}", extension_name);                 \
+        suitable = false;                                                                          \
+    }
+
+#define LOG_EXTENSION(extension_name)                                                              \
+    if (!loaded_extensions.contains(extension_name)) {                                             \
+        LOG_INFO(Render_Vulkan, "Device doesn't support extension {}", extension_name);            \
+    }
+
+    FOR_EACH_VK_RECOMMENDED_EXTENSION(LOG_EXTENSION);
+    FOR_EACH_VK_MANDATORY_EXTENSION(CHECK_EXTENSION);
+#ifdef _WIN32
+    FOR_EACH_VK_MANDATORY_EXTENSION_WIN32(CHECK_EXTENSION);
+#else
+    FOR_EACH_VK_MANDATORY_EXTENSION_GENERIC(CHECK_EXTENSION);
+#endif
+
+    if (requires_swapchain) {
+        CHECK_EXTENSION(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+    }
+
+#undef LOG_EXTENSION
+#undef CHECK_EXTENSION
+
+    // Generate the linked list of features to test.
+    features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+
+    // Set next pointer.
+    void** next = &features2.pNext;
+
+    // Test all features we know about. If the feature is not available in core at our
+    // current API version, and was not enabled by an extension, skip testing the feature.
+    // We set the structure sType explicitly here as it is zeroed by the constructor.
+#define FEATURE(prefix, struct_name, macro_name, var_name)                                         \
+    features.var_name.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_##macro_name##_FEATURES;           \
+    SetNext(next, features.var_name);
+
+#define EXT_FEATURE(prefix, struct_name, macro_name, var_name)                                     \
+    if (extensions.var_name) {                                                                     \
+        features.var_name.sType =                                                                  \
+            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_##macro_name##_FEATURES_##prefix;                    \
+        SetNext(next, features.var_name);                                                          \
+    }
+
+    FOR_EACH_VK_FEATURE_1_1(FEATURE);
+    FOR_EACH_VK_FEATURE_EXT(EXT_FEATURE);
+    if (instance_version >= VK_API_VERSION_1_2) {
+        FOR_EACH_VK_FEATURE_1_2(FEATURE);
+    } else {
+        FOR_EACH_VK_FEATURE_1_2(EXT_FEATURE);
+    }
+    if (instance_version >= VK_API_VERSION_1_3) {
+        FOR_EACH_VK_FEATURE_1_3(FEATURE);
+    } else {
+        FOR_EACH_VK_FEATURE_1_3(EXT_FEATURE);
+    }
+
+#undef EXT_FEATURE
+#undef FEATURE
+
+    // Perform the feature test.
+    physical.GetFeatures2(features2);
+    features.features = features2.features;
+
+    // Some features are mandatory. Check those.
+#define CHECK_FEATURE(feature, name)                                                               \
+    if (!features.feature.name) {                                                                  \
+        LOG_ERROR(Render_Vulkan, "Missing required feature {}", #name);                            \
+        suitable = false;                                                                          \
+    }
+
+#define LOG_FEATURE(feature, name)                                                                 \
+    if (!features.feature.name) {                                                                  \
+        LOG_INFO(Render_Vulkan, "Device doesn't support feature {}", #name);                       \
+    }
+
+    FOR_EACH_VK_RECOMMENDED_FEATURE(LOG_FEATURE);
+    FOR_EACH_VK_MANDATORY_FEATURE(CHECK_FEATURE);
+
+#undef LOG_FEATURE
+#undef CHECK_FEATURE
+
+    // Generate linked list of properties.
+    properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+
+    // Set next pointer.
+    next = &properties2.pNext;
+
+    // Get driver info.
+    properties.driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
+    SetNext(next, properties.driver);
+
+    // Retrieve relevant extension properties.
+    if (extensions.shader_float_controls) {
+        properties.float_controls.sType =
+            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES;
+        SetNext(next, properties.float_controls);
+    }
+    if (extensions.push_descriptor) {
+        properties.push_descriptor.sType =
+            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR;
+        SetNext(next, properties.push_descriptor);
+    }
+    if (extensions.subgroup_size_control) {
+        properties.subgroup_size_control.sType =
+            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES;
+        SetNext(next, properties.subgroup_size_control);
+    }
+    if (extensions.transform_feedback) {
+        properties.transform_feedback.sType =
+            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
+        SetNext(next, properties.transform_feedback);
+    }
+
+    // Perform the property fetch.
+    physical.GetProperties2(properties2);
+    properties.properties = properties2.properties;
+
+    // Unload extensions if feature support is insufficient.
+    RemoveUnsuitableExtensions();
+
+    // Check limits.
+    struct Limit {
         u32 minimum;
         u32 value;
         const char* name;
     };
-    const VkPhysicalDeviceLimits& limits{properties.limits};
+
+    const VkPhysicalDeviceLimits& limits{properties.properties.limits};
     const std::array limits_report{
-        LimitTuple{65536, limits.maxUniformBufferRange, "maxUniformBufferRange"},
-        LimitTuple{16, limits.maxViewports, "maxViewports"},
-        LimitTuple{8, limits.maxColorAttachments, "maxColorAttachments"},
-        LimitTuple{8, limits.maxClipDistances, "maxClipDistances"},
-    };
-    for (const auto& tuple : limits_report) {
-        if (tuple.value < tuple.minimum) {
-            LOG_ERROR(Render_Vulkan, "{} has to be {} or greater but it is {}", tuple.name,
-                      tuple.minimum, tuple.value);
-            throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
-        }
-    }
-    VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures demote{};
-    demote.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES;
-    demote.pNext = nullptr;
-
-    VkPhysicalDeviceVariablePointerFeatures variable_pointers{};
-    variable_pointers.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES;
-    variable_pointers.pNext = &demote;
-
-    VkPhysicalDeviceRobustness2FeaturesEXT robustness2{};
-    robustness2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT;
-    robustness2.pNext = &variable_pointers;
-
-    VkPhysicalDeviceTimelineSemaphoreFeatures timeline_semaphore{};
-    timeline_semaphore.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES;
-    timeline_semaphore.pNext = &robustness2;
-
-    VkPhysicalDevice16BitStorageFeatures bit16_storage{};
-    bit16_storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES;
-    bit16_storage.pNext = &timeline_semaphore;
-
-    VkPhysicalDevice8BitStorageFeatures bit8_storage{};
-    bit8_storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES;
-    bit8_storage.pNext = &bit16_storage;
-
-    VkPhysicalDeviceHostQueryResetFeatures host_query_reset{};
-    host_query_reset.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES;
-    host_query_reset.pNext = &bit8_storage;
-
-    VkPhysicalDeviceShaderDrawParametersFeatures draw_parameters{};
-    draw_parameters.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES;
-    draw_parameters.pNext = &host_query_reset;
-
-    VkPhysicalDeviceFeatures2 features2{};
-    features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
-    features2.pNext = &draw_parameters;
-
-    physical.GetFeatures2(features2);
-
-    const VkPhysicalDeviceFeatures& features{features2.features};
-    std::array feature_report{
-        std::make_pair(features.robustBufferAccess, "robustBufferAccess"),
-        std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),
-        std::make_pair(features.imageCubeArray, "imageCubeArray"),
-        std::make_pair(features.independentBlend, "independentBlend"),
-        std::make_pair(features.multiDrawIndirect, "multiDrawIndirect"),
-        std::make_pair(features.drawIndirectFirstInstance, "drawIndirectFirstInstance"),
-        std::make_pair(features.depthClamp, "depthClamp"),
-        std::make_pair(features.samplerAnisotropy, "samplerAnisotropy"),
-        std::make_pair(features.largePoints, "largePoints"),
-        std::make_pair(features.multiViewport, "multiViewport"),
-        std::make_pair(features.depthBiasClamp, "depthBiasClamp"),
-        std::make_pair(features.fillModeNonSolid, "fillModeNonSolid"),
-        std::make_pair(features.wideLines, "wideLines"),
-        std::make_pair(features.geometryShader, "geometryShader"),
-        std::make_pair(features.tessellationShader, "tessellationShader"),
-        std::make_pair(features.sampleRateShading, "sampleRateShading"),
-        std::make_pair(features.dualSrcBlend, "dualSrcBlend"),
-        std::make_pair(features.logicOp, "logicOp"),
-        std::make_pair(features.occlusionQueryPrecise, "occlusionQueryPrecise"),
-        std::make_pair(features.fragmentStoresAndAtomics, "fragmentStoresAndAtomics"),
-        std::make_pair(features.shaderImageGatherExtended, "shaderImageGatherExtended"),
-        std::make_pair(features.shaderStorageImageWriteWithoutFormat,
-                       "shaderStorageImageWriteWithoutFormat"),
-        std::make_pair(features.shaderClipDistance, "shaderClipDistance"),
-        std::make_pair(features.shaderCullDistance, "shaderCullDistance"),
-        std::make_pair(variable_pointers.variablePointers, "variablePointers"),
-        std::make_pair(variable_pointers.variablePointersStorageBuffer,
-                       "variablePointersStorageBuffer"),
-        std::make_pair(robustness2.robustBufferAccess2, "robustBufferAccess2"),
-        std::make_pair(robustness2.robustImageAccess2, "robustImageAccess2"),
-        std::make_pair(robustness2.nullDescriptor, "nullDescriptor"),
-        std::make_pair(demote.shaderDemoteToHelperInvocation, "shaderDemoteToHelperInvocation"),
-        std::make_pair(timeline_semaphore.timelineSemaphore, "timelineSemaphore"),
-        std::make_pair(bit16_storage.storageBuffer16BitAccess, "storageBuffer16BitAccess"),
-        std::make_pair(bit16_storage.uniformAndStorageBuffer16BitAccess,
-                       "uniformAndStorageBuffer16BitAccess"),
-        std::make_pair(bit8_storage.storageBuffer8BitAccess, "storageBuffer8BitAccess"),
-        std::make_pair(bit8_storage.uniformAndStorageBuffer8BitAccess,
-                       "uniformAndStorageBuffer8BitAccess"),
-        std::make_pair(host_query_reset.hostQueryReset, "hostQueryReset"),
-        std::make_pair(draw_parameters.shaderDrawParameters, "shaderDrawParameters"),
+        Limit{65536, limits.maxUniformBufferRange, "maxUniformBufferRange"},
+        Limit{16, limits.maxViewports, "maxViewports"},
+        Limit{8, limits.maxColorAttachments, "maxColorAttachments"},
+        Limit{8, limits.maxClipDistances, "maxClipDistances"},
     };
 
-    bool has_all_required_features = true;
-    for (const auto& [is_supported, name] : feature_report) {
-        if (!is_supported) {
-            LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name);
-            has_all_required_features = false;
+    for (const auto& [min, value, name] : limits_report) {
+        if (value < min) {
+            LOG_ERROR(Render_Vulkan, "{} has to be {} or greater but it is {}", name, min, value);
+            suitable = false;
         }
     }
 
-    if (!has_all_required_features) {
-        throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
+    // Return whether we were suitable.
+    return suitable;
+}
+
+void Device::RemoveExtensionIfUnsuitable(bool is_suitable, const std::string& extension_name) {
+    if (loaded_extensions.contains(extension_name) && !is_suitable) {
+        LOG_WARNING(Render_Vulkan, "Removing unsuitable extension {}", extension_name);
+        loaded_extensions.erase(extension_name);
     }
 }
 
-std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
-    std::vector<const char*> extensions = ExtensionsRequiredForInstanceVersion(instance_version);
-    if (requires_surface) {
-        extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
-    }
+void Device::RemoveUnsuitableExtensions() {
+    // VK_EXT_custom_border_color
+    extensions.custom_border_color = features.custom_border_color.customBorderColors &&
+                                     features.custom_border_color.customBorderColorWithoutFormat;
+    RemoveExtensionIfUnsuitable(extensions.custom_border_color,
+                                VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
 
-    bool has_khr_shader_float16_int8{};
-    bool has_khr_workgroup_memory_explicit_layout{};
-    bool has_khr_pipeline_executable_properties{};
-    bool has_khr_image_format_list{};
-    bool has_khr_swapchain_mutable_format{};
-    bool has_ext_subgroup_size_control{};
-    bool has_ext_transform_feedback{};
-    bool has_ext_custom_border_color{};
-    bool has_ext_extended_dynamic_state{};
-    bool has_ext_extended_dynamic_state_2{};
-    bool has_ext_extended_dynamic_state_3{};
-    bool has_ext_shader_atomic_int64{};
-    bool has_ext_provoking_vertex{};
-    bool has_ext_vertex_input_dynamic_state{};
-    bool has_ext_line_rasterization{};
-    bool has_ext_primitive_topology_list_restart{};
-    bool has_ext_depth_clip_control{};
-    for (const std::string& extension : supported_extensions) {
-        const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name,
-                              bool push) {
-            if (extension != name) {
-                return;
-            }
-            if (push) {
-                extensions.push_back(name);
-            }
-            if (status) {
-                status->get() = true;
-            }
-        };
-        test(nv_viewport_swizzle, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME, true);
-        test(nv_viewport_array2, VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME, true);
-        test(nv_geometry_shader_passthrough, VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME,
-             true);
-        test(khr_uniform_buffer_standard_layout,
-             VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, true);
-        test(khr_spirv_1_4, VK_KHR_SPIRV_1_4_EXTENSION_NAME, true);
-        test(khr_push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, true);
-        test(has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false);
-        test(khr_draw_indirect_count, VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME, true);
-        test(ext_depth_range_unrestricted, VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true);
-        test(ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true);
-        test(has_ext_primitive_topology_list_restart,
-             VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME, true);
-        test(ext_sampler_filter_minmax, VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME, true);
-        test(ext_shader_viewport_index_layer, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME,
-             true);
-        test(ext_tooling_info, VK_EXT_TOOLING_INFO_EXTENSION_NAME, true);
-        test(ext_shader_stencil_export, VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, true);
-        test(ext_conservative_rasterization, VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME,
-             true);
-        test(has_ext_depth_clip_control, VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME, false);
-        test(has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, false);
-        test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false);
-        test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false);
-        test(has_ext_extended_dynamic_state_2, VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME,
-             false);
-        test(has_ext_extended_dynamic_state_3, VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME,
-             false);
-        test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, true);
-        test(has_ext_provoking_vertex, VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, false);
-        test(has_ext_vertex_input_dynamic_state, VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME,
-             false);
-        test(has_ext_shader_atomic_int64, VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME, false);
-        test(has_khr_workgroup_memory_explicit_layout,
-             VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME, false);
-        test(has_khr_image_format_list, VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, false);
-        test(has_khr_swapchain_mutable_format, VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME,
-             false);
-        test(has_ext_line_rasterization, VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, false);
-        test(ext_memory_budget, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, true);
-        if (Settings::values.enable_nsight_aftermath) {
-            test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME,
-                 true);
-        }
-        if (Settings::values.renderer_shader_feedback) {
-            test(has_khr_pipeline_executable_properties,
-                 VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME, false);
-        }
-    }
-    VkPhysicalDeviceFeatures2 features{};
-    features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+    // VK_EXT_depth_clip_control
+    extensions.depth_clip_control = features.depth_clip_control.depthClipControl;
+    RemoveExtensionIfUnsuitable(extensions.depth_clip_control,
+                                VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME);
 
-    VkPhysicalDeviceProperties2 physical_properties{};
-    physical_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+    // VK_EXT_extended_dynamic_state
+    extensions.extended_dynamic_state = features.extended_dynamic_state.extendedDynamicState;
+    RemoveExtensionIfUnsuitable(extensions.extended_dynamic_state,
+                                VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
 
-    if (has_khr_shader_float16_int8) {
-        VkPhysicalDeviceShaderFloat16Int8Features float16_int8_features;
-        float16_int8_features.sType =
-            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES;
-        float16_int8_features.pNext = nullptr;
-        features.pNext = &float16_int8_features;
+    // VK_EXT_extended_dynamic_state2
+    extensions.extended_dynamic_state2 = features.extended_dynamic_state2.extendedDynamicState2;
+    RemoveExtensionIfUnsuitable(extensions.extended_dynamic_state2,
+                                VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
 
-        physical.GetFeatures2(features);
-        is_float16_supported = float16_int8_features.shaderFloat16;
-        is_int8_supported = float16_int8_features.shaderInt8;
-        extensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME);
-    }
-    if (has_ext_subgroup_size_control) {
-        VkPhysicalDeviceSubgroupSizeControlFeatures subgroup_features;
-        subgroup_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES;
-        subgroup_features.pNext = nullptr;
-        features.pNext = &subgroup_features;
-        physical.GetFeatures2(features);
+    // VK_EXT_extended_dynamic_state3
+    dynamic_state3_blending =
+        features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable &&
+        features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation &&
+        features.extended_dynamic_state3.extendedDynamicState3ColorWriteMask;
+    dynamic_state3_enables =
+        features.extended_dynamic_state3.extendedDynamicState3DepthClampEnable &&
+        features.extended_dynamic_state3.extendedDynamicState3LogicOpEnable;
 
-        VkPhysicalDeviceSubgroupSizeControlProperties subgroup_properties;
-        subgroup_properties.sType =
-            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES;
-        subgroup_properties.pNext = nullptr;
-        physical_properties.pNext = &subgroup_properties;
-        physical.GetProperties2(physical_properties);
+    extensions.extended_dynamic_state3 = dynamic_state3_blending || dynamic_state3_enables;
+    dynamic_state3_blending = dynamic_state3_blending && extensions.extended_dynamic_state3;
+    dynamic_state3_enables = dynamic_state3_enables && extensions.extended_dynamic_state3;
+    RemoveExtensionIfUnsuitable(extensions.extended_dynamic_state3,
+                                VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
 
-        is_warp_potentially_bigger = subgroup_properties.maxSubgroupSize > GuestWarpSize;
+    // VK_EXT_provoking_vertex
+    extensions.provoking_vertex =
+        features.provoking_vertex.provokingVertexLast &&
+        features.provoking_vertex.transformFeedbackPreservesProvokingVertex;
+    RemoveExtensionIfUnsuitable(extensions.provoking_vertex,
+                                VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME);
 
-        if (subgroup_features.subgroupSizeControl &&
-            subgroup_properties.minSubgroupSize <= GuestWarpSize &&
-            subgroup_properties.maxSubgroupSize >= GuestWarpSize) {
-            extensions.push_back(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME);
-            guest_warp_stages = subgroup_properties.requiredSubgroupSizeStages;
-            ext_subgroup_size_control = true;
-        }
+    // VK_KHR_shader_atomic_int64
+    extensions.shader_atomic_int64 = features.shader_atomic_int64.shaderBufferInt64Atomics &&
+                                     features.shader_atomic_int64.shaderSharedInt64Atomics;
+    RemoveExtensionIfUnsuitable(extensions.shader_atomic_int64,
+                                VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME);
+
+    // VK_EXT_shader_demote_to_helper_invocation
+    extensions.shader_demote_to_helper_invocation =
+        features.shader_demote_to_helper_invocation.shaderDemoteToHelperInvocation;
+    RemoveExtensionIfUnsuitable(extensions.shader_demote_to_helper_invocation,
+                                VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME);
+
+    // VK_EXT_subgroup_size_control
+    extensions.subgroup_size_control =
+        features.subgroup_size_control.subgroupSizeControl &&
+        properties.subgroup_size_control.minSubgroupSize <= GuestWarpSize &&
+        properties.subgroup_size_control.maxSubgroupSize >= GuestWarpSize;
+    RemoveExtensionIfUnsuitable(extensions.subgroup_size_control,
+                                VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME);
+
+    // VK_EXT_transform_feedback
+    extensions.transform_feedback =
+        features.transform_feedback.transformFeedback &&
+        features.transform_feedback.geometryStreams &&
+        properties.transform_feedback.maxTransformFeedbackStreams >= 4 &&
+        properties.transform_feedback.maxTransformFeedbackBuffers > 0 &&
+        properties.transform_feedback.transformFeedbackQueries &&
+        properties.transform_feedback.transformFeedbackDraw;
+    RemoveExtensionIfUnsuitable(extensions.transform_feedback,
+                                VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
+
+    // VK_EXT_vertex_input_dynamic_state
+    extensions.vertex_input_dynamic_state =
+        features.vertex_input_dynamic_state.vertexInputDynamicState;
+    RemoveExtensionIfUnsuitable(extensions.vertex_input_dynamic_state,
+                                VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
+
+    // VK_KHR_pipeline_executable_properties
+    if (Settings::values.renderer_shader_feedback.GetValue()) {
+        extensions.pipeline_executable_properties =
+            features.pipeline_executable_properties.pipelineExecutableInfo;
+        RemoveExtensionIfUnsuitable(extensions.pipeline_executable_properties,
+                                    VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME);
     } else {
-        is_warp_potentially_bigger = true;
-    }
-    if (has_ext_provoking_vertex) {
-        VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex;
-        provoking_vertex.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT;
-        provoking_vertex.pNext = nullptr;
-        features.pNext = &provoking_vertex;
-        physical.GetFeatures2(features);
-
-        if (provoking_vertex.provokingVertexLast &&
-            provoking_vertex.transformFeedbackPreservesProvokingVertex) {
-            extensions.push_back(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME);
-            ext_provoking_vertex = true;
-        }
-    }
-    if (has_ext_vertex_input_dynamic_state) {
-        VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT vertex_input;
-        vertex_input.sType =
-            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT;
-        vertex_input.pNext = nullptr;
-        features.pNext = &vertex_input;
-        physical.GetFeatures2(features);
-
-        if (vertex_input.vertexInputDynamicState) {
-            extensions.push_back(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
-            ext_vertex_input_dynamic_state = true;
-        }
-    }
-    if (has_ext_shader_atomic_int64) {
-        VkPhysicalDeviceShaderAtomicInt64Features atomic_int64;
-        atomic_int64.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES;
-        atomic_int64.pNext = nullptr;
-        features.pNext = &atomic_int64;
-        physical.GetFeatures2(features);
-
-        if (atomic_int64.shaderBufferInt64Atomics && atomic_int64.shaderSharedInt64Atomics) {
-            extensions.push_back(VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME);
-            ext_shader_atomic_int64 = true;
-        }
-    }
-    if (has_ext_transform_feedback) {
-        VkPhysicalDeviceTransformFeedbackFeaturesEXT tfb_features;
-        tfb_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT;
-        tfb_features.pNext = nullptr;
-        features.pNext = &tfb_features;
-        physical.GetFeatures2(features);
-
-        VkPhysicalDeviceTransformFeedbackPropertiesEXT tfb_properties;
-        tfb_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
-        tfb_properties.pNext = nullptr;
-        physical_properties.pNext = &tfb_properties;
-        physical.GetProperties2(physical_properties);
-
-        if (tfb_features.transformFeedback && tfb_features.geometryStreams &&
-            tfb_properties.maxTransformFeedbackStreams >= 4 &&
-            tfb_properties.maxTransformFeedbackBuffers && tfb_properties.transformFeedbackQueries &&
-            tfb_properties.transformFeedbackDraw) {
-            extensions.push_back(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
-            ext_transform_feedback = true;
-        }
-    }
-    if (has_ext_custom_border_color) {
-        VkPhysicalDeviceCustomBorderColorFeaturesEXT border_features;
-        border_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT;
-        border_features.pNext = nullptr;
-        features.pNext = &border_features;
-        physical.GetFeatures2(features);
-
-        if (border_features.customBorderColors && border_features.customBorderColorWithoutFormat) {
-            extensions.push_back(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
-            ext_custom_border_color = true;
-        }
-    }
-    if (has_ext_extended_dynamic_state) {
-        VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extended_dynamic_state;
-        extended_dynamic_state.sType =
-            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT;
-        extended_dynamic_state.pNext = nullptr;
-        features.pNext = &extended_dynamic_state;
-        physical.GetFeatures2(features);
-
-        if (extended_dynamic_state.extendedDynamicState) {
-            extensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
-            ext_extended_dynamic_state = true;
-        }
-    }
-    if (has_ext_extended_dynamic_state_2) {
-        VkPhysicalDeviceExtendedDynamicState2FeaturesEXT extended_dynamic_state_2;
-        extended_dynamic_state_2.sType =
-            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT;
-        extended_dynamic_state_2.pNext = nullptr;
-        features.pNext = &extended_dynamic_state_2;
-        physical.GetFeatures2(features);
-
-        if (extended_dynamic_state_2.extendedDynamicState2) {
-            extensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
-            ext_extended_dynamic_state_2 = true;
-            ext_extended_dynamic_state_2_extra =
-                extended_dynamic_state_2.extendedDynamicState2LogicOp;
-        }
-    }
-    if (has_ext_extended_dynamic_state_3) {
-        VkPhysicalDeviceExtendedDynamicState3FeaturesEXT extended_dynamic_state_3;
-        extended_dynamic_state_3.sType =
-            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT;
-        extended_dynamic_state_3.pNext = nullptr;
-        features.pNext = &extended_dynamic_state_3;
-        physical.GetFeatures2(features);
-
-        ext_extended_dynamic_state_3_blend =
-            extended_dynamic_state_3.extendedDynamicState3ColorBlendEnable &&
-            extended_dynamic_state_3.extendedDynamicState3ColorBlendEquation &&
-            extended_dynamic_state_3.extendedDynamicState3ColorWriteMask;
-
-        ext_extended_dynamic_state_3_enables =
-            extended_dynamic_state_3.extendedDynamicState3DepthClampEnable &&
-            extended_dynamic_state_3.extendedDynamicState3LogicOpEnable;
-
-        ext_extended_dynamic_state_3 =
-            ext_extended_dynamic_state_3_blend || ext_extended_dynamic_state_3_enables;
-        if (ext_extended_dynamic_state_3) {
-            extensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
-        }
-    }
-    if (has_ext_line_rasterization) {
-        VkPhysicalDeviceLineRasterizationFeaturesEXT line_raster;
-        line_raster.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT;
-        line_raster.pNext = nullptr;
-        features.pNext = &line_raster;
-        physical.GetFeatures2(features);
-        if (line_raster.rectangularLines && line_raster.smoothLines) {
-            extensions.push_back(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME);
-            ext_line_rasterization = true;
-        }
-    }
-    if (has_ext_depth_clip_control) {
-        VkPhysicalDeviceDepthClipControlFeaturesEXT depth_clip_control_features;
-        depth_clip_control_features.sType =
-            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT;
-        depth_clip_control_features.pNext = nullptr;
-        features.pNext = &depth_clip_control_features;
-        physical.GetFeatures2(features);
-
-        if (depth_clip_control_features.depthClipControl) {
-            extensions.push_back(VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME);
-            ext_depth_clip_control = true;
-        }
-    }
-    if (has_khr_workgroup_memory_explicit_layout) {
-        VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR layout;
-        layout.sType =
-            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR;
-        layout.pNext = nullptr;
-        features.pNext = &layout;
-        physical.GetFeatures2(features);
-
-        if (layout.workgroupMemoryExplicitLayout &&
-            layout.workgroupMemoryExplicitLayout8BitAccess &&
-            layout.workgroupMemoryExplicitLayout16BitAccess &&
-            layout.workgroupMemoryExplicitLayoutScalarBlockLayout) {
-            extensions.push_back(VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME);
-            khr_workgroup_memory_explicit_layout = true;
-        }
-    }
-    if (has_khr_pipeline_executable_properties) {
-        VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR executable_properties;
-        executable_properties.sType =
-            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR;
-        executable_properties.pNext = nullptr;
-        features.pNext = &executable_properties;
-        physical.GetFeatures2(features);
-
-        if (executable_properties.pipelineExecutableInfo) {
-            extensions.push_back(VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME);
-            khr_pipeline_executable_properties = true;
-        }
-    }
-    if (has_ext_primitive_topology_list_restart) {
-        VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT primitive_topology_list_restart{};
-        primitive_topology_list_restart.sType =
-            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT;
-        primitive_topology_list_restart.pNext = nullptr;
-        features.pNext = &primitive_topology_list_restart;
-        physical.GetFeatures2(features);
-
-        is_topology_list_restart_supported =
-            primitive_topology_list_restart.primitiveTopologyListRestart;
-        is_patch_list_restart_supported =
-            primitive_topology_list_restart.primitiveTopologyPatchListRestart;
-    }
-    if (requires_surface && has_khr_image_format_list && has_khr_swapchain_mutable_format) {
-        extensions.push_back(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME);
-        extensions.push_back(VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME);
-        khr_swapchain_mutable_format = true;
-    }
-    if (khr_push_descriptor) {
-        VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor;
-        push_descriptor.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR;
-        push_descriptor.pNext = nullptr;
-
-        physical_properties.pNext = &push_descriptor;
-        physical.GetProperties2(physical_properties);
-
-        max_push_descriptors = push_descriptor.maxPushDescriptors;
+        extensions.pipeline_executable_properties = false;
+        loaded_extensions.erase(VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME);
     }
 
-    has_null_descriptor = true;
-
-    return extensions;
+    // VK_KHR_workgroup_memory_explicit_layout
+    extensions.workgroup_memory_explicit_layout =
+        features.features.shaderInt16 &&
+        features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayout &&
+        features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayout8BitAccess &&
+        features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayout16BitAccess &&
+        features.workgroup_memory_explicit_layout.workgroupMemoryExplicitLayoutScalarBlockLayout;
+    RemoveExtensionIfUnsuitable(extensions.workgroup_memory_explicit_layout,
+                                VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME);
 }
 
 void Device::SetupFamilies(VkSurfaceKHR surface) {
@@ -1540,53 +945,6 @@ void Device::SetupFamilies(VkSurfaceKHR surface) {
     }
 }
 
-void Device::SetupFeatures() {
-    const VkPhysicalDeviceFeatures features{physical.GetFeatures()};
-    is_depth_bounds_supported = features.depthBounds;
-    is_formatless_image_load_supported = features.shaderStorageImageReadWithoutFormat;
-    is_shader_float64_supported = features.shaderFloat64;
-    is_shader_int64_supported = features.shaderInt64;
-    is_shader_int16_supported = features.shaderInt16;
-    is_shader_storage_image_multisample = features.shaderStorageImageMultisample;
-    is_blit_depth_stencil_supported = TestDepthStencilBlits();
-    is_optimal_astc_supported = IsOptimalAstcSupported(features);
-
-    const VkPhysicalDeviceLimits& limits{properties.limits};
-    max_vertex_input_attributes = limits.maxVertexInputAttributes;
-    max_vertex_input_bindings = limits.maxVertexInputBindings;
-}
-
-void Device::SetupProperties() {
-    float_controls.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES;
-
-    VkPhysicalDeviceProperties2KHR properties2{};
-    properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
-    properties2.pNext = &float_controls;
-
-    physical.GetProperties2(properties2);
-}
-
-void Device::CollectTelemetryParameters() {
-    VkPhysicalDeviceDriverProperties driver{
-        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES,
-        .pNext = nullptr,
-        .driverID = {},
-        .driverName = {},
-        .driverInfo = {},
-        .conformanceVersion = {},
-    };
-
-    VkPhysicalDeviceProperties2 device_properties{
-        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
-        .pNext = &driver,
-        .properties = {},
-    };
-    physical.GetProperties2(device_properties);
-
-    driver_id = driver.driverID;
-    vendor_name = driver.driverName;
-}
-
 u64 Device::GetDeviceMemoryUsage() const {
     VkPhysicalDeviceMemoryBudgetPropertiesEXT budget;
     budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
@@ -1602,7 +960,8 @@ u64 Device::GetDeviceMemoryUsage() const {
 void Device::CollectPhysicalMemoryInfo() {
     VkPhysicalDeviceMemoryBudgetPropertiesEXT budget{};
     budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
-    const auto mem_info = physical.GetMemoryProperties(ext_memory_budget ? &budget : nullptr);
+    const auto mem_info =
+        physical.GetMemoryProperties(extensions.memory_budget ? &budget : nullptr);
     const auto& mem_properties = mem_info.memoryProperties;
     const size_t num_properties = mem_properties.memoryHeapCount;
     device_access_memory = 0;
@@ -1618,7 +977,7 @@ void Device::CollectPhysicalMemoryInfo() {
         if (is_heap_local) {
             local_memory += mem_properties.memoryHeaps[element].size;
         }
-        if (ext_memory_budget) {
+        if (extensions.memory_budget) {
             device_initial_usage += budget.heapUsage[element];
             device_access_memory += budget.heapBudget[element];
             continue;
@@ -1634,7 +993,7 @@ void Device::CollectPhysicalMemoryInfo() {
 }
 
 void Device::CollectToolingInfo() {
-    if (!ext_tooling_info) {
+    if (!extensions.tooling_info) {
         return;
     }
     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 4bc2671632..4cfb20bc21 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -3,6 +3,7 @@
 
 #pragma once
 
+#include <set>
 #include <span>
 #include <string>
 #include <unordered_map>
@@ -11,6 +12,155 @@
 #include "common/common_types.h"
 #include "video_core/vulkan_common/vulkan_wrapper.h"
 
+// Define all features which may be used by the implementation here.
+// Vulkan version in the macro describes the minimum version required for feature availability.
+// If the Vulkan version is lower than the required version, the named extension is required.
+#define FOR_EACH_VK_FEATURE_1_1(FEATURE)                                                           \
+    FEATURE(EXT, SubgroupSizeControl, SUBGROUP_SIZE_CONTROL, subgroup_size_control)                \
+    FEATURE(KHR, 16BitStorage, 16BIT_STORAGE, bit16_storage)                                       \
+    FEATURE(KHR, ShaderAtomicInt64, SHADER_ATOMIC_INT64, shader_atomic_int64)                      \
+    FEATURE(KHR, ShaderDrawParameters, SHADER_DRAW_PARAMETERS, shader_draw_parameters)             \
+    FEATURE(KHR, ShaderFloat16Int8, SHADER_FLOAT16_INT8, shader_float16_int8)                      \
+    FEATURE(KHR, UniformBufferStandardLayout, UNIFORM_BUFFER_STANDARD_LAYOUT,                      \
+            uniform_buffer_standard_layout)                                                        \
+    FEATURE(KHR, VariablePointer, VARIABLE_POINTERS, variable_pointer)
+
+#define FOR_EACH_VK_FEATURE_1_2(FEATURE)                                                           \
+    FEATURE(EXT, HostQueryReset, HOST_QUERY_RESET, host_query_reset)                               \
+    FEATURE(KHR, 8BitStorage, 8BIT_STORAGE, bit8_storage)                                          \
+    FEATURE(KHR, TimelineSemaphore, TIMELINE_SEMAPHORE, timeline_semaphore)
+
+#define FOR_EACH_VK_FEATURE_1_3(FEATURE)                                                           \
+    FEATURE(EXT, ShaderDemoteToHelperInvocation, SHADER_DEMOTE_TO_HELPER_INVOCATION,               \
+            shader_demote_to_helper_invocation)
+
+// Define all features which may be used by the implementation and require an extension here.
+#define FOR_EACH_VK_FEATURE_EXT(FEATURE)                                                           \
+    FEATURE(EXT, CustomBorderColor, CUSTOM_BORDER_COLOR, custom_border_color)                      \
+    FEATURE(EXT, DepthClipControl, DEPTH_CLIP_CONTROL, depth_clip_control)                         \
+    FEATURE(EXT, ExtendedDynamicState, EXTENDED_DYNAMIC_STATE, extended_dynamic_state)             \
+    FEATURE(EXT, ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, extended_dynamic_state2)         \
+    FEATURE(EXT, ExtendedDynamicState3, EXTENDED_DYNAMIC_STATE_3, extended_dynamic_state3)         \
+    FEATURE(EXT, IndexTypeUint8, INDEX_TYPE_UINT8, index_type_uint8)                               \
+    FEATURE(EXT, LineRasterization, LINE_RASTERIZATION, line_rasterization)                        \
+    FEATURE(EXT, PrimitiveTopologyListRestart, PRIMITIVE_TOPOLOGY_LIST_RESTART,                    \
+            primitive_topology_list_restart)                                                       \
+    FEATURE(EXT, ProvokingVertex, PROVOKING_VERTEX, provoking_vertex)                              \
+    FEATURE(EXT, Robustness2, ROBUSTNESS_2, robustness2)                                           \
+    FEATURE(EXT, TransformFeedback, TRANSFORM_FEEDBACK, transform_feedback)                        \
+    FEATURE(EXT, VertexInputDynamicState, VERTEX_INPUT_DYNAMIC_STATE, vertex_input_dynamic_state)  \
+    FEATURE(KHR, PipelineExecutableProperties, PIPELINE_EXECUTABLE_PROPERTIES,                     \
+            pipeline_executable_properties)                                                        \
+    FEATURE(KHR, WorkgroupMemoryExplicitLayout, WORKGROUP_MEMORY_EXPLICIT_LAYOUT,                  \
+            workgroup_memory_explicit_layout)
+
+// Define miscellaneous extensions which may be used by the implementation here.
+#define FOR_EACH_VK_EXTENSION(EXTENSION)                                                           \
+    EXTENSION(EXT, CONSERVATIVE_RASTERIZATION, conservative_rasterization)                         \
+    EXTENSION(EXT, DEPTH_RANGE_UNRESTRICTED, depth_range_unrestricted)                             \
+    EXTENSION(EXT, MEMORY_BUDGET, memory_budget)                                                   \
+    EXTENSION(EXT, ROBUSTNESS_2, robustness_2)                                                     \
+    EXTENSION(EXT, SAMPLER_FILTER_MINMAX, sampler_filter_minmax)                                   \
+    EXTENSION(EXT, SHADER_STENCIL_EXPORT, shader_stencil_export)                                   \
+    EXTENSION(EXT, SHADER_VIEWPORT_INDEX_LAYER, shader_viewport_index_layer)                       \
+    EXTENSION(EXT, TOOLING_INFO, tooling_info)                                                     \
+    EXTENSION(EXT, VERTEX_ATTRIBUTE_DIVISOR, vertex_attribute_divisor)                             \
+    EXTENSION(KHR, DRIVER_PROPERTIES, driver_properties)                                           \
+    EXTENSION(KHR, EXTERNAL_MEMORY_FD, external_memory_fd)                                         \
+    EXTENSION(KHR, PUSH_DESCRIPTOR, push_descriptor)                                               \
+    EXTENSION(KHR, SAMPLER_MIRROR_CLAMP_TO_EDGE, sampler_mirror_clamp_to_edge)                     \
+    EXTENSION(KHR, SHADER_FLOAT_CONTROLS, shader_float_controls)                                   \
+    EXTENSION(KHR, SPIRV_1_4, spirv_1_4)                                                           \
+    EXTENSION(KHR, SWAPCHAIN, swapchain)                                                           \
+    EXTENSION(KHR, SWAPCHAIN_MUTABLE_FORMAT, swapchain_mutable_format)                             \
+    EXTENSION(NV, DEVICE_DIAGNOSTICS_CONFIG, device_diagnostics_config)                            \
+    EXTENSION(NV, GEOMETRY_SHADER_PASSTHROUGH, geometry_shader_passthrough)                        \
+    EXTENSION(NV, VIEWPORT_ARRAY2, viewport_array2)                                                \
+    EXTENSION(NV, VIEWPORT_SWIZZLE, viewport_swizzle)
+
+#define FOR_EACH_VK_EXTENSION_WIN32(EXTENSION)                                                     \
+    EXTENSION(KHR, EXTERNAL_MEMORY_WIN32, external_memory_win32)
+
+// Define extensions which must be supported.
+#define FOR_EACH_VK_MANDATORY_EXTENSION(EXTENSION_NAME)                                            \
+    EXTENSION_NAME(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME)                                             \
+    EXTENSION_NAME(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)                                 \
+    EXTENSION_NAME(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)                                        \
+    EXTENSION_NAME(VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME)                             \
+    EXTENSION_NAME(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME)
+
+#define FOR_EACH_VK_MANDATORY_EXTENSION_GENERIC(EXTENSION_NAME)                                    \
+    EXTENSION_NAME(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME)
+
+#define FOR_EACH_VK_MANDATORY_EXTENSION_WIN32(EXTENSION_NAME)                                      \
+    EXTENSION_NAME(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME)
+
+// Define extensions where the absence of the extension may result in a degraded experience.
+#define FOR_EACH_VK_RECOMMENDED_EXTENSION(EXTENSION_NAME)                                          \
+    EXTENSION_NAME(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME)                               \
+    EXTENSION_NAME(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME)                                 \
+    EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME)                                   \
+    EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME)                                 \
+    EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME)                                 \
+    EXTENSION_NAME(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME)                                       \
+    EXTENSION_NAME(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME)                               \
+    EXTENSION_NAME(VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME)                               \
+    EXTENSION_NAME(VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME)                                           \
+    EXTENSION_NAME(VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME)
+
+// Define features which must be supported.
+#define FOR_EACH_VK_MANDATORY_FEATURE(FEATURE_NAME)                                                \
+    FEATURE_NAME(bit16_storage, storageBuffer16BitAccess)                                          \
+    FEATURE_NAME(bit16_storage, uniformAndStorageBuffer16BitAccess)                                \
+    FEATURE_NAME(bit8_storage, storageBuffer8BitAccess)                                            \
+    FEATURE_NAME(bit8_storage, uniformAndStorageBuffer8BitAccess)                                  \
+    FEATURE_NAME(features, depthBiasClamp)                                                         \
+    FEATURE_NAME(features, depthClamp)                                                             \
+    FEATURE_NAME(features, drawIndirectFirstInstance)                                              \
+    FEATURE_NAME(features, dualSrcBlend)                                                           \
+    FEATURE_NAME(features, fillModeNonSolid)                                                       \
+    FEATURE_NAME(features, fragmentStoresAndAtomics)                                               \
+    FEATURE_NAME(features, geometryShader)                                                         \
+    FEATURE_NAME(features, imageCubeArray)                                                         \
+    FEATURE_NAME(features, independentBlend)                                                       \
+    FEATURE_NAME(features, largePoints)                                                            \
+    FEATURE_NAME(features, logicOp)                                                                \
+    FEATURE_NAME(features, multiDrawIndirect)                                                      \
+    FEATURE_NAME(features, multiViewport)                                                          \
+    FEATURE_NAME(features, occlusionQueryPrecise)                                                  \
+    FEATURE_NAME(features, robustBufferAccess)                                                     \
+    FEATURE_NAME(features, samplerAnisotropy)                                                      \
+    FEATURE_NAME(features, sampleRateShading)                                                      \
+    FEATURE_NAME(features, shaderClipDistance)                                                     \
+    FEATURE_NAME(features, shaderCullDistance)                                                     \
+    FEATURE_NAME(features, shaderImageGatherExtended)                                              \
+    FEATURE_NAME(features, shaderStorageImageWriteWithoutFormat)                                   \
+    FEATURE_NAME(features, tessellationShader)                                                     \
+    FEATURE_NAME(features, vertexPipelineStoresAndAtomics)                                         \
+    FEATURE_NAME(features, wideLines)                                                              \
+    FEATURE_NAME(host_query_reset, hostQueryReset)                                                 \
+    FEATURE_NAME(robustness2, nullDescriptor)                                                      \
+    FEATURE_NAME(robustness2, robustBufferAccess2)                                                 \
+    FEATURE_NAME(robustness2, robustImageAccess2)                                                  \
+    FEATURE_NAME(shader_demote_to_helper_invocation, shaderDemoteToHelperInvocation)               \
+    FEATURE_NAME(shader_draw_parameters, shaderDrawParameters)                                     \
+    FEATURE_NAME(timeline_semaphore, timelineSemaphore)                                            \
+    FEATURE_NAME(variable_pointer, variablePointers)                                               \
+    FEATURE_NAME(variable_pointer, variablePointersStorageBuffer)
+
+// Define features where the absence of the feature may result in a degraded experience.
+#define FOR_EACH_VK_RECOMMENDED_FEATURE(FEATURE_NAME)                                              \
+    FEATURE_NAME(custom_border_color, customBorderColors)                                          \
+    FEATURE_NAME(extended_dynamic_state, extendedDynamicState)                                     \
+    FEATURE_NAME(index_type_uint8, indexTypeUint8)                                                 \
+    FEATURE_NAME(primitive_topology_list_restart, primitiveTopologyListRestart)                    \
+    FEATURE_NAME(provoking_vertex, provokingVertexLast)                                            \
+    FEATURE_NAME(shader_float16_int8, shaderFloat16)                                               \
+    FEATURE_NAME(shader_float16_int8, shaderInt8)                                                  \
+    FEATURE_NAME(transform_feedback, transformFeedback)                                            \
+    FEATURE_NAME(uniform_buffer_standard_layout, uniformBufferStandardLayout)                      \
+    FEATURE_NAME(vertex_input_dynamic_state, vertexInputDynamicState)
+
 namespace Vulkan {
 
 class NsightAftermathTracker;
@@ -88,69 +238,69 @@ public:
 
     /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers.
     u32 ApiVersion() const {
-        return properties.apiVersion;
+        return properties.properties.apiVersion;
     }
 
     /// Returns the current driver version provided in Vulkan-formatted version numbers.
     u32 GetDriverVersion() const {
-        return properties.driverVersion;
+        return properties.properties.driverVersion;
     }
 
     /// Returns the device name.
     std::string_view GetModelName() const {
-        return properties.deviceName;
+        return properties.properties.deviceName;
     }
 
     /// Returns the driver ID.
     VkDriverIdKHR GetDriverID() const {
-        return driver_id;
+        return properties.driver.driverID;
     }
 
     bool ShouldBoostClocks() const;
 
     /// Returns uniform buffer alignment requeriment.
     VkDeviceSize GetUniformBufferAlignment() const {
-        return properties.limits.minUniformBufferOffsetAlignment;
+        return properties.properties.limits.minUniformBufferOffsetAlignment;
     }
 
     /// Returns storage alignment requeriment.
     VkDeviceSize GetStorageBufferAlignment() const {
-        return properties.limits.minStorageBufferOffsetAlignment;
+        return properties.properties.limits.minStorageBufferOffsetAlignment;
     }
 
     /// Returns the maximum range for storage buffers.
     VkDeviceSize GetMaxStorageBufferRange() const {
-        return properties.limits.maxStorageBufferRange;
+        return properties.properties.limits.maxStorageBufferRange;
     }
 
     /// Returns the maximum size for push constants.
     VkDeviceSize GetMaxPushConstantsSize() const {
-        return properties.limits.maxPushConstantsSize;
+        return properties.properties.limits.maxPushConstantsSize;
     }
 
     /// Returns the maximum size for shared memory.
     u32 GetMaxComputeSharedMemorySize() const {
-        return properties.limits.maxComputeSharedMemorySize;
+        return properties.properties.limits.maxComputeSharedMemorySize;
     }
 
     /// Returns float control properties of the device.
     const VkPhysicalDeviceFloatControlsPropertiesKHR& FloatControlProperties() const {
-        return float_controls;
+        return properties.float_controls;
     }
 
     /// Returns true if ASTC is natively supported.
     bool IsOptimalAstcSupported() const {
-        return is_optimal_astc_supported;
+        return features.features.textureCompressionASTC_LDR;
     }
 
     /// Returns true if the device supports float16 natively.
     bool IsFloat16Supported() const {
-        return is_float16_supported;
+        return features.shader_float16_int8.shaderFloat16;
     }
 
     /// Returns true if the device supports int8 natively.
     bool IsInt8Supported() const {
-        return is_int8_supported;
+        return features.shader_float16_int8.shaderInt8;
     }
 
     /// Returns true if the device warp size can potentially be bigger than guest's warp size.
@@ -160,32 +310,32 @@ public:
 
     /// Returns true if the device can be forced to use the guest warp size.
     bool IsGuestWarpSizeSupported(VkShaderStageFlagBits stage) const {
-        return guest_warp_stages & stage;
+        return properties.subgroup_size_control.requiredSubgroupSizeStages & stage;
     }
 
     /// Returns the maximum number of push descriptors.
     u32 MaxPushDescriptors() const {
-        return max_push_descriptors;
+        return properties.push_descriptor.maxPushDescriptors;
     }
 
     /// Returns true if formatless image load is supported.
     bool IsFormatlessImageLoadSupported() const {
-        return is_formatless_image_load_supported;
+        return features.features.shaderStorageImageReadWithoutFormat;
     }
 
     /// Returns true if shader int64 is supported.
     bool IsShaderInt64Supported() const {
-        return is_shader_int64_supported;
+        return features.features.shaderInt64;
     }
 
     /// Returns true if shader int16 is supported.
     bool IsShaderInt16Supported() const {
-        return is_shader_int16_supported;
+        return features.features.shaderInt16;
     }
 
     // Returns true if depth bounds is supported.
     bool IsDepthBoundsSupported() const {
-        return is_depth_bounds_supported;
+        return features.features.depthBounds;
     }
 
     /// Returns true when blitting from and to depth stencil images is supported.
@@ -195,151 +345,151 @@ public:
 
     /// Returns true if the device supports VK_NV_viewport_swizzle.
     bool IsNvViewportSwizzleSupported() const {
-        return nv_viewport_swizzle;
+        return extensions.viewport_swizzle;
     }
 
     /// Returns true if the device supports VK_NV_viewport_array2.
     bool IsNvViewportArray2Supported() const {
-        return nv_viewport_array2;
+        return extensions.viewport_array2;
     }
 
     /// Returns true if the device supports VK_NV_geometry_shader_passthrough.
     bool IsNvGeometryShaderPassthroughSupported() const {
-        return nv_geometry_shader_passthrough;
+        return extensions.geometry_shader_passthrough;
     }
 
     /// Returns true if the device supports VK_KHR_uniform_buffer_standard_layout.
     bool IsKhrUniformBufferStandardLayoutSupported() const {
-        return khr_uniform_buffer_standard_layout;
+        return extensions.uniform_buffer_standard_layout;
     }
 
     /// Returns true if the device supports VK_KHR_push_descriptor.
     bool IsKhrPushDescriptorSupported() const {
-        return khr_push_descriptor;
+        return extensions.push_descriptor;
     }
 
     /// Returns true if VK_KHR_pipeline_executable_properties is enabled.
     bool IsKhrPipelineExecutablePropertiesEnabled() const {
-        return khr_pipeline_executable_properties;
+        return extensions.pipeline_executable_properties;
     }
 
     /// Returns true if VK_KHR_swapchain_mutable_format is enabled.
     bool IsKhrSwapchainMutableFormatEnabled() const {
-        return khr_swapchain_mutable_format;
+        return extensions.swapchain_mutable_format;
     }
 
     /// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout.
     bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const {
-        return khr_workgroup_memory_explicit_layout;
+        return extensions.workgroup_memory_explicit_layout;
     }
 
     /// Returns true if the device supports VK_EXT_primitive_topology_list_restart.
     bool IsTopologyListPrimitiveRestartSupported() const {
-        return is_topology_list_restart_supported;
+        return features.primitive_topology_list_restart.primitiveTopologyListRestart;
     }
 
     /// Returns true if the device supports VK_EXT_primitive_topology_list_restart.
     bool IsPatchListPrimitiveRestartSupported() const {
-        return is_patch_list_restart_supported;
+        return features.primitive_topology_list_restart.primitiveTopologyPatchListRestart;
     }
 
     /// Returns true if the device supports VK_EXT_index_type_uint8.
     bool IsExtIndexTypeUint8Supported() const {
-        return ext_index_type_uint8;
+        return extensions.index_type_uint8;
     }
 
     /// Returns true if the device supports VK_EXT_sampler_filter_minmax.
     bool IsExtSamplerFilterMinmaxSupported() const {
-        return ext_sampler_filter_minmax;
+        return extensions.sampler_filter_minmax;
     }
 
     /// Returns true if the device supports VK_EXT_depth_range_unrestricted.
     bool IsExtDepthRangeUnrestrictedSupported() const {
-        return ext_depth_range_unrestricted;
+        return extensions.depth_range_unrestricted;
     }
 
     /// Returns true if the device supports VK_EXT_depth_clip_control.
     bool IsExtDepthClipControlSupported() const {
-        return ext_depth_clip_control;
+        return extensions.depth_clip_control;
     }
 
     /// Returns true if the device supports VK_EXT_shader_viewport_index_layer.
     bool IsExtShaderViewportIndexLayerSupported() const {
-        return ext_shader_viewport_index_layer;
+        return extensions.shader_viewport_index_layer;
     }
 
     /// Returns true if the device supports VK_EXT_subgroup_size_control.
     bool IsExtSubgroupSizeControlSupported() const {
-        return ext_subgroup_size_control;
+        return extensions.subgroup_size_control;
     }
 
     /// Returns true if the device supports VK_EXT_transform_feedback.
     bool IsExtTransformFeedbackSupported() const {
-        return ext_transform_feedback;
+        return extensions.transform_feedback;
     }
 
     /// Returns true if the device supports VK_EXT_custom_border_color.
     bool IsExtCustomBorderColorSupported() const {
-        return ext_custom_border_color;
+        return extensions.custom_border_color;
     }
 
     /// Returns true if the device supports VK_EXT_extended_dynamic_state.
     bool IsExtExtendedDynamicStateSupported() const {
-        return ext_extended_dynamic_state;
+        return extensions.extended_dynamic_state;
     }
 
     /// Returns true if the device supports VK_EXT_extended_dynamic_state2.
     bool IsExtExtendedDynamicState2Supported() const {
-        return ext_extended_dynamic_state_2;
+        return extensions.extended_dynamic_state2;
     }
 
     bool IsExtExtendedDynamicState2ExtrasSupported() const {
-        return ext_extended_dynamic_state_2_extra;
+        return features.extended_dynamic_state2.extendedDynamicState2LogicOp;
     }
 
     /// Returns true if the device supports VK_EXT_extended_dynamic_state3.
     bool IsExtExtendedDynamicState3Supported() const {
-        return ext_extended_dynamic_state_3;
+        return extensions.extended_dynamic_state3;
     }
 
     /// Returns true if the device supports VK_EXT_extended_dynamic_state3.
     bool IsExtExtendedDynamicState3BlendingSupported() const {
-        return ext_extended_dynamic_state_3_blend;
+        return dynamic_state3_blending;
     }
 
     /// Returns true if the device supports VK_EXT_extended_dynamic_state3.
     bool IsExtExtendedDynamicState3EnablesSupported() const {
-        return ext_extended_dynamic_state_3_enables;
+        return dynamic_state3_enables;
     }
 
     /// Returns true if the device supports VK_EXT_line_rasterization.
     bool IsExtLineRasterizationSupported() const {
-        return ext_line_rasterization;
+        return extensions.line_rasterization;
     }
 
     /// Returns true if the device supports VK_EXT_vertex_input_dynamic_state.
     bool IsExtVertexInputDynamicStateSupported() const {
-        return ext_vertex_input_dynamic_state;
+        return extensions.vertex_input_dynamic_state;
     }
 
     /// Returns true if the device supports VK_EXT_shader_stencil_export.
     bool IsExtShaderStencilExportSupported() const {
-        return ext_shader_stencil_export;
+        return extensions.shader_stencil_export;
     }
 
     /// Returns true if the device supports VK_EXT_conservative_rasterization.
     bool IsExtConservativeRasterizationSupported() const {
-        return ext_conservative_rasterization;
+        return extensions.conservative_rasterization;
     }
 
     /// Returns true if the device supports VK_EXT_provoking_vertex.
     bool IsExtProvokingVertexSupported() const {
-        return ext_provoking_vertex;
+        return extensions.provoking_vertex;
     }
 
     /// Returns true if the device supports VK_KHR_shader_atomic_int64.
     bool IsExtShaderAtomicInt64Supported() const {
-        return ext_shader_atomic_int64;
+        return extensions.shader_atomic_int64;
     }
 
     /// Returns the minimum supported version of SPIR-V.
@@ -347,7 +497,7 @@ public:
         if (instance_version >= VK_API_VERSION_1_3) {
             return 0x00010600U;
         }
-        if (khr_spirv_1_4) {
+        if (extensions.spirv_1_4) {
             return 0x00010400U;
         }
         return 0x00010000U;
@@ -365,11 +515,11 @@ public:
 
     /// Returns the vendor name reported from Vulkan.
     std::string_view GetVendorName() const {
-        return vendor_name;
+        return properties.driver.driverName;
     }
 
     /// Returns the list of available extensions.
-    const std::vector<std::string>& GetAvailableExtensions() const {
+    const std::set<std::string, std::less<>>& GetAvailableExtensions() const {
         return supported_extensions;
     }
 
@@ -378,7 +528,7 @@ public:
     }
 
     bool CanReportMemoryUsage() const {
-        return ext_memory_budget;
+        return extensions.memory_budget;
     }
 
     u64 GetDeviceMemoryUsage() const;
@@ -400,36 +550,29 @@ public:
     }
 
     bool HasNullDescriptor() const {
-        return has_null_descriptor;
+        return features.robustness2.nullDescriptor;
     }
 
     u32 GetMaxVertexInputAttributes() const {
-        return max_vertex_input_attributes;
+        return properties.properties.limits.maxVertexInputAttributes;
     }
 
     u32 GetMaxVertexInputBindings() const {
-        return max_vertex_input_bindings;
+        return properties.properties.limits.maxVertexInputBindings;
     }
 
 private:
-    /// Checks if the physical device is suitable.
-    void CheckSuitability(bool requires_swapchain) const;
+    /// Checks if the physical device is suitable and configures the object state
+    /// with all necessary info about its properties.
+    bool GetSuitability(bool requires_swapchain);
 
-    /// Loads extensions into a vector and stores available ones in this object.
-    std::vector<const char*> LoadExtensions(bool requires_surface);
+    // Remove extensions which have incomplete feature support.
+    void RemoveUnsuitableExtensions();
+    void RemoveExtensionIfUnsuitable(bool is_suitable, const std::string& extension_name);
 
     /// Sets up queue families.
     void SetupFamilies(VkSurfaceKHR surface);
 
-    /// Sets up device features.
-    void SetupFeatures();
-
-    /// Sets up device properties.
-    void SetupProperties();
-
-    /// Collects telemetry information from the device.
-    void CollectTelemetryParameters();
-
     /// Collects information about attached tools.
     void CollectToolingInfo();
 
@@ -440,91 +583,93 @@ private:
     std::vector<VkDeviceQueueCreateInfo> GetDeviceQueueCreateInfos() const;
 
     /// Returns true if ASTC textures are natively supported.
-    bool IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const;
+    bool ComputeIsOptimalAstcSupported() const;
 
     /// Returns true if the device natively supports blitting depth stencil images.
     bool TestDepthStencilBlits() const;
 
-    VkInstance instance;                                         ///< Vulkan instance.
-    vk::DeviceDispatch dld;                                      ///< Device function pointers.
-    vk::PhysicalDevice physical;                                 ///< Physical device.
-    VkPhysicalDeviceProperties properties;                       ///< Device properties.
-    VkPhysicalDeviceFloatControlsPropertiesKHR float_controls{}; ///< Float control properties.
-    vk::Device logical;                                          ///< Logical device.
-    vk::Queue graphics_queue;                                    ///< Main graphics queue.
-    vk::Queue present_queue;                                     ///< Main present queue.
-    u32 instance_version{};                                      ///< Vulkan onstance version.
-    u32 graphics_family{};                      ///< Main graphics queue family index.
-    u32 present_family{};                       ///< Main present queue family index.
-    VkDriverIdKHR driver_id{};                  ///< Driver ID.
-    VkShaderStageFlags guest_warp_stages{};     ///< Stages where the guest warp size can be forced.
-    u64 device_access_memory{};                 ///< Total size of device local memory in bytes.
-    u32 max_push_descriptors{};                 ///< Maximum number of push descriptors
-    u32 sets_per_pool{};                        ///< Sets per Description Pool
-    bool is_optimal_astc_supported{};           ///< Support for native ASTC.
-    bool is_float16_supported{};                ///< Support for float16 arithmetic.
-    bool is_int8_supported{};                   ///< Support for int8 arithmetic.
-    bool is_warp_potentially_bigger{};          ///< Host warp size can be bigger than guest.
-    bool is_formatless_image_load_supported{};  ///< Support for shader image read without format.
-    bool is_depth_bounds_supported{};           ///< Support for depth bounds.
-    bool is_shader_float64_supported{};         ///< Support for float64.
-    bool is_shader_int64_supported{};           ///< Support for int64.
-    bool is_shader_int16_supported{};           ///< Support for int16.
-    bool is_shader_storage_image_multisample{}; ///< Support for image operations on MSAA images.
-    bool is_blit_depth_stencil_supported{};     ///< Support for blitting from and to depth stencil.
-    bool is_topology_list_restart_supported{};  ///< Support for primitive restart with list
-                                                ///< topologies.
-    bool is_patch_list_restart_supported{};     ///< Support for primitive restart with list patch.
-    bool is_integrated{};                       ///< Is GPU an iGPU.
-    bool is_virtual{};                          ///< Is GPU a virtual GPU.
-    bool is_non_gpu{};                          ///< Is SoftwareRasterizer, FPGA, non-GPU device.
-    bool nv_viewport_swizzle{};                 ///< Support for VK_NV_viewport_swizzle.
-    bool nv_viewport_array2{};                  ///< Support for VK_NV_viewport_array2.
-    bool nv_geometry_shader_passthrough{};      ///< Support for VK_NV_geometry_shader_passthrough.
-    bool khr_draw_indirect_count{};             ///< Support for VK_KHR_draw_indirect_count.
-    bool khr_uniform_buffer_standard_layout{};  ///< Support for scalar uniform buffer layouts.
-    bool khr_spirv_1_4{};                       ///< Support for VK_KHR_spirv_1_4.
-    bool khr_workgroup_memory_explicit_layout{}; ///< Support for explicit workgroup layouts.
-    bool khr_push_descriptor{};                  ///< Support for VK_KHR_push_descritor.
-    bool khr_pipeline_executable_properties{};   ///< Support for executable properties.
-    bool khr_swapchain_mutable_format{};         ///< Support for VK_KHR_swapchain_mutable_format.
-    bool ext_index_type_uint8{};                 ///< Support for VK_EXT_index_type_uint8.
-    bool ext_sampler_filter_minmax{};            ///< Support for VK_EXT_sampler_filter_minmax.
-    bool ext_depth_clip_control{};               ///< Support for VK_EXT_depth_clip_control
-    bool ext_depth_range_unrestricted{};         ///< Support for VK_EXT_depth_range_unrestricted.
-    bool ext_shader_viewport_index_layer{};    ///< Support for VK_EXT_shader_viewport_index_layer.
-    bool ext_tooling_info{};                   ///< Support for VK_EXT_tooling_info.
-    bool ext_subgroup_size_control{};          ///< Support for VK_EXT_subgroup_size_control.
-    bool ext_transform_feedback{};             ///< Support for VK_EXT_transform_feedback.
-    bool ext_custom_border_color{};            ///< Support for VK_EXT_custom_border_color.
-    bool ext_extended_dynamic_state{};         ///< Support for VK_EXT_extended_dynamic_state.
-    bool ext_extended_dynamic_state_2{};       ///< Support for VK_EXT_extended_dynamic_state2.
-    bool ext_extended_dynamic_state_2_extra{}; ///< Support for VK_EXT_extended_dynamic_state2.
-    bool ext_extended_dynamic_state_3{};       ///< Support for VK_EXT_extended_dynamic_state3.
-    bool ext_extended_dynamic_state_3_blend{}; ///< Support for VK_EXT_extended_dynamic_state3.
-    bool ext_extended_dynamic_state_3_enables{}; ///< Support for VK_EXT_extended_dynamic_state3.
-    bool ext_line_rasterization{};               ///< Support for VK_EXT_line_rasterization.
-    bool ext_vertex_input_dynamic_state{};       ///< Support for VK_EXT_vertex_input_dynamic_state.
-    bool ext_shader_stencil_export{};            ///< Support for VK_EXT_shader_stencil_export.
-    bool ext_shader_atomic_int64{};              ///< Support for VK_KHR_shader_atomic_int64.
-    bool ext_conservative_rasterization{};       ///< Support for VK_EXT_conservative_rasterization.
-    bool ext_provoking_vertex{};                 ///< Support for VK_EXT_provoking_vertex.
-    bool ext_memory_budget{};                    ///< Support for VK_EXT_memory_budget.
-    bool nv_device_diagnostics_config{};         ///< Support for VK_NV_device_diagnostics_config.
-    bool has_broken_cube_compatibility{};        ///< Has broken cube compatiblity bit
-    bool has_renderdoc{};                        ///< Has RenderDoc attached
-    bool has_nsight_graphics{};                  ///< Has Nsight Graphics attached
-    bool supports_d24_depth{};                   ///< Supports D24 depth buffers.
-    bool cant_blit_msaa{};                       ///< Does not support MSAA<->MSAA blitting.
-    bool must_emulate_bgr565{};                  ///< Emulates BGR565 by swizzling RGB565 format.
-    bool has_null_descriptor{};                  ///< Has support for null descriptors.
-    u32 max_vertex_input_attributes{};           ///< Max vertex input attributes in pipeline
-    u32 max_vertex_input_bindings{};             ///< Max vertex input buffers in pipeline
+private:
+    VkInstance instance;         ///< Vulkan instance.
+    vk::DeviceDispatch dld;      ///< Device function pointers.
+    vk::PhysicalDevice physical; ///< Physical device.
+    vk::Device logical;          ///< Logical device.
+    vk::Queue graphics_queue;    ///< Main graphics queue.
+    vk::Queue present_queue;     ///< Main present queue.
+    u32 instance_version{};      ///< Vulkan instance version.
+    u32 graphics_family{};       ///< Main graphics queue family index.
+    u32 present_family{};        ///< Main present queue family index.
+
+    struct Extensions {
+#define EXTENSION(prefix, macro_name, var_name) bool var_name{};
+#define FEATURE(prefix, struct_name, macro_name, var_name) bool var_name{};
+
+        FOR_EACH_VK_FEATURE_1_1(FEATURE);
+        FOR_EACH_VK_FEATURE_1_2(FEATURE);
+        FOR_EACH_VK_FEATURE_1_3(FEATURE);
+        FOR_EACH_VK_FEATURE_EXT(FEATURE);
+        FOR_EACH_VK_EXTENSION(EXTENSION);
+        FOR_EACH_VK_EXTENSION_WIN32(EXTENSION);
+
+#undef EXTENSION
+#undef FEATURE
+    };
+
+    struct Features {
+#define FEATURE_CORE(prefix, struct_name, macro_name, var_name)                                    \
+    VkPhysicalDevice##struct_name##Features var_name{};
+#define FEATURE_EXT(prefix, struct_name, macro_name, var_name)                                     \
+    VkPhysicalDevice##struct_name##Features##prefix var_name{};
+
+        FOR_EACH_VK_FEATURE_1_1(FEATURE_CORE);
+        FOR_EACH_VK_FEATURE_1_2(FEATURE_CORE);
+        FOR_EACH_VK_FEATURE_1_3(FEATURE_CORE);
+        FOR_EACH_VK_FEATURE_EXT(FEATURE_EXT);
+
+#undef FEATURE_CORE
+#undef FEATURE_EXT
+
+        VkPhysicalDeviceFeatures features{};
+    };
+
+    struct Properties {
+        VkPhysicalDeviceDriverProperties driver{};
+        VkPhysicalDeviceFloatControlsProperties float_controls{};
+        VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor{};
+        VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};
+        VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback{};
+
+        VkPhysicalDeviceProperties properties{};
+    };
+
+    Extensions extensions{};
+    Features features{};
+    Properties properties{};
+
+    VkPhysicalDeviceFeatures2 features2{};
+    VkPhysicalDeviceProperties2 properties2{};
+
+    // Misc features
+    bool is_optimal_astc_supported{};       ///< Support for all guest ASTC formats.
+    bool is_blit_depth_stencil_supported{}; ///< Support for blitting from and to depth stencil.
+    bool is_warp_potentially_bigger{};      ///< Host warp size can be bigger than guest.
+    bool is_integrated{};                   ///< Is GPU an iGPU.
+    bool is_virtual{};                      ///< Is GPU a virtual GPU.
+    bool is_non_gpu{};                      ///< Is SoftwareRasterizer, FPGA, non-GPU device.
+    bool has_broken_cube_compatibility{};   ///< Has broken cube compatiblity bit
+    bool has_renderdoc{};                   ///< Has RenderDoc attached
+    bool has_nsight_graphics{};             ///< Has Nsight Graphics attached
+    bool supports_d24_depth{};              ///< Supports D24 depth buffers.
+    bool cant_blit_msaa{};                  ///< Does not support MSAA<->MSAA blitting.
+    bool must_emulate_bgr565{};             ///< Emulates BGR565 by swizzling RGB565 format.
+    bool dynamic_state3_blending{};         ///< Has all blending features of dynamic_state3.
+    bool dynamic_state3_enables{};          ///< Has all enables features of dynamic_state3.
+    u64 device_access_memory{};             ///< Total size of device local memory in bytes.
+    u32 sets_per_pool{};                    ///< Sets per Description Pool
 
     // Telemetry parameters
-    std::string vendor_name;                       ///< Device's driver name.
-    std::vector<std::string> supported_extensions; ///< Reported Vulkan extensions.
-    std::vector<size_t> valid_heap_memory;         ///< Heaps used.
+    std::set<std::string, std::less<>> supported_extensions; ///< Reported Vulkan extensions.
+    std::set<std::string, std::less<>> loaded_extensions;    ///< Loaded Vulkan extensions.
+    std::vector<size_t> valid_heap_memory;                   ///< Heaps used.
 
     /// Format properties dictionary.
     std::unordered_map<VkFormat, VkFormatProperties> format_properties;