Buffer Refresh Strategy

Overview

The Buffer Refresh Strategy (BRS) ensures that the front buffer contains all the drawings before letting the display driver flush this buffer into the display panel. The drawings are the drawings made since the last flush and the past. The past symbolizes the drawings made before the last flush and that has not been altered by the new drawings.

Automatic Refresh
Drawing Steps Back Buffer Front Buffer
Startup ../_images/ui_brs0.png ../_images/ui_brs0.png
Draw “background” ../_images/ui_brs1.png ../_images/ui_brs0.png
Draw “A” ../_images/ui_brs2.png ../_images/ui_brs0.png
Flush (swap) ../_images/ui_brs0.png ../_images/ui_brs2.png
Draw “B” ../_images/ui_brs3.png ../_images/ui_brs2.png
Refresh the past ../_images/ui_brs4.png ../_images/ui_brs2.png
Flush (swap) ../_images/ui_brs2.png ../_images/ui_brs4.png

This refreshing avoids running again all drawing algorithms (and layout) to fill the back buffer (here: the entire background, the “A” green background, and the “A”). Without this refreshing, the display will show the incomplete frame Draw “B”:

Missing Refresh
Drawing Steps Back Buffer Front Buffer
Startup ../_images/ui_brs0.png ../_images/ui_brs0.png
Draw “background” ../_images/ui_brs1.png ../_images/ui_brs0.png
Draw “A” ../_images/ui_brs2.png ../_images/ui_brs0.png
Flush (swap) ../_images/ui_brs0.png ../_images/ui_brs2.png
Draw “B” ../_images/ui_brs3.png ../_images/ui_brs2.png
Flush (swap) ../_images/ui_brs2.png ../_images/ui_brs3.png

When the new drawings overlap the past, it is useless to refresh the past:

Useless Refresh
Drawing Steps Back Buffer Front Buffer
  ../_images/ui_brs2.png ../_images/ui_brs4.png
Draw “C” ../_images/ui_brs5.png ../_images/ui_brs4.png
Flush (swap) ../_images/ui_brs4.png ../_images/ui_brs5.png
Draw “D” ../_images/ui_brs6.png ../_images/ui_brs5.png
Flush (swap) ../_images/ui_brs5.png ../_images/ui_brs6.png

Timeline

Basic Principle

This illustration symbolizes the basic principle of the Graphics Engine’s timeline:

../_images/ui_brs_line4.png
  • drawing(s) symbolizes one or several drawings in the back buffer.
  • flush symbolizes the call to the LLAPI LLUI_DISPLAY_IMPL_flush() that allows the display driver to update the display panel content according to the display connection (serial or parallel).
  • post-flush symbolizes the moment between the end of flush (end of swap, end of transmission, or end of copy) and the unlocking of the Graphics Engine (the call to LLUI_DISPLAY_setDrawingBuffer()). Before this call, the Graphics Engine is not allowed to draw in the buffer.

Note

The time between the post-flush and drawing(s) depends on the application: the first drawing after a flush can occur immediately after the post-flush or later.

Additional Hooks

The Graphics Engine provides some hooks (through dedicated LLAPI) to be notified of further details:

../_images/ui_brs_line5.png
  • new region symbolizes that the following drawing(s) will be drawn in a region other than the previous drawings.
  • refresh symbolizes that the last drawing has been done, and a call to LLUI_DISPLAY_IMPL_flush() will be performed just after.

During these two new steps, the implementation can render into the back buffer (to restore the past), prepare the next flush (store the regions to flush), etc.

Implicit Region

A region is considered a new implicit region as soon as the MicroUI clip is updated and a drawing is performed. When a clip is considered an implicit region, a call to the LLAPI LLUI_DISPLAY_IMPL_newDrawingRegion(...) is performed. The following sequence illustrates when the LLAPI is called:

  Application Calls LLAPI
1 gc.setClip(...)  
2 [1] Painter.drawXX(...)
LLUI_DISPLAY_IMPL_newDrawingRegion(..., true)
LLUI_PAINTER_IMPL_drawXX(...)
3 [2] Painter.drawYY(...) LLUI_PAINTER_IMPL_drawYY(...)
4 [3] gc.setClip(...)  
5 gc.setClip(...)  
6 Painter.drawZZ(...)
LLUI_DISPLAY_IMPL_newDrawingRegion(..., true)
LLUI_PAINTER_IMPL_drawZZ(...)
[1]The LLAPI argument drawing_now is valued to true: this means a call to a drawing action will be called just after (implicit region).
[2]The second drawing uses the same region as the first one: the region is not notified again.
[3]The clip is not recognized as an implicit region because no drawing is performed just after.

