Skip to content

Commit c81da29

Browse files
committed
perf: improve dirty rectangle collection
1 parent d858333 commit c81da29

4 files changed

Lines changed: 103 additions & 72 deletions

File tree

include/LCUI/util/rect.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,6 @@ LCUI_API int RectList_Add(LinkedList *list, LCUI_Rect *rect);
113113
/** 删除脏矩形 */
114114
LCUI_API int RectList_Delete(LinkedList *list, LCUI_Rect *rect);
115115

116-
/**
117-
* Split each rectangle with the bounding box
118-
*/
119-
LCUI_API
120-
size_t RectList_SplitWith(LinkedList *rects, const LCUI_Rect *bounding,
121-
LinkedList *splited_rects);
122-
123116
#define RectList_Clear(LIST) LinkedList_Clear(LIST, free)
124117

125118
LCUI_END_HEADER

src/display.c

Lines changed: 89 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,25 @@
5252
#define DEFAULT_WIDTH 800
5353
#define DEFAULT_HEIGHT 600
5454

55+
#ifdef USE_OPENMP
56+
/**
57+
* Parallel rendering threads
58+
* We recommend that you set it to half the number of CPU logical cores
59+
*/
60+
#define PARALLEL_RENDERING_THREADS 4
61+
#else
62+
#define PARALLEL_RENDERING_THREADS 1
63+
#endif
64+
5565
typedef struct SurfaceRecordRec_ {
56-
LCUI_BOOL rendered; /**< whether new content has been rendered */
57-
LinkedList rects; /**< rectangles to be render */
58-
LCUI_Surface surface; /**< target surface */
59-
LCUI_Widget widget; /**< target widget */
66+
/**< whether new content has been rendered */
67+
LCUI_BOOL rendered;
68+
69+
/** dirty rectangles for rendering */
70+
LinkedList rects;
71+
72+
LCUI_Surface surface;
73+
LCUI_Widget widget;
6074
} SurfaceRecordRec, *SurfaceRecord;
6175

6276
static struct LCUI_DisplayModule {
@@ -99,51 +113,80 @@ static void DrawBorder(LCUI_PaintContext paint)
99113
Graph_DrawHorizLine(&paint->canvas, color, 1, pos, end_x);
100114
}
101115

102-
static void SurfaceRecord_DumpRects(SurfaceRecord record,
103-
LinkedList *rects)
116+
static void SurfaceRecord_DumpRects(SurfaceRecord record, LinkedList *rects)
104117
{
118+
typedef struct DirtyLayerRec {
119+
LinkedList rects;
120+
LCUI_Rect rect;
121+
int diry;
122+
} DirtyLayerRec, *DirtyLayer;
123+
124+
int i;
125+
int max_dirty;
126+
int layer_width = LCUIDisplay_GetWidth();
127+
int layer_height = LCUIDisplay_GetHeight();
128+
105129
LCUI_Rect rect;
106-
const int width = Surface_GetWidth(record->surface);
107-
const int height = Surface_GetHeight(record->surface);
108-
109-
/* top left */
110-
rect.x = 0;
111-
rect.y = 0;
112-
rect.width = width / 2;
113-
rect.height = height / 2;
114-
RectList_SplitWith(&record->rects, &rect, rects);
115-
116-
/* top right */
117-
rect.x = width / 2;
118-
rect.width = width - rect.x;
119-
RectList_SplitWith(&record->rects, &rect, rects);
120-
121-
/* bottom left */
122-
rect.x = 0;
123-
rect.y = height / 2;
124-
rect.width = width / 2;
125-
rect.height = height - rect.y;
126-
RectList_SplitWith(&record->rects, &rect, rects);
127-
128-
/* bottom right */
129-
rect.x = width / 2;
130-
rect.width = width - rect.x;
131-
RectList_SplitWith(&record->rects, &rect, rects);
130+
LCUI_Rect *sub_rect;
131+
DirtyLayer layer;
132+
DirtyLayerRec layers[PARALLEL_RENDERING_THREADS];
133+
LinkedListNode *node;
132134

135+
layer_height = max(200, layer_height / PARALLEL_RENDERING_THREADS + 1);
136+
max_dirty = 0.8 * layer_width * layer_height;
137+
for (i = 0; i < PARALLEL_RENDERING_THREADS; ++i) {
138+
layer = &layers[i];
139+
layer->diry = 0;
140+
layer->rect.y = i * layer_height;
141+
layer->rect.x = 0;
142+
layer->rect.width = layer_width;
143+
layer->rect.height = layer_height;
144+
LinkedList_Init(&layer->rects);
145+
}
146+
sub_rect = malloc(sizeof(LCUI_Rect));
147+
for (LinkedList_Each(node, &record->rects)) {
148+
rect = *(LCUI_Rect *)node->data;
149+
for (i = 0; i < PARALLEL_RENDERING_THREADS; ++i) {
150+
layer = &layers[i];
151+
if (layer->diry >= max_dirty) {
152+
continue;
153+
}
154+
if (!LCUIRect_GetOverlayRect(&layer->rect, &rect,
155+
sub_rect)) {
156+
continue;
157+
}
158+
LinkedList_Append(&layer->rects, sub_rect);
159+
rect.y += sub_rect->height;
160+
rect.height -= sub_rect->height;
161+
layer->diry += sub_rect->width * sub_rect->height;
162+
sub_rect = malloc(sizeof(LCUI_Rect));
163+
if (rect.height < 1) {
164+
break;
165+
}
166+
}
167+
}
168+
for (i = 0; i < PARALLEL_RENDERING_THREADS; ++i) {
169+
layer = &layers[i];
170+
if (layer->diry >= max_dirty) {
171+
RectList_AddEx(rects, &layer->rect, FALSE);
172+
RectList_Clear(&layer->rects);
173+
} else {
174+
LinkedList_Concat(rects, &layer->rects);
175+
}
176+
}
133177
RectList_Clear(&record->rects);
178+
free(sub_rect);
134179
}
135180

