如需 Magma 的總覽資訊,包括背景、硬體需求和架構說明,請參閱「Magma:總覽」。
本文件說明驅動程式庫開發人員可遵循的程序,將 Vulkan 驅動程式庫移植至 Fuchsia。
需求條件
將 Vulkan 驅動程式庫移植至 Fuchsia 需要以下項目:
- 硬體文件 (登錄規格、運作理論)。
- 參考 Vulkan 實作項目 (Linux)。
- 用戶端驅動程式庫 (ICD) 應提供符合 Vulkan 1.1/1.2 的實作項目。
硬體必須通過啟動程序,才能提供網路存取、磁碟儲存空間和 fx pave 功能。
目前 Magma 僅支援 UMA 裝置,但如果您有意嘗試,可以嘗試將其移植至具有獨立記憶體的 GPU。
建立系統輔助程式虛設檔
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。廠商專屬驅動程式庫會先繫結,並匯出 banjo 介面,讓 MSD 開啟/關閉 GPU、變更時脈等。這樣做的好處是,只要實作新的廠商專屬驅動程式庫,就能輕鬆將 MSD 移植至新硬體,而無須修改。如需這項做法的範例,請參閱 msd-arm-mali 和 aml-gpu。
如果 GPU IP 供應商允許對 SoC 中的 IP 區塊進行多項自訂,則為每個 SoC 建立獨立的 MSD 可提供更大的彈性,甚至可能是必要的做法。不同 SoC 的 MSD 實作可能會共用不受 SoC 限制的程式碼程式庫,但會編譯為獨立的驅動程式。
是否要分工?(PCI 版本)
PCI GPU 通常會包含顯示控制器硬體。顯示控制器驅動程式庫最好與 GPU 硬體分開實作,因為這樣就能在磁碟可供存取前提供啟動主控台。顯示控制器應公開硬體專屬的 banjo 介面,而 MSD 可繫結至顯示器驅動程式庫。
請參閱 msd-intel-gen 和 intel-display,瞭解分成兩個部分的 PCI 驅動程式庫範例。
開機
由於 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_context_execute_immediate_commands
- msd_connection_set_notification_callback
- 建立訊號量
- msd_semaphore_import
- msd_semaphore_destroy
- 錯誤處理
- 電源管理
硬體成功開機後,下一步就是決定如何將現有的 ioctl 對應至 MSD 進入點。
在大多數情況下,Linux DRI ioctl 和 MSD 函式之間的對應方式相當簡單。記憶體管理是例外狀況:在 Magma 中,ICD 會分配及對應記憶體,而非 MSD (或核心驅動程式庫)。由於 MSD 必須將現有的緩衝區匯入 GPU 硬體,因此這可能會變更分配 VMOs 的部分指令流程。
如果這種做法不適用於某些類型的記憶體,驅動程式庫可能會使用 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。應使用 Bazel SDK 建構 ICD。ICD 建構作業可以轉移至 Bazel,或包裝在 Bazel 建構作業中。rules_foreign_cc 就是如何包裝現有建構的絕佳範例。
由於 ICD abi 限制,ICD 必須以靜態方式連結至所有依附元件。只能參照下列共用程式庫:
libc.so
libzircon.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。如載入器服務說明文件所述,ICD 必須包含在中繼資料和資訊清單 JSON 檔案的 Fuchsia 套件中。您可以使用 Bazel SDK 存放區指令,將這個套件提供給裝置。
如果 ICD 套件包含在universe 中,您可以執行 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
是否已載入。錯誤會傳送至 syslog。 - 執行 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_query
搭配 MAGMA_QUERY_VENDOR_ID
,判斷要使用哪個裝置。
這個階段結束後,magma_*
函式就會運作,因此 ioctl()
呼叫可以逐步轉換為等效的 Magma 呼叫。
這個階段的測試:
- vkreadback (繪製顏色,然後讀取 framebuffer 值)。這是 Magma L0 的一部分。
- Vulkan 相容性測試。理想情況下,完成這個階段後,通過率應為 100%。詳情請參閱 Magma 測試策略。
移除不允許使用的符號
連結 ICD 時,請使用版本指令碼,確保該系統只會公開 Fuchsia 系統 ABI 允許的符號。
您只能使用符號許可清單中列出的符號。如要確認這一點,請將許可清單與在 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,可讓您從/至 VMOs 匯入/匯出 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 提供及維護系統驅動程式。