Note

The very first drawing’s region after a flush is systematically considered as implicit.

Explicit Region

The application can explicitly call the LLAPI LLUI_DISPLAY_IMPL_newDrawingRegion(...) by calling the API GraphicsContext.notifyDrawingRegion(). The LLAPI parameters are:

  • the region is the current MicroUI clip,
  • the argument drawing_now is valued to false: this means no drawing will follow this call (explicit region).

Declaring explicit regions is mainly useful when it is performed before the very first drawing. It indicates to the BRS that several regions will be altered before the next flush. These regions don’t need to be restored with the past (their content will change).

  Application Calls LLAPI
1 gc.setClip(...)  
2 [4] gc.notifyDrawingRegion(...) LLUI_DISPLAY_IMPL_newDrawingRegion(..., false)
3 [5] Painter.drawXX(...)
LLUI_DISPLAY_IMPL_newDrawingRegion(..., true)
LLUI_PAINTER_IMPL_drawXX(...)
4 Painter.drawYY(...) LLUI_PAINTER_IMPL_drawYY(...)
5 [6] gc.notifyDrawingRegion(...) LLUI_DISPLAY_IMPL_newDrawingRegion(..., false)
6 [7] Painter.drawZZ(...) LLUI_PAINTER_IMPL_drawZZ(...)
[4]The LLAPI is immediately called.
[5]The step 2 doesn’t change the flow of the implicit region: a call to LLUI_DISPLAY_IMPL_newDrawingRegion(..., true) is always performed even if a call to LLUI_DISPLAY_IMPL_newDrawingRegion(..., false) is performed just before.
[6]The clip has not changed, but the LLAPI is explicitly called again.
[7]The clip has not changed, so the implicit region is not notified.

Flush vs Refresh

The Graphics Engine does not store the regions (implicit or explicit). The BRS is responsible for implementing the LLAPI (the hooks, see above) and managing these regions.

When the application calls Display.flush(), the Graphics Engine immediately calls the LLAPI LLUI_DISPLAY_IMPL_refresh(). This call allows the BRS:

  • to finalize (if required) the back buffer (no drawing will be performed into the buffer until the next call to LLUI_DISPLAY_setDrawingBuffer()),
  • and to call the LCD driver flush function LLUI_DISPLAY_IMPL_flush() by giving the region(s) to update on the display panel.

Strategies

Several strategies are available according to different considerations:

  • the display connection (serial or parallel),
  • the buffer policy (direct, single, swap),
  • if the past has to be restored,
  • if the past is systematically restored,
  • when the past is restored,
  • etc.

The following chapters describe the strategies:

Strategy: Single

Principle

This strategy considers that the drawings are always performed in the same back buffer (single buffer policy). In this case, the restoration is useless because the back buffer always contains the past.

Single Buffer (serial)

Single Buffer (serial)

Note

This chapter uses the display connection serial to describe the flow, but it is similar to the display connection parallel (copy instead of transmit).

The principle of this strategy is to cumulate the drawing regions. The refresh consists in transmitting these regions (a list of rectangles) that have been modified since the last flush (or a unique rectangle that encapsulates all the regions) to the LCD driver through the LLAPI LLUI_DISPLAY_IMPL_flush().

The implicit and explicit regions have the same meaning: a dirty region to flush to the front buffer.

Behavior

The following table illustrates how the strategy works:

Strategy “Single”
Drawing Steps Strategy Work Back Buffer Front Buffer
Startup   ../_images/ui_brs0.png ../_images/ui_brs0.png
Implicit region background Store the region full-screen ../_images/ui_brs0.png ../_images/ui_brs0.png
Draw “background”   ../_images/ui_brs1.png ../_images/ui_brs0.png
Implicit region A The region A is included in the region full-screen: nothing to do ../_images/ui_brs1.png ../_images/ui_brs0.png
Draw “A”   ../_images/ui_brs2.png ../_images/ui_brs0.png
Refresh
Call LLUI_DISPLAY_IMPL_flush() (flush the region full-screen)
Clear the list of regions
../_images/ui_brs2.png ../_images/ui_brs2.png
Implicit region B Store the region B ../_images/ui_brs2.png ../_images/ui_brs2.png
Draw “B”   ../_images/ui_brs4.png ../_images/ui_brs2.png
Implicit region C Store the region C ../_images/ui_brs4.png ../_images/ui_brs2.png
Draw “C”   ../_images/ui_brs7.png ../_images/ui_brs2.png
Refresh
Call LLUI_DISPLAY_IMPL_flush() (flush the regions B and C)
Clear the list of regions
../_images/ui_brs7.png ../_images/ui_brs7.png

