如要瞭解 Magma 的背景、硬體需求和架構說明等總覽資訊,請參閱「Magma:總覽」。
本文件說明驅動程式庫開發人員可遵循的程序,將 Vulkan 驅動程式庫移植到 Fuchsia。
需求條件
將 Vulkan 驅動程式庫移植到 Fuchsia 需要下列項目:
- 硬體說明文件 (暫存器規格、運作原理)。
- Vulkan 參考實作項目 (Linux)。
- 用戶端驅動程式庫 (ICD) 應提供符合 Vulkan 1.1/1.2 的實作項目。
硬體必須通過啟動程序,才能運作網路存取、磁碟儲存空間和 fx pave 功能。
目前 Magma 僅支援 UMA 裝置,但如果您有雄心壯志,可以嘗試移植到具有獨立記憶體的 GPU。
建立 Stub 系統驅動程式庫
Magma 系統驅動程式庫 (MSD) 類似於其他作業系統上的核心驅動程式庫。此時,請考慮是否要從其他作業系統移植現有的核心驅動程式庫,或是從頭編寫一個。
此時請閱讀「驅動程式概念」一節,瞭解 Fuchsia 驅動程式庫模型。
這項選擇取決於現有核心驅動程式庫程式碼的許多方面。注意事項:
- 驅動程式庫是否有平台抽象層,還是依附於 Linux 核心介面?
- 授權。
- 它的 ioctl 介面與 Magma 進入點有多相似?
第一個編碼步驟是建立可建構的基本 MSD。MSD 位於驅動程式庫目錄中。這些檔案是使用 GN 建構系統建構為 fuchsia_drivers。Magma 系統驅動程式庫必須是開放原始碼,但不得為 GPL,且必須託管於 fuchsia.googlesource.com。
Fuchsia 驅動程式是正常的使用者空間程序。也就是說,他們可以存取大部分的 c 程式庫,以及部分 POSIX API。與大多數程序不同,不允許存取檔案系統。
目前 Magma 支援兩種不同的裝置類型:平台裝置和 PCI 裝置。
- SoC 通常會有平台裝置。這些裝置並非隨插即用,而是需要主機板驅動程式,才能將適當的資源委派給這些裝置。
- PCI 裝置位於 PCI 匯流排上,並由 PCI 匯流排驅動程式委派資源。
Fuchsia 驅動程式庫架構支援這兩者,因此可以建立及繫結為一般 Fuchsia 驅動程式。
要分攤責任嗎?(SoC 版本)
在 SoC 上,GPU 硬體通常會以獨立 IP 區塊的形式提供,可由 SoC 供應商自訂。視供應商的自訂程度而定,有幾種可能的做法。
- 統一 MSD,但會先載入 SoC 專屬的驅動程式庫。
- 請為每個 SoC 或 SoC 供應商分別製作 MSD。
如果 SoC 的自訂項目不多,最好使用統一的 MSD。廠商專屬驅動程式庫會先繫結,並匯出 MSD 的 Banjo 介面,以開啟/關閉 GPU、變更時脈等。這樣做的好處是,只要實作新的廠商專屬驅動程式庫,就能輕鬆將 MSD 移植到新硬體,不必進行修改。如需這個方法的範例,請參閱 msd-arm-mali 和 aml-gpu。
為每個 SoC 提供獨立的 MSD 可帶來更多彈性,如果 GPU IP 供應商允許在 SoC 中對 IP 區塊進行許多自訂作業,這項做法可能就很有必要。不同 SoC 的 MSD 實作項目可能會共用 SoC 獨立程式碼的程式庫,但會編譯為獨立的驅動程式。
要分攤責任嗎?(PCI 版本)
PCI GPU 通常包含螢幕控制器硬體。顯示控制器驅動程式庫最好與 GPU 硬體分開實作,因為這樣就能儲存在 bootfs 中,並在磁碟存取前提供開機控制台。顯示控制器應公開硬體專屬的 banjo 介面,而 MSD 可以繫結至顯示驅動程式庫。
如要查看分成兩部分的 PCI 驅動程式庫範例,請參閱 msd-intel-gen 和 intel-display。
開啟電源
MSD 現在正在建構中,下一個步驟是編寫程式碼,重設裝置並讓裝置進入運作模式。這類資訊可能包括:
- 開啟裝置電源 (可能使用 fuchsia.hardware.power.Device banjo 介面)。
- 啟用時鐘 (可能使用 fuchsia.hardware.clock.Clock FIDL 介面)。
- 啟用匯流排主控或記憶體存取權。
- 正在載入韌體。
驅動程式也應視需要取得 MMIO 範圍的存取權,並開始處理中斷。對於 SoC,必須修改板載驅動程式,將這些資源傳遞至 MSD 或 SoC 專屬驅動程式庫,並新增裝置供 MSD 繫結。
這個階段的測試:
- 在驅動程式庫啟動時記錄 MMIO 暫存器。
實作 MSD
以下是驅動程式庫可實作的主要函式清單:
- 初始化硬體
- msd_driver_create
- msd_driver_configure
- msd_driver_destroy
- msd_driver_create_device
- msd_device_destroy
- 支援參數查詢
- msd_device_query
- 支援狀態傾印
- msd_device_dump_status
- 建立連結
- msd_device_open
- msd_connection_close
- 建立緩衝區
- msd_buffer_import
- msd_buffer_destroy
- 設定記憶體空間和緩衝區對應
- msd_connection_map_buffer_gpu
- msd_connection_unmap_buffer_gpu
- msd_connection_commit_buffer
- msd_connection_release_buffer
- 設定硬體環境
- msd_connection_create_context
- msd_context_destroy
- 指令緩衝區排程
- msd_context_execute_command_buffer
- msd_connection_set_notification_callback
- 建立信號燈
- msd_semaphore_import
- msd_semaphore_destroy
- 錯誤處理
- 電源管理
硬體順利啟動後,下一步是決定如何將現有的 ioctl 對應至 MSD 進入點。
在大多數情況下,Linux DRI ioctl 和 MSD 函式之間的對應關係很簡單。但記憶體管理是例外情況:在 Magma 中,記憶體是由 ICD 分配及對應,而非 MSD (或核心驅動程式庫)。這可能會改變分配 VMO 的部分指令流程,因為 MSD 必須將現有緩衝區匯入 GPU 硬體。
如果這種方法不適用於某些類型的記憶體,驅動程式庫可能會使用 Sysmem 堆積來處理該記憶體的配置作業。用戶端會使用 Sysmem 分配記憶體,並透過一般的 Magma 介面匯入控制代碼。接著,MSD 就能與 sysmem 通訊,取得更多記憶體相關資訊。
驅動程式可能不需要實作所有函式。建議您視 ICD 的需求,逐步實作 MSD 函式。這有助於在實作 MSD 函式時提供背景資訊,並避免在不需要的函式上浪費精力。
這個階段的測試:
- 驅動程式庫專屬單元測試 (非硬體專屬)
- 硬體專屬驅動程式庫測試 (請參閱範例)。這些測試應盡量減少 GPU 的運作,例如寫入暫存器,或導致 GPU 修改記憶體位置。
- 使用 Magma 介面的驅動程式庫專屬整合測試。
- magma-conformance-tests (Magma L0 的一部分)。
- magma-info-test (Magma L0 的一部分)。
建構 ICD
IHV ICD 必須移植到 Fuchsia。ICD 應使用 Bazel SDK 建構。ICD 建構作業可以移植到 Bazel,或包裝在 Bazel 建構作業中。rules_foreign_cc 是包裝現有建構作業的好例子。
由於 ICD ABI 限制,ICD 必須以靜態方式連結至所有依附元件。他們只能參照下列共用程式庫:
libc.solibzircon.so
這會限制 ICD 可使用的依附元件。舉例來說,以下列出一些不允許使用的程式庫和可能的替代方案:
- HLCPP:必須換成新的 C++ 繫結。
- syslog:可以替換為 syslog/structured_backend。
- async-default:必須一律明確指定非同步調度器。
- libtrace-engine:目前沒有替代方案。
- libsvc:可以替換為
fuchsia.io呼叫和vk_icdInitializeOpenInNamespaceCallback(請參閱下文)。
在這個階段,您可以視需要將所有其他參照設為虛設常式。ICD 也必須連結至 SDK 中提供的 Magma 執行階段程式庫,如 @fuchsia_pkg//pkg/magma_client。
Vulkan 載入器服務會從套件擷取 ICD,並向 Vulkan 用戶端宣傳。ICD 必須包含在 Fuchsia 套件中,並附上中繼資料和資訊清單 JSON 檔案,如載入器服務文件所述。您可以使用 Bazel SDK 存放區指令,將這個套件提供給裝置。
如果 ICD 套件包含在宇宙中,可以透過 fx shell killall vulkan_loader.cm 重新載入。之後啟動的元件會取得新的 ICD 套件,而舊版元件在建立 Vulkan 執行個體時會失敗。
ICD 必須匯出特定符號集,詳情請參閱 Vulkan ABI 定義。您應該在這個時間點實作這些方法。
這個階段的測試:
readelf -d,確保除了libc.so和libzircon.so之外,共用程式庫沒有其他依附元件。- 使用
fx shell cat /svc/fuchsia.vulkan.loader.Loader啟動 Vulkan 載入器,並檢查ffx inspect show core/vulkan_loader是否已載入。錯誤會記錄在系統記錄檔中。 - 執行 vulkan_icd_load 測試。這項測試會檢查系統上是否有任何 ICD 正常運作,因此請務必先移除系統上的其他 ICD,再執行測試。
將 ICD 連線至 Magma
此時,ICD 應使用提供給 vk_icdInitializeOpenInNamespaceCallback 的回呼,連線至 /loader-gpu-devices/class/gpu 目錄。ICD 可以使用 fuchsia.io.Directory FIDL 通訊協定列出目錄內容。這個目錄包含系統上所有 MSD 的裝置節點,每個節點的名稱都是不重複的三位數。數字在開機期間會保持穩定,但只要重新載入 MSD (例如重新啟動裝置時),數字就可能會變更。
每個 magma 裝置路徑都可以使用 vk_icdInitializeOpenInNamespaceCallback 開啟,而產生的 zircon 管道可以使用 magma_device_import 提供給 libmagma。如果系統有多個 magma 裝置,驅動程式庫必須使用 magma_queryMAGMA_QUERY_VENDOR_ID 來判斷要使用哪個裝置。
這個階段結束後,magma_* 函式就會開始運作,因此 ioctl() 呼叫可以逐步轉換為對等的 Magma 呼叫。
這個階段的測試:
- vkreadback (繪製顏色,然後讀回 frame buffer 值)。這是 Magma L0 的一部分。
- Vulkan 一致性測試。理想情況下,完成這個階段後,通過率應為 100%。詳情請參閱 Magma 測試策略。
移除不允許的符號
連結 ICD 時,請使用版本指令碼,確保只公開 Fuchsia 系統 ABI 允許的符號。
ICD 只能使用符號許可清單中列出的符號。如要檢查,請將允許清單與在 ICD 共用程式庫上執行 llvm-nm -gD 取得的清單進行比較。
部分不支援的檔案作業可能會替換為對 OpenInNamespace 回呼的呼叫,並提供給 vk_icdInitializeOpenInNamespaceCallback。
這個階段的測試:
- icd_conformance 測試成功。
實作 Fuchsia 擴充功能
目前 ICD 無法與 scenic 搭配使用,且未整合視窗系統。驅動程式必須實作 Fuchsia 專用的 Vulkan 擴充功能。用戶端驅動程式庫應提供符合 Vulkan 1.0/1.1/1.2 的實作項目。
VK_FUCHSIA_external_memory
這項擴充功能與 VK_KHR_external_memory_fd 類似,可從/向 VMO 匯入/匯出 VkDeviceMemory。這項擴充功能已上傳至 Vulkan 規格。
這個階段的測試:
vkext --gtest_filter=VulkanExtension.*(Magma L0 的一部分)。
VK_FUCHSIA_external_semaphore
這項擴充功能與 VK_KHR_external_semaphore_fd 類似,可將二進位信號燈匯入/匯出至 Zircon 事件。這項擴充功能已上傳至 Vulkan 規格。
這個階段的測試:
vkext --gtest_filter=VulkanExtension.*(Magma L0 的一部分)。vulkan-cts-zircon(Vulkan CTS 的一部分)。
VK_FUCHSIA_buffer_collection
這個擴充功能會與 sysmem 互動,並允許用戶端協商圖片格式和分配記憶體。詳情請參閱 sysmem 說明文件。
這項擴充功能目前仍在開發中,可能會有所變動,但可在 Fuchsia 內部 Vulkan 標頭中找到。
這個階段的測試:
vkext(Magma L0 的一部分)。- vkcube-on-fb (動畫,使用 VK_KHR_swapchain - Magma L1 的一部分)。
驗證
上述各小節列出的所有測試都必須通過。如需更多詳細資料和完整的測試案例清單,請參閱測試策略說明文件。
長期支援
必須使用硬體供應商提供的新程式碼,更新 MSD 和 ICD。 理想情況下,程式碼會上游化,而 GPU 供應商會使用 Zircon DDK 提供及維護系統驅動程式。