Layers 暴露給api層,不像傳統圖形API集成在驅動里面,開發者根據自己的需要進行開啟,最終目的還是為了提高性能。
The Loader
he loader is the central arbiter in the Vulkan runtime. The application talks directly to the loader and only to the loader, which then deals with enumerating and validating the layers requested, enumerating ICDs and organising them and presenting a unified interface to the application.
ICD是就是不同廠商對圖形API所做的驅動文件, Vulkan Loader 何時加載 ICD 驅動文件,vulkan initialize 這篇文章詳細描述了vulkan是如何初始化,以及為什么需要這么做。
那么這么做的意義是什么呢?直接調用這些函數指針不就完事了嗎?恰巧vulkan的一個思想就是,去除掉驗證層,那么驗證層能放在何處?也就是放在這個SDK里,類似各種Graphic Debugger的實現,Vulkan有很多Validation Layer,可以根據需求載入,在真正的函數調用之前,截取一些信息,獲得一些信息,最后再調用真正的接口。也就是說整個SDK不僅僅是一個函數指針獲取器,還是一個Graphic Debugger。
可以自定義一個layer,然后在layer里面指定自己需要監控的函數。
{ "file_format_version" : "1.0.0", "layer" : { "name": "VK_LAYER_SAMPLE_SampleLayer", "type": "GLOBAL", "library_path": ".\\sample_layer.dll", "api_version": "1.0.0", "implementation_version": "1", "description": "Sample layer - https://renderdoc.org/vulkan-layer-guide.html", "functions": { "vkGetInstanceProcAddr": "SampleLayer_GetInstanceProcAddr", "vkGetDeviceProcAddr": "SampleLayer_GetDeviceProcAddr" }, } }
When our layer's
vkCreateInstance
is called, the loader has inserted extra data that we can use for initialisation. In particular, it makes use of Vulkan'ssType/pNext
extensibility. In theVkInstanceCreateInfo
struct, it begins in exactly the same way as many other Vulkan structures with aVkStructureType sType;
andconst void *pNext
. These two elements define a linked list of extra extension information. You can iterate through the list even if you don't recognise all of the entries in the list because they all start with thesType/pNext
.
VK_LAYER_EXPORT VkResult VKAPI_CALL SampleLayer_CreateInstance( const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance) { VkLayerInstanceCreateInfo *layerCreateInfo = (VkLayerInstanceCreateInfo *)pCreateInfo->pNext; // step through the chain of pNext until we get to the link info while(layerCreateInfo && (layerCreateInfo->sType != VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO || layerCreateInfo->function != VK_LAYER_LINK_INFO)) { layerCreateInfo = (VkLayerInstanceCreateInfo *)layerCreateInfo->pNext; } if(layerCreateInfo == NULL) { // No loader instance create info return VK_ERROR_INITIALIZATION_FAILED; } PFN_vkGetInstanceProcAddr gpa = layerCreateInfo->u.pLayerInfo->pfnNextGetInstanceProcAddr; // move chain on for next layer layerCreateInfo->u.pLayerInfo = layerCreateInfo->u.pLayerInfo->pNext; PFN_vkCreateInstance createFunc = (PFN_vkCreateInstance)gpa(VK_NULL_HANDLE, "vkCreateInstance"); VkResult ret = createFunc(pCreateInfo, pAllocator, pInstance); // fetch our own dispatch table for the functions we need, into the next layer VkLayerInstanceDispatchTable dispatchTable; dispatchTable.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)gpa(*pInstance, "vkGetInstanceProcAddr"); dispatchTable.DestroyInstance = (PFN_vkDestroyInstance)gpa(*pInstance, "vkDestroyInstance"); dispatchTable.EnumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties)gpa(*pInstance, "vkEnumerateDeviceExtensionProperties"); return VK_SUCCESS; }