15 #include "ui_display_brs.h"
16 #if defined UI_FEATURE_BRS && UI_FEATURE_BRS == UI_FEATURE_BRS_PREDRAW
22 #include "ui_rect_collection.h"
23 #include "ui_rect_util.h"
33 #ifndef UI_FEATURE_BRS_DRAWING_BUFFER_COUNT
34 #error "Require the available number of display buffers (back and front buffers)."
35 #elif UI_FEATURE_BRS_DRAWING_BUFFER_COUNT < 2
36 #warning "This strategy is not optimized for less than two buffers."
46 #if UI_FEATURE_BRS_DRAWING_BUFFER_COUNT > 1u
55 static uint32_t index_dirty_region_to_restore = 0;
57 static bool backbuffer_ready =
true;
59 ui_rect_t diff[4] = { UI_RECT_EMPTY, UI_RECT_EMPTY, UI_RECT_EMPTY, UI_RECT_EMPTY };
61 #ifdef UI_FEATURE_BRS_FLUSH_SINGLE_RECTANGLE
67 static ui_rect_t flush_bounds = {
84 static void _remove_drawing_regions(MICROUI_GraphicsContext *gc, ui_rect_t *region) {
88 ui_rect_t *r = dirty_regions[i].data;
89 while (r != UI_RECT_COLLECTION_get_end(&dirty_regions[i])) {
90 if (!UI_RECT_is_empty(r) && UI_RECT_contains_rect(region, r)) {
92 UI_RECT_mark_empty(r);
102 static void _add_drawing_region(MICROUI_GraphicsContext *gc, ui_rect_t *region) {
104 ui_rect_t *previous = UI_RECT_COLLECTION_get_last(&dirty_regions[i]);
105 if ((NULL == previous) || !UI_RECT_contains_rect(previous, region)) {
108 ui_rect_t new_region;
109 if (!UI_RECT_COLLECTION_is_full(&dirty_regions[i])) {
110 new_region = *region;
113 UI_RECT_COLLECTION_clear(&dirty_regions[i]);
114 new_region = UI_RECT_new_xyxy(0, 0, gc->image.width - 1, gc->image.height - 1);
116 UI_RECT_COLLECTION_add_rect(&dirty_regions[i], new_region);
120 #ifdef UI_FEATURE_BRS_FLUSH_SINGLE_RECTANGLE
121 flush_bounds.x1 = MIN(flush_bounds.x1, region->x1);
122 flush_bounds.y1 = MIN(flush_bounds.y1, region->y1);
123 flush_bounds.x2 = MAX(flush_bounds.x2, region->x2);
124 flush_bounds.y2 = MAX(flush_bounds.y2, region->y2);
141 static bool _check_restore(MICROUI_GraphicsContext *gc,
const ui_rect_t *dirty_region,
bool *clear_past) {
145 if (!UI_RECT_COLLECTION_is_empty(&dirty_regions[index_dirty_region_to_restore])) {
149 if (!UI_RECT_is_empty(dirty_regions[index_dirty_region_to_restore].data)) {
152 if (LLUI_DISPLAY_getBufferAddress(LLUI_DISPLAY_getSourceImage(&gc->image)) !=
153 LLUI_DISPLAY_getBufferAddress(&gc->image)) {
156 if ((dirty_region->x1 == 0) && (dirty_region->y1 == 0) && (dirty_region->x2 == (gc->image.width - 1)) &&
157 (dirty_region->y2 == (gc->image.height - 1))) {
184 static DRAWING_Status _restore_sub_rect(MICROUI_GraphicsContext *gc, MICROUI_Image *previous_buffer) {
185 DRAWING_Status restore_status = DRAWING_DONE;
188 ui_rect_t *r = &diff[ri];
189 if (!UI_RECT_is_empty(r)) {
190 UI_LOG_START(BRS_RestoreRegion, r->x1, r->y1, UI_RECT_get_width(r), UI_RECT_get_height(r));
191 restore_status = UI_DISPLAY_BRS_restore(gc, previous_buffer, r);
192 UI_RECT_mark_empty(r);
195 }
while ((DRAWING_DONE == restore_status) && (ri < 4));
196 return restore_status;
213 static DRAWING_Status _prepare_back_buffer(MICROUI_GraphicsContext *gc, ui_rect_t *dirty_region) {
214 DRAWING_Status restore_status = DRAWING_DONE;
215 bool clear_past =
false;
217 if (_check_restore(gc, dirty_region, &clear_past)) {
218 MICROUI_Image *previous_buffer = LLUI_DISPLAY_getSourceImage(&gc->image);
219 LLUI_DISPLAY_configureClip(gc,
false);
222 restore_status = _restore_sub_rect(gc, previous_buffer);
224 if (DRAWING_DONE == restore_status) {
225 ui_rect_t *r = dirty_regions[index_dirty_region_to_restore].data;
226 while ((DRAWING_DONE == restore_status) &&
227 (r != UI_RECT_COLLECTION_get_end(&dirty_regions[index_dirty_region_to_restore]))) {
228 if (!UI_RECT_is_empty(r)) {
230 if (0u < UI_RECT_subtract(diff, r, dirty_region)) {
232 restore_status = _restore_sub_rect(gc, previous_buffer);
236 UI_RECT_mark_empty(r);
242 clear_past = DRAWING_DONE == restore_status;
248 UI_RECT_COLLECTION_clear(&dirty_regions[index_dirty_region_to_restore]);
249 #if UI_FEATURE_BRS_DRAWING_BUFFER_COUNT > 1
250 index_dirty_region_to_restore++;
255 return restore_status;
267 DRAWING_Status LLUI_DISPLAY_IMPL_newDrawingRegion(MICROUI_GraphicsContext *gc, ui_rect_t *region,
bool drawing_now) {
269 DRAWING_Status ret = DRAWING_DONE;
271 if (!backbuffer_ready) {
275 _remove_drawing_regions(gc, region);
278 ret = _prepare_back_buffer(gc, region);
280 if (DRAWING_DONE == ret) {
282 backbuffer_ready =
true;
285 _add_drawing_region(gc, region);
290 _add_drawing_region(gc, region);
301 DRAWING_Status LLUI_DISPLAY_IMPL_refresh(MICROUI_GraphicsContext *gc, uint8_t flushIdentifier) {
302 #ifdef UI_FEATURE_BRS_FLUSH_SINGLE_RECTANGLE
304 UI_LOG_START(BRS_FlushSingle, flushIdentifier, UI_LOG_BUFFER(&gc->image), flush_bounds.x1, flush_bounds.y1,
305 UI_RECT_get_width(&flush_bounds), UI_RECT_get_height(&flush_bounds));
308 LLUI_DISPLAY_IMPL_flush(gc, flushIdentifier, &flush_bounds, 1);
311 flush_bounds.x1 = INT16_MAX;
312 flush_bounds.y1 = INT16_MAX;
318 size_t size = UI_RECT_COLLECTION_get_length(&dirty_regions[index_dirty_region_to_restore]);
320 ui_rect_t *rect = &dirty_regions[index_dirty_region_to_restore].data[0];
321 UI_LOG_START(BRS_FlushSingle, flushIdentifier, UI_LOG_BUFFER(&gc->image), rect->x1, rect->y1, UI_RECT_get_width(rect),
322 UI_RECT_get_height(rect));
324 UI_LOG_START(BRS_FlushMulti, flushIdentifier, UI_LOG_BUFFER(&gc->image), size);
327 LLUI_DISPLAY_IMPL_flush(gc, flushIdentifier, dirty_regions[index_dirty_region_to_restore].data,
328 UI_RECT_COLLECTION_get_length(&dirty_regions[index_dirty_region_to_restore]));
332 backbuffer_ready =
false;
#define UI_FEATURE_BRS_DRAWING_BUFFER_COUNT
Defines the available number of drawing buffers; in other words, the number of buffers the Graphics E...