From b814cd10f36823922be4e7e179f1d3aa9978f0a5 Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Mon, 20 Jan 2025 21:33:43 +0000 Subject: [PATCH] Make device extensions configurable --- generator/vk_layer/source/device.cpp | 3 + generator/vk_layer/source/device.hpp | 18 +- layer_example/source/device.cpp | 3 + layer_example/source/device.hpp | 18 +- layer_gpu_support/source/device.cpp | 5 + layer_gpu_support/source/device.hpp | 16 +- layer_gpu_timeline/source/device.cpp | 3 + layer_gpu_timeline/source/device.hpp | 5 + source_common/framework/manual_functions.cpp | 210 +++++++++++-------- 9 files changed, 176 insertions(+), 105 deletions(-) diff --git a/generator/vk_layer/source/device.cpp b/generator/vk_layer/source/device.cpp index 3371cff..65b0393 100644 --- a/generator/vk_layer/source/device.cpp +++ b/generator/vk_layer/source/device.cpp @@ -39,6 +39,9 @@ */ static std::unordered_map> g_devices; +/* See header for documentation. */ +const std::vector Device::extraExtensions { }; + /* See header for documentation. */ void Device::store( VkDevice handle, diff --git a/generator/vk_layer/source/device.hpp b/generator/vk_layer/source/device.hpp index c0e1f0a..569699e 100644 --- a/generator/vk_layer/source/device.hpp +++ b/generator/vk_layer/source/device.hpp @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: MIT * ---------------------------------------------------------------------------- - * Copyright (c) 2024 Arm Limited + * Copyright (c) 2024-2025 Arm Limited * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -132,6 +132,17 @@ class Device ~Device() = default; public: + /** + * @brief The driver function dispatch table. + */ + DeviceDispatchTable driver {}; + + /** + * @brief The minimum set of device extensions needed by this layer. + */ + static const std::vector extraExtensions; + +private: /** * @brief The instance this device is created with. */ @@ -146,9 +157,4 @@ class Device * @brief The device handle this device is created with. */ const VkDevice device; - - /** - * @brief The driver function dispatch table. - */ - DeviceDispatchTable driver {}; }; diff --git a/layer_example/source/device.cpp b/layer_example/source/device.cpp index 3371cff..65b0393 100644 --- a/layer_example/source/device.cpp +++ b/layer_example/source/device.cpp @@ -39,6 +39,9 @@ */ static std::unordered_map> g_devices; +/* See header for documentation. */ +const std::vector Device::extraExtensions { }; + /* See header for documentation. */ void Device::store( VkDevice handle, diff --git a/layer_example/source/device.hpp b/layer_example/source/device.hpp index c0e1f0a..569699e 100644 --- a/layer_example/source/device.hpp +++ b/layer_example/source/device.hpp @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: MIT * ---------------------------------------------------------------------------- - * Copyright (c) 2024 Arm Limited + * Copyright (c) 2024-2025 Arm Limited * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -132,6 +132,17 @@ class Device ~Device() = default; public: + /** + * @brief The driver function dispatch table. + */ + DeviceDispatchTable driver {}; + + /** + * @brief The minimum set of device extensions needed by this layer. + */ + static const std::vector extraExtensions; + +private: /** * @brief The instance this device is created with. */ @@ -146,9 +157,4 @@ class Device * @brief The device handle this device is created with. */ const VkDevice device; - - /** - * @brief The driver function dispatch table. - */ - DeviceDispatchTable driver {}; }; diff --git a/layer_gpu_support/source/device.cpp b/layer_gpu_support/source/device.cpp index cf669a4..3f0bd21 100644 --- a/layer_gpu_support/source/device.cpp +++ b/layer_gpu_support/source/device.cpp @@ -33,6 +33,11 @@ */ static std::unordered_map> g_devices; +/* See header for documentation. */ +const std::vector Device::extraExtensions { + "VK_KHR_timeline_semaphore" +}; + /* See header for documentation. */ void Device::store( VkDevice handle, diff --git a/layer_gpu_support/source/device.hpp b/layer_gpu_support/source/device.hpp index c3dd12b..569699e 100644 --- a/layer_gpu_support/source/device.hpp +++ b/layer_gpu_support/source/device.hpp @@ -132,6 +132,17 @@ class Device ~Device() = default; public: + /** + * @brief The driver function dispatch table. + */ + DeviceDispatchTable driver {}; + + /** + * @brief The minimum set of device extensions needed by this layer. + */ + static const std::vector extraExtensions; + +private: /** * @brief The instance this device is created with. */ @@ -146,9 +157,4 @@ class Device * @brief The device handle this device is created with. */ const VkDevice device; - - /** - * @brief The driver function dispatch table. - */ - DeviceDispatchTable driver {}; }; diff --git a/layer_gpu_timeline/source/device.cpp b/layer_gpu_timeline/source/device.cpp index 1e140ff..707c1a1 100644 --- a/layer_gpu_timeline/source/device.cpp +++ b/layer_gpu_timeline/source/device.cpp @@ -40,6 +40,9 @@ */ static std::unordered_map> g_devices; +/* See header for documentation. */ +const std::vector Device::extraExtensions { }; + /* See header for documentation. */ std::unique_ptr Device::commsModule; diff --git a/layer_gpu_timeline/source/device.hpp b/layer_gpu_timeline/source/device.hpp index b56de83..7e9f9bb 100644 --- a/layer_gpu_timeline/source/device.hpp +++ b/layer_gpu_timeline/source/device.hpp @@ -170,6 +170,11 @@ class Device */ DeviceDispatchTable driver {}; + /** + * @brief The minimum set of device extensions needed by this layer. + */ + static const std::vector extraExtensions; + private: /** * @brief The instance this device is created with. diff --git a/source_common/framework/manual_functions.cpp b/source_common/framework/manual_functions.cpp index 2da9a90..6cd1acb 100644 --- a/source_common/framework/manual_functions.cpp +++ b/source_common/framework/manual_functions.cpp @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: MIT * ---------------------------------------------------------------------------- - * Copyright (c) 2024 Arm Limited + * Copyright (c) 2024-2025 Arm Limited * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -94,6 +94,29 @@ VkLayerInstanceCreateInfo* getChainInfo( return const_cast(info); } +/** + * @brief Helper to search a Vulkan "pNext" list for a matching structure. + */ +template +T* searchNextList( + VkStructureType sType, + const void* pNext +) { + const auto* pStruct = reinterpret_cast(pNext); + while(pStruct) + { + if (pStruct->sType == sType) + { + break; + } + pStruct = reinterpret_cast(pStruct->pNext); + } + + // Const cast is not ideal here but we don't have functionality to + // clone a writable copy of the entire pNext chain yet ... + return const_cast(pStruct); +} + /* See header for documentation. */ VkLayerDeviceCreateInfo* getChainInfo( const VkDeviceCreateInfo* pCreateInfo @@ -407,22 +430,30 @@ std::vector cloneExtensionList( return data; } +/** + * Enable VK_EXT_debug_utils if not enabled. + * + * Enabling this requires passing the extension string to vkCreateInstance(). + * + * @param supported The list of supported extension, or empty if unknown. + * @param active The list of active extensions. + */ static void enableInstanceVkExtDebugUtils( - const std::vector& supportedExtensions, - std::vector& newExtensions + const std::vector& supported, + std::vector& active ) { const std::string target { "VK_EXT_debug_utils" }; - // Test if the desired extension is supported. If supportedExtensions - // is empty then we didn't query and assume it is supported. - if (supportedExtensions.size() && !isIn(target, supportedExtensions)) + // Test if the desired extension is supported. If supported list is + // empty then we didn't query and assume extension is supported. + if (supported.size() && !isIn(target, supported)) { LAYER_ERR("Instance extension not available: %s", target.c_str()); return; } // If it is already enabled then do nothing - if (isIn(target, newExtensions)) + if (isIn(target, active)) { LAYER_LOG("Instance extension already enabled: %s", target.c_str()); return; @@ -430,106 +461,89 @@ static void enableInstanceVkExtDebugUtils( // Else add it to the list of enable extensions LAYER_LOG("Instance extension added: %s", target.c_str()); - newExtensions.push_back(target.c_str()); + active.push_back(target.c_str()); } +/** + * Enable VK_KHR_timeline_semaphore if not enabled. + * + * Enabling this requires passing the extension string to vkCreateDevice(), + * and passing either VkPhysicalDeviceTimelineSemaphoreFeatures or + * VkPhysicalDeviceVulkan12Features with the feature enabled. + * + * If the user has the extension enabled we patch t + * + * @param createInfo The createInfo we can search to find user config. + * @param supported The list of supported extensions. + * @param active The list of active extensions. + * @param newFeatures Pre-allocated struct we can use if we need to add it. + */ static void enableDeviceVkKhrTimelineSemaphore( VkDeviceCreateInfo& createInfo, - std::vector& supportedExtensions, - std::vector& newEnabledExtensions, - VkPhysicalDeviceTimelineSemaphoreFeatures newTimelineFeatures + std::vector& supported, + std::vector& active, + VkPhysicalDeviceTimelineSemaphoreFeatures newFeatures ) { - static const char* target = "VK_KHR_timeline_semaphore"; + const std::string target { "VK_KHR_timeline_semaphore" }; - // Extension is not supported ... - bool isSupported = isIn(target, supportedExtensions); - if (!isSupported) + // Test if the desired extension is supported + if (!isIn(target, supported)) { - LAYER_LOG("Device extension not available: %s", target); + LAYER_LOG("Device extension not available: %s", target.c_str()); return; } - // Extension is not enabled ... - bool isEnabled = isInExtensionList( - target, - createInfo.enabledExtensionCount, - createInfo.ppEnabledExtensionNames); - - // Clone the extension list into our copy, if needed - if (!isEnabled && !newEnabledExtensions.size()) + // If it is not already enabled then add to the list + if (!isIn(target, active)) { - newEnabledExtensions = cloneExtensionList( - createInfo.enabledExtensionCount, - createInfo.ppEnabledExtensionNames); + LAYER_LOG("Instance extension added: %s", target.c_str()); + active.push_back(target.c_str()); } - // Add the extension to the end of the list - newEnabledExtensions.push_back(target); - createInfo.enabledExtensionCount = newEnabledExtensions.size(); - createInfo.ppEnabledExtensionNames = newEnabledExtensions.data(); - - // Enable the extension/feature - bool timeline_enabled { false }; + // Check if user provided a VkPhysicalDeviceTimelineSemaphoreFeatures + auto* config1 = searchNextList( + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, + createInfo.pNext); - // Check VkPhysicalDeviceTimelineSemaphoreFeatures - auto* pTSF = reinterpret_cast(createInfo.pNext); - while(pTSF) + if (config1) { - if (pTSF->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES) + if (!config1->timelineSemaphore) { - break; + LAYER_LOG("Instance extension force enabled: %s", target.c_str()); + config1->timelineSemaphore = true; } - pTSF = reinterpret_cast(pTSF->pNext); - } - - // Make sure it is enabled in the existing structure, if present - if (pTSF) - { - if (!pTSF->timelineSemaphore) { - // TODO: Const cast is not safe and we should be cloning the entire pNext chain if we - // need modify anything, but this is painful and const_cast works most of the time - auto* pWritableTSF = const_cast(pTSF); - pWritableTSF->timelineSemaphore = true; - LAYER_LOG("Enabling additional extension: %s", target); + else + { + LAYER_LOG("Instance extension already enabled: %s", target.c_str()); } - - timeline_enabled = true; } - // Check VkPhysicalDeviceVulkan12Features - auto* pV12F = reinterpret_cast(createInfo.pNext); - while(pV12F) + // Check if user provided a VkPhysicalDeviceVulkan12Features + auto* config2 = searchNextList( + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, + createInfo.pNext); + + if (config2) { - if (pV12F->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES) + if (!config2->timelineSemaphore) { - break; + LAYER_LOG("Instance extension force enabled: %s", target.c_str()); + config2->timelineSemaphore = true; } - - pV12F = reinterpret_cast(pV12F->pNext); - } - - // Make sure it is enabled in the existing structure, if present - if (pV12F) - { - if (!pV12F->timelineSemaphore) { - // TODO: Const cast is not safe and we should be cloning the entire pNext chain if we - // need modify anything, but this is painful and const_cast works most of the time - auto* pWritableV12F = const_cast(pV12F); - pWritableV12F->timelineSemaphore = true; - LAYER_LOG("Enabling additional extension: %s", target); + else + { + LAYER_LOG("Instance extension already enabled: %s", target.c_str()); } - - timeline_enabled = true; } - // Enable it if not enabled already by the application - if (!timeline_enabled) + // Add a config if not configured by the application + if (!config1 && !config2) { - newTimelineFeatures.pNext = const_cast(createInfo.pNext); - newTimelineFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; - newTimelineFeatures.timelineSemaphore = true; - createInfo.pNext = reinterpret_cast(&newTimelineFeatures); - LAYER_LOG("Enabling additional extension: %s", target); + newFeatures.pNext = const_cast(createInfo.pNext); + newFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; + newFeatures.timelineSemaphore = true; + createInfo.pNext = reinterpret_cast(&newFeatures); + LAYER_LOG("Instance extension config added: %s", target.c_str()); } } @@ -852,16 +866,36 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkCreateDevice_default( // Create structures we allocate here, but populated elsewhere VkPhysicalDeviceTimelineSemaphoreFeatures newTimelineFeatures; - std::vector newEnabledExtensions; - // Enable timeline semaphores - enableDeviceVkKhrTimelineSemaphore( - newCreateInfo, - supportedExtensions, - newEnabledExtensions, - newTimelineFeatures); + // Create a copy of the extension list we can patch + std::vector newExtensions; + const auto start = pCreateInfo->ppEnabledExtensionNames; + const auto end = pCreateInfo->ppEnabledExtensionNames + pCreateInfo->enabledExtensionCount; + newExtensions.insert(newExtensions.end(), start, end); + + // Enable extra extensions + for (const auto& newExt : Device::extraExtensions) + { + if (newExt == "VK_KHR_timeline_semaphore") + { + enableDeviceVkKhrTimelineSemaphore( + newCreateInfo, + supportedExtensions, + newExtensions, + newTimelineFeatures); + } + else + { + LAYER_ERR("Unknown instance extension: %s", newExt.c_str()); + } + } + + // Patch extension pointer and size after extending it + newCreateInfo.enabledExtensionCount = newExtensions.size(); + newCreateInfo.ppEnabledExtensionNames = newExtensions.data(); - auto fpCreateDevice = reinterpret_cast(fpGetInstanceProcAddr(layer->instance, "vkCreateDevice")); + auto fpCreateDeviceRaw = fpGetInstanceProcAddr(layer->instance, "vkCreateDevice"); + auto fpCreateDevice = reinterpret_cast(fpCreateDeviceRaw); if (!fpCreateDevice) { return VK_ERROR_INITIALIZATION_FAILED;