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 LOG_REGION(UI_LOG_BRS_RemoveRegion, r);
93 UI_RECT_mark_empty(r);
103 static void _add_drawing_region(MICROUI_GraphicsContext *gc, ui_rect_t *region) {
105 ui_rect_t *previous = UI_RECT_COLLECTION_get_last(&dirty_regions[i]);
106 if ((NULL == previous) || !UI_RECT_contains_rect(previous, region)) {
109 ui_rect_t new_region;
110 if (!UI_RECT_COLLECTION_is_full(&dirty_regions[i])) {
111 new_region = *region;
114 LLTRACE_record_event_void(LLUI_EVENT_group, LLUI_EVENT_offset + UI_LOG_BRS_ClearList);
115 UI_RECT_COLLECTION_clear(&dirty_regions[i]);
116 new_region = UI_RECT_new_xyxy(0, 0, gc->image.width - 1, gc->image.height - 1);
118 LOG_REGION(UI_LOG_BRS_AddRegion, &new_region);
119 UI_RECT_COLLECTION_add_rect(&dirty_regions[i], new_region);
123 #ifdef UI_FEATURE_BRS_FLUSH_SINGLE_RECTANGLE
124 flush_bounds.x1 = MIN(flush_bounds.x1, region->x1);
125 flush_bounds.y1 = MIN(flush_bounds.y1, region->y1);
126 flush_bounds.x2 = MAX(flush_bounds.x2, region->x2);
127 flush_bounds.y2 = MAX(flush_bounds.y2, region->y2);
144 static bool _check_restore(MICROUI_GraphicsContext *gc,
const ui_rect_t *dirty_region,
bool *clear_past) {
148 if (!UI_RECT_COLLECTION_is_empty(&dirty_regions[index_dirty_region_to_restore])) {
152 if (!UI_RECT_is_empty(dirty_regions[index_dirty_region_to_restore].data)) {
155 if (LLUI_DISPLAY_getBufferAddress(LLUI_DISPLAY_getSourceImage(&gc->image)) !=
156 LLUI_DISPLAY_getBufferAddress(&gc->image)) {
159 if ((dirty_region->x1 == 0) && (dirty_region->y1 == 0) && (dirty_region->x2 == (gc->image.width - 1)) &&
160 (dirty_region->y2 == (gc->image.height - 1))) {
187 static DRAWING_Status _restore_sub_rect(MICROUI_GraphicsContext *gc, MICROUI_Image *previous_buffer) {
188 DRAWING_Status restore_status = DRAWING_DONE;
191 ui_rect_t *r = &diff[ri];
192 if (!UI_RECT_is_empty(r)) {
193 LOG_REGION(UI_LOG_BRS_RestoreRegion, r);
194 restore_status = UI_DISPLAY_BRS_restore(gc, previous_buffer, r);
195 UI_RECT_mark_empty(r);
198 }
while ((DRAWING_DONE == restore_status) && (ri < 4));
199 return restore_status;
216 static DRAWING_Status _prepare_back_buffer(MICROUI_GraphicsContext *gc, ui_rect_t *dirty_region) {
217 DRAWING_Status restore_status = DRAWING_DONE;
218 bool clear_past =
false;
220 if (_check_restore(gc, dirty_region, &clear_past)) {
221 MICROUI_Image *previous_buffer = LLUI_DISPLAY_getSourceImage(&gc->image);
222 LLUI_DISPLAY_configureClip(gc,
false);
225 restore_status = _restore_sub_rect(gc, previous_buffer);
227 if (DRAWING_DONE == restore_status) {
228 ui_rect_t *r = dirty_regions[index_dirty_region_to_restore].data;
229 while ((DRAWING_DONE == restore_status) &&
230 (r != UI_RECT_COLLECTION_get_end(&dirty_regions[index_dirty_region_to_restore]))) {
231 if (!UI_RECT_is_empty(r)) {
233 if (0u < UI_RECT_subtract(diff, r, dirty_region)) {
235 restore_status = _restore_sub_rect(gc, previous_buffer);
239 UI_RECT_mark_empty(r);
245 clear_past = DRAWING_DONE == restore_status;
251 UI_RECT_COLLECTION_clear(&dirty_regions[index_dirty_region_to_restore]);
252 #if UI_FEATURE_BRS_DRAWING_BUFFER_COUNT > 1
253 index_dirty_region_to_restore++;
258 if (DRAWING_DONE == restore_status) {
260 backbuffer_ready =
true;
263 _add_drawing_region(gc, dirty_region);
266 return restore_status;
278 DRAWING_Status LLUI_DISPLAY_IMPL_newDrawingRegion(MICROUI_GraphicsContext *gc, ui_rect_t *region,
bool drawing_now) {
279 LOG_REGION(UI_LOG_BRS_NewDrawing, region);
281 DRAWING_Status ret = DRAWING_DONE;
283 if (!backbuffer_ready) {
285 _remove_drawing_regions(gc, region);
287 ret = _prepare_back_buffer(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 LLTRACE_record_event_u32x6(LLUI_EVENT_group, LLUI_EVENT_offset + UI_LOG_BRS_FlushSingle, flushIdentifier,
305 (uint32_t)LLUI_DISPLAY_getBufferAddress(&gc->image), flush_bounds.x1, flush_bounds.y1,
306 flush_bounds.x2, flush_bounds.y2);
309 LLUI_DISPLAY_IMPL_flush(gc, flushIdentifier, &flush_bounds, 1);
312 flush_bounds.x1 = INT16_MAX;
313 flush_bounds.y1 = INT16_MAX;
319 size_t size = UI_RECT_COLLECTION_get_length(&dirty_regions[index_dirty_region_to_restore]);
321 ui_rect_t *rect = &dirty_regions[index_dirty_region_to_restore].data[0];
322 LLTRACE_record_event_u32x6(LLUI_EVENT_group, LLUI_EVENT_offset + UI_LOG_BRS_FlushSingle, flushIdentifier,
323 (uint32_t)LLUI_DISPLAY_getBufferAddress(&gc->image), rect->x1, rect->y1, rect->x2,
326 LLTRACE_record_event_u32x3(LLUI_EVENT_group, LLUI_EVENT_offset + UI_LOG_BRS_FlushMulti, flushIdentifier,
327 (uint32_t)LLUI_DISPLAY_getBufferAddress(&gc->image), size);
330 LLUI_DISPLAY_IMPL_flush(gc, flushIdentifier, dirty_regions[index_dirty_region_to_restore].data,
331 UI_RECT_COLLECTION_get_length(&dirty_regions[index_dirty_region_to_restore]));
335 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...