Note

This illustration considers that the clip changes before each drawing and fits the drawing’s bounds

Use

Here are the steps around the strategy describing how to use it:

  1. Some drawings are performed in the back buffer.
  2. A Display.flush() is asked, the Graphics Engine calls LLUI_DISPLAY_IMPL_refresh().
  3. The strategy calls LLUI_DISPLAY_IMPL_flush().
  4. The display driver has to implement LLUI_DISPLAY_IMPL_flush(), which consists in transmitting the back buffer data to the front buffer.
  5. As soon as the transmission is performed, the BSP has to notify the Graphics Engine by calling LLUI_DISPLAY_setDrawingBuffer(), giving the same back buffer address (there is only one buffer).
  6. The Graphics Engine is now unlocked, and a new drawing can start in the back buffer.

Strategy: Predraw

Principle

This strategy considers that the drawings are always performed in a buffer, and a swap with another buffer is made by the implementation of LLUI_DISPLAY_IMPL_flush(). In this case, the restoration is mandatory because the new back buffer must contain the past before the buffer swapping.

The principle of this strategy is to cumulate the drawing regions and restore them just before the very first drawing after a flush. The refresh consists in calling the LLAPI LLUI_DISPLAY_IMPL_flush() that will swap the buffers.

Some regions to restore are updated or removed according to the implicit and explicit regions given before the very first drawing after a flush. These regions are the regions that the application will alter, so it is useless to restore them. For instance, if the very first drawing after a flush fully fills the buffer (erase the buffer), the past is not restored.

The implicit and explicit regions after the very first drawing have the same signification: a dirty region to restore before the very first drawing after the next flush.

Behavior

The following table illustrates how the strategy works:

Strategy “Predraw”
Drawing Steps Strategy Work Back Buffer Front Buffer
Startup   ../_images/ui_brs0.png ../_images/ui_brs0.png
Implicit region background Store the region full-screen ../_images/ui_brs0.png ../_images/ui_brs0.png
Draw “background”   ../_images/ui_brs1.png ../_images/ui_brs0.png
Implicit region A The region A is included in the region full-screen: nothing to do ../_images/ui_brs1.png ../_images/ui_brs0.png
Draw “A”   ../_images/ui_brs2.png ../_images/ui_brs0.png
Refresh Call LLUI_DISPLAY_IMPL_flush() (swap the buffers) ../_images/ui_brs0.png ../_images/ui_brs2.png
Implicit region B
Restore the region full-screen expect the region B
Clear the list of regions
Store the region B
../_images/ui_brs8.png ../_images/ui_brs2.png
Draw “B”   ../_images/ui_brs4.png ../_images/ui_brs2.png
Refresh Call LLUI_DISPLAY_IMPL_flush() (swap the buffers) ../_images/ui_brs2.png ../_images/ui_brs4.png
Implicit region C Nothing to restore because the region B equals the region C ../_images/ui_brs2.png ../_images/ui_brs4.png
Draw “C”   ../_images/ui_brs5.png ../_images/ui_brs4.png
Refresh Call LLUI_DISPLAY_IMPL_flush() (swap the buffers) ../_images/ui_brs4.png ../_images/ui_brs5.png

Note

This illustration considers that the clip changes before each drawing and fits the drawing’s bounds

Read the Display

Before the very first drawing after a flush, the content of the back buffer does not contain the past (the restoration has not been performed). As a consequence, the first read actions (GraphicsContext.readPixel(), Painter.drawDisplayRegion(), etc.) cannot use the back buffer as the source buffer. The algorithm has to call LLUI_DISPLAY_getSourceImage() to retrieve a pointer to the front buffer address.

Use (Swap Double Buffer)

Here are the steps around the strategy describing how to use it in double buffer policy.

Swap Double Buffer

Swap Double Buffer

