1 /**
2 * MIT License
3 *
4 * -----------------------------------------------------------------------------
5 * Copyright (c) 2008-24 Think Silicon Single Member PC
6 * -----------------------------------------------------------------------------
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights to
11 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 * the Software, and to permit persons to whom the Software is furnished to do so,
13 * subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next paragraph)
16 * shall be included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
19 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
22 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
23 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 */
26
27 /**
28 * @file lv_draw_nema_gfx_fill.c
29 *
30 */
31
32 /*********************
33 * INCLUDES
34 *********************/
35 #include "lv_draw_nema_gfx.h"
36
37 #if LV_USE_NEMA_GFX
38
39
40 /**********************
41 * STATIC PROTOTYPES
42 **********************/
43
44 static void _draw_nema_gfx_tile(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * dsc, const lv_area_t * coords);
45
46 static void _draw_nema_gfx_img(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * dsc, const lv_area_t * coords);
47
48 static uint32_t lv_nemagfx_mask_cf_to_nema(lv_color_format_t cf);
49
50 /**********************
51 * STATIC FUNCTIONS
52 **********************/
53
_draw_nema_gfx_tile(lv_draw_unit_t * draw_unit,const lv_draw_image_dsc_t * dsc,const lv_area_t * coords)54 static void _draw_nema_gfx_tile(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * dsc, const lv_area_t * coords)
55 {
56
57 lv_image_decoder_dsc_t decoder_dsc;
58 lv_result_t res = lv_image_decoder_open(&decoder_dsc, dsc->src, NULL);
59 if(res != LV_RESULT_OK) {
60 LV_LOG_ERROR("Failed to open image");
61 return;
62 }
63
64 int32_t img_w = dsc->header.w;
65 int32_t img_h = dsc->header.h;
66
67 lv_area_t tile_area;
68 if(lv_area_get_width(&dsc->image_area) >= 0) {
69 tile_area = dsc->image_area;
70 }
71 else {
72 tile_area = *coords;
73 }
74 lv_area_set_width(&tile_area, img_w);
75 lv_area_set_height(&tile_area, img_h);
76
77 int32_t tile_x_start = tile_area.x1;
78
79 while(tile_area.y1 <= draw_unit->clip_area->y2) {
80 while(tile_area.x1 <= draw_unit->clip_area->x2) {
81
82 lv_area_t clipped_img_area;
83 if(lv_area_intersect(&clipped_img_area, &tile_area, draw_unit->clip_area)) {
84 _draw_nema_gfx_img(draw_unit, dsc, &tile_area);
85 }
86
87 tile_area.x1 += img_w;
88 tile_area.x2 += img_w;
89 }
90
91 tile_area.y1 += img_h;
92 tile_area.y2 += img_h;
93 tile_area.x1 = tile_x_start;
94 tile_area.x2 = tile_x_start + img_w - 1;
95 }
96
97 lv_image_decoder_close(&decoder_dsc);
98 }
99
_draw_nema_gfx_img(lv_draw_unit_t * draw_unit,const lv_draw_image_dsc_t * dsc,const lv_area_t * coords)100 static void _draw_nema_gfx_img(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * dsc, const lv_area_t * coords)
101 {
102 if(dsc->opa <= LV_OPA_MIN) return;
103
104 lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *)draw_unit;
105
106 lv_layer_t * layer = draw_unit->target_layer;
107 const lv_image_dsc_t * img_dsc = dsc->src;
108
109 bool masked = dsc->bitmap_mask_src != NULL;
110
111 lv_area_t blend_area;
112 /*Let's get the blend area which is the intersection of the area to fill and the clip area.*/
113 if(!lv_area_intersect(&blend_area, coords, draw_unit->clip_area))
114 return; /*Fully clipped, nothing to do*/
115
116 lv_area_t rel_clip_area;
117 lv_area_copy(&rel_clip_area, draw_unit->clip_area);
118 lv_area_move(&rel_clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
119
120 bool has_transform = (dsc->rotation != 0 || dsc->scale_x != LV_SCALE_NONE || dsc->scale_y != LV_SCALE_NONE);
121 bool recolor = (dsc->recolor_opa > LV_OPA_MIN);
122
123 /*Make the blend area relative to the buffer*/
124 lv_area_move(&blend_area, -layer->buf_area.x1, -layer->buf_area.y1);
125
126 uint32_t tex_w = lv_area_get_width(coords);
127 uint32_t tex_h = lv_area_get_height(coords);
128
129 nema_set_clip(rel_clip_area.x1, rel_clip_area.y1, lv_area_get_width(&rel_clip_area),
130 lv_area_get_height(&rel_clip_area));
131
132 lv_color_format_t dst_cf = layer->draw_buf->header.cf;
133 uint32_t dst_nema_cf = lv_nemagfx_cf_to_nema(dst_cf);
134
135 const void * src_buf = img_dsc->data;
136
137 uint32_t blending_mode = lv_nemagfx_blending_mode(dsc->blend_mode);
138
139 lv_color_format_t src_cf = img_dsc->header.cf;
140
141 /*Image contains Alpha*/
142 if(src_cf == LV_COLOR_FORMAT_ARGB8888 || src_cf == LV_COLOR_FORMAT_XRGB8888) {
143 blending_mode |= NEMA_BLOP_SRC_PREMULT;
144 }
145
146 uint32_t src_nema_cf = lv_nemagfx_cf_to_nema(src_cf);
147 /* the stride should be computed internally for NEMA_TSC images and images missing a stride value */
148 int32_t src_stride = (src_cf >= LV_COLOR_FORMAT_NEMA_TSC_START && src_cf <= LV_COLOR_FORMAT_NEMA_TSC_END)
149 || img_dsc->header.stride == 0 ? -1 : (int32_t)img_dsc->header.stride;
150
151 nema_bind_dst_tex((uintptr_t)NEMA_VIRT2PHYS(layer->draw_buf->data), lv_area_get_width(&(layer->buf_area)),
152 lv_area_get_height(&(layer->buf_area)), dst_nema_cf,
153 lv_area_get_width(&(layer->buf_area))*lv_color_format_get_size(dst_cf));
154
155 nema_bind_src_tex((uintptr_t)(src_buf), tex_w, tex_h, src_nema_cf, src_stride,
156 dsc->antialias ? NEMA_FILTER_BL : NEMA_FILTER_PS);
157
158 /*Guard for previous NemaGFX Version*/
159 #ifdef NEMA_BLOP_RECOLOR
160 if(recolor) {
161 lv_color32_t col32 = lv_color_to_32(dsc->recolor, LV_OPA_MIX2(dsc->recolor_opa, dsc->opa));
162 uint32_t color = nema_rgba(col32.red, col32.green, col32.blue, col32.alpha);
163 nema_set_recolor_color(color);
164 blending_mode |= NEMA_BLOP_RECOLOR;
165 }
166 #endif
167
168 if(dsc->opa < 255) {
169 uint32_t rgba = ((uint32_t)dsc->opa << 24U) | ((uint32_t)dsc->opa << 16U) | ((uint32_t)dsc->opa << 8U) | ((
170 uint32_t)dsc->opa);
171 nema_set_const_color(rgba);
172 blending_mode |= NEMA_BLOP_MODULATE_A;
173 }
174
175 if(!has_transform && masked && !recolor) {
176 if(dsc->bitmap_mask_src->header.cf == LV_COLOR_FORMAT_A8 || dsc->bitmap_mask_src->header.cf == LV_COLOR_FORMAT_L8) {
177 blending_mode |= NEMA_BLOP_STENCIL_TXTY;
178 const lv_image_dsc_t * mask = dsc->bitmap_mask_src;
179 const void * mask_buf = mask->data;
180
181 const lv_area_t * image_area;
182 lv_area_t mask_area;
183 if(lv_area_get_width(&dsc->image_area) < 0) image_area = coords;
184 else image_area = &dsc->image_area;
185
186 lv_area_set(&mask_area, 0, 0, dsc->bitmap_mask_src->header.w - 1, dsc->bitmap_mask_src->header.h - 1);
187 lv_area_align(image_area, &mask_area, LV_ALIGN_CENTER, 0, 0);
188
189 mask_buf += dsc->bitmap_mask_src->header.w * (coords->y1 - mask_area.y1) + (coords->x1 - mask_area.x1);
190
191 nema_bind_tex(NEMA_TEX3, (uintptr_t)NEMA_VIRT2PHYS(mask_buf), mask->header.w, mask->header.h,
192 lv_nemagfx_mask_cf_to_nema(mask->header.cf),
193 mask->header.stride, NEMA_FILTER_BL);
194 }
195 }
196
197 nema_set_blend_blit(blending_mode);
198
199 if(!has_transform) {
200 nema_blit_rect((coords->x1 - layer->buf_area.x1),
201 (coords->y1 - layer->buf_area.y1), tex_w, tex_h);
202 }
203 else {
204 /*Calculate the transformed points*/
205 float x0 = (coords->x1 - layer->buf_area.x1);
206 float y0 = (coords->y1 - layer->buf_area.y1);
207 float x1 = x0 + tex_w ;
208 float y1 = y0;
209 float x2 = x0 + tex_w ;
210 float y2 = y0 + tex_h;
211 float x3 = x0 ;
212 float y3 = y0 + tex_h;
213
214 nema_matrix3x3_t m;
215 nema_mat3x3_load_identity(m);
216 nema_mat3x3_translate(m, -x0, -y0);
217 nema_mat3x3_translate(m, -(float)dsc->pivot.x, -(float)dsc->pivot.y);
218 nema_mat3x3_rotate(m, (dsc->rotation / 10.0f)); /* angle is 1/10 degree */
219 float scale_x = 1.f * dsc->scale_x / LV_SCALE_NONE;
220 float scale_y = 1.f * dsc->scale_y / LV_SCALE_NONE;
221 nema_mat3x3_scale(m, (float)scale_x, (float)scale_y);
222 nema_mat3x3_translate(m, (float)dsc->pivot.x, (float)dsc->pivot.y);
223 nema_mat3x3_translate(m, x0, y0);
224
225 /*Apply Transformation Matrix to Vertices*/
226 nema_mat3x3_mul_vec(m, &x0, &y0);
227 nema_mat3x3_mul_vec(m, &x1, &y1);
228 nema_mat3x3_mul_vec(m, &x2, &y2);
229 nema_mat3x3_mul_vec(m, &x3, &y3);
230
231 nema_blit_quad_fit(x0, y0,
232 x1, y1,
233 x2, y2,
234 x3, y3);
235 }
236
237 nema_cl_submit(&(draw_nema_gfx_unit->cl));
238
239 }
240
241 /*NemaGFX does mask operations with A8,A4,A2 and A1 formats*/
lv_nemagfx_mask_cf_to_nema(lv_color_format_t cf)242 static uint32_t lv_nemagfx_mask_cf_to_nema(lv_color_format_t cf)
243 {
244 switch(cf) {
245 case LV_COLOR_FORMAT_A1:
246 return NEMA_A1;
247 case LV_COLOR_FORMAT_A2:
248 return NEMA_A2;
249 case LV_COLOR_FORMAT_A4:
250 return NEMA_A4;
251 case LV_COLOR_FORMAT_A8:
252 case LV_COLOR_FORMAT_L8:
253 default:
254 break;
255 }
256
257 return NEMA_A8;
258 }
259
260 /**********************
261 * GLOBAL FUNCTIONS
262 **********************/
lv_draw_nema_gfx_img(lv_draw_unit_t * draw_unit,const lv_draw_image_dsc_t * dsc,const lv_area_t * coords)263 void lv_draw_nema_gfx_img(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * dsc, const lv_area_t * coords)
264 {
265
266 if(!dsc->tile) {
267 _draw_nema_gfx_img(draw_unit, dsc, coords);
268 }
269 else {
270 _draw_nema_gfx_tile(draw_unit, dsc, coords);
271 }
272
273 }
274 #endif
275