16 #include "ui_display_brs.h"
17 #if defined UI_DISPLAY_BRS && UI_DISPLAY_BRS == UI_DISPLAY_BRS_PREDRAW
23 #include "ui_rect_collection.h"
24 #include "ui_rect_util.h"
34 #ifndef UI_DISPLAY_BRS_DRAWING_BUFFER_COUNT
35 #error "Require the available number of display buffers (back and front buffers)."
36 #elif UI_DISPLAY_BRS_DRAWING_BUFFER_COUNT < 2
37 #warning "This strategy is not optimized for less than two buffers."
47 #if UI_DISPLAY_BRS_DRAWING_BUFFER_COUNT > 1u
56 static uint32_t index_dirty_region_to_restore = 0;
58 static bool backbuffer_ready =
true;
60 ui_rect_t diff[4] = { UI_RECT_EMPTY, UI_RECT_EMPTY, UI_RECT_EMPTY, UI_RECT_EMPTY } ;
62 #ifdef UI_DISPLAY_BRS_FLUSH_SINGLE_RECTANGLE
68 static ui_rect_t flush_bounds = {
85 static void _remove_drawing_regions(MICROUI_GraphicsContext* gc, ui_rect_t* region) {
88 for(uint32_t i = 0u; i < (UI_DISPLAY_BRS_DRAWING_BUFFER_COUNT - 1u); i++) {
89 ui_rect_t* r = dirty_regions[i].data;
90 while (r != UI_RECT_COLLECTION_get_end(&dirty_regions[i])) {
91 if (!UI_RECT_is_empty(r) && UI_RECT_contains_rect(region, r)) {
93 LOG_REGION(UI_LOG_BRS_RemoveRegion, r);
94 UI_RECT_mark_empty(r);
104 static void _add_drawing_region(MICROUI_GraphicsContext* gc, ui_rect_t* region) {
106 for(uint32_t i = 0u; i < (UI_DISPLAY_BRS_DRAWING_BUFFER_COUNT - 1u); i++) {
107 ui_rect_t* previous = UI_RECT_COLLECTION_get_last(&dirty_regions[i]);
108 if ((NULL == previous) || !UI_RECT_contains_rect(previous, region)){
111 ui_rect_t new_region;
112 if (!UI_RECT_COLLECTION_is_full(&dirty_regions[i])) {
113 new_region = *region;
117 LLTRACE_record_event_void(LLUI_EVENT_group, LLUI_EVENT_offset + UI_LOG_BRS_ClearList);
118 UI_RECT_COLLECTION_clear(&dirty_regions[i]);
119 new_region = UI_RECT_new_xyxy(0, 0, gc->image.width - 1, gc->image.height - 1);
121 LOG_REGION(UI_LOG_BRS_AddRegion, &new_region);
122 UI_RECT_COLLECTION_add_rect(&dirty_regions[i], new_region);
126 #ifdef UI_DISPLAY_BRS_FLUSH_SINGLE_RECTANGLE
127 flush_bounds.x1 = MIN(flush_bounds.x1, region->x1);
128 flush_bounds.y1 = MIN(flush_bounds.y1, region->y1);
129 flush_bounds.x2 = MAX(flush_bounds.x2, region->x2);
130 flush_bounds.y2 = MAX(flush_bounds.y2, region->y2);
147 static bool _check_restore(MICROUI_GraphicsContext* gc, ui_rect_t* dirty_region,
bool* clear_past) {
152 if (!UI_RECT_COLLECTION_is_empty(&dirty_regions[index_dirty_region_to_restore])) {
156 if (!UI_RECT_is_empty(dirty_regions[index_dirty_region_to_restore].data)) {
159 if (LLUI_DISPLAY_getBufferAddress(LLUI_DISPLAY_getSourceImage(&gc->image)) != LLUI_DISPLAY_getBufferAddress(&gc->image)) {
162 if ((dirty_region->x1 == 0) && (dirty_region->y1 == 0) && (dirty_region->x2 == (gc->image.width - 1)) && (dirty_region->y2 == (gc->image.height - 1))) {
191 static DRAWING_Status _restore_sub_rect(MICROUI_GraphicsContext* gc, MICROUI_Image* previous_buffer) {
192 DRAWING_Status restore_status = DRAWING_DONE;
195 ui_rect_t* r = &diff[ri];
196 if (!UI_RECT_is_empty(r)) {
197 LOG_REGION(UI_LOG_BRS_RestoreRegion, r);
198 restore_status = UI_DISPLAY_BRS_restore(gc, previous_buffer, r);
199 UI_RECT_mark_empty(r);
202 }
while((DRAWING_DONE == restore_status) && (ri < 4));
203 return restore_status;
220 static DRAWING_Status _prepare_back_buffer(MICROUI_GraphicsContext* gc, ui_rect_t* dirty_region) {
222 DRAWING_Status restore_status = DRAWING_DONE;
223 bool clear_past =
false;
225 if (_check_restore(gc, dirty_region, &clear_past)) {
226 MICROUI_Image* previous_buffer = LLUI_DISPLAY_getSourceImage(&gc->image);
227 LLUI_DISPLAY_configureClip(gc,
false);
230 restore_status = _restore_sub_rect(gc, previous_buffer);
232 if (DRAWING_DONE == restore_status) {
233 ui_rect_t* r = dirty_regions[index_dirty_region_to_restore].data;
234 while ((DRAWING_DONE == restore_status) && (r != UI_RECT_COLLECTION_get_end(&dirty_regions[index_dirty_region_to_restore]))) {
235 if (!UI_RECT_is_empty(r)) {
238 if (0u < UI_RECT_subtract(diff, r, dirty_region)) {
240 restore_status = _restore_sub_rect(gc, previous_buffer);
244 UI_RECT_mark_empty(r);
250 clear_past = DRAWING_DONE == restore_status;
256 UI_RECT_COLLECTION_clear(&dirty_regions[index_dirty_region_to_restore]);
257 #if UI_DISPLAY_BRS_DRAWING_BUFFER_COUNT > 1
258 index_dirty_region_to_restore++;
259 index_dirty_region_to_restore %= (uint32_t) UI_DISPLAY_BRS_DRAWING_BUFFER_COUNT - 1u;
263 if (DRAWING_DONE == restore_status) {
265 backbuffer_ready =
true;
268 _add_drawing_region(gc, dirty_region);
271 return restore_status;
283 DRAWING_Status LLUI_DISPLAY_IMPL_newDrawingRegion(MICROUI_GraphicsContext* gc, ui_rect_t* region,
bool drawing_now) {
285 LOG_REGION(UI_LOG_BRS_NewDrawing, region);
287 DRAWING_Status ret = DRAWING_DONE;
289 if (!backbuffer_ready) {
292 _remove_drawing_regions(gc, region);
295 ret = _prepare_back_buffer(gc, region);
299 _add_drawing_region(gc, region);
310 DRAWING_Status LLUI_DISPLAY_IMPL_refresh(MICROUI_GraphicsContext* gc, uint8_t flushIdentifier) {
312 #ifdef UI_DISPLAY_BRS_FLUSH_SINGLE_RECTANGLE
314 LLTRACE_record_event_u32x6(LLUI_EVENT_group, LLUI_EVENT_offset + UI_LOG_BRS_FlushSingle, flushIdentifier, (uint32_t)LLUI_DISPLAY_getBufferAddress(&gc->image), flush_bounds.x1, flush_bounds.y1, flush_bounds.x2, flush_bounds.y2);
317 LLUI_DISPLAY_IMPL_flush(gc, flushIdentifier, &flush_bounds, 1);
320 flush_bounds.x1 = INT16_MAX;
321 flush_bounds.y1 = INT16_MAX;
327 size_t size = UI_RECT_COLLECTION_get_length(&dirty_regions[index_dirty_region_to_restore]);
329 ui_rect_t* rect = &dirty_regions[index_dirty_region_to_restore].data[0];
330 LLTRACE_record_event_u32x6(LLUI_EVENT_group, LLUI_EVENT_offset + UI_LOG_BRS_FlushSingle, flushIdentifier, (uint32_t)LLUI_DISPLAY_getBufferAddress(&gc->image), rect->x1, rect->y1, rect->x2, rect->y2);
333 LLTRACE_record_event_u32x3(LLUI_EVENT_group, LLUI_EVENT_offset + UI_LOG_BRS_FlushMulti, flushIdentifier, (uint32_t)LLUI_DISPLAY_getBufferAddress(&gc->image), size);
336 LLUI_DISPLAY_IMPL_flush(gc, flushIdentifier, dirty_regions[index_dirty_region_to_restore].data, UI_RECT_COLLECTION_get_length(&dirty_regions[index_dirty_region_to_restore]));
340 backbuffer_ready =
false;