The two buffers have the same role alternatively, back buffer and front buffer:

  1. Some drawings are performed in the back buffer.
  2. A Display.flush() is asked, the Graphics Engine calls LLUI_DISPLAY_IMPL_refresh().
  3. The strategy calls LLUI_DISPLAY_IMPL_flush().
  4. The display driver has to implement LLUI_DISPLAY_IMPL_flush() that consists in swapping the back and front buffers.
  5. As soon as the display uses the new front buffer (the new back buffer is now freed), the BSP has to notify the Graphics Engine by calling LLUI_DISPLAY_setDrawingBuffer(), giving the new back buffer address (== previous front buffer).
  6. The Graphics Engine is now unlocked.
  7. Before the very first drawing, this strategy copies the regions to restore from the previous back buffer to the new back buffer.
  8. A new drawing can start in the new back buffer.

Use (Swap Triple Buffer)

Here are the steps around the strategy describing how to use it in triple buffer policy.

Swap Triple Buffer

Swap Triple Buffer

The three buffers have the same role alternatively: back buffers (A and B) and front buffer (C). On startup, the front buffer is mapped on buffer (C), buffer (A) is the back buffer, and the buffer (B) is not used yet:

  • buffer (A): the application’s back buffer
  • buffer (B): free
  • buffer (C): LCD driver’s buffer
  1. Some drawings are performed in the back buffer (A).
  2. A Display.flush() is asked, the Graphics Engine calls LLUI_DISPLAY_IMPL_refresh().
  3. The strategy calls LLUI_DISPLAY_IMPL_flush().
  4. The display driver has to implement LLUI_DISPLAY_IMPL_flush() that consists in swapping the buffers: the new LCD refresh task will read the data from buffer (A), and the next drawings will be done in buffer (B), but the buffer (C) is still in use (the LCD driver keeps using this buffer to refresh the LCD).
    • buffer (A): next LCD driver’s buffer
    • buffer (B): new the application’s back buffer
    • buffer (C): current LCD driver’s buffer
  5. The buffer (B) is immediately available (free): the BSP has to notify the Graphics Engine by calling LLUI_DISPLAY_setDrawingBuffer(), giving the buffer (B)’s address.
  6. The Graphics Engine is now unlocked.
  7. Before the very first drawing, this strategy copies the regions to restore from the previous back buffer (A) to the new back buffer (B).
  8. Some drawings are performed in the back buffer (B).
  9. A second Display.flush() is asked, the Graphics Engine calls LLUI_DISPLAY_IMPL_refresh().
  10. The strategy calls LLUI_DISPLAY_IMPL_flush().
  11. The system is locked: the LCD driver does not use the buffer (A) as the source buffer yet.
  12. As soon as the LCD driver uses the buffer (A) (the LCD driver keeps using this buffer to refresh the LCD), the buffer (C) becomes available (free).
  • buffer (A): current LCD driver’s buffer
  • buffer (B): application’s back buffer
  • buffer (C): free
  1. The buffer (C) will now be used for the next drawings. Go to step 5.

Use (Copy and Swap Buffer)

Here are the steps around the strategy describing how to use it in copy and swap buffer policy.

Copy and Swap (serial)

Copy and Swap (serial)

Note

This chapter uses the display connection serial to describe the flow, but it is similar to the display connection parallel (copy instead of transmit).

The two buffers have the same role alternatively: back buffer and transmission buffer. On startup, the transmission buffer has yet to be used.

In this policy, the implementation of LLUI_DISPLAY_IMPL_flush() consists in swapping the back buffers and transmitting the content of the back buffer to the front buffer (SPI, DSI, etc.). This subtlety allows the reuse of the same back buffer after the end of the transmission: this prevents the restoration of the past.

  1. Some drawings are performed in the back buffer.
  2. A Display.flush() is asked, the Graphics Engine calls LLUI_DISPLAY_IMPL_refresh().
  3. The strategy calls LLUI_DISPLAY_IMPL_flush().
  4. The display driver has to implement LLUI_DISPLAY_IMPL_flush() which consists in starting the transmission of the back buffer content to the LCD device’s buffer and swapping both buffers (back and transmission buffers).
  5. The new back buffer is immediately available (free); the BSP has to notify the Graphics Engine by calling LLUI_DISPLAY_setDrawingBuffer(), giving the new back buffer address (== previous transmission buffer).
  6. The Graphics Engine is now unlocked.
  7. Before the very first drawing, this strategy copies the regions to restore from the previous back buffer to the new back buffer.
  8. Some drawings are performed in the back buffer.
  9. A second Display.flush() is asked, the Graphics Engine calls LLUI_DISPLAY_IMPL_refresh().
  10. The strategy calls LLUI_DISPLAY_IMPL_flush().
  11. The system is locked: the LCD driver still needs to finish transmitting the transmission buffer data to the LCD device’s buffer.
  12. As soon as the transmission is done, the BSP has to notify the Graphics Engine by calling LLUI_DISPLAY_setDrawingBuffer(), giving the new back buffer address (== previous transmission buffer).
  13. The application is sleeping (doesn’t want to draw in the back buffer)

