1 /**
2  * @file lv_draw_dave2d.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_draw_dave2d.h"
10 #if LV_USE_DRAW_DAVE2D
11 #include "../../lv_draw_buf_private.h"
12 #include "../../../misc/lv_area_private.h"
13 
14 /*********************
15  *      DEFINES
16  *********************/
17 #define DRAW_UNIT_ID_DAVE2D     4
18 
19 /**********************
20  *      TYPEDEFS
21  **********************/
22 
23 /**********************
24  *  STATIC PROTOTYPES
25  **********************/
26 #if LV_USE_OS
27     static void _dave2d_render_thread_cb(void * ptr);
28 #endif
29 
30 static void execute_drawing(lv_draw_dave2d_unit_t * u);
31 
32 #if defined(RENESAS_CORTEX_M85)
33     #if (BSP_CFG_DCACHE_ENABLED)
34         static void _dave2d_buf_invalidate_cache_cb(const lv_draw_buf_t * draw_buf, const lv_area_t * area);
35     #endif
36 #endif
37 
38 static int32_t _dave2d_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task);
39 
40 static int32_t lv_draw_dave2d_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer);
41 
42 static d2_s32 lv_dave2d_init(void);
43 
44 static void lv_draw_buf_dave2d_init_handlers(void);
45 
46 void dave2d_execute_dlist_and_flush(void);
47 
48 /**********************
49  *  GLOBAL PROTOTYPES
50  **********************/
51 
52 /**********************
53  *  STATIC VARIABLES
54  **********************/
55 
56 d2_device * _d2_handle;
57 d2_renderbuffer * _renderbuffer;
58 d2_renderbuffer * _blit_renderbuffer;
59 
60 lv_ll_t  _ll_Dave2D_Tasks;
61 
62 #if LV_USE_OS
63     lv_mutex_t xd2Semaphore;
64 #endif
65 
66 /**********************
67  *      MACROS
68  **********************/
69 
70 /**********************
71  *   GLOBAL FUNCTIONS
72  **********************/
73 
lv_draw_dave2d_init(void)74 void lv_draw_dave2d_init(void)
75 {
76     d2_s32 result = D2_OK;
77 
78     lv_draw_buf_dave2d_init_handlers();
79 
80     lv_draw_dave2d_unit_t * draw_dave2d_unit = lv_draw_create_unit(sizeof(lv_draw_dave2d_unit_t));
81     draw_dave2d_unit->base_unit.dispatch_cb = lv_draw_dave2d_dispatch;
82     draw_dave2d_unit->base_unit.evaluate_cb = _dave2d_evaluate;
83     draw_dave2d_unit->base_unit.name = "DAVE2D";
84     draw_dave2d_unit->idx = DRAW_UNIT_ID_DAVE2D;
85 
86     result = lv_dave2d_init();
87     LV_ASSERT(D2_OK == result);
88 
89 #if LV_USE_OS
90     lv_result_t res;
91     res =  lv_mutex_init(&xd2Semaphore);
92     LV_ASSERT(LV_RESULT_OK == res);
93 
94     draw_dave2d_unit->pd2Mutex    = &xd2Semaphore;
95 #endif
96 
97     draw_dave2d_unit->d2_handle = _d2_handle;
98     draw_dave2d_unit->renderbuffer = _renderbuffer;
99     lv_ll_init(&_ll_Dave2D_Tasks, 4);
100 
101 #if LV_USE_OS
102     lv_thread_init(&draw_dave2d_unit->thread, "dave2d", LV_THREAD_PRIO_HIGH, _dave2d_render_thread_cb, 8 * 1024,
103                    draw_dave2d_unit);
104 #endif
105 
106 }
107 
108 /**********************
109  *   STATIC FUNCTIONS
110  **********************/
111 
lv_draw_buf_dave2d_init_handlers(void)112 static void lv_draw_buf_dave2d_init_handlers(void)
113 {
114 
115 #if defined(RENESAS_CORTEX_M85)
116 #if (BSP_CFG_DCACHE_ENABLED)
117     lv_draw_buf_handlers_t * handlers = lv_draw_buf_get_handlers();
118     handlers->invalidate_cache_cb = _dave2d_buf_invalidate_cache_cb;
119 #endif
120 #endif
121 }
122 
123 #if defined(RENESAS_CORTEX_M85)
124 #if (BSP_CFG_DCACHE_ENABLED)
_dave2d_buf_invalidate_cache_cb(const lv_draw_buf_t * draw_buf,const lv_area_t * area)125 static void _dave2d_buf_invalidate_cache_cb(const lv_draw_buf_t * draw_buf, const lv_area_t * area)
126 {
127     const lv_image_header_t * header = &draw_buf->header;
128     uint32_t stride = header->stride;
129     lv_color_format_t cf = header->cf;
130 
131     uint8_t * address = draw_buf->data;
132     int32_t i = 0;
133     uint32_t bytes_per_pixel = lv_color_format_get_size(cf);
134     int32_t width = lv_area_get_width(area);
135     int32_t lines = lv_area_get_height(area);
136     int32_t bytes_to_flush_per_line = (int32_t)width * (int32_t)bytes_per_pixel;
137 
138     /* Stride is in bytes, not pixels */
139     address = address + (area->x1 * (int32_t)bytes_per_pixel) + (stride * (uint32_t)area->y1);
140 
141     for(i = 0; i < lines; i++) {
142         SCB_CleanInvalidateDCache_by_Addr(address, bytes_to_flush_per_line);
143         address += stride;
144     }
145 }
146 #endif
147 #endif
148 
149 /**
150  * @todo
151  * LVGL needs to use hardware acceleration for buf_copy and do not affect GPU rendering.
152  */
153 #if 0
154 static void _dave2d_buf_copy(void * dest_buf, uint32_t dest_w, uint32_t dest_h, const lv_area_t * dest_area,
155                              void * src_buf,  uint32_t src_w, uint32_t src_h, const lv_area_t * src_area, lv_color_format_t color_format)
156 {
157     d2_s32     result;
158 
159 #if LV_USE_OS
160     lv_result_t  status;
161 
162     status = lv_mutex_lock(&xd2Semaphore);
163     LV_ASSERT(LV_RESULT_OK == status);
164 #endif
165 
166     d2_u32 src_blend_mode = d2_getblendmodesrc(_d2_handle);
167     d2_u32 dst_blend_mode = d2_getblendmodedst(_d2_handle);
168 
169     result = d2_selectrenderbuffer(_d2_handle, _blit_renderbuffer);
170     LV_ASSERT(D2_OK == result);
171 
172     result = d2_setblendmode(_d2_handle, d2_bm_one, d2_bm_zero);
173     LV_ASSERT(D2_OK == result);
174 
175     // Generate render operations
176     result = d2_framebuffer(_d2_handle, (uint16_t *)dest_buf, DISPLAY_HSIZE_INPUT0, DISPLAY_BUFFER_STRIDE_PIXELS_INPUT0,
177                             DISPLAY_VSIZE_INPUT0, lv_draw_dave2d_cf_fb_get());
178     LV_ASSERT(D2_OK == result);
179 
180     result = d2_cliprect(_d2_handle, (d2_border)dest_area->x1, (d2_border)dest_area->y1, (d2_border)dest_area->x2,
181                          (d2_border)dest_area->y2);
182     LV_ASSERT(D2_OK == result);
183 
184     result = d2_setblitsrc(_d2_handle, (void *) src_buf, (d2_s32)src_w, (d2_s32)src_w, (d2_s32)src_h,
185                            lv_draw_dave2d_lv_colour_fmt_to_d2_fmt(color_format));
186     LV_ASSERT(D2_OK == result);
187 
188     result = d2_blitcopy(_d2_handle, (d2_s32)src_w, (d2_s32)src_h, (d2_blitpos)src_area->x1, (d2_blitpos)src_area->y1,
189                          D2_FIX4(dest_w), D2_FIX4(dest_h),
190                          D2_FIX4(dest_area->x1), D2_FIX4(dest_area->y1), 0);
191     LV_ASSERT(D2_OK == result);
192 
193     // Execute render operations
194     result = d2_executerenderbuffer(_d2_handle, _blit_renderbuffer, 0);
195     LV_ASSERT(D2_OK == result) ;
196 
197     result = d2_flushframe(_d2_handle);
198     LV_ASSERT(D2_OK == result);
199 
200     result = d2_selectrenderbuffer(_d2_handle, _renderbuffer);
201     LV_ASSERT(D2_OK == result);
202 
203     result = d2_setblendmode(_d2_handle, src_blend_mode, dst_blend_mode);
204     LV_ASSERT(D2_OK != result);
205 
206 #if LV_USE_OS
207     status = lv_mutex_unlock(&xd2Semaphore);
208     LV_ASSERT(LV_RESULT_OK == status);
209 #endif
210 
211 }
212 #endif
213 
214 #define USE_D2 (1)
215 
_dave2d_evaluate(lv_draw_unit_t * u,lv_draw_task_t * t)216 static int32_t _dave2d_evaluate(lv_draw_unit_t * u, lv_draw_task_t * t)
217 {
218     LV_UNUSED(u);
219     int32_t ret = 0;
220 
221     lv_draw_dsc_base_t * draw_dsc_base = (lv_draw_dsc_base_t *) t->draw_dsc;
222 
223     if(!lv_draw_dave2d_is_dest_cf_supported(draw_dsc_base->layer->color_format))
224         return 0;
225 
226     switch(t->type) {
227         case LV_DRAW_TASK_TYPE_FILL: {
228 #if USE_D2
229                 lv_draw_fill_dsc_t * dsc = t->draw_dsc;
230                 if(dsc->grad.dir == LV_GRAD_DIR_NONE
231                    || ((dsc->grad.dir != LV_GRAD_DIR_NONE)
232                        && ((dsc->grad.stops[0].color.blue == dsc->grad.stops[dsc->grad.stops_count - 1].color.blue)
233                            && (dsc->grad.stops[0].color.red   == dsc->grad.stops[dsc->grad.stops_count - 1].color.red)
234                            && (dsc->grad.stops[0].color.green == dsc->grad.stops[dsc->grad.stops_count - 1].color.green)))) {
235 
236                     t->preferred_draw_unit_id = DRAW_UNIT_ID_DAVE2D;
237                     t->preference_score = 0;
238 
239                 }
240                 else
241 #endif
242                 {
243                 }
244                 ret =  0;
245                 break;
246             }
247         case LV_DRAW_TASK_TYPE_LAYER: {
248                 ret = 0;
249                 break;
250             }
251 
252         case LV_DRAW_TASK_TYPE_IMAGE: {
253                 lv_draw_image_dsc_t * dsc = t->draw_dsc;
254                 if((dsc->header.cf >= LV_COLOR_FORMAT_PROPRIETARY_START) || (dsc->header.cf == LV_COLOR_FORMAT_RGB888)) {
255                     ret = 0;
256                     break;
257                 }
258 #if USE_D2
259                 t->preferred_draw_unit_id = DRAW_UNIT_ID_DAVE2D;
260                 t->preference_score = 0;
261 #endif
262                 ret = 0;
263                 break;
264             }
265 
266         case LV_DRAW_TASK_TYPE_BORDER: {
267 #if USE_D2
268                 t->preferred_draw_unit_id = DRAW_UNIT_ID_DAVE2D;
269                 t->preference_score = 0;
270 #endif
271                 ret = 0;
272                 break;
273             }
274 
275         case  LV_DRAW_TASK_TYPE_BOX_SHADOW: {
276                 ret = 0;
277                 break;
278             }
279 
280         case  LV_DRAW_TASK_TYPE_LABEL: {
281 #if USE_D2
282                 t->preferred_draw_unit_id = DRAW_UNIT_ID_DAVE2D;
283                 t->preference_score = 0;
284 #endif
285                 ret = 0;
286                 break;
287             }
288 
289         case LV_DRAW_TASK_TYPE_LINE: {
290 #if USE_D2
291                 t->preferred_draw_unit_id = DRAW_UNIT_ID_DAVE2D;
292                 t->preference_score = 0;
293 #endif
294                 ret = 0;
295                 break;
296             }
297 
298         case  LV_DRAW_TASK_TYPE_ARC: {
299 #if USE_D2
300                 t->preferred_draw_unit_id = DRAW_UNIT_ID_DAVE2D;
301                 t->preference_score = 0;
302 #endif
303                 ret = 0;
304                 break;
305             }
306 
307         case LV_DRAW_TASK_TYPE_TRIANGLE: {
308 #if USE_D2
309                 lv_draw_fill_dsc_t * dsc = t->draw_dsc;
310                 if(dsc->grad.dir == LV_GRAD_DIR_NONE
311                    || ((dsc->grad.dir != LV_GRAD_DIR_NONE)
312                        && ((dsc->grad.stops[0].color.blue == dsc->grad.stops[dsc->grad.stops_count - 1].color.blue)
313                            && (dsc->grad.stops[0].color.red   == dsc->grad.stops[dsc->grad.stops_count - 1].color.red)
314                            && (dsc->grad.stops[0].color.green == dsc->grad.stops[dsc->grad.stops_count - 1].color.green)))) {
315                     t->preferred_draw_unit_id = DRAW_UNIT_ID_DAVE2D;
316                     t->preference_score = 0;
317                 }
318                 else {
319                 }
320 #endif
321                 ret = 0;
322                 break;
323             }
324 
325         case  LV_DRAW_TASK_TYPE_MASK_RECTANGLE: {
326 #if 0//USE_D2
327                 t->preferred_draw_unit_id = DRAW_UNIT_ID_DAVE2D;
328                 t->preference_score = 0;
329 #endif
330                 ret = 0;
331                 break;
332             }
333 
334         case LV_DRAW_TASK_TYPE_MASK_BITMAP: {
335                 ret = 0;
336                 break;
337             }
338 
339         default:
340             ret = 0;
341             break;
342     }
343 
344     return ret;
345 }
346 
347 #define DAVE2D_REFERRING_WATERMARK  10
348 
lv_draw_dave2d_dispatch(lv_draw_unit_t * draw_unit,lv_layer_t * layer)349 static int32_t lv_draw_dave2d_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
350 {
351     lv_draw_dave2d_unit_t * draw_dave2d_unit = (lv_draw_dave2d_unit_t *) draw_unit;
352 #if  (0 == D2_RENDER_EACH_OPERATION)
353     static uint32_t ref_count = 0;
354 #endif
355 
356     /*Return immediately if it's busy with draw task*/
357     if(draw_dave2d_unit->task_act) return 0;
358 
359     lv_draw_task_t * t = NULL;
360     t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_DAVE2D);
361     while(t && t->preferred_draw_unit_id != DRAW_UNIT_ID_DAVE2D) {
362         t->state = LV_DRAW_TASK_STATE_READY;
363         t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_DAVE2D);
364     }
365 
366     if(t == NULL) {
367 #if  (0 == D2_RENDER_EACH_OPERATION)
368         if(false == lv_ll_is_empty(&_ll_Dave2D_Tasks)) {
369             ref_count = 0;
370             dave2d_execute_dlist_and_flush();
371         }
372 #endif
373         return LV_DRAW_UNIT_IDLE;  /*Couldn't start rendering*/
374     }
375 
376     /* Return if target buffer format is not supported. */
377     if(!lv_draw_dave2d_is_dest_cf_supported(layer->color_format)) {
378         return LV_DRAW_UNIT_IDLE; /*Couldn't start rendering*/
379     }
380 
381     void * buf = lv_draw_layer_alloc_buf(layer);
382     if(buf == NULL) {
383         return LV_DRAW_UNIT_IDLE;  /*Couldn't start rendering*/
384     }
385 
386 #if  (0 == D2_RENDER_EACH_OPERATION)
387     ref_count += lv_draw_get_dependent_count(t);
388 
389     if(DAVE2D_REFERRING_WATERMARK < ref_count) {
390         ref_count = 0;
391         dave2d_execute_dlist_and_flush();
392     }
393 
394     lv_draw_task_t ** p_new_list_entry;
395     p_new_list_entry = lv_ll_ins_tail(&_ll_Dave2D_Tasks);
396     *p_new_list_entry = t;
397 #endif
398 
399     t->state = LV_DRAW_TASK_STATE_IN_PROGRESS;
400     draw_dave2d_unit->base_unit.target_layer = layer;
401     draw_dave2d_unit->base_unit.clip_area = &t->clip_area;
402     draw_dave2d_unit->task_act = t;
403 
404 #if LV_USE_OS
405     /*Let the render thread work*/
406     lv_thread_sync_signal(&draw_dave2d_unit->sync);
407 #else
408     execute_drawing(draw_dave2d_unit);
409 #if  (D2_RENDER_EACH_OPERATION)
410     draw_dave2d_unit->task_act->state = LV_DRAW_TASK_STATE_READY;
411 #endif
412     draw_dave2d_unit->task_act = NULL;
413 
414     /*The draw unit is free now. Request a new dispatching as it can get a new task*/
415     lv_draw_dispatch_request();
416 
417 #endif
418     return 1;
419 }
420 
421 #if LV_USE_OS
_dave2d_render_thread_cb(void * ptr)422 static void _dave2d_render_thread_cb(void * ptr)
423 {
424     lv_draw_dave2d_unit_t * u = ptr;
425 
426     lv_thread_sync_init(&u->sync);
427 
428     while(1) {
429         while(u->task_act == NULL) {
430             lv_thread_sync_wait(&u->sync);
431         }
432 
433         execute_drawing(u);
434 
435         /*Cleanup*/
436 #if  (D2_RENDER_EACH_OPERATION)
437         u->task_act->state = LV_DRAW_TASK_STATE_READY;
438 #endif
439         u->task_act = NULL;
440 
441         /*The draw unit is free now. Request a new dispatching as it can get a new task*/
442         lv_draw_dispatch_request();
443     }
444 }
445 #endif
446 
execute_drawing(lv_draw_dave2d_unit_t * u)447 static void execute_drawing(lv_draw_dave2d_unit_t * u)
448 {
449     /*Render the draw task*/
450     lv_draw_task_t * t = u->task_act;
451 
452 #if defined(RENESAS_CORTEX_M85)
453 #if (BSP_CFG_DCACHE_ENABLED)
454     lv_layer_t * layer = u->base_unit.target_layer;
455     lv_area_t clipped_area;
456     int32_t x;
457     int32_t y;
458 
459     lv_area_intersect(&clipped_area,  &t->area, u->base_unit.clip_area);
460 
461     x = 0 - u->base_unit.target_layer->buf_area.x1;
462     y = 0 - u->base_unit.target_layer->buf_area.y1;
463 
464     lv_area_move(&clipped_area, x, y);
465 
466     /* Invalidate cache */
467     lv_draw_buf_invalidate_cache(layer->draw_buf, &clipped_area);
468 #endif
469 #endif
470 
471     switch(t->type) {
472         case LV_DRAW_TASK_TYPE_FILL:
473             lv_draw_dave2d_fill(u, t->draw_dsc, &t->area);
474             break;
475         case LV_DRAW_TASK_TYPE_BORDER:
476             lv_draw_dave2d_border(u, t->draw_dsc, &t->area);
477             break;
478         case LV_DRAW_TASK_TYPE_BOX_SHADOW:
479             //lv_draw_dave2d_box_shadow(u, t->draw_dsc, &t->area);
480             break;
481 #if 0
482         case LV_DRAW_TASK_TYPE_BG_IMG:
483             //lv_draw_dave2d_bg_image(u, t->draw_dsc, &t->area);
484             break;
485 #endif
486         case LV_DRAW_TASK_TYPE_LABEL:
487             lv_draw_dave2d_label(u, t->draw_dsc, &t->area);
488             break;
489         case LV_DRAW_TASK_TYPE_IMAGE:
490             lv_draw_dave2d_image(u, t->draw_dsc, &t->area);
491             break;
492         case LV_DRAW_TASK_TYPE_LINE:
493             lv_draw_dave2d_line(u, t->draw_dsc);
494             break;
495         case LV_DRAW_TASK_TYPE_ARC:
496             lv_draw_dave2d_arc(u, t->draw_dsc, &t->area);
497             break;
498         case LV_DRAW_TASK_TYPE_TRIANGLE:
499             lv_draw_dave2d_triangle(u, t->draw_dsc);
500             break;
501         case LV_DRAW_TASK_TYPE_LAYER:
502             //lv_draw_dave2d_layer(u, t->draw_dsc, &t->area);
503             break;
504         case LV_DRAW_TASK_TYPE_MASK_RECTANGLE:
505             //lv_draw_dave2d_mask_rect(u, t->draw_dsc, &t->area);
506             break;
507         default:
508             break;
509     }
510 
511 }
512 
lv_dave2d_init(void)513 static d2_s32 lv_dave2d_init(void)
514 {
515     d2_s32 result = D2_OK;
516 
517     if(_d2_handle != NULL) {
518         return D2_NOMEMORY;
519     }
520 
521     _d2_handle = d2_opendevice(0);
522     if(_d2_handle == NULL) {
523         return D2_NOMEMORY;
524     }
525 
526     /* bind the hardware */
527     result = d2_inithw(_d2_handle, 0);
528     if(result != D2_OK) {
529         LV_LOG_ERROR("Could NOT d2_inithw");
530         d2_closedevice(_d2_handle);
531         return result;
532     }
533 
534     //
535     // Set various D2 parameters
536     //
537     result = d2_setblendmode(_d2_handle, d2_bm_alpha, d2_bm_one_minus_alpha);
538     result = d2_setalphamode(_d2_handle, d2_am_constant);
539     result = d2_setalpha(_d2_handle, UINT8_MAX);
540     result = d2_setantialiasing(_d2_handle, 1);
541     result = d2_setlinecap(_d2_handle, d2_lc_butt);
542     result = d2_setlinejoin(_d2_handle, d2_lj_miter);
543 
544     /* set blocksize for default displaylist */
545     result = d2_setdlistblocksize(_d2_handle, 25);
546     if(D2_OK != result) {
547         LV_LOG_ERROR("Could NOT d2_setdlistblocksize");
548         d2_closedevice(_d2_handle);
549         return result;
550     }
551 
552     _blit_renderbuffer = d2_newrenderbuffer(_d2_handle, 20, 20);
553     if(!_blit_renderbuffer) {
554         LV_LOG_ERROR("NO renderbuffer");
555         d2_closedevice(_d2_handle);
556 
557         return D2_NOMEMORY;
558     }
559 
560     _renderbuffer = d2_newrenderbuffer(_d2_handle, 20, 20);
561     if(!_renderbuffer) {
562         LV_LOG_ERROR("NO renderbuffer");
563         d2_closedevice(_d2_handle);
564 
565         return D2_NOMEMORY;
566     }
567 
568     result = d2_selectrenderbuffer(_d2_handle, _renderbuffer);
569     if(D2_OK != result) {
570         LV_LOG_ERROR("Could NOT d2_selectrenderbuffer");
571         d2_closedevice(_d2_handle);
572     }
573 
574     return result;
575 }
576 
dave2d_execute_dlist_and_flush(void)577 void dave2d_execute_dlist_and_flush(void)
578 {
579 #if LV_USE_OS
580     lv_result_t  status;
581 
582     status = lv_mutex_lock(&xd2Semaphore);
583     LV_ASSERT(LV_RESULT_OK == status);
584 #endif
585 
586     d2_s32     result;
587     lv_draw_task_t ** p_list_entry;
588     lv_draw_task_t * p_list_entry1;
589 
590     // Execute render operations
591     result = d2_executerenderbuffer(_d2_handle, _renderbuffer, 0);
592     LV_ASSERT(D2_OK == result);
593 
594     result = d2_flushframe(_d2_handle);
595     LV_ASSERT(D2_OK == result);
596 
597     result = d2_selectrenderbuffer(_d2_handle, _renderbuffer);
598     LV_ASSERT(D2_OK == result);
599 
600     while(false == lv_ll_is_empty(&_ll_Dave2D_Tasks)) {
601         p_list_entry = lv_ll_get_tail(&_ll_Dave2D_Tasks);
602         p_list_entry1 = *p_list_entry;
603         p_list_entry1->state = LV_DRAW_TASK_STATE_READY;
604         lv_ll_remove(&_ll_Dave2D_Tasks, p_list_entry);
605         lv_free(p_list_entry);
606     }
607 
608 #if LV_USE_OS
609     status = lv_mutex_unlock(&xd2Semaphore);
610     LV_ASSERT(LV_RESULT_OK == status);
611 #endif
612 }
613 
614 #endif /*LV_USE_DRAW_DAVE2D*/
615