| /* Copyright (c) 2026 The Khronos Group Inc. |
| * Copyright (c) 2026 Valve Corporation |
| * Copyright (c) 2026 LunarG, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "gpuav/core/gpuav.h" |
| #include "generated/dispatch_functions.h" |
| |
| namespace gpuav { |
| |
| static std::vector<VkExtensionProperties> GetAvailableExtensions(VkPhysicalDevice physical_device) { |
| VkResult err; |
| uint32_t extension_count = 512; |
| std::vector<VkExtensionProperties> extensions(extension_count); |
| for (;;) { |
| err = DispatchEnumerateDeviceExtensionProperties(physical_device, nullptr, &extension_count, extensions.data()); |
| if (err == VK_SUCCESS) { |
| extensions.resize(extension_count); |
| return extensions; |
| } else if (err == VK_INCOMPLETE) { |
| extension_count *= 2; // wasn't enough space, increase it |
| extensions.resize(extension_count); |
| } else { |
| return {}; |
| } |
| } |
| } |
| |
| static bool IsExtensionAvailable(const char* extension_name, const std::vector<VkExtensionProperties>& available_extensions) { |
| for (const VkExtensionProperties& ext : available_extensions) { |
| if (strncmp(extension_name, ext.extensionName, VK_MAX_EXTENSION_NAME_SIZE) == 0) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| // We end up printing lots of warning for GPU-AV that really have no use for any object. |
| // Instead of spamming with a VkInstance, just explicitly don't print anything |
| static const VulkanTypedHandle kNoObjects; |
| |
| // In PreCallRecord we try to turn on as many features as possible on behalf of the app (and warn the user if we are doing it). |
| // Later after device creation, we can decide if the required Vulkan feature for each GPU-AV setting is found and report errors |
| void Instance::AddFeatures(VkPhysicalDevice physical_device, vku::safe_VkDeviceCreateInfo* modified_create_info, |
| const Location& loc) { |
| // Query things here to make sure we don't attempt to add a feature this is just not supported |
| VkPhysicalDeviceCooperativeMatrixFeaturesKHR supported_coop_mat_feature = vku::InitStructHelper(); |
| VkPhysicalDeviceRobustness2FeaturesKHR supported_robustness2_feature = vku::InitStructHelper(&supported_coop_mat_feature); |
| VkPhysicalDeviceShaderFloat16Int8Features supported_shader_float16_int8_feature = |
| vku::InitStructHelper(&supported_robustness2_feature); |
| VkPhysicalDevice8BitStorageFeatures supported_8bit_feature = vku::InitStructHelper(&supported_shader_float16_int8_feature); |
| VkPhysicalDevice16BitStorageFeatures supported_16bit_feature = vku::InitStructHelper(&supported_8bit_feature); |
| VkPhysicalDeviceBufferDeviceAddressFeatures supported_bda_feature = vku::InitStructHelper(&supported_16bit_feature); |
| VkPhysicalDeviceScalarBlockLayoutFeatures supported_scalar_feature = vku::InitStructHelper(&supported_bda_feature); |
| VkPhysicalDeviceVulkanMemoryModelFeatures supported_memory_model_feature = vku::InitStructHelper(&supported_scalar_feature); |
| VkPhysicalDeviceTimelineSemaphoreFeatures supported_timeline_feature = vku::InitStructHelper(&supported_memory_model_feature); |
| VkPhysicalDeviceFeatures2 features_2 = vku::InitStructHelper(&supported_timeline_feature); |
| DispatchGetPhysicalDeviceFeatures2(physical_device, &features_2); |
| |
| std::string adjustment_warnings; |
| |
| // First core features |
| { |
| const VkPhysicalDeviceFeatures& supported_features = features_2.features; |
| |
| VkPhysicalDeviceFeatures* modified_features = const_cast<VkPhysicalDeviceFeatures*>(modified_create_info->pEnabledFeatures); |
| if (!modified_features) { |
| if (auto* modified_features_2 = const_cast<VkPhysicalDeviceFeatures2*>( |
| vku::FindStructInPNextChain<VkPhysicalDeviceFeatures2>(modified_create_info->pNext))) { |
| modified_features = &modified_features_2->features; |
| } else { |
| // The user has no VkPhysicalDeviceFeatures, so we are adding it for them |
| modified_features = new VkPhysicalDeviceFeatures; |
| memset(modified_features, 0, sizeof(VkPhysicalDeviceFeatures)); |
| modified_create_info->pEnabledFeatures = modified_features; |
| } |
| } |
| |
| if (modified_features) { |
| if (supported_features.fragmentStoresAndAtomics && !modified_features->fragmentStoresAndAtomics) { |
| adjustment_warnings += "\tForcing fragmentStoresAndAtomics to VK_TRUE\n"; |
| modified_features->fragmentStoresAndAtomics = VK_TRUE; |
| } |
| if (supported_features.vertexPipelineStoresAndAtomics && !modified_features->vertexPipelineStoresAndAtomics) { |
| adjustment_warnings += "\tForcing vertexPipelineStoresAndAtomics to VK_TRUE\n"; |
| modified_features->vertexPipelineStoresAndAtomics = VK_TRUE; |
| } |
| if (supported_features.shaderInt64 && !modified_features->shaderInt64) { |
| adjustment_warnings += "\tForcing shaderInt64 to VK_TRUE\n"; |
| modified_features->shaderInt64 = VK_TRUE; |
| } |
| if (gpuav_settings.force_on_robustness && supported_features.robustBufferAccess && |
| !modified_features->robustBufferAccess) { |
| adjustment_warnings += "\tForcing robustBufferAccess to VK_TRUE\n"; |
| modified_features->robustBufferAccess = VK_TRUE; |
| } |
| if (supported_features.shaderInt16 && !modified_features->shaderInt16) { |
| adjustment_warnings += "\tForcing shaderInt16 to VK_TRUE\n"; |
| modified_features->shaderInt16 = VK_TRUE; |
| } |
| } |
| } |
| |
| // Build extension list once |
| std::vector<VkExtensionProperties> available_extensions = GetAvailableExtensions(physical_device); |
| |
| if (supported_timeline_feature.timelineSemaphore) { |
| auto add_timeline_semaphore = [modified_create_info, &adjustment_warnings]() { |
| if (auto* ts_features = const_cast<VkPhysicalDeviceTimelineSemaphoreFeatures*>( |
| vku::FindStructInPNextChain<VkPhysicalDeviceTimelineSemaphoreFeatures>(modified_create_info))) { |
| if (ts_features->timelineSemaphore == VK_FALSE) { |
| adjustment_warnings += "\tForcing VkPhysicalDeviceTimelineSemaphoreFeatures::timelineSemaphore to VK_TRUE\n"; |
| ts_features->timelineSemaphore = VK_TRUE; |
| } |
| } else { |
| adjustment_warnings += |
| "\tAdding a VkPhysicalDeviceTimelineSemaphoreFeatures to pNext with timelineSemaphore set to VK_TRUE\n"; |
| VkPhysicalDeviceTimelineSemaphoreFeatures new_ts_features = vku::InitStructHelper(); |
| new_ts_features.timelineSemaphore = VK_TRUE; |
| vku::AddToPnext(*modified_create_info, new_ts_features); |
| } |
| }; |
| |
| if (api_version > VK_API_VERSION_1_1) { |
| if (auto* features12 = const_cast<VkPhysicalDeviceVulkan12Features*>( |
| vku::FindStructInPNextChain<VkPhysicalDeviceVulkan12Features>(modified_create_info->pNext))) { |
| if (features12->timelineSemaphore == VK_FALSE) { |
| adjustment_warnings += "\tForcing VkPhysicalDeviceVulkan12Features::timelineSemaphore to VK_TRUE\n"; |
| features12->timelineSemaphore = VK_TRUE; |
| } |
| } else { |
| add_timeline_semaphore(); |
| } |
| } else if (IsExtensionAvailable(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME, available_extensions)) { |
| // Only adds if not found already |
| vku::AddExtension(*modified_create_info, VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME); |
| add_timeline_semaphore(); |
| timeline_khr_ = true; |
| } |
| } |
| |
| if (supported_memory_model_feature.vulkanMemoryModel) { |
| auto add_memory_model = [modified_create_info, &adjustment_warnings]() { |
| if (auto* mm_features = const_cast<VkPhysicalDeviceVulkanMemoryModelFeatures*>( |
| vku::FindStructInPNextChain<VkPhysicalDeviceVulkanMemoryModelFeatures>(modified_create_info))) { |
| if (mm_features->vulkanMemoryModel == VK_FALSE) { |
| adjustment_warnings += "\tForcing VkPhysicalDeviceVulkanMemoryModelFeatures::vulkanMemoryModel to VK_TRUE\n"; |
| mm_features->vulkanMemoryModel = VK_TRUE; |
| } |
| if (mm_features->vulkanMemoryModelDeviceScope == VK_FALSE) { |
| adjustment_warnings += |
| "\tForcing VkPhysicalDeviceVulkanMemoryModelFeatures::vulkanMemoryModelDeviceScope to VK_TRUE\n"; |
| mm_features->vulkanMemoryModelDeviceScope = VK_TRUE; |
| } |
| } else { |
| adjustment_warnings += |
| "\tAdding a VkPhysicalDeviceVulkanMemoryModelFeatures to pNext with vulkanMemoryModel and " |
| "vulkanMemoryModelDeviceScope set to VK_TRUE\n"; |
| VkPhysicalDeviceVulkanMemoryModelFeatures new_mm_features = vku::InitStructHelper(); |
| new_mm_features.vulkanMemoryModel = VK_TRUE; |
| new_mm_features.vulkanMemoryModelDeviceScope = VK_TRUE; |
| vku::AddToPnext(*modified_create_info, new_mm_features); |
| } |
| }; |
| |
| if (api_version > VK_API_VERSION_1_1) { |
| if (auto* features12 = const_cast<VkPhysicalDeviceVulkan12Features*>( |
| vku::FindStructInPNextChain<VkPhysicalDeviceVulkan12Features>(modified_create_info->pNext))) { |
| if (features12->vulkanMemoryModel == VK_FALSE) { |
| adjustment_warnings += "\tForcing VkPhysicalDeviceVulkan12Features::vulkanMemoryModel to VK_TRUE\n"; |
| features12->vulkanMemoryModel = VK_TRUE; |
| } |
| if (features12->vulkanMemoryModelDeviceScope == VK_FALSE) { |
| adjustment_warnings += "\tForcing VkPhysicalDeviceVulkan12Features::vulkanMemoryModelDeviceScope to VK_TRUE\n"; |
| features12->vulkanMemoryModelDeviceScope = VK_TRUE; |
| } |
| } else { |
| add_memory_model(); |
| } |
| } else if (IsExtensionAvailable(VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME, available_extensions)) { |
| // Only adds if not found already |
| vku::AddExtension(*modified_create_info, VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME); |
| add_memory_model(); |
| } |
| } |
| |
| if (supported_bda_feature.bufferDeviceAddress) { |
| auto add_bda = [modified_create_info, &adjustment_warnings]() { |
| // Add buffer device address feature |
| if (auto* bda_features = const_cast<VkPhysicalDeviceBufferDeviceAddressFeatures*>( |
| vku::FindStructInPNextChain<VkPhysicalDeviceBufferDeviceAddressFeatures>(modified_create_info))) { |
| if (!bda_features->bufferDeviceAddress) { |
| adjustment_warnings += |
| "\tForcing VkPhysicalDeviceBufferDeviceAddressFeatures::bufferDeviceAddress to VK_TRUE\n"; |
| bda_features->bufferDeviceAddress = VK_TRUE; |
| } |
| } else { |
| adjustment_warnings += |
| "\tAdding a VkPhysicalDeviceBufferDeviceAddressFeatures to pNext with bufferDeviceAddress set to VK_TRUE\n"; |
| VkPhysicalDeviceBufferDeviceAddressFeatures new_bda_features = vku::InitStructHelper(); |
| new_bda_features.bufferDeviceAddress = VK_TRUE; |
| vku::AddToPnext(*modified_create_info, new_bda_features); |
| } |
| }; |
| |
| if (api_version >= VK_API_VERSION_1_2) { |
| if (auto* features12 = const_cast<VkPhysicalDeviceVulkan12Features*>( |
| vku::FindStructInPNextChain<VkPhysicalDeviceVulkan12Features>(modified_create_info->pNext))) { |
| if (!features12->bufferDeviceAddress) { |
| adjustment_warnings += "\tForcing VkPhysicalDeviceVulkan12Features::bufferDeviceAddress to VK_TRUE\n"; |
| features12->bufferDeviceAddress = VK_TRUE; |
| } |
| } else { |
| add_bda(); |
| } |
| } else if (IsExtensionAvailable(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, available_extensions)) { |
| // Only adds if not found already |
| vku::AddExtension(*modified_create_info, VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| add_bda(); |
| } |
| } |
| |
| if (supported_scalar_feature.scalarBlockLayout) { |
| auto add_scalar = [modified_create_info, &adjustment_warnings]() { |
| if (auto* bda_features = const_cast<VkPhysicalDeviceScalarBlockLayoutFeatures*>( |
| vku::FindStructInPNextChain<VkPhysicalDeviceScalarBlockLayoutFeatures>(modified_create_info))) { |
| if (!bda_features->scalarBlockLayout) { |
| adjustment_warnings += "\tForcing VkPhysicalDeviceScalarBlockLayoutFeatures::scalarBlockLayout to VK_TRUE\n"; |
| bda_features->scalarBlockLayout = VK_TRUE; |
| } |
| } else { |
| adjustment_warnings += |
| "\tAdding a VkPhysicalDeviceScalarBlockLayoutFeatures to pNext with scalarBlockLayout set to VK_TRUE\n"; |
| VkPhysicalDeviceScalarBlockLayoutFeatures new_bda_features = vku::InitStructHelper(); |
| new_bda_features.scalarBlockLayout = VK_TRUE; |
| vku::AddToPnext(*modified_create_info, new_bda_features); |
| } |
| }; |
| |
| if (api_version >= VK_API_VERSION_1_2) { |
| if (auto* features12 = const_cast<VkPhysicalDeviceVulkan12Features*>( |
| vku::FindStructInPNextChain<VkPhysicalDeviceVulkan12Features>(modified_create_info->pNext))) { |
| if (!features12->scalarBlockLayout) { |
| adjustment_warnings += "\tForcing VkPhysicalDeviceVulkan12Features::scalarBlockLayout to VK_TRUE\n"; |
| features12->scalarBlockLayout = VK_TRUE; |
| } |
| } else { |
| add_scalar(); |
| } |
| } else if (IsExtensionAvailable(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME, available_extensions)) { |
| // Only adds if not found already |
| vku::AddExtension(*modified_create_info, VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); |
| add_scalar(); |
| } |
| } |
| |
| if (supported_8bit_feature.storageBuffer8BitAccess) { |
| auto add_8bit_access = [modified_create_info, &adjustment_warnings]() { |
| // Add storageBuffer8BitAccess feature |
| if (auto* eight_bit_access_feature = const_cast<VkPhysicalDevice8BitStorageFeatures*>( |
| vku::FindStructInPNextChain<VkPhysicalDevice8BitStorageFeatures>(modified_create_info))) { |
| if (!eight_bit_access_feature->storageBuffer8BitAccess) { |
| adjustment_warnings += "\tForcing VkPhysicalDevice8BitStorageFeatures::storageBuffer8BitAccess to VK_TRUE\n"; |
| eight_bit_access_feature->storageBuffer8BitAccess = VK_TRUE; |
| } |
| } else { |
| adjustment_warnings += |
| "\tAdding a VkPhysicalDevice8BitStorageFeatures to pNext with storageBuffer8BitAccess " |
| "set to VK_TRUE\n"; |
| VkPhysicalDevice8BitStorageFeatures new_8bit_features = vku::InitStructHelper(); |
| new_8bit_features.storageBuffer8BitAccess = VK_TRUE; |
| vku::AddToPnext(*modified_create_info, new_8bit_features); |
| } |
| }; |
| |
| if (api_version >= VK_API_VERSION_1_2) { |
| if (auto* features12 = const_cast<VkPhysicalDeviceVulkan12Features*>( |
| vku::FindStructInPNextChain<VkPhysicalDeviceVulkan12Features>(modified_create_info->pNext))) { |
| if (!features12->storageBuffer8BitAccess) { |
| adjustment_warnings += "\tForcing VkPhysicalDeviceVulkan12Features::storageBuffer8BitAccess to VK_TRUE\n"; |
| features12->storageBuffer8BitAccess = VK_TRUE; |
| } |
| } else { |
| add_8bit_access(); |
| } |
| } else if (IsExtensionAvailable(VK_KHR_8BIT_STORAGE_EXTENSION_NAME, available_extensions)) { |
| // Only adds if not found already |
| vku::AddExtension(*modified_create_info, VK_KHR_8BIT_STORAGE_EXTENSION_NAME); |
| add_8bit_access(); |
| } |
| } |
| |
| if (supported_shader_float16_int8_feature.shaderInt8) { |
| auto add_int8 = [modified_create_info, &adjustment_warnings]() { |
| // Add shaderInt8 feature |
| if (auto* sixteen_bit_access_feature = const_cast<VkPhysicalDeviceShaderFloat16Int8Features*>( |
| vku::FindStructInPNextChain<VkPhysicalDeviceShaderFloat16Int8Features>(modified_create_info))) { |
| if (!sixteen_bit_access_feature->shaderInt8) { |
| adjustment_warnings += "\tForcing VkPhysicalDeviceShaderFloat16Int8Features::shaderInt8 to VK_TRUE\n"; |
| sixteen_bit_access_feature->shaderInt8 = VK_TRUE; |
| } |
| } else { |
| adjustment_warnings += |
| "\tAdding a VkPhysicalDeviceShaderFloat16Int8Features to pNext with shaderInt8 " |
| "set to VK_TRUE\n"; |
| VkPhysicalDeviceShaderFloat16Int8Features new_16bit_features = vku::InitStructHelper(); |
| new_16bit_features.shaderInt8 = VK_TRUE; |
| vku::AddToPnext(*modified_create_info, new_16bit_features); |
| } |
| }; |
| |
| if (api_version >= VK_API_VERSION_1_2) { |
| if (auto* features12 = const_cast<VkPhysicalDeviceVulkan12Features*>( |
| vku::FindStructInPNextChain<VkPhysicalDeviceVulkan12Features>(modified_create_info->pNext))) { |
| if (!features12->shaderInt8) { |
| adjustment_warnings += "\tForcing VkPhysicalDeviceVulkan12Features::shaderInt8 to VK_TRUE\n"; |
| features12->shaderInt8 = VK_TRUE; |
| } |
| } else { |
| add_int8(); |
| } |
| } else if (IsExtensionAvailable(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, available_extensions)) { |
| // Only adds if not found already |
| vku::AddExtension(*modified_create_info, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); |
| add_int8(); |
| } |
| } |
| |
| if (supported_16bit_feature.storageBuffer16BitAccess) { |
| auto add_16bit_access = [modified_create_info, &adjustment_warnings]() { |
| // Add storageBuffer16BitAccess feature |
| if (auto* sixteen_bit_access_feature = const_cast<VkPhysicalDevice16BitStorageFeatures*>( |
| vku::FindStructInPNextChain<VkPhysicalDevice16BitStorageFeatures>(modified_create_info))) { |
| if (!sixteen_bit_access_feature->storageBuffer16BitAccess) { |
| adjustment_warnings += "\tForcing VkPhysicalDevice16BitStorageFeatures::storageBuffer16BitAccess to VK_TRUE\n"; |
| sixteen_bit_access_feature->storageBuffer16BitAccess = VK_TRUE; |
| } |
| } else { |
| adjustment_warnings += |
| "\tAdding a VkPhysicalDevice16BitStorageFeatures to pNext with storageBuffer16BitAccess " |
| "set to VK_TRUE\n"; |
| VkPhysicalDevice16BitStorageFeatures new_16bit_features = vku::InitStructHelper(); |
| new_16bit_features.storageBuffer16BitAccess = VK_TRUE; |
| vku::AddToPnext(*modified_create_info, new_16bit_features); |
| } |
| }; |
| |
| if (api_version >= VK_API_VERSION_1_1) { |
| if (auto* features11 = const_cast<VkPhysicalDeviceVulkan11Features*>( |
| vku::FindStructInPNextChain<VkPhysicalDeviceVulkan11Features>(modified_create_info->pNext))) { |
| if (!features11->storageBuffer16BitAccess) { |
| adjustment_warnings += "\tForcing VkPhysicalDeviceVulkan11Features::storageBuffer16BitAccess to VK_TRUE\n"; |
| features11->storageBuffer16BitAccess = VK_TRUE; |
| } |
| } else { |
| add_16bit_access(); |
| } |
| } else if (IsExtensionAvailable(VK_KHR_16BIT_STORAGE_EXTENSION_NAME, available_extensions)) { |
| // Only adds if not found already |
| vku::AddExtension(*modified_create_info, VK_KHR_16BIT_STORAGE_EXTENSION_NAME); |
| add_16bit_access(); |
| } |
| } |
| |
| if (gpuav_settings.debug_printf_enabled || gpuav_settings.debug_descriptor_enabled) { |
| if (!IsExtensionAvailable(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME, available_extensions)) { |
| adjustment_warnings += |
| "\tVK_KHR_shader_non_semantic_info is not available on selected device, DebugPrintf/DebugDescriptor may produce " |
| "SPIR-V " |
| "that could fail to compile the shader\n"; |
| } else { |
| vku::AddExtension(*modified_create_info, VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME); |
| } |
| } |
| |
| if (gpuav_settings.force_on_robustness && |
| (supported_robustness2_feature.robustBufferAccess2 || supported_robustness2_feature.robustImageAccess2)) { |
| const bool has_ext = IsExtensionAvailable(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, available_extensions); |
| const bool has_khr = IsExtensionAvailable(VK_KHR_ROBUSTNESS_2_EXTENSION_NAME, available_extensions); |
| if (has_ext || has_khr) { |
| // Only adds if not found already |
| if (has_khr) { |
| vku::AddExtension(*modified_create_info, VK_KHR_ROBUSTNESS_2_EXTENSION_NAME); |
| } else { |
| vku::AddExtension(*modified_create_info, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME); |
| } |
| |
| if (auto* robust_buffer_2_feature = const_cast<VkPhysicalDeviceRobustness2FeaturesKHR*>( |
| vku::FindStructInPNextChain<VkPhysicalDeviceRobustness2FeaturesKHR>(modified_create_info))) { |
| if (!robust_buffer_2_feature->robustBufferAccess2 && supported_robustness2_feature.robustBufferAccess2) { |
| adjustment_warnings += "\tForcing VkPhysicalDeviceRobustness2FeaturesKHR::robustBufferAccess2 to VK_TRUE\n"; |
| robust_buffer_2_feature->robustBufferAccess2 = VK_TRUE; |
| } |
| if (!robust_buffer_2_feature->robustImageAccess2 && supported_robustness2_feature.robustImageAccess2) { |
| adjustment_warnings += "\tForcing VkPhysicalDeviceRobustness2FeaturesKHR::robustImageAccess2 to VK_TRUE\n"; |
| robust_buffer_2_feature->robustImageAccess2 = VK_TRUE; |
| } |
| } else { |
| VkPhysicalDeviceRobustness2FeaturesKHR new_robust_buffer_2_feature = vku::InitStructHelper(); |
| if (supported_robustness2_feature.robustBufferAccess2) { |
| adjustment_warnings += |
| "\tAdding a VkPhysicalDeviceRobustness2FeaturesKHR to pNext with robustBufferAccess2 set to VK_TRUE\n"; |
| new_robust_buffer_2_feature.robustBufferAccess2 = VK_TRUE; |
| } |
| if (supported_robustness2_feature.robustImageAccess2) { |
| adjustment_warnings += |
| "\tAdding a VkPhysicalDeviceRobustness2FeaturesKHR to pNext with robustImageAccess2 set to VK_TRUE\n"; |
| new_robust_buffer_2_feature.robustImageAccess2 = VK_TRUE; |
| } |
| vku::AddToPnext(*modified_create_info, new_robust_buffer_2_feature); |
| } |
| } |
| } |
| |
| if (gpuav_settings.force_on_robustness && supported_coop_mat_feature.cooperativeMatrixRobustBufferAccess) { |
| // Because they need to have VkPhysicalDeviceCooperativeMatrixFeaturesKHR::cooperativeMatrix to even use this extensions, we |
| // don't add it, we only need to update the other feature bit for them |
| if (auto* coop_mat_feature = const_cast<VkPhysicalDeviceCooperativeMatrixFeaturesKHR*>( |
| vku::FindStructInPNextChain<VkPhysicalDeviceCooperativeMatrixFeaturesKHR>(modified_create_info))) { |
| if (!coop_mat_feature->cooperativeMatrixRobustBufferAccess) { |
| adjustment_warnings += |
| "\tForcing VkPhysicalDeviceCooperativeMatrixFeaturesKHR::cooperativeMatrixRobustBufferAccess to VK_TRUE\n"; |
| coop_mat_feature->cooperativeMatrixRobustBufferAccess = VK_TRUE; |
| } |
| } |
| } |
| |
| if (!adjustment_warnings.empty()) { |
| AdjustmentWarning(kNoObjects, loc, adjustment_warnings.c_str()); |
| } |
| } |
| |
| } // namespace gpuav |