黃爸爸狗園

本園只有sanitizer,沒有狗籠

0%

GBA圖形處理邏輯模擬 (一)

cover

GBA模擬器的開發之路,如果說CPU部分是思考"我到底該怎麼做才對",那圖形的部分就會是"我到底要怎麼做才會"

本系列文將會把重點聚焦在如何正確的實作一個GBA的圖形系統模擬函式庫,並提出一些手法來提升模擬的效率

GBA圖形系統規格

相較於近代的主機都普遍配有GPU來負責圖形渲染工作,GBA也有一塊獨立於CPU的處理邏輯負責圖形工作,也就是PPU(Pixel Processing Unit)

我們可以先來看一下PPU主要提供那些圖形處理功能: 1. 輸出畫面為240*160 pixels 2. 色彩格式為RGB555 3. 具有以下兩種渲染模式: - Tile based: 基於利用尺寸為8*8的tile組合畫面,具有渲染速度快,還可以利用硬體仿射變換功能 - Bitmap based: 直接由CPU將圖形資料以Pixel為單位寫入VRAM,自由度較高但效率差,須妥善利用DMA來實作 4. 最大支援128個Sprites於螢幕上顯示 5. 支援數種圖形特效: - Rotation/Scaling - alpha blending - fade-in/out - mosaic - window

記憶體區段

PPU的工作記憶體位於0x0500'0000~0x07ff'ffff,不同的段落具有不同的用途,描述如下:

memory map
  1. Palette memory: 0x0500'0000 ~ 0x0500'03ff
    • 功用為調色盤,一分為二,前半段為背景專用,後半段為OBJ使用
    • 各具有256色,皆為RGB555格式
    • Bus為16 bit
  2. Video RAM(VRAM): 0x0600'0000 ~ 0x0601'7fff
    • 圖形系統的主記憶體,內容會根據繪圖模式有所不同,後面會詳述
    • Bus為16 bit
  3. OBJ Attributes(OAM): 0x0700'0000 ~ 0x0700'03ff
    • 用於描述各Sprite的屬性,以及Sprite在作仿射變換時所使用的矩陣內容
    • Bus為32 bit

聰明的小吉們應該有注意到一件事,我們在上面提到的address為0x0500'0000~0x07ff'ffff

但是下面再說明功能的時候,描述的範圍只有一部分,那剩下沒有涵蓋到(途中的黑色部分)的部分到底有沒有用???

這裡就必須要提及GBA系統的Undefined behavior,其中的Memory mirror章節有提到GBA硬體的Bus在面對這些奇怪的R/W時會有那些行為

具體模擬的細節我會在MMU相關的文章內作說明

開發環境

我們的目標是要設計一個負責繪製GBA遊戲畫面的library,而非完全地將邏輯內嵌至模擬器主程式內,所以為了讓我們可以在沒有模擬除了PPU以外的功能的狀態下也能夠對PPU進行debug,我們勢必要開發一個前端,去調用PPU library所開出的介面來產生畫面

重點來了,阿你就沒有模擬整個系統,PPU怎麼會知道要繪製什麼東西???

pic

而問題的答案也很簡單,找另外一個模擬器,直接去dump他的memory再寫進我們的PPU memory即可

有一個除錯器NO$GBA可以幫我們做到這件事情,我們在後續的開發流程也會持續的使用這個工具來協助我們釐清問題

模擬流程

上面的說明中我有特別提到PPU在GBA系統中扮演的角色類似於我們現代電腦系統的GPU,但是其工作原理其實與GPU差異很大

現在的GPU基本上擅長一次處理大量的頂點或貼圖資料,但GBA的繪製流程是以scanline為單位,一條一條畫,同時繪圖狀態會根據H-Blank與V-Blank作變化

因此,我們並不會直接就利用GPU來繪製我們模擬器的遊戲畫面,而是先行使用CPU在main memory上產生出pixel format為RGB555的frame buffer後,緊接著一次做完整個畫面的RGB555 to RGBA8888的轉換,最後一步才是透過ImGUI把buffer的內容轉成texture,交由GPU渲染。