通過部分影像緩衝降低記憶體使用率
本節透過時鐘應用程式範例,說明如何在含 GRAM 的顯示器上,設定並使用局部影像緩衝區來降低記憶體需求 (需犧牲部分效能)。
下面是在STM32L4R9Discovery評估套件上運行的應用的影片
完整影像緩衝記憶體
影像緩衝區通常是一個大型記憶體陣列,其存儲空間足以容納顯示器上的所有可用像素。 如果在解析度為480 x 272的24位元顯示器上執行,則完整大小的影像緩衝區可容納480 x 272 x 3位元組 = 391,680位元組。
一些應用可能有2(“雙重緩衝”)甚至3個影像緩衝區。 在這種情況下,要求的總儲存空間將是783,360和1,175,040位元組。
在繪製UI的任何一個部分時,TouchGFX向影像緩衝區寫入像素值,在所有繪製操作完成後,影像緩衝區被傳輸到顯示器。 通常會將整個影像緩衝區傳輸到顯示器,即使只更新了UI的一部分。 在傳輸前,通常可以將影像緩衝分成許多小塊進行更新。
更新1、更新2、更新3、……、更新N,傳輸至顯示器
在某些情況下,特別是在沒有外部RAM的低成本解決方案中,影像緩衝區必須足夠小,以使應用程式的其餘部分能夠和影像緩衝共用內部RAM。 部分影像緩衝區在這種情況下十分有用。
部分影像緩衝記憶體
部分影像緩衝區使TouchGFX應用程式能夠在幾個小於完整大小的影像緩衝區之上運行。 影像緩衝區的數量和大小是可配置的。 此技術可大幅降低應用程式的存儲空間要求,但也帶來了一些限制:
- 部分影像緩衝區只能在具有內置記憶體的顯示器上工作。 這些顯示器通常是DSI顯示器或具有平行匯流排連接(DBI A/B型,8080/6800)或SPI匯流排連接的顯示器。
- 複雜應用可能發生撕裂。
不同於使用影像緩衝區將每一個像素顯示在顯示器上,部分影像緩衝區通常只覆蓋部分區域。 在本文使用的時鐘範例中,使用了三個大小均為11,700位元組的影像緩衝區。 這會導致影像緩衝區佔用記憶體35,100位元組的空間。
當應用程式需要更新UI的某一部分時,TouchGFX將選擇配置的部分影像緩衝區中的其中一個,在該部分影像緩衝中完成其繪圖操作,並將該部分傳輸到顯示器。 將對需要渲染的所有UI區域重複此操作 - 這會將更新和傳輸資料的公式變更為:
更新1、傳輸1、更新2、傳輸2、更新3、傳輸3、……、更新N、傳輸N
在某些情況下,可以在更新下一個緩衝區的同時進行一個部分影像緩衝區的傳輸。
顯示器畫面撕裂
相比於使用完整影像緩衝區,在使用部分影像緩衝區時,TouchGFX傳輸UI上更新的更快。 由於顯示器需要定期刷新,在最多16 ms後(就60 fps顯示器而言),顯示器將在其螢幕上顯示接收到的更新。 因此,在所有更新傳輸完畢之前,對顯示器的最初更新可能會被用戶注意到。
如果繪圖操作和傳輸的完整序列需要花費較長時間才能完成( > 16 ms),則用戶很可能會看到上一幀與下一幀的組合。 這被稱為畫面撕裂。 因此,部分影像緩衝區不適合使用複雜動畫、需要長時間渲染的應用。
顯示器更新範例
在討論如何在應用程式中配置部分影像緩衝區之前,我們先來看一個具體範例,該範例顯示了一個用移動的圓弧代表秒數的數位時鐘。 綠色圓弧每秒移動6度,一分鐘完成一整圈。 用如下圖所示的四個小部件構建UI:
以下是更新數位時鐘和圓弧的程式碼:
MainView.cpp
void MainView::handleTickEvent()
{
ticks++;
if (ticks == 10)
{
ticks = 0;
secs += 1;
if (secs == 60) //increment minutes
{
secs = 0;
min += 1;
if (min == 60) //increment hours
{
min = 0;
hour += 1;
if (hour == 24)
{
hour = 0;
}
}
//Only update digital clock when minutes or hours change
digitalClock.setTime24Hour(hour, min, secs);
}
//Always update seconds
circleSeconds.updateArc(secs*6 - 20, secs*6);
}
}
下圖所示為在圓弧接近頂點和數位時鐘更新時前幾秒更新的區域(灰色矩形)。 在前兩幀中,只有秒數在變化(第58和59秒)。 在第三幀中,秒數達到60,小時和分鐘的文字更新:
上面第三幅圖像中更新的矩形為154 x 60個像素、20 x 12個像素和33 x 8個像素。 在使用標準影像緩衝區時,這些矩形會被存入完整個影像緩衝區中(覆蓋之前的像素),完整影像緩衝區隨後被傳輸到顯示器。 在使用部分影像緩衝區時,這三個矩形會被存入它們自己的小影像緩衝區中,小影像緩衝區隨後立即被傳輸到顯示器並予以顯示。
配置部分影像緩衝區
為了讓 TouchGFX 使用局部影像緩衝區,需要執行以下步驟:
- 用記憶體緩衝區創建影像緩衝區分配器物件
- 配置TouchGFX HAL類以使用該分配器
- 寫入程式碼以將緩衝區傳輸至顯示器
步驟1和2由TouchGFX Generator通過STM32CubeMX自動生成,而步驟3是一個專用驅動程式,用於將像素傳輸至顯示器。
Further reading
以下設定範例使用 3 個大小為 1920 位元組的局部影像緩衝區區塊, 來繪製上節所述的更新區域。
首先來看分配用於繪製小圓圈更新的兩個影像緩衝區的位置和大小(上面第二幅圖) (假設24Bpp):
矩形 | x | y | 寬度 | 高度 | 像素 |
---|---|---|---|---|---|
矩形1 | 112 | 56 | 22 | 14 | 308個像素 = 924位元組 |
矩形2 | 153 | 42 | 29 | 11 | 319個像素 = 957位元組 |
這些矩形都很小,可以放入由影像緩衝區分配器分配的塊中。
在上面的第三幅圖中,更新了3個矩形:小矩形更新圓圈,較大的矩形覆蓋文字:
矩形 | x | y | 寬度 | 高度 | 像素 |
---|---|---|---|---|---|
矩形1 | 126 | 51 | 20 | 12 | 240個像素 = 720位元組 |
矩形2 | 165 | 42 | 33 | 8 | 264個像素 = 792位元組 |
矩形3 | 118 | 165 | 154 | 60 | 9,240個像素 = 27,720位元組 |
同樣地,矩形1和2很小,可以放入由影像緩衝區分配器分配的塊中,但影像緩衝區3過大。 此矩形過大,將分成多個可放入影像緩衝區(11,700位元組)的矩形。
這裡我們更新了3個矩形,但分配器只有2個塊。 在這種情況下,TouchGFX將等待第一個塊傳輸完畢,然後重複使用塊。
將影像緩衝區傳輸到螢幕
將局部影像緩衝區塊傳輸到顯示器的程式碼實作, 具體取決於使用的顯示器介面。 如需操作範例, 請參閱以下文章:
結論
在本文中,我們討論了對於顯示器具有集成影像緩衝記憶體的平臺而言,部分影像緩衝區策略如何降低其存儲空間要求。