Vulkan:初始化 前篇


轉載請注明:http://www.cnblogs.com/vertexshader/articles/5225675.html,歡迎入群54288273一起扯淡。

 

前序的什么環境配置等工作就不總結了,所有的資料和SDK都匯總在這個地址,按照要求安裝和配置就可以了。

吐槽優先!

萬事開頭先吐槽,Vulkan SDK簡直就是日了狗了我想說,函數的名稱終於達到了又長又臭的地步,以至於Demo代碼看起來是這樣的:

1 err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL);

一個函數的名稱就達到了35個字符,這還是短的,還有更長的,加加參數一個函數就可以占幾行了。

到底做了啥?

這次Vulkan不像OpenGL一樣是無SDK的,它妥妥的出了一個叫做Vulkan SDK的東西,似乎我們只需要include這個頭文件,link這些lib就接入了Vulkan的SDK。不過我在Demo里看到了一些函數仍然需要通過vkGetInstanceProcAddr的方式獲取函數指針,這時候我就對這個SDK的行為產生了懷疑和興趣。

回顧一下以前了解OpenGL的經驗,OpenGL Runtime是由不同的Manufactory所實現的ICD(Installable Client Driver)來支持的。通過載入默認OpenGL庫的方式,獲取相應的函數指針,完成整個API的初始化的。這個不同於Direct3D,由於Direct3D的封閉性,其Runtime是在操作系統層面實現的。而Vulkan又是OpenGL的繼承者,又是由一大堆的Manufactory在背后默默地支持,可以充分地懷疑其應該是通過和過去OpenGL類似的方式獲取函數指針實現的。

還好Vulkan SDK是開源的,果然不假,搜索整個代碼在vk_loader_platform.h發現了:

typedef HMODULE loader_platform_dl_handle;
static loader_platform_dl_handle
loader_platform_open_library(const char *libPath) {
    return LoadLibrary(libPath);
}

打上斷點,看看搞了毛:

loader_platform_open_library(const char * libPath)
loader_scanned_icd_add(...)
loader_icd_scan(...)
vkCreateInstance(...)
main()

而這時候libPath的值是“C:\\Windows\\System32\\nvoglv32.dll”,追溯上游,發現其在函數vkCreateInstance中調用了loader_icd_scan這個接口,而這個接口又調用了loader_get_manifest_files這個接口,

loader_get_manifest_files內部有一代碼是:

loc = loader_get_registry_files(inst, loc);

這個loader_get_registry_files則是調用了RegOpenKeyEx這個接口,也就是從注冊表中獲得鍵值,而loc的值則是預定義的宏“SOFTWARE\\Khronos\\Vulkan\\Drivers”。打開注冊表,看看這個值到底是個啥哇:

指向了一個json文件,打開這個json文件看看其中內容:

{
    "file_format_version" : "1.0.0",
    "ICD": {
        "library_path": "nvoglv64.dll",
        "api_version" : "1.0.4"
    }
}

原來被騙了!

之前的json文件原來指定了庫的名稱和API的版本,那么nv-vk64.dll和nvoglv64.dll到底有什么接口呢,可以直接打開dll查看其接口和偏移:

是不是有很多vk的接口?但是只有一個接口是核心的,就是vk_icdGetInstanceProcAddr這個接口,在后續的loader_scanned_icd_add調用中,代碼從載入的庫中獲得了這個函數指針,然后干了一件事情:

fp_create_inst = (PFN_vkCreateInstance)fp_get_proc_addr(NULL, "vkCreateInstance");

原來是創建了入口的函數指針實例!說好的vkCreateInstance接口,也就是包在外面的一層,並不是真正的vkCreateInstance。那么也就是說整個流程就是,Vulkan Loader掃描注冊表獲得相應的json文件,載入這個json文件,載入dll,獲得入口函數指針,載入相應函數指針。也就是說這套方法仍然和過去OpenGL的方法一致。而這個載入過程,通過檢查函數調用,也會在vkEnumerateInstanceExtensionProperties等接口中調用。而SDK中的接口,都是對函數指針包了一層,例如vkCreateBuffer:

LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
               const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
    const VkLayerDispatchTable *disp;

    disp = loader_get_dispatch(device);

    return disp->CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
}

整個VkLayerDispatchTable就是函數指針的集合。

為啥這么干?

那么這么做的意義是什么呢?直接調用這些函數指針不就完事了嗎?恰巧vulkan的一個思想就是,去除掉驗證層,那么驗證層能放在何處?也就是放在這個SDK里,類似各種Graphic Debugger的實現,Vulkan有很多Validation Layer,可以根據需求載入,在真正的函數調用之前,截取一些信息,獲得一些信息,最后再調用真正的接口。也就是說整個SDK不僅僅是一個函數指針獲取器,還是一個Graphic Debugger。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM