這是一個由 @icculus、@madebr、@glebm、@jayschwa、@ccawley2011 以及我共同完成的專案,我負責最後的穩定性修復和遺漏的功能補齊,感謝所有人的貢獻。

這是對 DOS 的一個相當完整的移植,僅遺漏了音訊錄製等少數功能。我已在 DOSBox 中使用 DevilutionX 進行了廣泛測試,但未在真實硬體上進行測試。我未添加的功能主要是因為沒有好的方法來測試它們是否能正確運作。

在多執行緒方面,我從 PS2 的移植中獲得了一些概念啟發。

恭喜!SDL3 for DOS 是一項了不起的成就!

我們已快速將我們的遊戲移植與之整合,所有核心系統都已正常運作,包括期待已久的多執行緒音訊,音效表現非常出色!

然而,目前 Ad Lib FM 背景音樂出現了速度問題。我們的專案主要使用 Ad Lib 音樂和 MIDI 作為背景音樂,並希望在 DOS 下使用音效卡硬體來降低 CPU 負載。請問是否有一個頻率較高(39Hz 或以上)且相對穩定、受 CPU 負載影響最小的時脈機制?或者我們應該改變方法?謝謝!

計時器以 1.19MHz 運行,應該是精確的。軟體 MIDI 播放器可能會非常消耗 CPU,我們或許可以在 SDL mixer 中透過 OPL 讓 MIDI 音樂運作,我已經有一些基礎功能。

計時器以 1.19MHz 運行,應該是精確的。軟體 MIDI 播放器可能會非常消耗 CPU,我們或許可以在 SDL mixer 中透過 OPL 讓 MIDI 音樂運作,我已經有一些基礎功能。

1.19MHz?哇,我認為這應該足夠精確了。我需要看一下...

順帶一提,不只是 MIDI。我們使用自訂的 AdPlug 直接操作 OPL2/3 來播放背景音樂。

我們檢查了程式碼,確實,計時器沒問題,但我們如何實現高於 19.8Hz(18.2Hz)的回呼(callback)呢?

計時器以 1.19MHz 運行,應該是精確的。軟體 MIDI 播放器可能會非常消耗 CPU,我們或許可以在 SDL mixer 中透過 OPL 讓 MIDI 音樂運作,我已經有一些基礎功能。

我們檢查了程式碼,確實,計時器沒問題。但我們如何實現高於 19.8Hz 的回呼呢?

我不知道 19.8Hz 是從哪裡來的,那是你的 FPS 嗎?如果是的話,在你的遊戲迴圈中加入一些 SDL_Delay(0) 來更頻繁地進行任務切換,然後你就可以呼叫事件迴圈了。

計時器以 1.19MHz 運行,應該是精確的。軟體 MIDI 播放器可能會非常消耗 CPU,我們或許可以在 SDL mixer 中透過 OPL 讓 MIDI 音樂運作,我已經有一些基礎功能。

我們檢查了程式碼,確實,計時器沒問題。但我們如何實現高於 19.8Hz 的回呼呢?

我不知道 19.8Hz 是從哪裡來的,那是你的 FPS 嗎?如果是的話,在你的遊戲迴圈中加入一些 SDL_Delay(0) 來更頻繁地進行任務切換,然後你就可以呼叫事件迴圈了。

哦,抱歉,是我們的錯誤,是 18.2Hz。

你可以透過計算目前 CPU 上某些指令需要花費多少時間,然後增加或減少更多指令來獲得所需的延遲,從而衍生出你自己的計時器。

抱歉!現在我會試著重新組織我的話,希望能釐清問題。

我們使用 SDL_Timer 實現了 Ad Lib 音樂播放,但發現播放速度受到系統其他部分負載的影響太大。例如,每當畫面上出現 CPU 密集的效果時,音樂速度就會明顯變慢。

因此,我們希望使用 IRQ0 的 ISR 來播放背景音樂,但 18.2Hz 的預設頻率對於硬體 Ad Lib 音樂來說不夠精確。我們希望有一個更高頻率的穩定時脈。然而,據我們所知,自行重新編程這個頻率會導致整個系統出現故障。我們該怎麼辦?

便宜的解決方案是在你的程式碼中散佈 SDL_Delay(0),可能是在執行重度效果的程式碼前後。這樣你就可以比你的幀率允許的更頻繁地將控制權交給其他執行緒。然而,如果你的目前聲音產生依賴於精確計時而不是僅僅頻繁計時,那麼這將無法解決問題。

在這種情況下,你必須確保你的音樂執行緒是安全重入的(沒有 malloc / free),然後將它與現有的中斷鏈接起來。這與 Sound Blaster 驅動程式的工作方式類似。

