1 /**
2  * @file lv_draw_sdl.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "../lv_draw_private.h"
10 #if LV_USE_DRAW_SDL
11 #include LV_SDL_INCLUDE_PATH
12 #include "lv_draw_sdl.h"
13 #include "../../core/lv_refr_private.h"
14 #include "../../display/lv_display_private.h"
15 #include "../../stdlib/lv_string.h"
16 #include "../../drivers/sdl/lv_sdl_window.h"
17 #include "../../misc/cache/lv_cache_entry_private.h"
18 #include "../../misc/lv_area_private.h"
19 
20 /*********************
21  *      DEFINES
22  *********************/
23 #define DRAW_UNIT_ID_SDL     100
24 
25 /**********************
26  *      TYPEDEFS
27  **********************/
28 
29 typedef struct {
30     lv_draw_unit_t base_unit;
31     lv_draw_task_t * task_act;
32     lv_cache_t * texture_cache;
33     lv_draw_buf_t render_draw_buf;
34 } lv_draw_sdl_unit_t;
35 
36 typedef struct {
37     lv_draw_dsc_base_t * draw_dsc;
38     int32_t w;
39     int32_t h;
40     SDL_Texture * texture;
41 } cache_data_t;
42 
43 /**********************
44  *  STATIC PROTOTYPES
45  **********************/
46 static void execute_drawing(lv_draw_sdl_unit_t * u);
47 
48 static int32_t dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer);
49 
50 static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task);
51 static bool draw_to_texture(lv_draw_sdl_unit_t * u, cache_data_t * cache_data);
52 
53 /**********************
54  *  GLOBAL PROTOTYPES
55  **********************/
56 
57 /**********************
58  *  STATIC VARIABLES
59  **********************/
60 static SDL_Texture * layer_get_texture(lv_layer_t * layer);
61 
62 /**********************
63  *      MACROS
64  **********************/
65 
66 /**********************
67  *   GLOBAL FUNCTIONS
68  **********************/
sdl_texture_cache_create_cb(cache_data_t * cached_data,void * user_data)69 static bool sdl_texture_cache_create_cb(cache_data_t * cached_data, void * user_data)
70 {
71     return draw_to_texture((lv_draw_sdl_unit_t *)user_data, cached_data);
72 }
73 
sdl_texture_cache_free_cb(cache_data_t * cached_data,void * user_data)74 static void sdl_texture_cache_free_cb(cache_data_t * cached_data, void * user_data)
75 {
76     LV_UNUSED(user_data);
77 
78     lv_free(cached_data->draw_dsc);
79     SDL_DestroyTexture(cached_data->texture);
80     cached_data->draw_dsc = NULL;
81     cached_data->texture = NULL;
82 }
83 
sdl_texture_cache_compare_cb(const cache_data_t * lhs,const cache_data_t * rhs)84 static lv_cache_compare_res_t sdl_texture_cache_compare_cb(const cache_data_t * lhs, const cache_data_t * rhs)
85 {
86     if(lhs == rhs) return 0;
87 
88     if(lhs->w != rhs->w) {
89         return lhs->w > rhs->w ? 1 : -1;
90     }
91     if(lhs->h != rhs->h) {
92         return lhs->h > rhs->h ? 1 : -1;
93     }
94 
95     uint32_t lhs_dsc_size = lhs->draw_dsc->dsc_size;
96     uint32_t rhs_dsc_size = rhs->draw_dsc->dsc_size;
97 
98     if(lhs_dsc_size != rhs_dsc_size) {
99         return lhs_dsc_size > rhs_dsc_size ? 1 : -1;
100     }
101 
102     const uint8_t * left_draw_dsc = (const uint8_t *)lhs->draw_dsc;
103     const uint8_t * right_draw_dsc = (const uint8_t *)rhs->draw_dsc;
104     left_draw_dsc += sizeof(lv_draw_dsc_base_t);
105     right_draw_dsc += sizeof(lv_draw_dsc_base_t);
106 
107     int cmp_res = lv_memcmp(left_draw_dsc, right_draw_dsc, lhs->draw_dsc->dsc_size - sizeof(lv_draw_dsc_base_t));
108 
109     if(cmp_res != 0) {
110         return cmp_res > 0 ? 1 : -1;
111     }
112 
113     return 0;
114 }
115 
lv_draw_sdl_init(void)116 void lv_draw_sdl_init(void)
117 {
118     lv_draw_sdl_unit_t * draw_sdl_unit = lv_draw_create_unit(sizeof(lv_draw_sdl_unit_t));
119     draw_sdl_unit->base_unit.dispatch_cb = dispatch;
120     draw_sdl_unit->base_unit.evaluate_cb = evaluate;
121     draw_sdl_unit->base_unit.name = "SDL";
122     draw_sdl_unit->texture_cache = lv_cache_create(&lv_cache_class_lru_rb_count,
123     sizeof(cache_data_t), 128, (lv_cache_ops_t) {
124         .compare_cb = (lv_cache_compare_cb_t)sdl_texture_cache_compare_cb,
125         .create_cb = (lv_cache_create_cb_t)sdl_texture_cache_create_cb,
126         .free_cb = (lv_cache_free_cb_t)sdl_texture_cache_free_cb,
127     });
128     lv_cache_set_name(draw_sdl_unit->texture_cache, "SDL_TEXTURE");
129 
130     lv_draw_buf_init(&draw_sdl_unit->render_draw_buf, 0, 0, LV_COLOR_FORMAT_ARGB8888, LV_STRIDE_AUTO, NULL, 0);
131 }
132 
133 /**********************
134  *   STATIC FUNCTIONS
135  **********************/
136 
dispatch(lv_draw_unit_t * draw_unit,lv_layer_t * layer)137 static int32_t dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
138 {
139     lv_draw_sdl_unit_t * draw_sdl_unit = (lv_draw_sdl_unit_t *) draw_unit;
140 
141     /*Return immediately if it's busy with a draw task*/
142     if(draw_sdl_unit->task_act) return 0;
143 
144     lv_draw_task_t * t = NULL;
145     t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_SDL);
146     if(t == NULL) return -1;
147 
148     lv_display_t * disp = lv_refr_get_disp_refreshing();
149     SDL_Texture * texture = layer_get_texture(layer);
150     if(layer != disp->layer_head && texture == NULL) {
151         void * buf = lv_draw_layer_alloc_buf(layer);
152         if(buf == NULL) return -1;
153 
154         SDL_Renderer * renderer = lv_sdl_window_get_renderer(disp);
155         int32_t w = lv_area_get_width(&layer->buf_area);
156         int32_t h = lv_area_get_height(&layer->buf_area);
157         layer->user_data = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
158                                              SDL_TEXTUREACCESS_TARGET, w, h);
159     }
160 
161     t->state = LV_DRAW_TASK_STATE_IN_PROGRESS;
162     draw_sdl_unit->base_unit.target_layer = layer;
163     draw_sdl_unit->base_unit.clip_area = &t->clip_area;
164     draw_sdl_unit->task_act = t;
165 
166     execute_drawing(draw_sdl_unit);
167 
168     draw_sdl_unit->task_act->state = LV_DRAW_TASK_STATE_READY;
169     draw_sdl_unit->task_act = NULL;
170 
171     /*The draw unit is free now. Request a new dispatching as it can get a new task*/
172     lv_draw_dispatch_request();
173     return 1;
174 }
175 
evaluate(lv_draw_unit_t * draw_unit,lv_draw_task_t * task)176 static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task)
177 {
178     LV_UNUSED(draw_unit);
179 
180     if(task->type == LV_DRAW_TASK_TYPE_IMAGE &&
181        ((lv_draw_image_dsc_t *)task->draw_dsc)->header.cf >= LV_COLOR_FORMAT_PROPRIETARY_START) {
182         return 0;
183     }
184 
185     /*If not refreshing the display probably it's a canvas rendering
186      *which his not support in SDL as it's not a texture.*/
187     if(lv_refr_get_disp_refreshing() == NULL) return 0;
188 
189     if(((lv_draw_dsc_base_t *)task->draw_dsc)->user_data == NULL) {
190         task->preference_score = 0;
191         task->preferred_draw_unit_id = DRAW_UNIT_ID_SDL;
192     }
193     return 0;
194 }
195 
draw_to_texture(lv_draw_sdl_unit_t * u,cache_data_t * cache_data)196 static bool draw_to_texture(lv_draw_sdl_unit_t * u, cache_data_t * cache_data)
197 {
198     lv_draw_task_t * task = u->task_act;
199 
200     lv_layer_t dest_layer;
201     lv_layer_init(&dest_layer);
202 
203     int32_t texture_w = lv_area_get_width(&task->_real_area);
204     int32_t texture_h = lv_area_get_height(&task->_real_area);
205 
206     if(!lv_draw_buf_reshape(&u->render_draw_buf, LV_COLOR_FORMAT_ARGB8888, texture_w, texture_h, LV_STRIDE_AUTO)) {
207         uint8_t * data = u->render_draw_buf.unaligned_data;
208         uint32_t data_size = LV_DRAW_BUF_SIZE(texture_w, texture_h, LV_COLOR_FORMAT_ARGB8888);
209         if(data == NULL) data = malloc(data_size);
210         else data = realloc(data, data_size);
211 
212         LV_ASSERT_MALLOC(data);
213         lv_result_t init_result = lv_draw_buf_init(&u->render_draw_buf, texture_w, texture_h, LV_COLOR_FORMAT_ARGB8888,
214                                                    LV_STRIDE_AUTO, data, data_size);
215         LV_ASSERT(init_result == LV_RESULT_OK);
216     }
217 
218 
219     dest_layer.draw_buf = &u->render_draw_buf;
220     dest_layer.color_format = LV_COLOR_FORMAT_ARGB8888;
221     dest_layer.buf_area = task->_real_area;
222     dest_layer._clip_area = task->_real_area;
223     dest_layer.phy_clip_area = task->_real_area;
224     lv_memzero(u->render_draw_buf.data, lv_area_get_size(&task->_real_area) * 4);
225 
226     lv_display_t * disp = lv_refr_get_disp_refreshing();
227 
228     lv_obj_t * obj = ((lv_draw_dsc_base_t *)task->draw_dsc)->obj;
229     bool original_send_draw_task_event = false;
230     if(obj) {
231         original_send_draw_task_event = lv_obj_has_flag(obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
232         lv_obj_remove_flag(obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
233     }
234 
235     switch(task->type) {
236         case LV_DRAW_TASK_TYPE_FILL: {
237                 lv_draw_fill_dsc_t * fill_dsc = task->draw_dsc;
238                 lv_draw_rect_dsc_t rect_dsc;
239                 lv_draw_rect_dsc_init(&rect_dsc);
240                 rect_dsc.base.user_data = lv_sdl_window_get_renderer(disp);
241                 rect_dsc.bg_color = fill_dsc->color;
242                 rect_dsc.bg_grad = fill_dsc->grad;
243                 rect_dsc.radius = fill_dsc->radius;
244                 rect_dsc.bg_opa = fill_dsc->opa;
245 
246                 lv_draw_rect(&dest_layer, &rect_dsc, &task->area);
247             }
248             break;
249         case LV_DRAW_TASK_TYPE_BORDER: {
250                 lv_draw_border_dsc_t * border_dsc = task->draw_dsc;
251                 lv_draw_rect_dsc_t rect_dsc;
252                 lv_draw_rect_dsc_init(&rect_dsc);
253                 rect_dsc.base.user_data = lv_sdl_window_get_renderer(disp);
254                 rect_dsc.bg_opa = LV_OPA_TRANSP;
255                 rect_dsc.radius = border_dsc->radius;
256                 rect_dsc.border_color = border_dsc->color;
257                 rect_dsc.border_opa = border_dsc->opa;
258                 rect_dsc.border_side = border_dsc->side;
259                 rect_dsc.border_width = border_dsc->width;
260                 lv_draw_rect(&dest_layer, &rect_dsc, &task->area);
261                 break;
262             }
263         case LV_DRAW_TASK_TYPE_BOX_SHADOW: {
264                 lv_draw_box_shadow_dsc_t * box_shadow_dsc = task->draw_dsc;
265                 lv_draw_rect_dsc_t rect_dsc;
266                 lv_draw_rect_dsc_init(&rect_dsc);
267                 rect_dsc.base.user_data = lv_sdl_window_get_renderer(disp);
268                 rect_dsc.bg_opa = LV_OPA_0;
269                 rect_dsc.radius = box_shadow_dsc->radius;
270                 rect_dsc.bg_color = box_shadow_dsc->color;
271                 rect_dsc.shadow_opa = box_shadow_dsc->opa;
272                 rect_dsc.shadow_width = box_shadow_dsc->width;
273                 rect_dsc.shadow_spread = box_shadow_dsc->spread;
274                 rect_dsc.shadow_offset_x = box_shadow_dsc->ofs_x;
275                 rect_dsc.shadow_offset_y = box_shadow_dsc->ofs_y;
276                 lv_draw_rect(&dest_layer, &rect_dsc, &task->area);
277                 break;
278             }
279         case LV_DRAW_TASK_TYPE_LABEL: {
280                 lv_draw_label_dsc_t label_dsc;
281                 lv_memcpy(&label_dsc, task->draw_dsc, sizeof(label_dsc));
282                 label_dsc.base.user_data = lv_sdl_window_get_renderer(disp);
283                 lv_draw_label(&dest_layer, &label_dsc, &task->area);
284             }
285             break;
286         case LV_DRAW_TASK_TYPE_ARC: {
287                 lv_draw_arc_dsc_t arc_dsc;
288                 lv_memcpy(&arc_dsc, task->draw_dsc, sizeof(arc_dsc));
289                 arc_dsc.base.user_data = lv_sdl_window_get_renderer(disp);
290                 lv_draw_arc(&dest_layer, &arc_dsc);
291             }
292             break;
293         case LV_DRAW_TASK_TYPE_LINE: {
294                 lv_draw_line_dsc_t line_dsc;
295                 lv_memcpy(&line_dsc, task->draw_dsc, sizeof(line_dsc));
296                 line_dsc.base.user_data = lv_sdl_window_get_renderer(disp);
297                 lv_draw_line(&dest_layer, &line_dsc);
298             }
299             break;
300         case LV_DRAW_TASK_TYPE_TRIANGLE: {
301                 lv_draw_triangle_dsc_t triangle_dsc;
302                 lv_memcpy(&triangle_dsc, task->draw_dsc, sizeof(triangle_dsc));
303                 triangle_dsc.base.user_data = lv_sdl_window_get_renderer(disp);
304                 lv_draw_triangle(&dest_layer, &triangle_dsc);
305             }
306             break;
307         case LV_DRAW_TASK_TYPE_IMAGE: {
308                 lv_draw_image_dsc_t image_dsc;
309                 lv_memcpy(&image_dsc, task->draw_dsc, sizeof(image_dsc));
310                 image_dsc.base.user_data = lv_sdl_window_get_renderer(disp);
311                 lv_draw_image(&dest_layer, &image_dsc, &task->area);
312                 break;
313             }
314         default:
315             return false;
316     }
317 
318     while(dest_layer.draw_task_head) {
319         lv_draw_dispatch_layer(disp, &dest_layer);
320         if(dest_layer.draw_task_head) {
321             lv_draw_dispatch_wait_for_request();
322         }
323     }
324 
325     SDL_Texture * texture = SDL_CreateTexture(lv_sdl_window_get_renderer(disp), SDL_PIXELFORMAT_ARGB8888,
326                                               SDL_TEXTUREACCESS_STATIC, texture_w, texture_h);
327     SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
328     SDL_UpdateTexture(texture, NULL, u->render_draw_buf.data, texture_w * 4);
329 
330     lv_draw_dsc_base_t * base_dsc = task->draw_dsc;
331 
332     cache_data->draw_dsc = lv_malloc(base_dsc->dsc_size);
333     lv_memcpy((void *)cache_data->draw_dsc, base_dsc, base_dsc->dsc_size);
334     cache_data->w = texture_w;
335     cache_data->h = texture_h;
336     cache_data->texture = texture;
337 
338     if(obj) {
339         lv_obj_update_flag(obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS, original_send_draw_task_event);
340     }
341 
342     return true;
343 }
344 
blend_texture_layer(lv_draw_sdl_unit_t * u)345 static void blend_texture_layer(lv_draw_sdl_unit_t * u)
346 {
347     lv_display_t * disp = lv_refr_get_disp_refreshing();
348     SDL_Renderer * renderer = lv_sdl_window_get_renderer(disp);
349 
350     SDL_Rect clip_rect;
351     clip_rect.x = u->base_unit.clip_area->x1;
352     clip_rect.y = u->base_unit.clip_area->y1;
353     clip_rect.w = lv_area_get_width(u->base_unit.clip_area);
354     clip_rect.h = lv_area_get_height(u->base_unit.clip_area);
355 
356     lv_draw_task_t * t = u->task_act;
357     lv_draw_image_dsc_t * draw_dsc = t->draw_dsc;
358     SDL_Rect rect;
359     rect.w = (lv_area_get_width(&t->area) * draw_dsc->scale_x) / 256;
360     rect.h = (lv_area_get_height(&t->area) * draw_dsc->scale_y) / 256;
361 
362     rect.x = -draw_dsc->pivot.x;
363     rect.y = -draw_dsc->pivot.y;
364     rect.x = (rect.x * draw_dsc->scale_x) / 256;
365     rect.y = (rect.y * draw_dsc->scale_y) / 256;
366     rect.x += t->area.x1 + draw_dsc->pivot.x;
367     rect.y += t->area.y1 + draw_dsc->pivot.y;
368 
369     lv_layer_t * src_layer = (lv_layer_t *)draw_dsc->src;
370     SDL_Texture * src_texture = layer_get_texture(src_layer);
371 
372     SDL_SetTextureAlphaMod(src_texture, draw_dsc->opa);
373     SDL_SetTextureBlendMode(src_texture, SDL_BLENDMODE_BLEND);
374     SDL_SetRenderTarget(renderer, layer_get_texture(u->base_unit.target_layer));
375     SDL_RenderSetClipRect(renderer, &clip_rect);
376 
377     SDL_Point center = {draw_dsc->pivot.x, draw_dsc->pivot.y};
378     SDL_RenderCopyEx(renderer, src_texture, NULL, &rect, draw_dsc->rotation / 10, &center, SDL_FLIP_NONE);
379 
380     SDL_DestroyTexture(src_texture);
381     SDL_RenderSetClipRect(renderer, NULL);
382 }
383 
draw_from_cached_texture(lv_draw_sdl_unit_t * u)384 static void draw_from_cached_texture(lv_draw_sdl_unit_t * u)
385 {
386     lv_draw_task_t * t = u->task_act;
387 
388     cache_data_t data_to_find;
389     data_to_find.draw_dsc = (lv_draw_dsc_base_t *)t->draw_dsc;
390 
391     data_to_find.w = lv_area_get_width(&t->_real_area);
392     data_to_find.h = lv_area_get_height(&t->_real_area);
393     data_to_find.texture = NULL;
394 
395     /*user_data stores the renderer to differentiate it from SW rendered tasks.
396      *However the cached texture is independent from the renderer so use NULL user_data*/
397     void * user_data_saved = data_to_find.draw_dsc->user_data;
398     data_to_find.draw_dsc->user_data = NULL;
399 
400     /*Absolute coordinates are different for the same draw_dsc on a different position.
401      *So make everything relative to 0;0  before caching*/
402     lv_area_t a = t->area;
403     if(t->type == LV_DRAW_TASK_TYPE_IMAGE) {
404         lv_draw_image_dsc_t * img_dsc = (lv_draw_image_dsc_t *)data_to_find.draw_dsc;
405         lv_area_move(&img_dsc->image_area, -t->area.x1, -t->area.y1);
406     }
407     else if(t->type == LV_DRAW_TASK_TYPE_TRIANGLE) {
408         lv_draw_triangle_dsc_t * tri_dsc = (lv_draw_triangle_dsc_t *)data_to_find.draw_dsc;
409         tri_dsc->p[0].x -= t->area.x1;
410         tri_dsc->p[0].y -= t->area.y1;
411         tri_dsc->p[1].x -= t->area.x1;
412         tri_dsc->p[1].y -= t->area.y1;
413         tri_dsc->p[2].x -= t->area.x1;
414         tri_dsc->p[2].y -= t->area.y1;
415     }
416     else if(t->type == LV_DRAW_TASK_TYPE_LINE) {
417         lv_draw_line_dsc_t * line_dsc = (lv_draw_line_dsc_t *)data_to_find.draw_dsc;
418         line_dsc->p1.x -= t->area.x1;
419         line_dsc->p1.y -= t->area.y1;
420         line_dsc->p2.x -= t->area.x1;
421         line_dsc->p2.y -= t->area.y1;
422     }
423     else if(t->type == LV_DRAW_TASK_TYPE_ARC) {
424         lv_draw_arc_dsc_t * arc_dsc = (lv_draw_arc_dsc_t *)data_to_find.draw_dsc;
425         arc_dsc->center.x -= t->area.x1;
426         arc_dsc->center.y -= t->area.y1;
427     }
428 
429     lv_area_move(&t->area, -a.x1, -a.y1);
430     lv_area_move(&t->_real_area, -a.x1, -a.y1);
431 
432     lv_cache_entry_t * entry_cached = lv_cache_acquire_or_create(u->texture_cache, &data_to_find, u);
433 
434     lv_area_move(&t->area, a.x1, a.y1);
435     lv_area_move(&t->_real_area, a.x1, a.y1);
436 
437     if(!entry_cached) {
438         return;
439     }
440 
441     data_to_find.draw_dsc->user_data = user_data_saved;
442 
443     cache_data_t * data_cached = lv_cache_entry_get_data(entry_cached);
444     SDL_Texture * texture = data_cached->texture;
445     lv_display_t * disp = lv_refr_get_disp_refreshing();
446     SDL_Renderer * renderer = lv_sdl_window_get_renderer(disp);
447 
448     lv_layer_t * dest_layer = u->base_unit.target_layer;
449     SDL_Rect clip_rect;
450     clip_rect.x = u->base_unit.clip_area->x1 - dest_layer->buf_area.x1;
451     clip_rect.y = u->base_unit.clip_area->y1 - dest_layer->buf_area.y1;
452     clip_rect.w = lv_area_get_width(u->base_unit.clip_area);
453     clip_rect.h = lv_area_get_height(u->base_unit.clip_area);
454 
455     SDL_Rect rect;
456 
457     SDL_SetRenderTarget(renderer, layer_get_texture(dest_layer));
458 
459     rect.x = t->_real_area.x1 - dest_layer->buf_area.x1;
460     rect.y = t->_real_area.y1 - dest_layer->buf_area.y1;
461     rect.w = data_cached->w;
462     rect.h = data_cached->h;
463 
464     SDL_RenderSetClipRect(renderer, &clip_rect);
465     SDL_RenderCopy(renderer, texture, NULL, &rect);
466 
467     SDL_RenderSetClipRect(renderer, NULL);
468 
469     lv_cache_release(u->texture_cache, entry_cached, u);
470 
471     /*Do not cache non static (const) texts as the text's pointer can be freed/reallocated
472      *at any time resulting in a wild pointer in the cached draw dsc. */
473     if(t->type == LV_DRAW_TASK_TYPE_LABEL) {
474         lv_draw_label_dsc_t * label_dsc = t->draw_dsc;
475         if(!label_dsc->text_static) {
476             lv_cache_drop(u->texture_cache, &data_to_find, NULL);
477         }
478     }
479 }
480 
execute_drawing(lv_draw_sdl_unit_t * u)481 static void execute_drawing(lv_draw_sdl_unit_t * u)
482 {
483     lv_draw_task_t * t = u->task_act;
484 
485     if(t->type == LV_DRAW_TASK_TYPE_FILL) {
486         lv_draw_fill_dsc_t * fill_dsc = t->draw_dsc;
487         if(fill_dsc->radius == 0 && fill_dsc->grad.dir == LV_GRAD_DIR_NONE) {
488             SDL_Rect rect;
489             lv_layer_t * layer = u->base_unit.target_layer;
490             lv_area_t fill_area = t->area;
491             lv_area_intersect(&fill_area, &fill_area, u->base_unit.clip_area);
492 
493             rect.x = fill_area.x1 - layer->buf_area.x1;
494             rect.y = fill_area.y1 - layer->buf_area.y1;
495             rect.w = lv_area_get_width(&fill_area);
496             rect.h = lv_area_get_height(&fill_area);
497             lv_display_t * disp = lv_refr_get_disp_refreshing();
498             SDL_Renderer * renderer = lv_sdl_window_get_renderer(disp);
499             SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
500             SDL_SetRenderDrawColor(renderer, fill_dsc->color.red, fill_dsc->color.green, fill_dsc->color.blue, fill_dsc->opa);
501             SDL_RenderSetClipRect(renderer, NULL);
502             SDL_RenderFillRect(renderer, &rect);
503             return;
504         }
505     }
506 
507     if(t->type == LV_DRAW_TASK_TYPE_LAYER) {
508         blend_texture_layer(u);
509         return;
510     }
511 
512     draw_from_cached_texture(u);
513 }
514 
layer_get_texture(lv_layer_t * layer)515 static SDL_Texture * layer_get_texture(lv_layer_t * layer)
516 {
517     return layer->user_data;
518 }
519 
520 #endif /*LV_USE_DRAW_SDL*/
521