Hint

Optimization: As soon as the transmission to the LCD device’s buffer is done, the BSP should call again LLUI_DISPLAY_setDrawingBuffer() by giving the transmission buffer (which is now free). If the drawing has yet to start in the back buffer, the Graphics Engine will reuse this transmission buffer as a new back buffer instead of using the other one; the restoration becomes useless.

  1. The BSP should notify the Graphics Engine again by calling LLUI_DISPLAY_setDrawingBuffer(), giving the transmission buffer address: the Graphics Engine will reuse this buffer for future drawings, and the strategy will not need to restore anything.

Strategy: Default

Principle

This strategy is the default strategy used when no explicit strategy is selected. This strategy is implemented in the Graphics Engine, and its behavior is minimalist. However, this strategy can be used for the direct buffer policy.

Direct Buffer

Direct Buffer

This strategy considers that the drawings are always performed in the same back buffer. In this case, the restoration is useless because the buffer always contains the past. Furthermore, as the LCD driver uses the same buffer to refresh the display panel, this strategy has nothing to do.

Behavior

The following table illustrates how the strategy works:

Strategy “Direct”
Drawing Steps Strategy Work Front Buffer
Startup   ../_images/ui_brs0.png
Implicit region background   ../_images/ui_brs0.png
Draw “background”   ../_images/ui_brs1.png
Implicit region A   ../_images/ui_brs1.png
Draw “A”   ../_images/ui_brs2.png
Refresh Call LLUI_DISPLAY_IMPL_flush() (nothing to do) ../_images/ui_brs2.png

Note

This illustration considers that the clip changes before each drawing and fits the drawing’s bounds

Use

Here are the steps around the strategy describing how to use it:

  1. Some drawings are performed in the buffer.
  2. A Display.flush() is asked, the Graphics Engine calls LLUI_DISPLAY_IMPL_refresh().
  3. The strategy calls LLUI_DISPLAY_IMPL_flush().
  4. The display driver has to implement LLUI_DISPLAY_IMPL_flush(): at least enable the LCD refresh interrupt to wait until the end of the refresh (or use a software task).
  5. In the LCD refresh interrupt (here, the display panel shows the latest frame for sure), the BSP has to notify the Graphics Engine by calling LLUI_DISPLAY_setDrawingBuffer(), giving the same buffer address.
  6. The Graphics Engine is now unlocked.
  7. Some drawings are performed in the back buffer.

Strategy: Custom

Principle

This strategy symbolizes the strategy implemented by the BSP (the other strategies are implemented in the MicroUI C Module or in the Graphics Engine). This strategy is useful to map a specific behavior according to a specific application, the number of buffers, how the display panel is mapped, etc.

The BSP has the responsibility to implement the following functions (in addition to LLUI_DISPLAY_IMPL_flush()):

  • LLUI_DISPLAY_IMPL_newDrawingRegion()
  • LLUI_DISPLAY_IMPL_refresh()

Warning

Both functions are already implemented as weak functions in the Graphics Engine (see Strategy: Default)

Behavior

The following table illustrates how the strategy works:

Strategy “Custom”
Drawing Steps Strategy Work Back Buffer
Startup   ../_images/ui_brs0.png
Implicit region background Implement LLUI_DISPLAY_IMPL_newDrawingRegion() ../_images/ui_brs0.png
Draw “background”   ../_images/ui_brs1.png
Implicit region A Implement LLUI_DISPLAY_IMPL_newDrawingRegion() ../_images/ui_brs1.png
Draw “A”   ../_images/ui_brs2.png
Refresh Implement LLUI_DISPLAY_IMPL_refresh() ../_images/ui_brs2.png

