系列: 與 AI 一起學寫程式

回顧 GDC 與行動平台閃電戰

GDC 前夕版本發布與雙平台行動推進。

一套 C API,每一種介面 GDC 示範建置,iOS 和 Android 同一週出貨 RakuAI C API 觸控 / 音訊 / GPU / 資產 iOS · Metal Android · Oboe 桌面示範 瀏覽器後備 空間音訊:每個平台都有 HRTF 定位
新增一個平台是一種已知的形狀,不是一個沒有邊界的架構難題。

一個跑著真實程式碼的真實引擎,勝過任何簡報。RakuAI 帶著一個去了 GDC,同一週出貨了兩個行動平台,並證明了新增一種介面是一種已知的形狀——不是一次重寫。

GDC 是一個月前的事了。回程班機上寫滿了筆記。在走廊和場邊會議裡展開的對話,至今仍在收件匣裡迴盪。今天是把行前出貨了什麼、差點沒趕上什麼、以及帶回來什麼寫下來的合適星期六。

GDC 是那種讓你在三天高密度對話裡搞清楚哪些假設站得住、哪些其實只是被你當成事實的猜測的地方。我兩種答案都帶回來了,還帶回一份比預期更長的後續聯絡名單。

版本標籤說明了一切

我隨身帶去的筆電上跑的版本是 v1.3.8.26.10.09。把版本號推上去的那個 commit 只有一行訊息:「GDC 2026 Eve Release」。那是 3 月 25 日。隔天早上我就在飛機上了。

GDC 前夕的那個 commit 是我想寫的重點,因為它差一點就沒落地。

飛出去前四十八小時

大家都同意是「示範建置」的那個建置,在 GDC 前一週用四種不同的方式壞掉了。修正的 commit 是 3 月 7 日的 b70a48dc,收在一個標題為「fix(demos): fix black screens, crashes, and expand API test coverage」的單一 PR 裡。那四種壞法:

黑畫面。動畫展示、AI 行為測試、CSG 布林測試和玩法框架測試全都渲染成黑的。原因是少了一個示範程式需要用來註冊除錯繪製資源的 raku_editor_init() 呼叫。CMake 連結目標在前一個衝刺被重構過,編輯器函式庫被從示範二進位檔裡修剪掉了,因為沒有人注意到它們依賴它。修法:加回連結、恢復 init 呼叫。

一個空指標當機。SLM 對話示範在啟動時因為空的 QA 指標而當掉。對話模型載入器在「找不到設定檔」的路徑上提早返回,卻沒有標示錯誤。修法:把錯誤揭露出來,並附上一份可用的設定檔。

一個立刻斷線的網路示範。網路 echo 示範開了 socket、完成交握,然後就關閉了。斷線偵測在第一個閒置影格就觸發,而不是在真正的逾時之後。修法:用真正的逾時取代「第一個閒置」。

一個在沒有 OpenXR 執行期時以 1 退出的 XR 測試。在沒有執行期的環境下以非零值退出,對一台可能沒裝 XR 執行期的示範機器來說是錯誤的預設行為。修法:優雅地以 0 退出,記錄執行期不存在。

這些沒有一個是聰明的修法。它們全是那種在開發者機器上看起來沒事、在陌生人機器上看起來壞掉的東西。距離這種出差還有四十八小時,正是這些失敗浮現的時刻,因為示範終於跑在它接下來一週真正要住的那台筆電上,跑在會在十五秒內形成看法的人面前。

我需要及時弄好的打磨 commit

還有兩個 3 月 26 日的 commit,就在我出發前一天。

地面的鏡面反射。世界模型示範有一片綠色地面和幾個漂浮的形狀。套上全域鏡面材質之後,綠色地面在示範燈光下被洗成白色。修法只有十行:地面用霧面材質,鏡面只留給動態物件。示範瞬間看起來像刻意的美術方向,而不是一個除錯到一半的引擎。

在研討會筆電上強制使用 NVIDIA 獨顯。同時有 Intel UHD 和 NVIDIA 獨立顯卡的混合筆電,除非有明確的提示,否則預設用 Intel 晶片。提示就是兩個匯出符號:NVIDIA Optimus 用 NvOptimusEnablement,AMD 的對應版本用 AmdPowerXpressRequestHighPerformance。把它們加進示範二進位檔就強制走獨顯了。HUD 現在也會在標題列印出 GPU 名稱,讓我一眼就能看到示範實際跑在什麼上面。結果:跑在 Quadro T2000 上而不是內建 UHD 上。影格時間掉了一半以上。

這兩個 commit 都不到五十行。但它們就是「示範跑三十幀」和「示範跑九十幀而且看起來是刻意為之」之間的差別。

變成更好展示工具的瀏覽器後備方案

