跳轉到主要內容

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

This section explains, by exemplifying with a clock application, how to configure and use Partial Frame Buffers with a display with GRAM, to lower memory requirements at the expense of some performance.

下面是在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個像素。 在使用標準影像緩衝區時,這些矩形會被存入完整個影像緩衝區中(覆蓋之前的像素),完整影像緩衝區隨後被傳輸到顯示器。 在使用部分影像緩衝區時,這三個矩形會被存入它們自己的小影像緩衝區中,小影像緩衝區隨後立即被傳輸到顯示器並予以顯示。

配置部分影像緩衝區

The following steps are required for TouchGFX to use partial frame buffers:

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

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

Further reading
Read the TouchGFX Generator User Guide for information about how to configure partial frame buffers.

An example configuration with 3 partial framebuffer block of size 1920bytes used to draw the updates areas from the above section is shown below.

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

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

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

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

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

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

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

將影像緩衝區傳輸到螢幕

The implementation of the code to transfer partial framebuffer blocks to the display depends on the display interface use. For examples on how this can be done, see the following articles:

結論

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