1 /**
2 * @file lv_draw_pxp_blend.c
3 *
4 */
5
6 /**
7 * MIT License
8 *
9 * Copyright 2020-2023 NXP
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights to
14 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
15 * the Software, and to permit persons to whom the Software is furnished to do so,
16 * subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice (including the next paragraph)
19 * shall be included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
22 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
23 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
25 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
26 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 *
28 */
29
30 /*********************
31 * INCLUDES
32 *********************/
33
34 #include "lv_draw_pxp_blend.h"
35
36 #if LV_USE_GPU_NXP_PXP
37 #include "lvgl_support.h"
38
39 /*********************
40 * DEFINES
41 *********************/
42
43 #if LV_COLOR_16_SWAP
44 #error Color swap not implemented. Disable LV_COLOR_16_SWAP feature.
45 #endif
46
47 #if LV_COLOR_DEPTH == 16
48 #define PXP_OUT_PIXEL_FORMAT kPXP_OutputPixelFormatRGB565
49 #define PXP_AS_PIXEL_FORMAT kPXP_AsPixelFormatRGB565
50 #define PXP_PS_PIXEL_FORMAT kPXP_PsPixelFormatRGB565
51 #define PXP_TEMP_BUF_SIZE LCD_WIDTH * LCD_HEIGHT * 2U
52 #elif LV_COLOR_DEPTH == 32
53 #define PXP_OUT_PIXEL_FORMAT kPXP_OutputPixelFormatARGB8888
54 #define PXP_AS_PIXEL_FORMAT kPXP_AsPixelFormatARGB8888
55 #if (!(defined(FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT) && FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT)) && \
56 (!(defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3))
57 #define PXP_PS_PIXEL_FORMAT kPXP_PsPixelFormatARGB8888
58 #else
59 #define PXP_PS_PIXEL_FORMAT kPXP_PsPixelFormatRGB888
60 #endif
61 #define PXP_TEMP_BUF_SIZE LCD_WIDTH * LCD_HEIGHT * 4U
62 #elif
63 #error Only 16bit and 32bit color depth are supported. Set LV_COLOR_DEPTH to 16 or 32.
64 #endif
65
66 /**********************
67 * TYPEDEFS
68 **********************/
69
70 /**********************
71 * STATIC PROTOTYPES
72 **********************/
73
74 static LV_ATTRIBUTE_MEM_ALIGN uint8_t temp_buf[PXP_TEMP_BUF_SIZE];
75
76 /**
77 * BLock Image Transfer - copy rectangular image from src buffer to dst buffer
78 * with combination of transformation (rotation, scale, recolor) and opacity, alpha channel
79 * or color keying. This requires two steps. First step is used for transformation into
80 * a temporary buffer and the second one will handle the color format or opacity.
81 *
82 * @param[in/out] dest_buf Destination buffer
83 * @param[in] dest_area Area with relative coordinates of destination buffer
84 * @param[in] dest_stride Stride of destination buffer in pixels
85 * @param[in] src_buf Source buffer
86 * @param[in] src_area Area with relative coordinates of source buffer
87 * @param[in] src_stride Stride of source buffer in pixels
88 * @param[in] dsc Image descriptor
89 * @param[in] cf Color format
90 */
91 static void lv_pxp_blit_opa(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
92 const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
93 const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf);
94
95 /**
96 * BLock Image Transfer - copy rectangular image from src buffer to dst buffer
97 * with transformation and full opacity.
98 *
99 * @param[in/out] dest_buf Destination buffer
100 * @param[in] dest_area Area with relative coordinates of destination buffer
101 * @param[in] dest_stride Stride of destination buffer in pixels
102 * @param[in] src_buf Source buffer
103 * @param[in] src_area Area with relative coordinates of source buffer
104 * @param[in] src_stride Stride of source buffer in pixels
105 * @param[in] dsc Image descriptor
106 * @param[in] cf Color format
107 */
108 static void lv_pxp_blit_cover(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride,
109 const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
110 const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf);
111
112 /**
113 * BLock Image Transfer - copy rectangular image from src buffer to dst buffer
114 * without transformation but handling color format or opacity.
115 *
116 * @param[in/out] dest_buf Destination buffer
117 * @param[in] dest_area Area with relative coordinates of destination buffer
118 * @param[in] dest_stride Stride of destination buffer in pixels
119 * @param[in] src_buf Source buffer
120 * @param[in] src_area Area with relative coordinates of source buffer
121 * @param[in] src_stride Stride of source buffer in pixels
122 * @param[in] dsc Image descriptor
123 * @param[in] cf Color format
124 */
125 static void lv_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
126 const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
127 const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf);
128
129 /**********************
130 * STATIC VARIABLES
131 **********************/
132
133 /**********************
134 * MACROS
135 **********************/
136
137 /**********************
138 * GLOBAL FUNCTIONS
139 **********************/
140
lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,lv_color_t color,lv_opa_t opa)141 void lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
142 lv_color_t color, lv_opa_t opa)
143 {
144 lv_coord_t dest_w = lv_area_get_width(dest_area);
145 lv_coord_t dest_h = lv_area_get_height(dest_area);
146
147 lv_gpu_nxp_pxp_reset();
148
149 /*OUT buffer configure*/
150 pxp_output_buffer_config_t outputConfig = {
151 .pixelFormat = PXP_OUT_PIXEL_FORMAT,
152 .interlacedMode = kPXP_OutputProgressive,
153 .buffer0Addr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_area->x1),
154 .buffer1Addr = (uint32_t)NULL,
155 .pitchBytes = dest_stride * sizeof(lv_color_t),
156 .width = dest_w,
157 .height = dest_h
158 };
159
160 PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputConfig);
161
162 if(opa >= (lv_opa_t)LV_OPA_MAX) {
163 /*Simple color fill without opacity - AS disabled*/
164 PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
165
166 }
167 else {
168 /*Fill with opacity - AS used as source (same as OUT)*/
169 pxp_as_buffer_config_t asBufferConfig = {
170 .pixelFormat = PXP_AS_PIXEL_FORMAT,
171 .bufferAddr = (uint32_t)outputConfig.buffer0Addr,
172 .pitchBytes = outputConfig.pitchBytes
173 };
174
175 PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig);
176 PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U);
177 }
178
179 /*Disable PS, use as color generator*/
180 PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
181 PXP_SetProcessSurfaceBackGroundColor(LV_GPU_NXP_PXP_ID, lv_color_to32(color));
182
183 /**
184 * Configure Porter-Duff blending - src settings are unused for fill without opacity (opa = 0xff).
185 *
186 * Note: srcFactorMode and dstFactorMode are inverted in fsl_pxp.h:
187 * srcFactorMode is actually applied on PS alpha value
188 * dstFactorMode is actually applied on AS alpha value
189 */
190 pxp_porter_duff_config_t pdConfig = {
191 .enable = 1,
192 .dstColorMode = kPXP_PorterDuffColorNoAlpha,
193 .srcColorMode = kPXP_PorterDuffColorNoAlpha,
194 .dstGlobalAlphaMode = kPXP_PorterDuffGlobalAlpha,
195 .srcGlobalAlphaMode = kPXP_PorterDuffGlobalAlpha,
196 .dstFactorMode = kPXP_PorterDuffFactorStraight,
197 .srcFactorMode = (opa >= (lv_opa_t)LV_OPA_MAX) ? kPXP_PorterDuffFactorStraight : kPXP_PorterDuffFactorInversed,
198 .dstGlobalAlpha = opa,
199 .srcGlobalAlpha = opa,
200 .dstAlphaMode = kPXP_PorterDuffAlphaStraight, /*don't care*/
201 .srcAlphaMode = kPXP_PorterDuffAlphaStraight /*don't care*/
202 };
203
204 PXP_SetPorterDuffConfig(LV_GPU_NXP_PXP_ID, &pdConfig);
205
206 lv_gpu_nxp_pxp_run();
207 }
208
lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,const lv_color_t * src_buf,const lv_area_t * src_area,lv_coord_t src_stride,lv_opa_t opa,lv_disp_rot_t angle)209 void lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
210 const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
211 lv_opa_t opa, lv_disp_rot_t angle)
212 {
213 lv_coord_t dest_w = lv_area_get_width(dest_area);
214 lv_coord_t dest_h = lv_area_get_height(dest_area);
215 lv_coord_t src_w = lv_area_get_width(src_area);
216 lv_coord_t src_h = lv_area_get_height(src_area);
217
218 lv_gpu_nxp_pxp_reset();
219
220 /* convert rotation angle */
221 pxp_rotate_degree_t pxp_rot;
222 switch(angle) {
223 case LV_DISP_ROT_NONE:
224 pxp_rot = kPXP_Rotate0;
225 break;
226 case LV_DISP_ROT_90:
227 pxp_rot = kPXP_Rotate90;
228 break;
229 case LV_DISP_ROT_180:
230 pxp_rot = kPXP_Rotate180;
231 break;
232 case LV_DISP_ROT_270:
233 pxp_rot = kPXP_Rotate270;
234 break;
235 default:
236 pxp_rot = kPXP_Rotate0;
237 break;
238 }
239 PXP_SetRotateConfig(LV_GPU_NXP_PXP_ID, kPXP_RotateOutputBuffer, pxp_rot, kPXP_FlipDisable);
240
241 pxp_as_blend_config_t asBlendConfig = {
242 .alpha = opa,
243 .invertAlpha = false,
244 .alphaMode = kPXP_AlphaRop,
245 .ropMode = kPXP_RopMergeAs
246 };
247
248 if(opa >= (lv_opa_t)LV_OPA_MAX) {
249 /*Simple blit, no effect - Disable PS buffer*/
250 PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
251 }
252 else {
253 pxp_ps_buffer_config_t psBufferConfig = {
254 .pixelFormat = PXP_PS_PIXEL_FORMAT,
255 .swapByte = false,
256 .bufferAddr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_area->x1),
257 .bufferAddrU = 0U,
258 .bufferAddrV = 0U,
259 .pitchBytes = dest_stride * sizeof(lv_color_t)
260 };
261
262 asBlendConfig.alphaMode = kPXP_AlphaOverride;
263
264 PXP_SetProcessSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &psBufferConfig);
265 PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U);
266 }
267
268 /*AS buffer - source image*/
269 pxp_as_buffer_config_t asBufferConfig = {
270 .pixelFormat = PXP_AS_PIXEL_FORMAT,
271 .bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_area->x1),
272 .pitchBytes = src_stride * sizeof(lv_color_t)
273 };
274 PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig);
275 PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, src_w - 1U, src_h - 1U);
276 PXP_SetAlphaSurfaceBlendConfig(LV_GPU_NXP_PXP_ID, &asBlendConfig);
277 PXP_EnableAlphaSurfaceOverlayColorKey(LV_GPU_NXP_PXP_ID, false);
278
279 /*Output buffer.*/
280 pxp_output_buffer_config_t outputBufferConfig = {
281 .pixelFormat = (pxp_output_pixel_format_t)PXP_OUT_PIXEL_FORMAT,
282 .interlacedMode = kPXP_OutputProgressive,
283 .buffer0Addr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_area->x1),
284 .buffer1Addr = (uint32_t)0U,
285 .pitchBytes = dest_stride * sizeof(lv_color_t),
286 .width = dest_w,
287 .height = dest_h
288 };
289 PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig);
290
291 lv_gpu_nxp_pxp_run();
292 }
293
lv_gpu_nxp_pxp_blit_transform(lv_color_t * dest_buf,lv_area_t * dest_area,lv_coord_t dest_stride,const lv_color_t * src_buf,const lv_area_t * src_area,lv_coord_t src_stride,const lv_draw_img_dsc_t * dsc,lv_img_cf_t cf)294 void lv_gpu_nxp_pxp_blit_transform(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride,
295 const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
296 const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf)
297 {
298 bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP);
299 bool has_rotation = (dsc->angle != 0);
300
301 if(has_recolor || has_rotation) {
302 if(dsc->opa >= (lv_opa_t)LV_OPA_MAX && !lv_img_cf_has_alpha(cf) && !lv_img_cf_is_chroma_keyed(cf)) {
303 lv_pxp_blit_cover(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, dsc, cf);
304 return;
305 }
306 else {
307 /*Recolor and/or rotation with alpha or opacity is done in two steps.*/
308 lv_pxp_blit_opa(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, dsc, cf);
309 return;
310 }
311 }
312
313 lv_pxp_blit_cf(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, dsc, cf);
314 }
315
lv_gpu_nxp_pxp_buffer_copy(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,const lv_color_t * src_buf,const lv_area_t * src_area,lv_coord_t src_stride)316 void lv_gpu_nxp_pxp_buffer_copy(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
317 const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride)
318 {
319 lv_coord_t src_width = lv_area_get_width(src_area);
320 lv_coord_t src_height = lv_area_get_height(src_area);
321
322 lv_gpu_nxp_pxp_reset();
323
324 const pxp_pic_copy_config_t picCopyConfig = {
325 .srcPicBaseAddr = (uint32_t)src_buf,
326 .srcPitchBytes = src_stride * sizeof(lv_color_t),
327 .srcOffsetX = src_area->x1,
328 .srcOffsetY = src_area->y1,
329 .destPicBaseAddr = (uint32_t)dest_buf,
330 .destPitchBytes = dest_stride * sizeof(lv_color_t),
331 .destOffsetX = dest_area->x1,
332 .destOffsetY = dest_area->y1,
333 .width = src_width,
334 .height = src_height,
335 .pixelFormat = PXP_AS_PIXEL_FORMAT
336 };
337
338 PXP_StartPictureCopy(LV_GPU_NXP_PXP_ID, &picCopyConfig);
339
340 lv_gpu_nxp_pxp_wait();
341 }
342
343 /**********************
344 * STATIC FUNCTIONS
345 **********************/
346
lv_pxp_blit_opa(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,const lv_color_t * src_buf,const lv_area_t * src_area,lv_coord_t src_stride,const lv_draw_img_dsc_t * dsc,lv_img_cf_t cf)347 static void lv_pxp_blit_opa(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
348 const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
349 const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf)
350 {
351 lv_area_t temp_area;
352 lv_area_copy(&temp_area, dest_area);
353 lv_coord_t temp_stride = dest_stride;
354 lv_coord_t temp_w = lv_area_get_width(&temp_area);
355 lv_coord_t temp_h = lv_area_get_height(&temp_area);
356
357 /*Step 1: Transform with full opacity to temporary buffer*/
358 lv_pxp_blit_cover((lv_color_t *)temp_buf, &temp_area, temp_stride, src_buf, src_area, src_stride, dsc, cf);
359
360 /*Switch width and height if angle requires it*/
361 if(dsc->angle == 900 || dsc->angle == 2700) {
362 temp_area.x2 = temp_area.x1 + temp_h - 1;
363 temp_area.y2 = temp_area.y1 + temp_w - 1;
364 }
365
366 /*Step 2: Blit temporary result with required opacity to output*/
367 lv_pxp_blit_cf(dest_buf, &temp_area, dest_stride, (lv_color_t *)temp_buf, &temp_area, temp_stride, dsc, cf);
368 }
lv_pxp_blit_cover(lv_color_t * dest_buf,lv_area_t * dest_area,lv_coord_t dest_stride,const lv_color_t * src_buf,const lv_area_t * src_area,lv_coord_t src_stride,const lv_draw_img_dsc_t * dsc,lv_img_cf_t cf)369 static void lv_pxp_blit_cover(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride,
370 const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
371 const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf)
372 {
373 lv_coord_t dest_w = lv_area_get_width(dest_area);
374 lv_coord_t dest_h = lv_area_get_height(dest_area);
375 lv_coord_t src_w = lv_area_get_width(src_area);
376 lv_coord_t src_h = lv_area_get_height(src_area);
377
378 bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP);
379 bool has_rotation = (dsc->angle != 0);
380
381 lv_point_t pivot = dsc->pivot;
382 lv_coord_t piv_offset_x;
383 lv_coord_t piv_offset_y;
384
385 lv_gpu_nxp_pxp_reset();
386
387 if(has_rotation) {
388 /*Convert rotation angle and calculate offsets caused by pivot*/
389 pxp_rotate_degree_t pxp_angle;
390 switch(dsc->angle) {
391 case 0:
392 pxp_angle = kPXP_Rotate0;
393 piv_offset_x = 0;
394 piv_offset_y = 0;
395 break;
396 case 900:
397 piv_offset_x = pivot.x + pivot.y - dest_h;
398 piv_offset_y = pivot.y - pivot.x;
399 pxp_angle = kPXP_Rotate90;
400 break;
401 case 1800:
402 piv_offset_x = 2 * pivot.x - dest_w;
403 piv_offset_y = 2 * pivot.y - dest_h;
404 pxp_angle = kPXP_Rotate180;
405 break;
406 case 2700:
407 piv_offset_x = pivot.x - pivot.y;
408 piv_offset_y = pivot.x + pivot.y - dest_w;
409 pxp_angle = kPXP_Rotate270;
410 break;
411 default:
412 piv_offset_x = 0;
413 piv_offset_y = 0;
414 pxp_angle = kPXP_Rotate0;
415 }
416 PXP_SetRotateConfig(LV_GPU_NXP_PXP_ID, kPXP_RotateOutputBuffer, pxp_angle, kPXP_FlipDisable);
417 lv_area_move(dest_area, piv_offset_x, piv_offset_y);
418 }
419
420 /*AS buffer - source image*/
421 pxp_as_buffer_config_t asBufferConfig = {
422 .pixelFormat = PXP_AS_PIXEL_FORMAT,
423 .bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_area->x1),
424 .pitchBytes = src_stride * sizeof(lv_color_t)
425 };
426 PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig);
427 PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, src_w - 1U, src_h - 1U);
428
429 /*Disable PS buffer*/
430 PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
431 if(has_recolor)
432 /*Use as color generator*/
433 PXP_SetProcessSurfaceBackGroundColor(LV_GPU_NXP_PXP_ID, lv_color_to32(dsc->recolor));
434
435 /*Output buffer*/
436 pxp_output_buffer_config_t outputBufferConfig = {
437 .pixelFormat = (pxp_output_pixel_format_t)PXP_OUT_PIXEL_FORMAT,
438 .interlacedMode = kPXP_OutputProgressive,
439 .buffer0Addr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_area->x1),
440 .buffer1Addr = (uint32_t)0U,
441 .pitchBytes = dest_stride * sizeof(lv_color_t),
442 .width = dest_w,
443 .height = dest_h
444 };
445 PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig);
446
447 if(has_recolor || lv_img_cf_has_alpha(cf)) {
448 /**
449 * Configure Porter-Duff blending.
450 *
451 * Note: srcFactorMode and dstFactorMode are inverted in fsl_pxp.h:
452 * srcFactorMode is actually applied on PS alpha value
453 * dstFactorMode is actually applied on AS alpha value
454 */
455 pxp_porter_duff_config_t pdConfig = {
456 .enable = 1,
457 .dstColorMode = kPXP_PorterDuffColorWithAlpha,
458 .srcColorMode = kPXP_PorterDuffColorNoAlpha,
459 .dstGlobalAlphaMode = kPXP_PorterDuffGlobalAlpha,
460 .srcGlobalAlphaMode = lv_img_cf_has_alpha(cf) ? kPXP_PorterDuffLocalAlpha : kPXP_PorterDuffGlobalAlpha,
461 .dstFactorMode = kPXP_PorterDuffFactorStraight,
462 .srcFactorMode = kPXP_PorterDuffFactorInversed,
463 .dstGlobalAlpha = has_recolor ? dsc->recolor_opa : 0x00,
464 .srcGlobalAlpha = 0xff,
465 .dstAlphaMode = kPXP_PorterDuffAlphaStraight, /*don't care*/
466 .srcAlphaMode = kPXP_PorterDuffAlphaStraight
467 };
468 PXP_SetPorterDuffConfig(LV_GPU_NXP_PXP_ID, &pdConfig);
469 }
470
471 lv_gpu_nxp_pxp_run();
472 }
473
lv_pxp_blit_cf(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,const lv_color_t * src_buf,const lv_area_t * src_area,lv_coord_t src_stride,const lv_draw_img_dsc_t * dsc,lv_img_cf_t cf)474 static void lv_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
475 const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
476 const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf)
477 {
478 lv_coord_t dest_w = lv_area_get_width(dest_area);
479 lv_coord_t dest_h = lv_area_get_height(dest_area);
480 lv_coord_t src_w = lv_area_get_width(src_area);
481 lv_coord_t src_h = lv_area_get_height(src_area);
482
483 lv_gpu_nxp_pxp_reset();
484
485 pxp_as_blend_config_t asBlendConfig = {
486 .alpha = dsc->opa,
487 .invertAlpha = false,
488 .alphaMode = kPXP_AlphaRop,
489 .ropMode = kPXP_RopMergeAs
490 };
491
492 if(dsc->opa >= (lv_opa_t)LV_OPA_MAX && !lv_img_cf_is_chroma_keyed(cf) && !lv_img_cf_has_alpha(cf)) {
493 /*Simple blit, no effect - Disable PS buffer*/
494 PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
495 }
496 else {
497 /*PS must be enabled to fetch background pixels.
498 PS and OUT buffers are the same, blend will be done in-place*/
499 pxp_ps_buffer_config_t psBufferConfig = {
500 .pixelFormat = PXP_PS_PIXEL_FORMAT,
501 .swapByte = false,
502 .bufferAddr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_area->x1),
503 .bufferAddrU = 0U,
504 .bufferAddrV = 0U,
505 .pitchBytes = dest_stride * sizeof(lv_color_t)
506 };
507 if(dsc->opa >= (lv_opa_t)LV_OPA_MAX) {
508 asBlendConfig.alphaMode = lv_img_cf_has_alpha(cf) ? kPXP_AlphaEmbedded : kPXP_AlphaOverride;
509 }
510 else {
511 asBlendConfig.alphaMode = lv_img_cf_has_alpha(cf) ? kPXP_AlphaMultiply : kPXP_AlphaOverride;
512 }
513 PXP_SetProcessSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &psBufferConfig);
514 PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U);
515 }
516
517 /*AS buffer - source image*/
518 pxp_as_buffer_config_t asBufferConfig = {
519 .pixelFormat = PXP_AS_PIXEL_FORMAT,
520 .bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_area->x1),
521 .pitchBytes = src_stride * sizeof(lv_color_t)
522 };
523 PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig);
524 PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, src_w - 1U, src_h - 1U);
525 PXP_SetAlphaSurfaceBlendConfig(LV_GPU_NXP_PXP_ID, &asBlendConfig);
526
527 if(lv_img_cf_is_chroma_keyed(cf)) {
528 lv_color_t colorKeyLow = LV_COLOR_CHROMA_KEY;
529 lv_color_t colorKeyHigh = LV_COLOR_CHROMA_KEY;
530
531 bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP);
532
533 if(has_recolor) {
534 /* New color key after recoloring */
535 lv_color_t colorKey = lv_color_mix(dsc->recolor, LV_COLOR_CHROMA_KEY, dsc->recolor_opa);
536
537 LV_COLOR_SET_R(colorKeyLow, colorKey.ch.red != 0 ? colorKey.ch.red - 1 : 0);
538 LV_COLOR_SET_G(colorKeyLow, colorKey.ch.green != 0 ? colorKey.ch.green - 1 : 0);
539 LV_COLOR_SET_B(colorKeyLow, colorKey.ch.blue != 0 ? colorKey.ch.blue - 1 : 0);
540
541 #if LV_COLOR_DEPTH == 16
542 LV_COLOR_SET_R(colorKeyHigh, colorKey.ch.red != 0x1f ? colorKey.ch.red + 1 : 0x1f);
543 LV_COLOR_SET_G(colorKeyHigh, colorKey.ch.green != 0x3f ? colorKey.ch.green + 1 : 0x3f);
544 LV_COLOR_SET_B(colorKeyHigh, colorKey.ch.blue != 0x1f ? colorKey.ch.blue + 1 : 0x1f);
545 #else /*LV_COLOR_DEPTH == 32*/
546 LV_COLOR_SET_R(colorKeyHigh, colorKey.ch.red != 0xff ? colorKey.ch.red + 1 : 0xff);
547 LV_COLOR_SET_G(colorKeyHigh, colorKey.ch.green != 0xff ? colorKey.ch.green + 1 : 0xff);
548 LV_COLOR_SET_B(colorKeyHigh, colorKey.ch.blue != 0xff ? colorKey.ch.blue + 1 : 0xff);
549 #endif
550 }
551
552 PXP_SetAlphaSurfaceOverlayColorKey(LV_GPU_NXP_PXP_ID, lv_color_to32(colorKeyLow),
553 lv_color_to32(colorKeyHigh));
554 }
555
556 PXP_EnableAlphaSurfaceOverlayColorKey(LV_GPU_NXP_PXP_ID, lv_img_cf_is_chroma_keyed(cf));
557
558 /*Output buffer.*/
559 pxp_output_buffer_config_t outputBufferConfig = {
560 .pixelFormat = (pxp_output_pixel_format_t)PXP_OUT_PIXEL_FORMAT,
561 .interlacedMode = kPXP_OutputProgressive,
562 .buffer0Addr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_area->x1),
563 .buffer1Addr = (uint32_t)0U,
564 .pitchBytes = dest_stride * sizeof(lv_color_t),
565 .width = dest_w,
566 .height = dest_h
567 };
568 PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig);
569
570 lv_gpu_nxp_pxp_run();
571 }
572
573 #endif /*LV_USE_GPU_NXP_PXP*/
574