Note

This illustration considers that the clip changes before each drawing and fits the drawing’s bounds

Use

Here are the steps around the strategy describing how to use it:

  1. Some drawings are performed in the buffer.
  2. A Display.flush() is asked, the Graphics Engine calls LLUI_DISPLAY_IMPL_refresh().
  3. The strategy has to implement LLUI_DISPLAY_IMPL_refresh() and call LLUI_DISPLAY_IMPL_flush().
  4. The display driver has to implement LLUI_DISPLAY_IMPL_flush().
  5. When the display panel shows the latest frame, the BSP has to notify the Graphics Engine by calling LLUI_DISPLAY_setDrawingBuffer(), giving the buffer address.
  6. The Graphics Engine is now unlocked.
  7. Some drawings are performed in the buffer.

Strategy: Legacy

Principle

This strategy mimics the behavior of the specification of the UI Pack 13.x, dedicated to the multi-buffers policies.

The specification consisted in:

  1. swapping the back buffer and the front buffer at flush time,
  2. letting the BSP restore itself to the back buffer with the content of the previous drawings (the past) before unlocking the Graphics Engine after a flush.

As a consequence, the past was always available before making the very first drawing after a flush.

The strategy Legacy is useful to keep the behavior of the VEE Ports made for UI Pack 13.x without updating them (except the signature of the LLAPI LLUI_DISPLAY_IMPL_flush()). This strategy merges all drawing regions into only one rectangle (that includes all drawing regions). This single rectangle is given to the function LLUI_DISPLAY_IMPL_flush().

Note

For the single buffer policy, it is recommended to migrate to the strategy single.

Behavior

The following table illustrates how the strategy works:

Strategy “Legacy”
Drawing Steps Strategy Work Back Buffer Front Buffer
Startup   ../_images/ui_brs0.png ../_images/ui_brs0.png
Implicit region background Store the region full-screen ../_images/ui_brs0.png ../_images/ui_brs0.png
Draw “background”   ../_images/ui_brs1.png ../_images/ui_brs0.png
Implicit region A Calculate the bounding box of the regions full-screen and A ../_images/ui_brs1.png ../_images/ui_brs0.png
Draw “A”   ../_images/ui_brs2.png ../_images/ui_brs0.png
Refresh Call LLUI_DISPLAY_IMPL_flush(): swap the buffers and restore the past ../_images/ui_brs2.png ../_images/ui_brs2.png
Implicit region B Store the region B ../_images/ui_brs2.png ../_images/ui_brs2.png
Draw “B”   ../_images/ui_brs4.png ../_images/ui_brs2.png
Refresh Call LLUI_DISPLAY_IMPL_flush(): swap the buffers and restore the past ../_images/ui_brs4.png ../_images/ui_brs4.png

Note

This illustration considers that the clip changes before each drawing and fits the drawing’s bounds

Use

Here are the steps around the strategy describing how to use it:

  1. Some drawings are performed in the buffer.
  2. A Display.flush() is asked, the Graphics Engine calls LLUI_DISPLAY_IMPL_refresh().
  3. The strategy calls LLUI_DISPLAY_IMPL_flush().
  4. The display driver has to implement LLUI_DISPLAY_IMPL_flush(): swap the back buffer and the front buffer.
  5. As soon as the display uses the new front buffer (the new back buffer is now freed), the BSP has to launch a copy of the new front buffer to the new back buffer (use the bounding box).
  6. As soon as the copy is done (the copy may be asynchronous), the BSP has to notify the Graphics Engine by calling LLUI_DISPLAY_setDrawingBuffer(), giving the new back buffer address.
  7. The Graphics Engine is now unlocked.
  8. Some drawings are performed in the back buffer.

MicroUI C Module

Principle

The MicroUI C module features some Buffer Refresh Strategies. To select a strategy, configure the define UI_DISPLAY_BRS in the configuration file ui_display_brs_configuration.h:

  • Set UI_DISPLAY_BRS_SINGLE to select the strategy Single.
  • Set UI_DISPLAY_BRS_PREDRAW to select the strategy Predraw.
  • Set UI_DISPLAY_BRS_LEGACY to select the strategy Legacy.
  • Unset the define UI_DISPLAY_BRS to select the strategy Default or to implement a Custom strategy.

Options

