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+
5565typedef 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
6276static 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
136181static 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 );
0 commit comments