microui  4.1.0
microui
ui_display_brs_single.c
1 /*
2  * Copyright 2023-2024 MicroEJ Corp. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be found with this software.
4  */
5 
6 /*
7  * @file
8  * @brief This file implements all the LLUI_DISPLAY_impl.h functions relating to the
9  * display buffer strategy (BRS) "single"
10  * @see UI_DISPLAY_BRS_SINGLE comment
11  * @author MicroEJ Developer Team
12  * @version 4.1.0
13  */
14 
15 #include "ui_display_brs.h"
16 #if defined UI_DISPLAY_BRS && UI_DISPLAY_BRS == UI_DISPLAY_BRS_SINGLE
17 
18 // --------------------------------------------------------------------------------
19 // Includes
20 // --------------------------------------------------------------------------------
21 
22 #include "ui_rect_collection.h"
23 
24 // --------------------------------------------------------------------------------
25 // Defines
26 // --------------------------------------------------------------------------------
27 
28 /*
29  * @brief This strategy uses only one buffer
30  * @see the comment of UI_DISPLAY_BRS_SINGLE.
31  */
32 #if defined UI_DISPLAY_BRS_DRAWING_BUFFER_COUNT && UI_DISPLAY_BRS_DRAWING_BUFFER_COUNT != 1
33 #error "This strategy uses always the same back buffer."
34 #endif
35 
36 // --------------------------------------------------------------------------------
37 // Private fields
38 // --------------------------------------------------------------------------------
39 
40 #ifndef UI_DISPLAY_BRS_FLUSH_SINGLE_RECTANGLE
41 
42 /*
43  * @brief A collection of rectangles to transmit to the LCD
44  */
45 static ui_rect_collection_t dirty_regions;
46 
47 #else // UI_DISPLAY_BRS_FLUSH_SINGLE_RECTANGLE
48 
49 /*
50  * @brief Rectangle given to LLUI_DISPLAY_IMPL_flush(): it includes all dirty regions since
51  * last call to flush().
52  */
53 static ui_rect_t flush_bounds = {
54  .x1 = INT16_MAX,
55  .y1 = INT16_MAX,
56  .x2 = 0,
57  .y2 = 0,
58 };
59 
60 #endif // UI_DISPLAY_BRS_FLUSH_SINGLE_RECTANGLE
61 
62 // --------------------------------------------------------------------------------
63 // LLUI_DISPLAY_impl.h API
64 // --------------------------------------------------------------------------------
65 
66 /*
67  * @brief See the header file for the function documentation.
68  *
69  * This function stores the new region as new region to transmit to the LCD at next call to flush().
70  */
71 DRAWING_Status LLUI_DISPLAY_IMPL_newDrawingRegion(MICROUI_GraphicsContext *gc, ui_rect_t *region, bool drawing_now) {
72  (void)drawing_now;
73 
74  LOG_REGION(UI_LOG_BRS_NewDrawing, region);
75 
76 #ifndef UI_DISPLAY_BRS_FLUSH_SINGLE_RECTANGLE
77 
78  ui_rect_t *previous = UI_RECT_COLLECTION_get_last(&dirty_regions);
79  if ((NULL == previous) || !UI_RECT_contains_rect(previous, region)) {
80  // add the dirty region if and only if previous dirty region does not
81  // include the new dirty region
82  ui_rect_t new_region;
83  if (!UI_RECT_COLLECTION_is_full(&dirty_regions)) {
84  new_region = *region;
85  } else {
86  // too many rectangles: replace them by only one whose fits the full display
87  LLTRACE_record_event_void(LLUI_EVENT_group, LLUI_EVENT_offset + UI_LOG_BRS_ClearList);
88  UI_RECT_COLLECTION_clear(&dirty_regions);
89  new_region = UI_RECT_new_xyxy(0, 0, gc->image.width - 1, gc->image.height - 1);
90  }
91  LOG_REGION(UI_LOG_BRS_AddRegion, &new_region);
92  UI_RECT_COLLECTION_add_rect(&dirty_regions, new_region);
93  }
94 #else // UI_DISPLAY_BRS_FLUSH_SINGLE_RECTANGLE
95  (void)gc;
96 
97  flush_bounds.x1 = MIN(flush_bounds.x1, region->x1);
98  flush_bounds.y1 = MIN(flush_bounds.y1, region->y1);
99  flush_bounds.x2 = MAX(flush_bounds.x2, region->x2);
100  flush_bounds.y2 = MAX(flush_bounds.y2, region->y2);
101 
102 #endif // UI_DISPLAY_BRS_FLUSH_SINGLE_RECTANGLE
103 
104  return DRAWING_DONE;
105 }
106 
107 /*
108  * @brief See the header file for the function documentation.
109  *
110  * This function calls LLUI_DISPLAY_IMPL_flush() with the rectangle that includes all dirty regions.
111  */
112 DRAWING_Status LLUI_DISPLAY_IMPL_refresh(MICROUI_GraphicsContext *gc, uint8_t flushIdentifier) {
113 #ifndef UI_DISPLAY_BRS_FLUSH_SINGLE_RECTANGLE
114 
115  size_t size = UI_RECT_COLLECTION_get_length(&dirty_regions);
116  if (1u == size) {
117  ui_rect_t *rect = &dirty_regions.data[0];
118  LLTRACE_record_event_u32x6(LLUI_EVENT_group, LLUI_EVENT_offset + UI_LOG_BRS_FlushSingle, flushIdentifier,
119  (uint32_t)LLUI_DISPLAY_getBufferAddress(&gc->image), rect->x1, rect->y1, rect->x2,
120  rect->y2);
121  } else {
122  LLTRACE_record_event_u32x3(LLUI_EVENT_group, LLUI_EVENT_offset + UI_LOG_BRS_FlushMulti, flushIdentifier,
123  (uint32_t)LLUI_DISPLAY_getBufferAddress(&gc->image), size);
124  }
125 
126  LLUI_DISPLAY_IMPL_flush(gc, flushIdentifier, dirty_regions.data, UI_RECT_COLLECTION_get_length(&dirty_regions));
127  UI_RECT_COLLECTION_clear(&dirty_regions);
128 
129 #else // UI_DISPLAY_BRS_FLUSH_SINGLE_RECTANGLE
130 
131  LLTRACE_record_event_u32x6(LLUI_EVENT_group, LLUI_EVENT_offset + UI_LOG_BRS_FlushSingle, flushIdentifier,
132  (uint32_t)LLUI_DISPLAY_getBufferAddress(&gc->image), flush_bounds.x1, flush_bounds.y1,
133  flush_bounds.x2, flush_bounds.y2);
134 
135  // refresh the LCD; use the flush_bounds as dirty region (includes all dirty regions)
136  LLUI_DISPLAY_IMPL_flush(gc, flushIdentifier, &flush_bounds, 1);
137 
138  // reset flush bounds to no flush again if there is no drawing until next flush
139  flush_bounds.x1 = INT16_MAX;
140  flush_bounds.y1 = INT16_MAX;
141  flush_bounds.x2 = 0;
142  flush_bounds.y2 = 0;
143 
144 #endif // UI_DISPLAY_BRS_FLUSH_SINGLE_RECTANGLE
145 
146  return DRAWING_DONE;
147 }
148 
149 #endif // UI_DISPLAY_BRS_PREDRAW
150 
151 // --------------------------------------------------------------------------------
152 // EOF
153 // --------------------------------------------------------------------------------