標籤:

vulkan踩坑記02——嚴肅官方與函數們

隨便寫寫

vulkan是真滴難學。盲目自信的我太甜了,將來肯定會被人騙到破產。

先前我一直看的是vulkan tutorial,效果不好,半途而棄了兩回,為了堅持我事不過三的原則,我決定徹底拋棄它換一款別的。

它給我感覺的問題是作者有實力但是在教學方面經驗不足,第一個畫三角形的例子開始不久就講validation layer,最後告訴我這其實是一個debug的工具,寫簡單代碼時幾乎用不上。另外我感覺無關的細節有點多,額,有點像高中生的自我意識一樣。

放棄之後我也開始下馬後炮,考慮這背後的原因,是我太笨了還是不夠努力。說實話這個問題還是挺難回答的。換個角度,可以類比成談戀愛,簡單接觸了一下沒看上眼。也許深入接觸之後會有成功的理由,不過大多數還是分開算了。

這之後我重新選擇了vulkan sample的官方文檔。為什麼當初我選擇看個人博客而不是官方呢?反思一下,我沒有花時間去做多個教程的評估工作,而是隨便選了一個。這難道也是你的坑嗎,vulkan?啊,文字這種單方面的記錄用來玩梗總感覺有點冷,果真吐槽役是不可缺少的,只能自己客串一下了。

記錄

大部分的事,只有去做了才知道困難。本來想寫成教程之類的,實際動手的時候才發現不現實。估計只有學到三百分的水平才能做出六十分的教程。

所以就先亂記一些零散的要點,藉此也可以鍛煉我的第七感,以便早日成為黃金聖鬥士。

create vulkan instance

說實話,我現在還不能對vkInstance大放厥詞,沒實力是這樣的。簡單來說,它連接著application和driver。

——話說為什麼都是英文啊?給我響應國家號召寫成應用和驅動啊。

——總感覺英文有味道吧。

——你這種很明顯會為了英文菜單付出三倍價格吧。

以後我再也不口嗨那些機翻味的書了。看英文沒問題,想翻譯成中文,這誰頂得住啊。所以大部分英文我就不翻了,逃避雖然可恥但很有用。

個人感覺比較有代表性的應該是vulkan中建立對象的介面形式。比如建立一個XX對象。

VkResult vkCreateXX(VkXXCreateInfo *,
VkAllocationCallback *,
VkXX *);

寫成這種模樣還是因為vulkan是一個C風格的庫,如果是C++的話,會善解人意一點。VkXXCreateInfo可以理解成對象的初始化參數。由於參數往往很多(很多沒用),所以要加一層結構整合一下。第二個參數則是內存的allocate函數,可以自己實現或者用NULL。不得不說vulkan的功能還是多,什麼都料到了。最後一個則指向對象地址。

至於為什麼不是返回一個對象而是通過指針傳入地址,我的想法是VkResult可以返回更多的信息,返回對象的話失敗情況只能返回一個NULL,具體的出錯類型是沒法做的,而通過VkResult文檔也能看出有一長串出錯信息。

enumerate physical devices

這裡就是為了選擇使用的顯卡。相比於openGL,雙顯卡的處理要容易一點。

具體的參數、方法之類的我就不談了,細節之類的考慮的越多越自閉,寫代碼和人生在這種奇怪的地方重合了。

這一章我主要是學到了獲取列表對象的模式。不知道為什麼vulkan要搞得這麼麻煩,獲取一組對象也需要三步走。第一步,獲取對象個數;第二步,分配對象空間;第三步,獲取對象。也許是因為vulkan中分配對象函數可以自定義,所以不能合成一步。大概這就是機器人有意識後的問題吧,走一步路都麻煩得要死。這麼想想,也許人的意識就算能放入機器中也不能做出栩栩如生的機器人吧,太麻煩了,重複低級的事太多了。

create logical device

在physical device之上需要建立logical device。這點有點像虛存之於實際內存。當然可以直接去操作實際物理設備,只是會存在我仍不能清晰簡明表述的各種不便和問題,就不提了。