136181
static size_t LCUIDisplay_RenderSurface(SurfaceRecord record)
137182
{
183+
int i = 0;
138184
size_t count = 0;
139-
int i;
140-
LCUI_Rect *rect;
141-
LCUI_PaintContext paint;
185+
LCUI_BOOL can_render;
186+
LCUI_Rect **rect_array;
142187
LCUI_SysEventRec ev;
143188
LinkedList rects;
144189
LinkedListNode *node;
145-
LCUI_BOOL can_render;
146-
LCUI_Rect **rectArray;
147190

148191
ev.type = LCUI_PAINT;
149192
can_render = record->widget && record->surface &&
@@ -155,22 +198,23 @@ static size_t LCUIDisplay_RenderSurface(SurfaceRecord record)
155198
return 0;
156199
}
157200

158-
rectArray = (LCUI_Rect **)malloc(sizeof(LCUI_Rect*) * rects.length);
159-
i = 0;
201+
rect_array = (LCUI_Rect **)malloc(sizeof(LCUI_Rect *) * rects.length);
160202
for (LinkedList_Each(node, &rects)) {
161-
rectArray[i] = node->data;
203+
rect_array[i] = node->data;
162204
i++;
163205
}
164206
#ifdef USE_OPENMP
165207
#pragma omp parallel for \
166208
default(none) \
167-
shared(can_render, display, rects, rectArray) \
168-
private(rect, paint) \
209+
shared(can_render, display, rects, rect_array) \
169210
firstprivate(record, ev) \
170211
reduction(+:count)
171212
#endif
172-
for (i = 0; i < rects.length; i++) {
173-
rect = rectArray[i];
213+
for (i = 0; i < rects.length; ++i) {
214+
LCUI_Rect *rect;
215+
LCUI_PaintContext paint;
216+
217+
rect = rect_array[i];
174218
ev.paint.rect = *rect;
175219
LCUI_TriggerEvent(&ev, NULL);
176220
if (!can_render) {
@@ -210,7 +254,6 @@ void LCUIDisplay_Update(void)
210254
if (!display.active) {
211255
return;
212256
}
213-
/* 遍历当前的 surface 记录列表 */
214257
for (LinkedList_Each(node, &display.surfaces)) {
215258
record = node->data;
216259
surface = record->surface;
@@ -344,13 +387,12 @@ static void LCUIDisplay_BindSurface(LCUI_Widget widget)
344387
record->surface = Surface_New();
345388
record->widget = widget;
346389
record->rendered = FALSE;
347-
LinkedList_Init(&record->rects);
348-
Surface_SetCaptionW(record->surface, widget->title);
349390
LCUIMetrics_ComputeRectActual(&rect, &widget->box.canvas);
350391
if (Widget_CheckStyleValid(widget, key_top) &&
351392
Widget_CheckStyleValid(widget, key_left)) {
352393
Surface_Move(record->surface, rect.x, rect.y);
353394
}
395+
Surface_SetCaptionW(record->surface, widget->title);
354396
Surface_Resize(record->surface, rect.width, rect.height);
355397
if (widget->computed_style.visible) {
356398
Surface_Show(record->surface);

src/gui/widget_paint.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* widget_paint.c -- LCUI widget paint module.
33
*
4-
* Copyright (c) 2018, Liu chao <lc-soft@live.cn> All rights reserved.
4+
* Copyright (c) 2018-2019, Liu chao <lc-soft@live.cn> All rights reserved.
55
*
66
* Redistribution and use in source and binary forms, with or without
77
* modification, are permitted provided that the following conditions are met:
@@ -39,6 +39,9 @@
3939
//#define DEBUG_FRAME_RENDER
4040
#define ComputeActualPX(VAL) LCUIMetrics_ComputeActual(VAL, LCUI_STYPE_PX)
4141

42+
#define MAX_VISIBLE_WIDTH 20000
43+
#define MAX_VISIBLE_HEIGHT 20000
44+
4245
#ifdef DEBUG_FRAME_RENDER
4346
#include <LCUI/image.h>
4447
#endif
@@ -183,8 +186,8 @@ LCUI_BOOL Widget_InvalidateArea(LCUI_Widget widget, LCUI_RectF *in_rect,
183186
int box_type)
184187
{
185188
int mode;
186-
LCUI_Rect area;
187189
LCUI_RectF rect;
190+
LCUI_Rect *actual_rect;
188191
LCUI_Widget w = widget;
189192
LCUI_Widget root = LCUIWidget_GetRoot();
190193
LCUI_RectGroup group;
@@ -209,9 +212,14 @@ LCUI_BOOL Widget_InvalidateArea(LCUI_Widget widget, LCUI_RectF *in_rect,
209212
rect.x += w->box.padding.x;
210213
rect.y += w->box.padding.y;
211214
}
212-
RectFToInvalidArea(&rect, &area);
215+
LCUIRectF_ValidateArea(&rect, MAX_VISIBLE_WIDTH, MAX_VISIBLE_HEIGHT);
216+
if (rect.width <= 0 || rect.height <= 0) {
217+
return FALSE;
218+
}
219+
actual_rect = malloc(sizeof(LCUI_Rect));
220+
RectFToInvalidArea(&rect, actual_rect);
213221
if (mode != LCUI_DMODE_SEAMLESS) {
214-
RectList_Add(&self.rects, &area);
222+
LinkedList_Append(&self.rects, actual_rect);
215223
return TRUE;
216224
}
217225
group = RBTree_CustomGetData(&self.groups, w);
@@ -221,12 +229,13 @@ LCUI_BOOL Widget_InvalidateArea(LCUI_Widget widget, LCUI_RectF *in_rect,
221229
LinkedList_Init(&group->rects);
222230
RBTree_CustomInsert(&self.groups, w, group);
223231
}
224-
return RectList_Add(&group->rects, &area) == 0;
232+
return LinkedList_Append(&group->rects, actual_rect) == 0;
225233
}
226234

227235
size_t Widget_GetInvalidArea(LCUI_Widget w, LinkedList *rects)
228236
{
229237
LCUI_RectGroup group;
238+
230239
if (!w || w == LCUIWidget_GetRoot()) {
231240
LinkedList_Concat(rects, &self.rects);
232241
return (size_t)rects->length;

src/util/rect.c

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -472,16 +472,3 @@ int RectList_Delete(LinkedList *list, LCUI_Rect *rect)
472472
LinkedList_Concat(list, &extra_list);
473473
return 1;
474474
}
475-
476-
size_t RectList_SplitWith(LinkedList *rects, const LCUI_Rect *bounding,
477-
LinkedList *splited_rects)
478-
{
479-
LCUI_Rect splited_rect;
480-
LinkedListNode *node;
481-
482-
for (LinkedList_Each(node, rects)) {
483-
LCUIRect_GetOverlayRect(bounding, node->data, &splited_rect);
484-
RectList_AddEx(splited_rects, &splited_rect, FALSE);
485-
}
486-
return splited_rects->length;
487-
}

0 commit comments

Comments
 (0)