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