先得提一下queue這個概念。我的理解是GPU接收的操作、指令以及這種那種,需要放在queue上。每一張顯卡具有不同的queue family屬性,這由硬體決定。vulkan沒有隱藏這些硬體的細節,我個人感覺這個還是太底層了一點,對菜雞友好度不夠。幸好physical device用的地方不多,獲取queue family屬性算一個。

queuefamily有queue type flags表明其下queue的用途,可以支持多種用途。logical device相比於physical device的不同在於logical device需要指明使用的queue family以及extension和layer。所以在同一physical device上建立多個logical device,使用不同的queuefamily是可以的。

create command buffer

在設置好了queue之後,就需要考慮往上面添加命令了。

估計是出於訪問速度的考慮,需要將command放入command buffer之後再將整個buffer提交給queue。從官方給的教程來看,command buffer中,實際存儲的是設備特定的指令,driver負責將用戶提交的command轉換成設備特定的instruction。一直以來認為很沒用的驅動乾的就是這種活,讓人說什麼好呢。

然後vulkan的一個特點出現了,你學了command buffer後,不能直接建個command buffer,需要再整個command buffer pool,通過這個pool來構造收回command buffer,可以提高command buffer的效率。這種感覺就像是dota里你好不容摸出一把影刀準備帶隊打架,隊友說你有個鎚子輸出,再去刷個大炮蝴蝶吧。雖然沒什麼不對,總歸讓人有點沮喪。

需要額外注意的就是command buffer pool和queue family是一一對應的。

create swap chain

對於渲染,一個很明顯的需求就是能直接看到渲染結果,這就要求建立一個窗口,將結果顯示在窗口上。

不過對現在的我來說意義不大,神奇的畢設要求做無窗口渲染,估計是將渲染結果直接輸出到文件。雖然變簡單了但是極度缺乏實例,只能先學一下窗口渲染怎麼做。話說這不是南轅北轍嗎?

在vulkan中,這是通過顯卡上具有presentation的queue來實現的,將渲染的結果image提交給queue,直接來說就是這樣。image指向設備內存中的一塊區域(具體在CPU還是GPU我也摸不著頭腦,估計是GPU)。

然後vulkan又開始了,在image之上又建立了swap chain結構,由一組image組成,然後又包含了一大堆我不懂的屬性。一點點學吧,菜要承認,挨打立正。

而且image是不能直接使用的。可以看一下文檔的resource章,裡面列了image結構體的內容。需要在這之上建立image view對象。至於為什麼不將image和image view使用融合魔法卡變成一個,額,這就是我眾多盲區中的一個了,還是不要想那麼多了,聽官方的就完事了。

create depth buffer

教程這裡突然冒出了depth buffer章。然而真相只有一個,前一章教建立image時,是通過swapchain完成的,很多細節都被代替完成了,而這裡為depth buffer建立image是純手工的。簡單來說,就是大工廠VS小作坊吧,或者是小聯盟和大聯盟的區別。

常考,建立一個能用的image的過程分為四步。一,建立image對象;二,在顯卡中分配內存;三,將對象綁定到內存;四,建立image view。這麼直接的東西變得這麼複雜還是因為host memory和device memory存在。我的理解是host memory也就是程序運行的內存中存放的是類似指針的東西,而顯卡內存中存放的是實際內容。我感覺這是渲染類程序難寫的罪魁禍首之一,都是內存但不一樣,設計到一系列數據的傳輸問題。具體怎麼傳,和誰傳,傳什麼,我是一問三不知。細節之類的問題就不要再想了,上層已經很複雜了。

最好別看

這裡記了我半天所看內容的一半,雖然實際花了我兩周。這個記錄寫起來比看代碼還累,所以就夾斷,留到下周。

寫作過程中還會遇到別的坑,比如我用別的編輯器寫md再傳上知乎,結果知乎的markdown支持很奇怪,標題沒有加粗效果並且不同層次的標題字型大小相同;想要貼一些弱智圖,結果找不到合適的圖片上傳網站;絞盡腦汁去玩梗,結果個人感覺8行又刪掉,大概一半時間都花在想梗上。

好累啊,周末還是休息一下吧。


推薦閱讀:

TAG:Vulkan |