跳轉到主要內容

通過部分影像緩衝降低記憶體使用率

本節透過時鐘應用程式範例,說明如何在含 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 使用局部影像緩衝區,需要執行以下步驟:

  1. 用記憶體緩衝區創建影像緩衝區分配器物件
  2. 配置TouchGFX HAL類以使用該分配器
  3. 寫入程式碼以將緩衝區傳輸至顯示器

步驟1和2由TouchGFX Generator通過STM32CubeMX自動生成,而步驟3是一個專用驅動程式,用於將像素傳輸至顯示器。

Further reading
閱讀 TouchGFX Generator 使用者指南,瞭解如何設定局部影像緩衝區。

以下設定範例使用 3 個大小為 1920 位元組的局部影像緩衝區區塊, 來繪製上節所述的更新區域。

首先來看分配用於繪製小圓圈更新的兩個影像緩衝區的位置和大小(上面第二幅圖) (假設24Bpp):

矩形xy寬度高度像素
矩形1112562214308個像素 = 924位元組
矩形2153422911319個像素 = 957位元組

這些矩形都很小,可以放入由影像緩衝區分配器分配的塊中。

在上面的第三幅圖中,更新了3個矩形:小矩形更新圓圈,較大的矩形覆蓋文字:

矩形xy寬度高度像素
矩形1126512012240個像素 = 720位元組
矩形216542338264個像素 = 792位元組
矩形3118165154609,240個像素 = 27,720位元組

同樣地,矩形1和2很小,可以放入由影像緩衝區分配器分配的塊中,但影像緩衝區3過大。 此矩形過大,將分成多個可放入影像緩衝區(11,700位元組)的矩形。

這裡我們更新了3個矩形,但分配器只有2個塊。 在這種情況下,TouchGFX將等待第一個塊傳輸完畢,然後重複使用塊。

將影像緩衝區傳輸到螢幕

將局部影像緩衝區塊傳輸到顯示器的程式碼實作, 具體取決於使用的顯示器介面。 如需操作範例, 請參閱以下文章:

結論

在本文中,我們討論了對於顯示器具有集成影像緩衝記憶體的平臺而言,部分影像緩衝區策略如何降低其存儲空間要求。