Demo演示地址07_wintest
有什么用
在android平台主流是用opengl es,android下vulkan與opengles紋理互通。 而在win平台,主流游戲還用的是DX11,如果只是把結果通過CPU的內存輸出,然后接到dx11,這個性能損失太大了,我們就需要Vulkan與DX11交互。 以及完成這個交互后,aoce我就不做dx11模塊了,我比較了oeip中的dx11模塊與當前的vulkan模塊性能相差不大,都比CUDA差,但是通用性更好。
主要實現
如果有興趣,可以看下aoce_vulkan/win32/VkWinImage類的實現,dx11與vulkan綁定的邏輯主要在這。
與opengles交互類似,資料不多,主要看到vulkan下有個vulkan_win32的頭文件,看到如VkImportMemoryWin32HandleInfoKHR這些結構,用google搜下,可以看到BindImageMemory有比較完整的交互邏輯,主要就是用DX11Texture共享紋理,注意這里要用NT句柄,就是相關MiscFlags需要包含D3D11_RESOURCE_MISC_SHARED_NTHANDLE,而在cuda/dx11交互里用cudaGraphicsD3D11RegisterResource用NT句柄 會失敗,所以最好用個標志表示是否需要NT句柄,NT句柄需要自己CreateSharedHandle,從NT句柄得到相應shader buffer需要通過ID3D11Device1拿到,余下的邏輯和非NT句柄差不多了,相關代碼aoce_win/DX11/Dx11SharedTex查看具體實現。
然后就是按照cuda/dx11交互那樣,vulkan最后輸出結果到綁定dx11texture上的那個vkImage,然后在dx11渲染的另外一個線程把上面的dx11texture結果輸出來就行,想的應該是這樣,然后就開始不斷啟動就報device lost,然后啟動幾次后機器卡死/死機藍屏,最開始我想的肯定是同步問題,繼續在vulkan_win32的頭文件找,找到如下VkWin32KeyedMutexAcquireReleaseInfoKHR結構,這個結構不就是 dx11不同線程交互的同步API的AcquireSync/ReleaseSync,根據這個結構搜索到dx11-vulkan-keymutex根據這里的邏輯改下,然后發現還是卡死/死機,我開始根據新增加代碼一行行屏蔽測試,不斷死機/藍屏,最后我忽然想到解決動態啟用/關閉層時遇到的一個問題,其中把運算結果復制給綁定dx11資源的vkImage,用的是vkCmdBlitImage,改成vkCmdCopyImage,然后問題解決,以前我因為vkCmdBlitImage里源和目標紋理不需要同樣大小就一直用的這個,我猜測這個API應該是需要渲染管線與交換鏈那一套的, 在這里我只有計算管線所以會導致問題,后面有時間驗證下這個問題。
這個問題解決后,可以正常運行了,但是,你不動窗口運行多久沒問題,但是一動窗口vulkan就報timeout,而這timeout一看就是VkWin32KeyedMutexAcquireReleaseInfoKHR上面的, 我猜測在移動窗口時,導致綁定dx11texture上的那個vkImage那個資源一直被dx11渲染占用着,所以就有這個問題,而我設計輸出層時,設計要求運行線程與輸出線程沒有等待關系,二個線程可以分別以自己楨率運行 ,就和我在cuda交互里的處理,設置timeout為0,檢查鎖,如果鎖timeout,就馬上放棄復制,線程繼續運行,而在這,我並不能通過這個接口實現這種邏輯。
最后想了想,vulkan運行線程中,我可以用vkFence知道是否在執行commandbuffer,那么在二次執行中先復制結果一個臨時dx11紋理中, 這樣也不需要針對這個臨時dx11紋理與vulkan執行線程同步,把原來的綁定dx11texture上的那個vkImage的MiscFlags中的D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX改成D3D11_RESOURCE_MISC_SHARED,然后把相關的 VkWin32KeyedMutexAcquireReleaseInfoKHR代碼去掉,vulkan執行comandbuffer執行完成后,使用vkFence等待,等待完成后把綁定dx11texture上的那個vkImage輸出到臨時dx11紋理中。
最后在Dx11的渲染線程中,把臨時dx11紋理結果拿出來渲染,現在移動窗口正常了。