GDC 那一週落地的另一樣東西,是位於 web/seed-explorer/ 的獨立瀏覽器示範。單一 HTML 檔、零相依,是執行期在原生側使用的 Simplex 雜訊地形產生器的 JavaScript 移植。它用 putImageData 把生成世界的三種視圖渲染到一個 512x512 的 canvas 上:生態域圖、高度圖、溫度圖。裡面還內建了 raku://seed/ URL 協定,讓種子可以分享。

這原本應該只是筆電出狀況或會場 wifi 一團糟時的備案。結果它變成我在場邊對話裡最常打開的東西。咖啡店桌上別人的筆電沒辦法當場安裝我們的 SDK,但它可以載入一個 URL。對話從「把二進位檔寄給我」變成「打開這個連結」。那是另一種層次的對話。瀏覽器示範會留在固定班底裡。

行動平台閃電戰

三月的另一半是 iOS 和 Android,兩者在同一週出貨。

Android。F1 系列的十二個 commit(F1.2 到 F1.15),從 NativeActivity 和 JNI 橋接骨架開始,到 Android 效能剖析器結束。中間包括:透過 JNI 接上觸控輸入、AAB 建置的 GitHub Actions 工作流程、Firebase Crashlytics 整合,以及啟用 Oboe 作為音訊後端。Oboe 是 Android 上低延遲音訊的正確選擇。包在它外面的 C API 包裝層,讓同一套音訊回呼可以跨平台運作。

iOS。F2 系列的七個 commit(F2.1 到 F2.7),花了兩天。從 Xcode 專案和 Swift 應用程式外殼開始。加了 arm64 交叉編譯工具鏈。接上 Metal 作為渲染器(F2.2 的 commit 訊息寫著「iOS Metal renderer integration, glue layer, CMake toolchain, 51 tests」,測試數量是我最自豪的部分)。透過 UIGestureRecognizer 加入手勢輸入。在 AVAudioEngine 之上蓋了空間音訊後端。透過 URLSession 接上資產包下載與快取。

兩個平台拿到的是同一種形狀:一層薄薄的原生層,把觸控、音訊、GPU 和資產遞送暴露給桌面執行期使用的同一套 C API。那就是契約。平台專屬的程式碼是實作。從這裡開始,新增一個平台是一種已知的形狀,不是一個沒有邊界的架構難題。

空間音訊是被低估的勝利

我一直被問到的那件工作是空間音訊。標頭檔在 include/raku/raku_spatial_audio.h。實作依平台切分:HRTF 處理負責空間定位、混音器群組負責逐聲道控制、效果(殘響、延遲),以及用於房間聲學的殘響區域。Android 上的音訊路徑是 Oboe。iOS 上是 AVAudioEngine。空間音訊的 commit 是 3 月 6 日的 e0aef6c6

這對 AR 引擎之所以重要,是因為音訊佔了臨場感的一半。視覺 AR 配上立體聲(或更糟,單聲道)音訊,使用者一轉頭沉浸感就碎了。會隨使用者移動而更新的空間音訊,讓虛擬內容感覺就在房間裡。成本是真實的:HRTF 處理不是免費的。收益也是真實的:從來沒有人在體驗過一次好的空間音訊示範之後,回頭要求把它關掉。

GDC 真正推動了什麼

三件值得寫下來的事。

合作夥伴對話。走廊上的對話和場邊會議,現在正一場場排上行事曆。大會的演講很精彩。但演講與演講之間的對話,才是這趟出差值回票價的原因。等未來某個星期六我專門寫合作夥伴方向時,這些線頭就是主要內容。

對這個領域現況更清楚的判讀。有世界模型的場次、有 AI 驅動內容管線的場次、有研究示範與可出貨執行期之間鴻溝的場次,還有幾家不同廠商的空間 AR 硬體路線圖。我對競爭版圖的一些假設是對的。幾件我一直默默擔心的事,結果威脅比我想的小。幾件我原本沒在擔心的事,結果值得更多注意。光是這次校準就值回機票了。

繼續前進的許可。GDC 是一個強制函數。我帶著到處跑的示範並不完美。但它是具體的,是一個跑著真實程式碼的真實引擎,回答的是和簡報完全不同類別的問題。「請寄後續資料給我」的回應數量之高,足以確認方向是對的。那就是指標。

行動平台出貨了。我展示的示範都能動。瀏覽器後備方案變成了一項特色。這個星期六用得值得。

為你臉上那台裝置打造的執行期

一套 C API、無所不在的空間音訊,以及一個為智慧眼鏡設計、具備熱感知的執行期——不是硬塞進去的 PC 引擎。看看你的 AI 在真實世界裡住在哪裡。

← 所有文章