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