然而,如果你的目前聲音產生依賴於精確計時而不是僅僅頻繁計時,那麼這將無法解決問題。

確實需要精確計時,至少足以驅動節拍器。先前的測試表明,雖然 18.2Hz 可以產生音樂,但聽起來像是一個節奏不穩的樂團在演奏。

在這種情況下,你必須確保你的音樂執行緒是安全重入的(沒有 malloc / free),然後將它與現有的中斷鏈接起來。這與 Sound Blaster 驅動程式的工作方式類似。

明白了。是否有針對此方法的特定演示?哪個現有的中斷會更合適?非常感謝!

在這種情況下,你必須確保你的音樂執行緒是安全重入的(沒有 malloc / free),然後將它與現有的中斷鏈接起來。這與 Sound Blaster 驅動程式的工作方式類似。

感謝您的見解!正如您所指出的,「便宜的解決方案」(SDL_Delay(0))無法保證裸機硬體音樂播放所需的絕對精確計時。

遵循您關於鏈接現有中斷的建議,我們的 vclock 實作透過雙管道架構來實現這一點,確保系統完全安全:

這完美地滿足了您提到的精確計時和重入性限制。請參閱:sdlpal/sdlpal@ 71338f6

這是一項傑出的成就。@AJenbo 和 @icculus - 非常感謝您們!這真正賦予了復古運算場景和向後相容性趨勢力量。

這方面有遇到什麼具體問題嗎?我記得使用 Sound Blaster 錄製音訊並不比播放困難多少。但可能我不知道所有細節。(雙關語)

共享函式庫載入支援(無 SDL_LoadObject)。

謹啟:一般來說,即使這也應該是可行的——DJGPP 有自己的支援來處理這類事情。https://www.delorie.com/djgpp/v2faq/faq22_15.html https://www.freebasic.net/forum/viewtopic.php?t=20929

是的,我並不反對 DXE 支援,只是還沒有人實作。

至於錄製:我認為 Sound Blasters 是半雙工的(它們可以錄製或播放,但不能同時進行),而且沒有人想處理這個問題。

這方面有遇到什麼具體問題嗎?我記得使用 Sound Blaster 錄製音訊並不比播放困難多少。但可能我不知道所有細節。(雙關語)

我確實找到了一個應該可以工作的麥克風,但最終我太懶了沒去實作。

是的,我並不反對 DXE 支援,只是還沒有人實作。

有一個草稿在 #15459,已經有一段時間沒有被關注了。

如果問題已解決,讓我們合併它。我們仍然需要 loadso 支援來載入隨機的 dxe 檔案,但這將使我們更接近啟用 dynapi 支援。

看來 SDL 對 OpenGL 的支援(SDL_GL_* 常式)也應該加入這個列表,不是嗎?

@icculus 請問,鑑於已新增 DOS 支援,現在將舊的圖形加速 API 渲染器後端加入的政策是什麼?例如 3dfx Glide,儘管當時有很多這類 API。

我開始著手 Glide 後端,但它有嚴重的限制:紋理必須是 2 的冪次方,不能超過 256x256,沒有渲染目標等等,所以我放棄了。

我並不反對合併 PR,如果有人完成了工作,因為對於許多 2D 遊戲來說,這些限制並不重要,並且可以在那些情況下顯著提高幀率,但我認為它將永遠是一個可選的 API,因為軟體渲染器在 Glide 會失敗的合理情況下不會失敗。

在 Lego Island 中,我直接將 Glide 作為其後端之一進行了實作:https://github.com/isledecomp/isle-portable/blob/master/miniwin/src/d3drm/backends/glide/renderer.cpp 它會將紋理調整到最接近的允許大小。

正如 icculus 所說,有很多陷阱,紋理不能跨越 2MB 的邊界,而且 Glide 支援的偵測不僅僅是有一點點損壞,所以掃描 PCI 供應商 ID 會更安全:https://github.com/isledecomp/isle-portable/blob/master/miniwin/src/internal/d3drmrenderer_glide.h#L105

為了繞過 256x256 的紋理限制,它在繪製大型 2D 圖像時直接將圖像寫入線性幀緩衝區(這意味著只有 3D 得到完全硬體加速)。請注意,我只在模擬器上測試過該實作(DOSBox-x 上的 Voodoo 1 和 PCem 上的 Voodoo 3),所以我不能確定實際效能如何。

附註:我認為如果他們無法合理地實作 SDL_Renderer,我會建議將其作為一個外部函式庫。

感謝兩位的回答。我隱約記得有 Glide 的 GL 包裝器可以繞過這些陷阱。但我不確定細節,也不知道它們是否支援 DOS。

成功合併此合併請求可能會關閉這些問題。