1 /**
2  * @file lv_gpu_d2_draw_label.c
3  *
4  * @description HAL layer for display driver
5  *
6  */
7 
8 /*********************
9  *      INCLUDES
10  *********************/
11 #include "../../draw/lv_draw_label.h"
12 #include "../../misc/lv_assert.h"
13 #include "../../core/lv_refr.h"
14 #include "lv_gpu_d2_ra6m3.h"
15 
16 #if LV_USE_GPU_RA6M3_G2D
17 #include LV_GPU_RA6M3_G2D_INCLUDE
18 
19 /**********************
20  *  STATIC VARIABLES
21  **********************/
22 
23 /**********************
24  *  GLOBAL VARIABLES
25  **********************/
26 extern const uint8_t _lv_bpp1_opa_table[2];
27 extern const uint8_t _lv_bpp2_opa_table[4];
28 extern const uint8_t _lv_bpp4_opa_table[16];
29 extern const uint8_t _lv_bpp8_opa_table[256];
30 
31 /**********************
32  *      MACROS
33  **********************/
34 
35 /**********************
36  *   GLOBAL FUNCTIONS
37  **********************/
38 
39 /**********************
40  *   STATIC FUNCTIONS
41  **********************/
42 
draw_letter_normal(lv_draw_ctx_t * draw_ctx,const lv_draw_label_dsc_t * dsc,const lv_point_t * pos,lv_font_glyph_dsc_t * g,const uint8_t * map_p)43 static void LV_ATTRIBUTE_FAST_MEM draw_letter_normal(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc,
44                                                      const lv_point_t * pos, lv_font_glyph_dsc_t * g, const uint8_t * map_p)
45 {
46 
47     const uint8_t * bpp_opa_table_p;
48     uint32_t bitmask_init;
49     uint32_t bitmask;
50     uint32_t bpp = g->bpp;
51     lv_opa_t opa = dsc->opa;
52     uint32_t shades;
53     if(bpp == 3) bpp = 4;
54 
55 #if LV_USE_IMGFONT
56     if(bpp == LV_IMGFONT_BPP) { //is imgfont
57         lv_area_t fill_area;
58         fill_area.x1 = pos->x;
59         fill_area.y1 = pos->y;
60         fill_area.x2 = pos->x + g->box_w - 1;
61         fill_area.y2 = pos->y + g->box_h - 1;
62         lv_draw_img_dsc_t img_dsc;
63         lv_draw_img_dsc_init(&img_dsc);
64         img_dsc.angle = 0;
65         img_dsc.zoom = LV_IMG_ZOOM_NONE;
66         img_dsc.opa = dsc->opa;
67         img_dsc.blend_mode = dsc->blend_mode;
68         lv_draw_img(draw_ctx, &img_dsc, &fill_area, map_p);
69         return;
70     }
71 #endif
72 
73     switch(bpp) {
74         case 1:
75             bpp_opa_table_p = _lv_bpp1_opa_table;
76             bitmask_init  = 0x80;
77             shades = 2;
78             break;
79         case 2:
80             bpp_opa_table_p = _lv_bpp2_opa_table;
81             bitmask_init  = 0xC0;
82             shades = 4;
83             break;
84         case 4:
85             bpp_opa_table_p = _lv_bpp4_opa_table;
86             bitmask_init  = 0xF0;
87             shades = 16;
88             break;
89         case 8:
90             bpp_opa_table_p = _lv_bpp8_opa_table;
91             bitmask_init  = 0xFF;
92             shades = 256;
93             break;       /*No opa table, pixel value will be used directly*/
94         default:
95             LV_LOG_WARN("lv_draw_letter: invalid bpp");
96             return; /*Invalid bpp. Can't render the letter*/
97     }
98 
99     static lv_opa_t opa_table[256];
100     static lv_opa_t prev_opa = LV_OPA_TRANSP;
101     static uint32_t prev_bpp = 0;
102     if(opa < LV_OPA_MAX) {
103         if(prev_opa != opa || prev_bpp != bpp) {
104             uint32_t i;
105             for(i = 0; i < shades; i++) {
106                 opa_table[i] = bpp_opa_table_p[i] == LV_OPA_COVER ? opa : ((bpp_opa_table_p[i] * opa) >> 8);
107             }
108         }
109         bpp_opa_table_p = opa_table;
110         prev_opa = opa;
111         prev_bpp = bpp;
112     }
113 
114     int32_t col, row;
115     int32_t box_w = g->box_w;
116     int32_t box_h = g->box_h;
117     int32_t width_bit = box_w * bpp; /*Letter width in bits*/
118 
119     /*Calculate the col/row start/end on the map*/
120     int32_t col_start = pos->x >= draw_ctx->clip_area->x1 ? 0 : draw_ctx->clip_area->x1 - pos->x;
121     int32_t col_end   = pos->x + box_w <= draw_ctx->clip_area->x2 ? box_w : draw_ctx->clip_area->x2 - pos->x + 1;
122     int32_t row_start = pos->y >= draw_ctx->clip_area->y1 ? 0 : draw_ctx->clip_area->y1 - pos->y;
123     int32_t row_end   = pos->y + box_h <= draw_ctx->clip_area->y2 ? box_h : draw_ctx->clip_area->y2 - pos->y + 1;
124 
125     /*Move on the map too*/
126     uint32_t bit_ofs = (row_start * width_bit) + (col_start * bpp);
127     map_p += bit_ofs >> 3;
128 
129     uint8_t letter_px;
130     uint32_t col_bit;
131     col_bit = bit_ofs & 0x7; /*"& 0x7" equals to "% 8" just faster*/
132 
133     lv_draw_sw_blend_dsc_t blend_dsc;
134     lv_memset_00(&blend_dsc, sizeof(blend_dsc));
135     blend_dsc.color = dsc->color;
136     blend_dsc.opa = LV_OPA_COVER;
137     blend_dsc.blend_mode = dsc->blend_mode;
138 
139     lv_coord_t hor_res = lv_disp_get_hor_res(_lv_refr_get_disp_refreshing());
140     uint32_t mask_buf_size = box_w * box_h > hor_res ? hor_res : box_w * box_h;
141     lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
142     blend_dsc.mask_buf = mask_buf;
143     int32_t mask_p = 0;
144 
145     lv_area_t fill_area;
146     fill_area.x1 = col_start + pos->x;
147     fill_area.x2 = col_end  + pos->x - 1;
148     fill_area.y1 = row_start + pos->y;
149     fill_area.y2 = fill_area.y1;
150 #if LV_DRAW_COMPLEX
151     lv_coord_t fill_w = lv_area_get_width(&fill_area);
152     lv_area_t mask_area;
153     lv_area_copy(&mask_area, &fill_area);
154     mask_area.y2 = mask_area.y1 + row_end;
155     bool mask_any = lv_draw_mask_is_any(&mask_area);
156 #endif
157     blend_dsc.blend_area = &fill_area;
158     blend_dsc.mask_area = &fill_area;
159 
160     uint32_t col_bit_max = 8 - bpp;
161     uint32_t col_bit_row_ofs = (box_w + col_start - col_end) * bpp;
162 
163     for(row = row_start ; row < row_end; row++) {
164 #if LV_DRAW_COMPLEX
165         int32_t mask_p_start = mask_p;
166 #endif
167         bitmask = bitmask_init >> col_bit;
168         for(col = col_start; col < col_end; col++) {
169             /*Load the pixel's opacity into the mask*/
170             letter_px = (*map_p & bitmask) >> (col_bit_max - col_bit);
171             if(letter_px) {
172                 mask_buf[mask_p] = bpp_opa_table_p[letter_px];
173             }
174             else {
175                 mask_buf[mask_p] = 0;
176             }
177 
178             /*Go to the next column*/
179             if(col_bit < col_bit_max) {
180                 col_bit += bpp;
181                 bitmask = bitmask >> bpp;
182             }
183             else {
184                 col_bit = 0;
185                 bitmask = bitmask_init;
186                 map_p++;
187             }
188 
189             /*Next mask byte*/
190             mask_p++;
191         }
192 
193 #if LV_DRAW_COMPLEX
194         /*Apply masks if any*/
195         if(mask_any) {
196             blend_dsc.mask_res = lv_draw_mask_apply(mask_buf + mask_p_start, fill_area.x1, fill_area.y2,
197                                                     fill_w);
198             if(blend_dsc.mask_res == LV_DRAW_MASK_RES_TRANSP) {
199                 lv_memset_00(mask_buf + mask_p_start, fill_w);
200             }
201         }
202 #endif
203 
204         if((uint32_t) mask_p + (col_end - col_start) < mask_buf_size) {
205             fill_area.y2 ++;
206         }
207         else {
208             blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
209             lv_draw_ra6m3_2d_blend(draw_ctx, &blend_dsc);
210 
211             fill_area.y1 = fill_area.y2 + 1;
212             fill_area.y2 = fill_area.y1;
213             mask_p = 0;
214         }
215 
216         col_bit += col_bit_row_ofs;
217         map_p += (col_bit >> 3);
218         col_bit = col_bit & 0x7;
219     }
220 
221     /*Flush the last part*/
222     if(fill_area.y1 != fill_area.y2) {
223         fill_area.y2--;
224         blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
225         lv_draw_ra6m3_2d_blend(draw_ctx, &blend_dsc);
226         mask_p = 0;
227     }
228 
229     lv_mem_buf_release(mask_buf);
230 }
231 
lv_draw_gpu_letter(lv_draw_ctx_t * draw_ctx,const lv_draw_label_dsc_t * dsc,const lv_point_t * pos_p,uint32_t letter)232 void lv_draw_gpu_letter(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc,  const lv_point_t * pos_p,
233                         uint32_t letter)
234 {
235     const lv_font_t * font_p = dsc->font;
236 
237     lv_opa_t opa = dsc->opa;
238     if(opa < LV_OPA_MIN) return;
239     if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
240 
241     if(font_p == NULL) {
242         LV_LOG_WARN("lv_draw_letter: font is NULL");
243         return;
244     }
245 
246     lv_font_glyph_dsc_t g;
247     bool g_ret = lv_font_get_glyph_dsc(font_p, &g, letter, '\0');
248     if(g_ret == false) {
249         /*Add warning if the dsc is not found
250          *but do not print warning for non printable ASCII chars (e.g. '\n')*/
251         if(letter >= 0x20 &&
252            letter != 0xf8ff && /*LV_SYMBOL_DUMMY*/
253            letter != 0x200c) { /*ZERO WIDTH NON-JOINER*/
254             LV_LOG_WARN("lv_draw_letter: glyph dsc. not found for U+%X", letter);
255         }
256         return;
257     }
258 
259     /*Don't draw anything if the character is empty. E.g. space*/
260     if((g.box_h == 0) || (g.box_w == 0)) return;
261 
262     lv_point_t gpos;
263     gpos.x = pos_p->x + g.ofs_x;
264     gpos.y = pos_p->y + (dsc->font->line_height - dsc->font->base_line) - g.box_h - g.ofs_y;
265 
266     /*If the letter is completely out of mask don't draw it*/
267     if(gpos.x + g.box_w < draw_ctx->clip_area->x1 ||
268        gpos.x > draw_ctx->clip_area->x2 ||
269        gpos.y + g.box_h < draw_ctx->clip_area->y1 ||
270        gpos.y > draw_ctx->clip_area->y2) {
271         return;
272     }
273 
274     const uint8_t * map_p = lv_font_get_glyph_bitmap(font_p, letter);
275     if(map_p == NULL) {
276         LV_LOG_WARN("lv_draw_letter: character's bitmap not found");
277         return;
278     }
279 
280     if(font_p->subpx) {
281 #if LV_DRAW_COMPLEX && LV_USE_FONT_SUBPX
282         draw_letter_subpx(pos_x, pos_y, &g, clip_area, map_p, color, opa, blend_mode);
283 #else
284         LV_LOG_WARN("Can't draw sub-pixel rendered letter because LV_USE_FONT_SUBPX == 0 in lv_conf.h");
285 #endif
286     }
287     else {
288         draw_letter_normal(draw_ctx, dsc, &gpos, &g, map_p);
289     }
290 }
291 
292 #endif
293