This article describes how the bitmap caching system can be used to create applications where the total size of the bitmaps is greater than the amount of RAM available. The techniques are mostly relevant if your external flash is not memory mapped.
- This article applies only to TouchGFX release 4.5 and later
Recall that bitmaps must be placed in addressable flash or RAM to be useable for TouchGFX.
The most basic setup is to have the bitmaps placed in external flash. The bitmaps are copied directly from the external flash to the frame buffer in RAM when shown on the LCD.
When your bitmaps are not stored in addressable flash (but maybe in a serial flash or sdcard) this setup will not work. The bitmaps must be copied to the bitmap cache. See the article Non-memory mapped external flash for an introduction to setting up bitmap caching.
Partiel Bitmap caching
When the amount of RAM that you can allocate for your bitmap cache is less than the total size of the bitmaps you can not cache all the bitmaps during startup.
You need to cache only the bitmaps needed for the first screen. When you change between your screens you can remove some or all of the cached bitmaps and cache the bitmaps needed for the next screen.
Cache Operations
The bitmap caching operations are all placed in the Bitmap class.
static bool Bitmap::cache(BitmapId id)
This method caches a bitmap. The bitmap is only cached if enough unused memory is available in the cache. Returns true if the bitmap was cached.
static bool Bitmap::cacheReplaceBitmap(BitmapId out, BitmapId in)
This method replaces a bitmap (out) in the cache with another bitmap (in). The method will only succeed if the bitmap to be replaced is cached and if the bitmaps have the same size (in bytes).
static bool Bitmap::cacheRemoveBitmap(BitmapId id)
This method removes a bitmap from the cache. The memory used by the bitmap can be used for caching of another bitmap afterwards.
static void Bitmap::clearCache()
This method removes all the cached bitmaps from the cache.
static void Bitmap::cacheAll()
This method caches all bitmaps. It can not be used if the amount of RAM allocated for the cache (or available) is less than the total size of the bitmaps.
The next two sections will describe two strategies for caching the needed bitmaps in a setup where your RAM cache is not large enough to hold all the bitmaps in your application.
Cache Bitmap on a Screen basis
Your application user interface is composed of a set of Views. The Views probably all use some bitmaps.
A simple strategy for caching is to cache all the bitmaps used by a View in the View::setupScreen method and clear the cache in the View::tearDownScreen method:
void Screen1View::setupScreen()
{
//ensure background is cached
Bitmap::cache(BITMAP_SCREEN2_ID);
//cache some icons
Bitmap::cache(BITMAP_ICON10_ID);
Bitmap::cache(BITMAP_ICON11_ID);
Bitmap::cache(BITMAP_ICON12_ID);
}
void Screen1View::tearDownScreen()
{
Bitmap::clearCache();
}
The memory requirement for the cache is the size of the bitmaps used by the "largest" screen.
The drawback of this method is that if two Views both use a bitmap, the bitmap will be erased from the cache on exit from the first View and cached again on entry to the second View.
The Bitmap::cacheRemoveBitmap can be used to selective uncache bitmaps and thus reduce this overhead. The drawback of the cacheRemoveBitmap is that the cache memory will be fragmented.
Replace the background Bitmap
If your application have a set of minor bitmaps (e.g. icons) and some full screen "background" bitmaps another strategy can be advised:
Cache all the small bitmaps prior to entering the first screen. A good place to do this is in the FrontendApplication constructor. Also cache the background bitmap for the first screen:
FrontendApplication::FrontendApplication(Model& m, FrontendHeap& heap)
: touchgfx::MVPApplication(),
transitionCallback(),
frontendHeap(heap),
model(m)
{
//cache some icons
Bitmap::cache(BITMAP_ICON10_ID);
Bitmap::cache(BITMAP_ICON11_ID);
Bitmap::cache(BITMAP_ICON12_ID);
//cache first background
Bitmap::cache(BITMAP_SCREEN1_ID);
backgroundBitmapCached = BITMAP_SCREEN1_ID; //remember ID
}
In the setupScreen method replace the cached background bitmap with the required bitmap:
Screen1View::setupScreen()
{
//ensure background is cached
Bitmap::cacheReplaceBitmap(backgroundBitmapCached, BITMAP_SCREEN1_ID);
backgroundBitmapCached = BITMAP_SCREEN1_ID;
}
void Screen1View::tearDownScreen()
{
//nothing cache related
}
The memory requirement for the cache is the size of the cached bitmaps and one background bitmap. Compared to the previous method the code is simpler to maintain as the views has less code. The performance is better as we move less bitmaps in and out of the cache.
The cacheReplaceBitmap operation is preferable to the cacheRemoveBitmap method as it does not fragment the memory.
Cache Memory Management
In order to get the full effect of the bitmap caching it is necessary to understand the internal operations of the cache.
The cache is implemented as a stack. New bitmaps are cached on top of the previously cached bitmaps. Memory used by a bitmap is marked as "free" when the bitmap is removed from the cache. The memory is not immediately useable unless the removed bitmap was on top of the stack.
If the bitmap was in "the middle" a compacting operation is performed the next time Bitmap::cache is called to reclaim the memory. This "costly" method can be avoided if you do not call Bitmap::cache with a "hole" in the cache.
The drawings below illustrates the principles.
Caching allocates on top of the previously allocated bitmaps:
Removal marks the used memory:
Allocating the next bitmap compacts the cache and allocates on the top:
When you remove the topmost (last allocated) bitmap is the memory freed immediately along with any free memory just below it:
The next cache operation will in this case not involve a compact.