Some strategies require some options to configure them. The options (some defines) are shared between the strategies:

  • UI_DISPLAY_BRS_DRAWING_BUFFER_COUNT (ui_display_brs_configuration.h): configures the available number of back buffers. Used by:
    • Predraw: allowed values are 1, 2, or 3 (1 is valid, but this strategy is not optimized for this use case). See the comment of the define UI_DISPLAY_BRS_PREDRAW to increase this value.
    • Single: allowed value is 1 (sanity check).
  • UI_DISPLAY_BRS_FLUSH_SINGLE_RECTANGLE (ui_display_brs_configuration.h): configures the number of rectangles that the strategy gives to the implementation of LLUI_DISPLAY_IMPL_flush(). If not set, the number of regions depends on the strategy. If set, only one region is given: the bounding box of all drawing regions. Used by:
    • Predraw: The list of regions is often useless (the LCD driver just has to swap the back and front buffers); however, this list can be used for the buffer policy Copy and Swap Buffer. Calculating the bounding box uses takes a bit of memory and time; if the bounding box is not used, it is recommended to refrain from enabling this option.
    • Single: The list of regions can be useful to refresh small parts of the front buffer.
    • Legacy: This option is never used, and the bounding box of all drawing regions is given to the implementation of LLUI_DISPLAY_IMPL_flush().
  • UI_RECT_COLLECTION_MAX_LENGTH (ui_rect_collection.h): configures the size of the arrays that hold a list of regions (ui_rect_collection_t). The default value is 8; when the collection is full, the strategy replaces all the regions with the bounding box of all regions. Used by:
    • Predraw: number of regions to restore per back buffer.
    • Single: number of regions that the LCD driver has to flush to the front buffer.

Weak Functions

Some strategies use the function UI_DISPLAY_BRS_restore() to copy a region from a buffer to another buffer. A default implementation of this function is available in the C file ui_display_brs.c. This implementation uses the standard memcpy. Override this function to use a GPU for instance.

Debug Traces

The strategies log some events; see Debug Traces (see “[BRS]” comments).

Simulation

Principle

The Display widget in the Front Panel is able to simulate the buffer refresh strategy. It also simulates the Buffer Policy.

The default values are:

  • Swap Double Buffer for the buffer policy.
  • Predraw for the buffer refresh strategy.

Usage

The buffer policy and the refresh strategy can be configured by adding an attribute to the Display widget in the .fp file. The value of these attributes is the fully qualified name of the class implementing the buffer policy or the refresh strategy. The attributes are:

  • bufferPolicyClass to set the buffer policy.
  • refreshStrategyClass to set the refresh strategy.

Example:

<ej.fp.widget.Display
  x="0" y="0" width="480" height="272"
  bufferPolicyClass="ej.fp.widget.display.buffer.SwapTripleBufferPolicy"
  refreshStrategyClass="ej.fp.widget.display.brs.PredrawRefreshStrategy"
/>

Available Implementations

The available buffer policies are:

The available refresh strategies are:

  • Single: ej.fp.widget.display.brs.SingleRefreshStrategy.
  • Predraw: ej.fp.widget.display.brs.PredrawRefreshStrategy.
  • Legacy: ej.fp.widget.display.brs.LegacyRefreshStrategy.

Custom Implementation

It is possible to create a new buffer policy by implementing ej.fp.widget.display.buffer.DisplayBufferPolicy.

The buffer policy is responsible for:

  • Allocating the necessary buffers, usually in setDisplayProperties(Widget, int, int, int):

    FrontPanel.getFrontPanel().newImage(width, height, initialColor, false);
    
  • Giving access to the back buffer (the buffer used to draw) in getBackBuffer().

  • Giving access to the front buffer (the buffer displayed in the Display widget) in getFrontBuffer().

  • Flushing the set of modified rectangles from the back buffer to the front buffer in flush(DisplayBufferManager, Rectangle[]) and requesting the display widget to be refreshed.

    this.displayWidget.repaint();
    

It is possible to create a new refresh strategy by implementing ej.fp.widget.display.brs.BufferRefreshStrategy.

The refresh strategy is responsible for:

  • Restoring the past to ensure that the content of the display is correct by calling DisplayBufferManager.restore(Rectangle).
  • Refreshing the display with what has been modified by calling DisplayBufferManager.flush(Rectangle[]) in refresh(DisplayBufferManager).

It is notified of the modified regions in newDrawingRegion(DisplayBufferManager, Rectangle, boolean).