From 091c10cbb39ec1e30012d15a8b1cb7b55f18ed9f Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Mon, 20 Jan 2025 11:51:19 +0000 Subject: [PATCH 1/6] Add functions for promoting version and extensions --- source_common/framework/manual_functions.cpp | 301 ++++++++++++++++++- source_common/framework/manual_functions.hpp | 56 +++- source_common/framework/utils.hpp | 9 +- 3 files changed, 343 insertions(+), 23 deletions(-) diff --git a/source_common/framework/manual_functions.cpp b/source_common/framework/manual_functions.cpp index bcae148..75b6b4f 100644 --- a/source_common/framework/manual_functions.cpp +++ b/source_common/framework/manual_functions.cpp @@ -181,6 +181,131 @@ PFN_vkVoidFunction getDeviceLayerFunction( return nullptr; } +/* See header for documentation. */ +APIVersion getInstanceAPIVersion( + PFN_vkGetInstanceProcAddr fpGetProcAddr +) { + auto fpFunctionRaw = fpGetProcAddr(nullptr, "vkEnumerateInstanceVersion"); + auto fpFunction = reinterpret_cast(fpFunctionRaw); + if (!fpFunction) + { + LAYER_ERR("Failed to get vkEnumerateInstanceVersion()"); + return { 0 , 0 }; + } + + uint32_t apiVersion = 0; + auto result = fpFunction(&apiVersion); + if (result != VK_SUCCESS) + { + LAYER_ERR("Failed to call vkEnumerateInstanceVersion()"); + return { 0 , 0 }; + } + + uint32_t major = VK_API_VERSION_MAJOR(apiVersion); + uint32_t minor = VK_API_VERSION_MINOR(apiVersion); + return { major, minor }; +} + +/* See header for documentation. */ +APIVersion getApplicationAPIVersion( + const VkInstanceCreateInfo* pCreateInfo +) { + uint32_t apiVersion = pCreateInfo->pApplicationInfo->apiVersion; + uint32_t major = VK_API_VERSION_MAJOR(apiVersion); + uint32_t minor = VK_API_VERSION_MINOR(apiVersion); + return { major, minor }; +} + +/* See header for documentation. */ +APIVersion getDeviceAPIVersion( + PFN_vkGetInstanceProcAddr fpGetProcAddr, + VkInstance instance, + VkPhysicalDevice physicalDevice +) { + auto fpFunctionRaw = fpGetProcAddr(instance, "vkGetPhysicalDeviceProperties"); + auto fpFunction = reinterpret_cast(fpFunctionRaw); + if (!fpFunction) + { + LAYER_ERR("Failed to get vkGetPhysicalDeviceProperties()"); + return { 0 , 0 }; + } + + VkPhysicalDeviceProperties properties {}; + fpFunction(physicalDevice, &properties); + + uint32_t major = VK_API_VERSION_MAJOR(properties.apiVersion); + uint32_t minor = VK_API_VERSION_MINOR(properties.apiVersion); + return { major, minor }; +} + +/** + * @brief Is version A >= version B. + */ +static bool isVersionGreaterEqual( + const APIVersion& a, + const APIVersion& b +) { + // Different major version + if(a.first != b.first) + { + return a.first > b.first; + } + + // Same major version, so test minor version + return a.second >= b.second; +} + +/** + * @brief Is version A > version B. + */ +static bool isVersionGreater( + const APIVersion& a, + const APIVersion& b +) { + // Different major version + if(a.first != b.first) + { + return a.first > b.first; + } + + // Same major version, so test minor version + return a.second > b.second; +} + +/* See header for documentation. */ +APIVersion increaseAPIVersion( + const APIVersion& userVersion, + const APIVersion& maxVersion, + const APIVersion& requiredVersion +) { + // User version is good enough to support the layer, so stick with that + if(isVersionGreaterEqual(userVersion, requiredVersion)) + { + LAYER_LOG( + "Instance API version %u.%u (user setting meets layer minimum)", + userVersion.first, userVersion.second); + + return userVersion; + } + + // Required version is higher than the max version so log a warning + // and try to continue using maxVersion but it may fail ... + if(isVersionGreater(requiredVersion, maxVersion)) + { + LAYER_ERR( + "Instance API version %u.%u (lower than layer minimum)", + maxVersion.first, maxVersion.second); + + return maxVersion; + } + + LAYER_ERR( + "Instance API version %u.%u (increased to layer minimum)", + requiredVersion.first, requiredVersion.second); + + return requiredVersion; +} + /* See header for documentation. */ std::vector getInstanceExtensionList( const VkInstanceCreateInfo* pCreateInfo @@ -253,13 +378,13 @@ std::vector getDeviceExtensionList( /* See header for documentation. */ bool isInExtensionList( - const std::string& target, + const char* target, uint32_t extensionCount, const char* const* extensionList ) { for(uint32_t i = 0; i < extensionCount; i++) { - if (target == extensionList[i]) + if (!strcmp(target, extensionList[i])) { return true; } @@ -282,6 +407,106 @@ std::vector cloneExtensionList( return data; } +void enableTimelineSemaphores( + VkDeviceCreateInfo& createInfo, + std::vector& supportedExtensions, + std::vector& newEnabledExtensions, + VkPhysicalDeviceTimelineSemaphoreFeatures newTimelineFeatures +) { + static const char* target = "VK_KHR_timeline_semaphore"; + + // Extension is not supported ... + bool isSupported = isIn(target, supportedExtensions); + if (!isSupported) + { + LAYER_LOG("WARNING: Cannot enable additional extension: %s", target); + 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()) + { + newEnabledExtensions = cloneExtensionList( + createInfo.enabledExtensionCount, + createInfo.ppEnabledExtensionNames); + } + + // 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 VkPhysicalDeviceTimelineSemaphoreFeatures + auto* pTSF = reinterpret_cast(createInfo.pNext); + while(pTSF) + { + if (pTSF->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES) + { + break; + } + 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); + } + + timeline_enabled = true; + } + + // Check VkPhysicalDeviceVulkan12Features + auto* pV12F = reinterpret_cast(createInfo.pNext); + while(pV12F) + { + if (pV12F->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES) + { + break; + } + + 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); + } + + timeline_enabled = true; + } + + // Enable it if not enabled already by the application + if (!timeline_enabled) + { + 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); + } +} + /** See Vulkan API for documentation. */ PFN_vkVoidFunction layer_vkGetInstanceProcAddr_default( VkInstance instance, @@ -478,6 +703,16 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkCreateInstance_default( auto* chainInfo = getChainInfo(pCreateInfo); auto fpGetInstanceProcAddr = chainInfo->u.pLayerInfo->pfnNextGetInstanceProcAddr; + + // For now assume all layers need Vulkan 1.1 or newer + // TODO: Make this configurable per layer + APIVersion appVersion = getApplicationAPIVersion(pCreateInfo); + APIVersion maxVersion = getInstanceAPIVersion(fpGetInstanceProcAddr); + APIVersion reqVersion { 1, 1 }; + + APIVersion targetVersion = increaseAPIVersion( + appVersion, maxVersion, reqVersion); + auto fpCreateInstanceRaw = fpGetInstanceProcAddr(nullptr, "vkCreateInstance"); auto fpCreateInstance = reinterpret_cast(fpCreateInstanceRaw); if (!fpCreateInstance) @@ -485,16 +720,27 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkCreateInstance_default( return VK_ERROR_INITIALIZATION_FAILED; } - // Create a copy we can write + // Create structure copies we can modify VkInstanceCreateInfo newCreateInfo = *pCreateInfo; + VkApplicationInfo newAppInfo = *pCreateInfo->pApplicationInfo; + + // Write the new application info + newAppInfo.apiVersion = VK_MAKE_API_VERSION( + 0, targetVersion.first, targetVersion.second, 0); + newCreateInfo.pApplicationInfo = &newAppInfo; // Query extension state - std::string targetExt("VK_EXT_debug_utils"); + const char* targetExt = "VK_EXT_debug_utils"; + // Assume common extensions are available (see comment at start of function) bool targetSupported = true; if (queryExtensions) { targetSupported = isIn(targetExt, supportedExtensions); + if (!targetSupported) + { + LAYER_LOG("WARNING: Cannot enable extension: %s", targetExt); + } } bool targetEnabled = isInExtensionList( @@ -502,35 +748,33 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkCreateInstance_default( pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames); - if (!targetSupported) - { - LAYER_LOG("WARNING: Cannot enable additional extension: %s", targetExt.c_str()); - } - // Enable the extension if we need to std::vector newExtList; if (targetSupported && !targetEnabled) { - LAYER_LOG("Enabling additional extension: %s", targetExt.c_str()); + LAYER_LOG("Enabling additional extension: %s", targetExt); newExtList = cloneExtensionList( pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames); - newExtList.push_back(targetExt.c_str()); + newExtList.push_back(targetExt); newCreateInfo.enabledExtensionCount = newExtList.size(); newCreateInfo.ppEnabledExtensionNames = newExtList.data(); } chainInfo->u.pLayerInfo = chainInfo->u.pLayerInfo->pNext; - auto res = fpCreateInstance(&newCreateInfo, pAllocator, pInstance); - if (res != VK_SUCCESS) + auto result = fpCreateInstance(&newCreateInfo, pAllocator, pInstance); + if (result != VK_SUCCESS) { - return res; + return result; } // Retake the lock to access layer-wide global store - auto instance = std::make_unique(*pInstance, fpGetInstanceProcAddr); + auto instance = std::make_unique( + *pInstance, + fpGetInstanceProcAddr); + { std::lock_guard lock { g_vulkanLock }; Instance::store(*pInstance, instance); @@ -576,9 +820,34 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkCreateDevice_default( // Release the lock to call into the driver lock.unlock(); + // Get the list is supported extensions + auto supportedExtensions = getDeviceExtensionList(layer->instance, physicalDevice, pCreateInfo); + + // Query the supported Vulkan version auto* chainInfo = getChainInfo(pCreateInfo); auto fpGetInstanceProcAddr = chainInfo->u.pLayerInfo->pfnNextGetInstanceProcAddr; auto fpGetDeviceProcAddr = chainInfo->u.pLayerInfo->pfnNextGetDeviceProcAddr; + + // Log this for support purposes ... + APIVersion apiVersion = getDeviceAPIVersion( + fpGetInstanceProcAddr, layer->instance, physicalDevice); + + LAYER_LOG("Device API version %u.%u", apiVersion.first, apiVersion.second); + + // Create structure copies we can modify + VkDeviceCreateInfo newCreateInfo = *pCreateInfo; + + // Create structures we allocate here, but populated elsewhere + VkPhysicalDeviceTimelineSemaphoreFeatures newTimelineFeatures; + std::vector newEnabledExtensions; + + // Enable timeline semaphores + enableTimelineSemaphores( + newCreateInfo, + supportedExtensions, + newEnabledExtensions, + newTimelineFeatures); + auto fpCreateDevice = reinterpret_cast(fpGetInstanceProcAddr(layer->instance, "vkCreateDevice")); if (!fpCreateDevice) { @@ -587,7 +856,7 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkCreateDevice_default( // Advance the link info for the next element on the chain chainInfo->u.pLayerInfo = chainInfo->u.pLayerInfo->pNext; - auto res = fpCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice); + auto res = fpCreateDevice(physicalDevice, &newCreateInfo, pAllocator, pDevice); if (res != VK_SUCCESS) { return res; diff --git a/source_common/framework/manual_functions.hpp b/source_common/framework/manual_functions.hpp index d66d70c..1c8bdd5 100644 --- a/source_common/framework/manual_functions.hpp +++ b/source_common/framework/manual_functions.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 @@ -40,11 +40,9 @@ #include "instance.hpp" #include "version.hpp" - -#include "framework/instance_functions.hpp" - #include "framework/device_dispatch_table.hpp" #include "framework/device_functions.hpp" +#include "framework/instance_functions.hpp" #include "framework/utils.hpp" /** @@ -109,6 +107,54 @@ PFN_vkVoidFunction getInstanceLayerFunction( PFN_vkVoidFunction getDeviceLayerFunction( const char* name); +/** + * @brief Fetch the maximum supported instance API version. + * + * @param fpGetProcAddr vkGetInstanceProcAddr() function pointer. + * + * @return The major/minor version numbers, or zeros on error. + */ +APIVersion getInstanceAPIVersion( + PFN_vkGetInstanceProcAddr fpGetProcAddr); + +/** + * @brief Fetch the application requested instance API version. + * + * @param pCreateInfo The application instance creation info. + * + * @return The major/minor version numbers. + */ +APIVersion getApplicationAPIVersion( + const VkInstanceCreateInfo* pCreateInfo); + +/** + * @brief Fetch the maximum supported device API version. + * + * @param fpGetProcAddr vkGetInstanceProcAddr() function pointer. + * @param instance The instance. + * @param physicalDevice The physical device. + * + * @return The major/minor version numbers, or zeros on error. + */ +APIVersion getDeviceAPIVersion( + PFN_vkGetInstanceProcAddr fpGetProcAddr, + VkInstance instance, + VkPhysicalDevice physicalDevice); + +/** + * @brief Return an increased API version, if supported. + * + * @param userVersion The user-requested version. + * @param maxVersion The max version supported by the platform. + * @param requiredVersion The layer-requested min version + * + * @return The major/minor version numbers, or zeros on error. + */ +APIVersion increaseAPIVersion( + const APIVersion& userVersion, + const APIVersion& maxVersion, + const APIVersion& requiredVersion); + /** * @brief Fetch the list of supported extensions from the instance. * @@ -148,7 +194,7 @@ std::vector getDeviceExtensionList( * @return @c true if @c target is found in @c extensionList. */ bool isInExtensionList( - const std::string& target, + const char* target, uint32_t extensionCount, const char* const* extensionList); diff --git a/source_common/framework/utils.hpp b/source_common/framework/utils.hpp index 43338fc..0a6913b 100644 --- a/source_common/framework/utils.hpp +++ b/source_common/framework/utils.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 @@ -56,7 +56,12 @@ #endif /** - * Tag type used for template function dispatch; + * @brief Type for a API version major/minor pair. + */ +using APIVersion = std::pair; + +/** + * @brief Tag type used for template function dispatch; */ struct user_tag {}; From 6f708e6a7851c7376e88166f59f618f97b7645b8 Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Mon, 20 Jan 2025 20:12:17 +0000 Subject: [PATCH 2/6] Add instance extension hook --- generator/vk_layer/source/instance.cpp | 8 ++ generator/vk_layer/source/instance.hpp | 12 ++- layer_example/source/instance.cpp | 10 ++- layer_example/source/instance.hpp | 12 ++- layer_gpu_support/source/instance.cpp | 8 ++ layer_gpu_support/source/instance.hpp | 10 +++ layer_gpu_timeline/source/instance.cpp | 8 ++ layer_gpu_timeline/source/instance.hpp | 12 ++- source_common/framework/manual_functions.cpp | 95 +++++++++++--------- source_common/framework/manual_functions.hpp | 2 +- 10 files changed, 131 insertions(+), 46 deletions(-) diff --git a/generator/vk_layer/source/instance.cpp b/generator/vk_layer/source/instance.cpp index 0b62857..e0ce2ad 100644 --- a/generator/vk_layer/source/instance.cpp +++ b/generator/vk_layer/source/instance.cpp @@ -34,6 +34,14 @@ */ static std::unordered_map> g_instances; +/* See header for documentation. */ +const APIVersion Instance::minAPIVersion { 1, 1 }; + +/* See header for documentation. */ +const std::vector Instance::extraExtensions { + "VK_EXT_debug_utils" +}; + /* See header for documentation. */ void Instance::store( VkInstance handle, diff --git a/generator/vk_layer/source/instance.hpp b/generator/vk_layer/source/instance.hpp index fc6af6b..b6bdea1 100644 --- a/generator/vk_layer/source/instance.hpp +++ b/generator/vk_layer/source/instance.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 @@ -131,4 +131,14 @@ class Instance * @brief The driver function dispatch table. */ InstanceDispatchTable driver {}; + + /** + * @brief The minimum API version needed by this layer. + */ + static const APIVersion minAPIVersion; + + /** + * @brief The minimum set of instance extensions needed by this layer. + */ + static const std::vector extraExtensions; }; diff --git a/layer_example/source/instance.cpp b/layer_example/source/instance.cpp index 0b62857..8fb5e88 100644 --- a/layer_example/source/instance.cpp +++ b/layer_example/source/instance.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 @@ -34,6 +34,14 @@ */ static std::unordered_map> g_instances; +/* See header for documentation. */ +const APIVersion Instance::minAPIVersion { 1, 1 }; + +/* See header for documentation. */ +const std::vector Instance::extraExtensions { + "VK_EXT_debug_utils" +}; + /* See header for documentation. */ void Instance::store( VkInstance handle, diff --git a/layer_example/source/instance.hpp b/layer_example/source/instance.hpp index fc6af6b..b6bdea1 100644 --- a/layer_example/source/instance.hpp +++ b/layer_example/source/instance.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 @@ -131,4 +131,14 @@ class Instance * @brief The driver function dispatch table. */ InstanceDispatchTable driver {}; + + /** + * @brief The minimum API version needed by this layer. + */ + static const APIVersion minAPIVersion; + + /** + * @brief The minimum set of instance extensions needed by this layer. + */ + static const std::vector extraExtensions; }; diff --git a/layer_gpu_support/source/instance.cpp b/layer_gpu_support/source/instance.cpp index add2605..8fb5e88 100644 --- a/layer_gpu_support/source/instance.cpp +++ b/layer_gpu_support/source/instance.cpp @@ -34,6 +34,14 @@ */ static std::unordered_map> g_instances; +/* See header for documentation. */ +const APIVersion Instance::minAPIVersion { 1, 1 }; + +/* See header for documentation. */ +const std::vector Instance::extraExtensions { + "VK_EXT_debug_utils" +}; + /* See header for documentation. */ void Instance::store( VkInstance handle, diff --git a/layer_gpu_support/source/instance.hpp b/layer_gpu_support/source/instance.hpp index 5791a44..081b26d 100644 --- a/layer_gpu_support/source/instance.hpp +++ b/layer_gpu_support/source/instance.hpp @@ -137,4 +137,14 @@ class Instance * @brief The layer configuration. */ const LayerConfig config; + + /** + * @brief The minimum API version needed by this layer. + */ + static const APIVersion minAPIVersion; + + /** + * @brief The minimum set of instance extensions needed by this layer. + */ + static const std::vector extraExtensions; }; diff --git a/layer_gpu_timeline/source/instance.cpp b/layer_gpu_timeline/source/instance.cpp index 0b62857..e0ce2ad 100644 --- a/layer_gpu_timeline/source/instance.cpp +++ b/layer_gpu_timeline/source/instance.cpp @@ -34,6 +34,14 @@ */ static std::unordered_map> g_instances; +/* See header for documentation. */ +const APIVersion Instance::minAPIVersion { 1, 1 }; + +/* See header for documentation. */ +const std::vector Instance::extraExtensions { + "VK_EXT_debug_utils" +}; + /* See header for documentation. */ void Instance::store( VkInstance handle, diff --git a/layer_gpu_timeline/source/instance.hpp b/layer_gpu_timeline/source/instance.hpp index fc6af6b..b6bdea1 100644 --- a/layer_gpu_timeline/source/instance.hpp +++ b/layer_gpu_timeline/source/instance.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 @@ -131,4 +131,14 @@ class Instance * @brief The driver function dispatch table. */ InstanceDispatchTable driver {}; + + /** + * @brief The minimum API version needed by this layer. + */ + static const APIVersion minAPIVersion; + + /** + * @brief The minimum set of instance extensions needed by this layer. + */ + static const std::vector extraExtensions; }; diff --git a/source_common/framework/manual_functions.cpp b/source_common/framework/manual_functions.cpp index 75b6b4f..2da9a90 100644 --- a/source_common/framework/manual_functions.cpp +++ b/source_common/framework/manual_functions.cpp @@ -299,7 +299,7 @@ APIVersion increaseAPIVersion( return maxVersion; } - LAYER_ERR( + LAYER_LOG( "Instance API version %u.%u (increased to layer minimum)", requiredVersion.first, requiredVersion.second); @@ -378,13 +378,13 @@ std::vector getDeviceExtensionList( /* See header for documentation. */ bool isInExtensionList( - const char* target, + std::string target, uint32_t extensionCount, const char* const* extensionList ) { for(uint32_t i = 0; i < extensionCount; i++) { - if (!strcmp(target, extensionList[i])) + if (target == extensionList[i]) { return true; } @@ -407,7 +407,33 @@ std::vector cloneExtensionList( return data; } -void enableTimelineSemaphores( +static void enableInstanceVkExtDebugUtils( + const std::vector& supportedExtensions, + std::vector& newExtensions +) { + 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)) + { + LAYER_ERR("Instance extension not available: %s", target.c_str()); + return; + } + + // If it is already enabled then do nothing + if (isIn(target, newExtensions)) + { + LAYER_LOG("Instance extension already enabled: %s", target.c_str()); + return; + } + + // Else add it to the list of enable extensions + LAYER_LOG("Instance extension added: %s", target.c_str()); + newExtensions.push_back(target.c_str()); +} + +static void enableDeviceVkKhrTimelineSemaphore( VkDeviceCreateInfo& createInfo, std::vector& supportedExtensions, std::vector& newEnabledExtensions, @@ -419,7 +445,7 @@ void enableTimelineSemaphores( bool isSupported = isIn(target, supportedExtensions); if (!isSupported) { - LAYER_LOG("WARNING: Cannot enable additional extension: %s", target); + LAYER_LOG("Device extension not available: %s", target); return; } @@ -704,14 +730,11 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkCreateInstance_default( auto* chainInfo = getChainInfo(pCreateInfo); auto fpGetInstanceProcAddr = chainInfo->u.pLayerInfo->pfnNextGetInstanceProcAddr; - // For now assume all layers need Vulkan 1.1 or newer - // TODO: Make this configurable per layer + // Work out what version we should use, promoting to meet layer requirement APIVersion appVersion = getApplicationAPIVersion(pCreateInfo); APIVersion maxVersion = getInstanceAPIVersion(fpGetInstanceProcAddr); - APIVersion reqVersion { 1, 1 }; - - APIVersion targetVersion = increaseAPIVersion( - appVersion, maxVersion, reqVersion); + APIVersion reqVersion = Instance::minAPIVersion; + APIVersion newVersion = increaseAPIVersion(appVersion, maxVersion, reqVersion); auto fpCreateInstanceRaw = fpGetInstanceProcAddr(nullptr, "vkCreateInstance"); auto fpCreateInstance = reinterpret_cast(fpCreateInstanceRaw); @@ -725,43 +748,33 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkCreateInstance_default( VkApplicationInfo newAppInfo = *pCreateInfo->pApplicationInfo; // Write the new application info - newAppInfo.apiVersion = VK_MAKE_API_VERSION( - 0, targetVersion.first, targetVersion.second, 0); + newAppInfo.apiVersion = VK_MAKE_API_VERSION(0, newVersion.first, newVersion.second, 0); newCreateInfo.pApplicationInfo = &newAppInfo; - // Query extension state - const char* targetExt = "VK_EXT_debug_utils"; + // 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); - // Assume common extensions are available (see comment at start of function) - bool targetSupported = true; - if (queryExtensions) + // Enable extra extensions + for (const auto& newExt : Instance::extraExtensions) { - targetSupported = isIn(targetExt, supportedExtensions); - if (!targetSupported) + if (newExt == "VK_EXT_debug_utils") + { + enableInstanceVkExtDebugUtils( + supportedExtensions, + newExtensions); + } + else { - LAYER_LOG("WARNING: Cannot enable extension: %s", targetExt); + LAYER_ERR("Unknown instance extension: %s", newExt.c_str()); } } - bool targetEnabled = isInExtensionList( - targetExt, - pCreateInfo->enabledExtensionCount, - pCreateInfo->ppEnabledExtensionNames); - - // Enable the extension if we need to - std::vector newExtList; - if (targetSupported && !targetEnabled) - { - LAYER_LOG("Enabling additional extension: %s", targetExt); - newExtList = cloneExtensionList( - pCreateInfo->enabledExtensionCount, - pCreateInfo->ppEnabledExtensionNames); - - newExtList.push_back(targetExt); - - newCreateInfo.enabledExtensionCount = newExtList.size(); - newCreateInfo.ppEnabledExtensionNames = newExtList.data(); - } + // Patch extension pointer and size after extending it + newCreateInfo.enabledExtensionCount = newExtensions.size(); + newCreateInfo.ppEnabledExtensionNames = newExtensions.data(); chainInfo->u.pLayerInfo = chainInfo->u.pLayerInfo->pNext; auto result = fpCreateInstance(&newCreateInfo, pAllocator, pInstance); @@ -842,7 +855,7 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkCreateDevice_default( std::vector newEnabledExtensions; // Enable timeline semaphores - enableTimelineSemaphores( + enableDeviceVkKhrTimelineSemaphore( newCreateInfo, supportedExtensions, newEnabledExtensions, diff --git a/source_common/framework/manual_functions.hpp b/source_common/framework/manual_functions.hpp index 1c8bdd5..c53500c 100644 --- a/source_common/framework/manual_functions.hpp +++ b/source_common/framework/manual_functions.hpp @@ -194,7 +194,7 @@ std::vector getDeviceExtensionList( * @return @c true if @c target is found in @c extensionList. */ bool isInExtensionList( - const char* target, + std::string target, uint32_t extensionCount, const char* const* extensionList); From b814cd10f36823922be4e7e179f1d3aa9978f0a5 Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Mon, 20 Jan 2025 21:33:43 +0000 Subject: [PATCH 3/6] 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; From 72849056ffaa259a7ad44ec378e32f42dac49792 Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Mon, 20 Jan 2025 21:39:01 +0000 Subject: [PATCH 4/6] Fix copyright years --- generator/vk_layer/source/device.cpp | 2 +- generator/vk_layer/source/instance.cpp | 2 +- layer_example/source/device.cpp | 2 +- layer_gpu_timeline/source/device.cpp | 2 +- layer_gpu_timeline/source/device.hpp | 2 +- layer_gpu_timeline/source/instance.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/generator/vk_layer/source/device.cpp b/generator/vk_layer/source/device.cpp index 65b0393..c145efa 100644 --- a/generator/vk_layer/source/device.cpp +++ b/generator/vk_layer/source/device.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 diff --git a/generator/vk_layer/source/instance.cpp b/generator/vk_layer/source/instance.cpp index e0ce2ad..8fb5e88 100644 --- a/generator/vk_layer/source/instance.cpp +++ b/generator/vk_layer/source/instance.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 diff --git a/layer_example/source/device.cpp b/layer_example/source/device.cpp index 65b0393..c145efa 100644 --- a/layer_example/source/device.cpp +++ b/layer_example/source/device.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 diff --git a/layer_gpu_timeline/source/device.cpp b/layer_gpu_timeline/source/device.cpp index 707c1a1..5905f78 100644 --- a/layer_gpu_timeline/source/device.cpp +++ b/layer_gpu_timeline/source/device.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 diff --git a/layer_gpu_timeline/source/device.hpp b/layer_gpu_timeline/source/device.hpp index 7e9f9bb..bec7885 100644 --- a/layer_gpu_timeline/source/device.hpp +++ b/layer_gpu_timeline/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 diff --git a/layer_gpu_timeline/source/instance.cpp b/layer_gpu_timeline/source/instance.cpp index e0ce2ad..8fb5e88 100644 --- a/layer_gpu_timeline/source/instance.cpp +++ b/layer_gpu_timeline/source/instance.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 From 939fc5254ccf9667745aa2c2b4c23d464e642c8b Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Mon, 20 Jan 2025 21:40:57 +0000 Subject: [PATCH 5/6] Fix build variant --- layer_gpu_support/source/device.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/layer_gpu_support/source/device.hpp b/layer_gpu_support/source/device.hpp index 569699e..cc4b16b 100644 --- a/layer_gpu_support/source/device.hpp +++ b/layer_gpu_support/source/device.hpp @@ -132,6 +132,11 @@ class Device ~Device() = default; public: + /** + * @brief The instance this device is created with. + */ + const Instance* instance; + /** * @brief The driver function dispatch table. */ @@ -143,11 +148,6 @@ class Device static const std::vector extraExtensions; private: - /** - * @brief The instance this device is created with. - */ - const Instance* instance; - /** * @brief The physical device this device is created with. */ From b883898f83f21524024474b1a7c1c74d58acdf7a Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Mon, 20 Jan 2025 22:37:10 +0000 Subject: [PATCH 6/6] Add queue serialization --- layer_gpu_support/source/device.cpp | 21 ++ layer_gpu_support/source/device.hpp | 10 + .../source/layer_device_functions_queue.cpp | 189 +++++++++++++++++- source_common/framework/manual_functions.cpp | 3 +- 4 files changed, 219 insertions(+), 4 deletions(-) diff --git a/layer_gpu_support/source/device.cpp b/layer_gpu_support/source/device.cpp index 3f0bd21..83f5208 100644 --- a/layer_gpu_support/source/device.cpp +++ b/layer_gpu_support/source/device.cpp @@ -93,4 +93,25 @@ Device::Device( device(_device) { initDriverDeviceDispatchTable(device, nlayerGetProcAddress, driver); + + VkSemaphoreTypeCreateInfo timelineCreateInfo { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, + .pNext = nullptr, + .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE, + .initialValue = queueSerializationTimelineSemCount + }; + + VkSemaphoreCreateInfo createInfo { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = &timelineCreateInfo, + .flags = 0 + }; + + auto result = driver.vkCreateSemaphore( + device, &createInfo, nullptr, &queueSerializationTimelineSem); + if (result != VK_SUCCESS) + { + LAYER_ERR("Failed vkCreateSemaphore() for queue serialization"); + queueSerializationTimelineSem = nullptr; + } } diff --git a/layer_gpu_support/source/device.hpp b/layer_gpu_support/source/device.hpp index cc4b16b..bb5c959 100644 --- a/layer_gpu_support/source/device.hpp +++ b/layer_gpu_support/source/device.hpp @@ -147,6 +147,16 @@ class Device */ static const std::vector extraExtensions; + /** + * @brief The timeline sem use for queue serialization. + */ + VkSemaphore queueSerializationTimelineSem { nullptr }; + + /** + * @brief The current timeline sem target value the next use waits for. + */ + uint64_t queueSerializationTimelineSemCount { 0 }; + private: /** * @brief The physical device this device is created with. diff --git a/layer_gpu_support/source/layer_device_functions_queue.cpp b/layer_gpu_support/source/layer_device_functions_queue.cpp index 01f4c25..2a99868 100644 --- a/layer_gpu_support/source/layer_device_functions_queue.cpp +++ b/layer_gpu_support/source/layer_device_functions_queue.cpp @@ -44,9 +44,65 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkQueueSubmit( std::unique_lock lock { g_vulkanLock }; auto* layer = Device::retrieve(queue); + // Serialize in the order submits are called + // TODO: This assumes a forward progress guarantee which is no longer + // guaranteed if the user is using timeline semaphores for syncs + + const uint64_t waitValue = layer->queueSerializationTimelineSemCount; + layer->queueSerializationTimelineSemCount++; + const uint64_t signalValue = layer->queueSerializationTimelineSemCount; + + VkPipelineStageFlags waitMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + + VkTimelineSemaphoreSubmitInfo timelineInfo { + .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO, + .pNext = nullptr, + .waitSemaphoreValueCount = 1, + .pWaitSemaphoreValues = &waitValue, + .signalSemaphoreValueCount = 1, + .pSignalSemaphoreValues = &signalValue + }; + + VkSubmitInfo submitInfoPre { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = &timelineInfo, + .waitSemaphoreCount = 1, + .pWaitSemaphores = &(layer->queueSerializationTimelineSem), + .pWaitDstStageMask = &waitMask, + .commandBufferCount = 0, + .pCommandBuffers = 0, + .signalSemaphoreCount = 0, + .pSignalSemaphores = nullptr + }; + + VkSubmitInfo submitInfoPost { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = &timelineInfo, + .waitSemaphoreCount = 0, + .pWaitSemaphores = 0, + .pWaitDstStageMask = 0, + .commandBufferCount = 0, + .pCommandBuffers = 0, + .signalSemaphoreCount = 1, + .pSignalSemaphores = &(layer->queueSerializationTimelineSem) + }; + // Release the lock to call into the driver lock.unlock(); - return layer->driver.vkQueueSubmit(queue, submitCount, pSubmits, fence); + + if (layer->instance->config.serialize_queue()) + { + layer->driver.vkQueueSubmit(queue, 1, &submitInfoPre, VK_NULL_HANDLE); + } + + auto result = layer->driver.vkQueueSubmit(queue, submitCount, pSubmits, fence); + + if (layer->instance->config.serialize_queue()) + { + layer->driver.vkQueueSubmit(queue, 1, &submitInfoPost, VK_NULL_HANDLE); + } + + return result; } /* See Vulkan API for documentation. */ @@ -63,9 +119,73 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkQueueSubmit2( std::unique_lock lock { g_vulkanLock }; auto* layer = Device::retrieve(queue); + // Serialize in the order submits are called + // TODO: This assumes a forward progress guarantee which is no longer + // guaranteed if the user is using timeline semaphores for syncs + + const uint64_t waitValue = layer->queueSerializationTimelineSemCount; + layer->queueSerializationTimelineSemCount++; + const uint64_t signalValue = layer->queueSerializationTimelineSemCount; + + VkSemaphoreSubmitInfo timelineInfoPre { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .pNext = nullptr, + .semaphore = layer->queueSerializationTimelineSem, + .value = waitValue, + .stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + .deviceIndex = 0 + }; + + VkSemaphoreSubmitInfo timelineInfoPost { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .pNext = nullptr, + .semaphore = layer->queueSerializationTimelineSem, + .value = signalValue, + .stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + .deviceIndex = 0 + }; + + VkSubmitInfo2 submitInfoPre { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + .pNext = nullptr, + .flags = 0, + .waitSemaphoreInfoCount = 1, + .pWaitSemaphoreInfos = &timelineInfoPre, + .commandBufferInfoCount = 0, + .pCommandBufferInfos = nullptr, + .signalSemaphoreInfoCount = 0, + .pSignalSemaphoreInfos = nullptr + }; + + VkSubmitInfo2 submitInfoPost { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + .pNext = nullptr, + .flags = 0, + .waitSemaphoreInfoCount = 0, + .pWaitSemaphoreInfos = nullptr, + .commandBufferInfoCount = 0, + .pCommandBufferInfos = nullptr, + .signalSemaphoreInfoCount = 1, + .pSignalSemaphoreInfos = &timelineInfoPost + }; + // Release the lock to call into the driver lock.unlock(); - return layer->driver.vkQueueSubmit2(queue, submitCount, pSubmits, fence); + + if (layer->instance->config.serialize_queue()) + { + layer->driver.vkQueueSubmit2(queue, 1, &submitInfoPre, VK_NULL_HANDLE); + } + + auto result = layer->driver.vkQueueSubmit2(queue, submitCount, pSubmits, fence); + + if (layer->instance->config.serialize_queue()) + { + layer->driver.vkQueueSubmit2(queue, 1, &submitInfoPost, VK_NULL_HANDLE); + } + + return result; + } /* See Vulkan API for documentation. */ @@ -82,7 +202,70 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkQueueSubmit2KHR( std::unique_lock lock { g_vulkanLock }; auto* layer = Device::retrieve(queue); + // Serialize in the order submits are called + // TODO: This assumes a forward progress guarantee which is no longer + // guaranteed if the user is using timeline semaphores for syncs + + const uint64_t waitValue = layer->queueSerializationTimelineSemCount; + layer->queueSerializationTimelineSemCount++; + const uint64_t signalValue = layer->queueSerializationTimelineSemCount; + + VkSemaphoreSubmitInfo timelineInfoPre { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .pNext = nullptr, + .semaphore = layer->queueSerializationTimelineSem, + .value = waitValue, + .stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + .deviceIndex = 0 + }; + + VkSemaphoreSubmitInfo timelineInfoPost { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .pNext = nullptr, + .semaphore = layer->queueSerializationTimelineSem, + .value = signalValue, + .stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + .deviceIndex = 0 + }; + + VkSubmitInfo2 submitInfoPre { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + .pNext = nullptr, + .flags = 0, + .waitSemaphoreInfoCount = 1, + .pWaitSemaphoreInfos = &timelineInfoPre, + .commandBufferInfoCount = 0, + .pCommandBufferInfos = nullptr, + .signalSemaphoreInfoCount = 0, + .pSignalSemaphoreInfos = nullptr + }; + + VkSubmitInfo2 submitInfoPost { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + .pNext = nullptr, + .flags = 0, + .waitSemaphoreInfoCount = 0, + .pWaitSemaphoreInfos = nullptr, + .commandBufferInfoCount = 0, + .pCommandBufferInfos = nullptr, + .signalSemaphoreInfoCount = 1, + .pSignalSemaphoreInfos = &timelineInfoPost + }; + // Release the lock to call into the driver lock.unlock(); - return layer->driver.vkQueueSubmit2KHR(queue, submitCount, pSubmits, fence); + + if (layer->instance->config.serialize_queue()) + { + layer->driver.vkQueueSubmit2KHR(queue, 1, &submitInfoPre, VK_NULL_HANDLE); + } + + auto result = layer->driver.vkQueueSubmit2KHR(queue, submitCount, pSubmits, fence); + + if (layer->instance->config.serialize_queue()) + { + layer->driver.vkQueueSubmit2KHR(queue, 1, &submitInfoPost, VK_NULL_HANDLE); + } + + return result; } diff --git a/source_common/framework/manual_functions.cpp b/source_common/framework/manual_functions.cpp index 6cd1acb..e56dda0 100644 --- a/source_common/framework/manual_functions.cpp +++ b/source_common/framework/manual_functions.cpp @@ -909,9 +909,10 @@ VKAPI_ATTR VkResult VKAPI_CALL layer_vkCreateDevice_default( return res; } + auto device = std::make_unique(layer, physicalDevice, *pDevice, fpGetDeviceProcAddr); + // Retake the lock to access layer-wide global store lock.lock(); - auto device = std::make_unique(layer, physicalDevice, *pDevice, fpGetDeviceProcAddr); Device::store(*pDevice, std::move(device)); return VK_SUCCESS;