display-dma2d  2.1.0
display-dma2d
drawing_dma2d.c
Go to the documentation of this file.
1 /*
2  * C
3  *
4  * Copyright 2019-2022 MicroEJ Corp. All rights reserved.
5  * Use of this source code is governed by a BSD-style license that can be found with this software.
6  */
7 
16 #ifdef __cplusplus
17 extern "C" {
18 #endif
19 
20 
21 /* Includes ------------------------------------------------------------------*/
22 
23 #include "drawing_dma2d.h"
24 #include "ui_drawing.h"
25 #include "ui_drawing_soft.h"
26 #include "bsp_util.h"
27 
28 /* Defines and Macros --------------------------------------------------------*/
29 
30 /*
31  * @brief Defines the DMA2D format according DRAWING_DMA2D_BPP.
32  */
33 #if DRAWING_DMA2D_BPP == 16
34 #define DRAWING_DMA2D_FORMAT DMA2D_RGB565
35 #elif DRAWING_DMA2D_BPP == 24
36 #define DRAWING_DMA2D_FORMAT DMA2D_RGB888
37 #elif DRAWING_DMA2D_BPP == 32
38 #define DRAWING_DMA2D_FORMAT DMA2D_ARGB8888
39 #else
40 #error "Define 'DRAWING_DMA2D_BPP' is required (16, 24 or 32)"
41 #endif
42 
43 /* Structs and Typedefs ------------------------------------------------------*/
44 
45 /*
46  * @brief Function used to notify the graphical engine about the end of DMA2D work.
47  * Available values are LLUI_DISPLAY_notifyAsynchronousDrawingEnd() and LLUI_DISPLAY_flushDone().
48  */
49 typedef void (*t_drawing_notification)(bool under_isr);
50 
51 /*
52  * @brief Working data when blending an image with the DMA2D
53  */
54 typedef struct {
55  uint8_t* src_address; // address of the image to draw
56  uint8_t* dest_address; // address of the destination
57  uint32_t src_stride; // source image' stride
58  uint32_t dest_stride; // destination' stride
59  jchar dest_width; // destination's width
60  jchar dest_height; // destination's height
61  jint x_src; // source image's region X coordinate
62  jint y_src; // source image's region Y coordinate
63  jint width; // region's width
64  jint height; // region's height
65  jint x_dest; // destination X coordinate
66  jint y_dest; // destination X coordinate
67  jint alpha; // opacity to apply
68  uint32_t src_dma2d_format; // source image's format in DMA2D format
69  uint32_t src_bpp; // source image's bpp
71 
72 /* Private fields ------------------------------------------------------------*/
73 
74 /*
75  * @brief STM32 HAL DMA2D declaration.
76  */
77 static DMA2D_HandleTypeDef g_hdma2d;
78 
79 /*
80  * @brief Next notification to call after DMA2D work.
81  */
82 static t_drawing_notification g_callback_notification;
83 
84 /*
85  * @brief This boolean is set to true before launching a DMA2D action and back to
86  * false during DMA2D interrupt. It allows to know if the DMA2D is running or not.
87  */
88 static bool g_dma2d_running;
89 
90 /*
91  * @brief Binary semaphore used to lock a DMA2D user when DMA2D is already running.
92  */
93 static void* g_dma2d_semaphore;
94 
95 /* Private functions ---------------------------------------------------------*/
96 
97 /*
98  * @brief Ensures DMA2D previous work is done before returning.
99  */
100 static inline void _drawing_dma2d_wait(void) {
101  while(g_dma2d_running) {
102  LLUI_DISPLAY_IMPL_binarySemaphoreTake(g_dma2d_semaphore);
103  }
104 }
105 
106 /*
107  * @brief Notify the DMA2D has finished previous job.
108  */
109 static inline void _drawing_dma2d_done(void) {
110  g_dma2d_running = false;
111  LLUI_DISPLAY_IMPL_binarySemaphoreGive(g_dma2d_semaphore, true);
112 }
113 
114 /*
115  * @brief Adjusts the given address to target the given point.
116  */
117 static inline uint8_t* _drawing_dma2d_adjust_address(uint8_t* address, uint32_t x, uint32_t y, uint32_t stride, uint32_t bpp) {
118  return address + ((((y * stride) + x) * bpp) / (uint32_t)8);
119 }
120 
121 /*
122  * @brief For A4 and A8 formats, alpha contains both the global alpha + wanted color.
123  */
124 static inline void _drawing_dma2d_configure_alpha_image_data(MICROUI_GraphicsContext* gc, jint* alphaAndColor) {
125  // for A4 and A8 formats, alphaAndColor is both the global alpha + wanted color
126  *(alphaAndColor) <<= 24;
127  *(alphaAndColor) |= (gc->foreground_color & 0xffffff);
128 }
129 
130 /*
131  * @brief Cleans the cache.
132  *
133  * Before each DMA_2D transfer, the data cache must be cleaned because the
134  * graphics memory is in the memory which is defined "cache enabled" in the MPU
135  * configuration.
136  *
137  * This feature is only required on STM32 CPUs that hold a cache.
138  */
139 static inline void _cleanDCache(void) {
140 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
141  SCB_CleanDCache();
142 #endif
143 }
144 
145 /*
146  * @brief Tells is the image to draw in the graphics context is compatible with the DMA2D.
147  *
148  * The image is compatible with the DMA2D when its format is supported by the DMA2D.
149  * Note for the A4 format: the odd left and right bands are drawn in sofware.
150  *
151  * @param[in] gc: the destination
152  * @param[in] image: the source
153  * @param[in] x_src: the source's region X coordinate
154  * @param[in] y_src: the source's region Y coordinate
155  * @param[in] width: the width of the region to draw
156  * @param[in] height: the width of the region to draw
157  * @param[in] x_dest: the destination X coordinate
158  * @param[in] y_dest: the destination Y coordinate
159  * @param[in] alpha: a point on the opacity to apply.
160  * @param[out] dma2d_blending_data: the data to configure the DMA2D registers
161  *
162  * @return true if the source is compatible with the DMA2D
163  */
164 static bool _drawing_dma2d_is_image_compatible_with_dma2d(MICROUI_GraphicsContext* gc, MICROUI_Image* image, jint x_src, jint y_src, jint width, jint height, jint x_dest, jint y_dest, jint alpha, DRAWING_DMA2D_blending_t* dma2d_blending_data){
165 
166  bool is_dma2d_compatible = true;
167  jint data_width = width;
168  jint data_x_src = x_src;
169  jint data_x_dest = x_dest;
170 
171  switch(image->format) {
172  case MICROUI_IMAGE_FORMAT_RGB565:
173  dma2d_blending_data->src_dma2d_format = CM_RGB565;
174  dma2d_blending_data->src_bpp = 16;
175  break;
176  case MICROUI_IMAGE_FORMAT_ARGB8888:
177  dma2d_blending_data->src_dma2d_format = CM_ARGB8888;
178  dma2d_blending_data->src_bpp = 32;
179  break;
180  case MICROUI_IMAGE_FORMAT_RGB888:
181  dma2d_blending_data->src_dma2d_format = CM_RGB888;
182  dma2d_blending_data->src_bpp = 24;
183  break;
184  case MICROUI_IMAGE_FORMAT_ARGB1555:
185  dma2d_blending_data->src_dma2d_format = CM_ARGB1555;
186  dma2d_blending_data->src_bpp = 16;
187  break;
188  case MICROUI_IMAGE_FORMAT_ARGB4444:
189  dma2d_blending_data->src_dma2d_format = CM_ARGB4444;
190  dma2d_blending_data->src_bpp = 16;
191  break;
192  case MICROUI_IMAGE_FORMAT_A4: {
193  // check DMA2D limitations: first and last vertical lines addresses must be aligned on 8 bits
194 
195  jint xAlign = data_x_src & 1;
196  jint wAlign = data_width & 1;
197 
198  if (xAlign == 0) {
199  if (wAlign != 0) {
200  // hard cannot draw last vertical line
201  --data_width;
202  UI_DRAWING_SOFT_drawImage(gc, image, data_x_src + data_width, y_src, 1, height, data_x_dest + data_width, y_dest, alpha);
203  }
204  // else: easy case: first and last vertical lines are aligned on 8 bits
205  }
206  else {
207  if (wAlign == 0) {
208  // worst case: hard cannot draw first and last vertical lines
209 
210  // first line
211  UI_DRAWING_SOFT_drawImage(gc, image, data_x_src, y_src, 1, height, data_x_dest, y_dest, alpha);
212 
213  // last line
214  --data_width;
215  UI_DRAWING_SOFT_drawImage(gc, image, data_x_src + data_width, y_src, 1, height, data_x_dest + data_width, y_dest, alpha);
216 
217  ++data_x_src;
218  ++data_x_dest;
219  --data_width;
220  }
221  else {
222  // cannot draw first vertical line
223  UI_DRAWING_SOFT_drawImage(gc, image, data_x_src, y_src, 1, height, data_x_dest, y_dest, alpha);
224  ++data_x_src;
225  ++data_x_dest;
226  --data_width;
227  }
228  }
229 
230  _drawing_dma2d_configure_alpha_image_data(gc, &alpha);
231  dma2d_blending_data->src_dma2d_format = CM_A4;
232  dma2d_blending_data->src_bpp = 4;
233  break;
234  }
235  case MICROUI_IMAGE_FORMAT_A8:
236  _drawing_dma2d_configure_alpha_image_data(gc, &alpha);
237  dma2d_blending_data->src_dma2d_format = CM_A8;
238  dma2d_blending_data->src_bpp = 8;
239  break;
240  default:
241  // unsupported image format
242  is_dma2d_compatible = false;
243  break;
244  }
245 
246  if (is_dma2d_compatible){
247  MICROUI_Image* dest = &gc->image;
248  dma2d_blending_data->src_address = LLUI_DISPLAY_getBufferAddress(image);
249  dma2d_blending_data->dest_address = LLUI_DISPLAY_getBufferAddress(dest);
250  dma2d_blending_data->src_stride = LLUI_DISPLAY_getStrideInPixels(image);
251  dma2d_blending_data->dest_stride = LLUI_DISPLAY_getStrideInPixels(dest);
252  dma2d_blending_data->dest_width = dest->width;
253  dma2d_blending_data->dest_height = dest->height;
254  dma2d_blending_data->x_src = data_x_src;
255  dma2d_blending_data->y_src = y_src;
256  dma2d_blending_data->width = data_width;
257  dma2d_blending_data->height = height;
258  dma2d_blending_data->x_dest = data_x_dest;
259  dma2d_blending_data->y_dest = y_dest;
260  dma2d_blending_data->alpha = alpha;
261  }
262 
263  return is_dma2d_compatible;
264 }
265 
266 /*
267  * @brief Configures the DMA2D to draw an image.
268  *
269  * This function ensures that the DMA2D is free before configuring the DMA2D.
270  *
271  * @param[in] dma2d_blending_data the blending configuration
272  */
273 static void _drawing_dma2d_blending_configure(DRAWING_DMA2D_blending_t* dma2d_blending_data) {
274 
275  _drawing_dma2d_wait();
276 
277  // de-init DMA2D
278  HAL_DMA2D_DeInit(&g_hdma2d);
279 
280  // configure background
281  g_hdma2d.LayerCfg[0].InputOffset = dma2d_blending_data->dest_stride - dma2d_blending_data->width;
282  g_hdma2d.LayerCfg[0].InputColorMode = DRAWING_DMA2D_FORMAT;
283  g_hdma2d.LayerCfg[0].AlphaMode = DMA2D_NO_MODIF_ALPHA;
284  g_hdma2d.LayerCfg[0].InputAlpha = 255;
285  HAL_DMA2D_ConfigLayer(&g_hdma2d, 0);
286 
287  // configure foreground
288  HAL_DMA2D_DisableCLUT(&g_hdma2d, 1);
289  g_hdma2d.LayerCfg[1].InputOffset = dma2d_blending_data->src_stride - dma2d_blending_data->width;
290  g_hdma2d.LayerCfg[1].InputColorMode = dma2d_blending_data->src_dma2d_format;
291  g_hdma2d.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA;
292  g_hdma2d.LayerCfg[1].InputAlpha = dma2d_blending_data->alpha;
293  HAL_DMA2D_ConfigLayer(&g_hdma2d, 1);
294 
295  // configure DMA2D
296  g_hdma2d.Init.Mode = DMA2D_M2M_BLEND;
297  g_hdma2d.Init.OutputOffset = dma2d_blending_data->dest_stride - dma2d_blending_data->width;
298  HAL_DMA2D_Init(&g_hdma2d) ;
299 
300  // configure environment (useless if false is returned)
301  g_callback_notification = &LLUI_DISPLAY_notifyAsynchronousDrawingEnd;
302 }
303 
304 /*
305  * @brief Starts the DMA2D drawing previously configured thanks _drawing_dma2d_blending_configure().
306  *
307  * @param[in] dma2d_blending_data the blending configuration
308  */
309 static inline void _drawing_dma2d_blending_start(DRAWING_DMA2D_blending_t* dma2d_blending_data){
310  uint8_t* srcAddr = _drawing_dma2d_adjust_address(dma2d_blending_data->src_address, dma2d_blending_data->x_src, dma2d_blending_data->y_src, dma2d_blending_data->src_stride, dma2d_blending_data->src_bpp);
311  uint8_t* destAddr = _drawing_dma2d_adjust_address(dma2d_blending_data->dest_address, dma2d_blending_data->x_dest, dma2d_blending_data->y_dest, dma2d_blending_data->dest_stride, DRAWING_DMA2D_BPP);
312  g_dma2d_running = true;
313 
314  // cppcheck-suppress [misra-c2012-11.4] allow cast address in u32 (see HAL_DMA2D_BlendingStart_IT())
315  HAL_DMA2D_BlendingStart_IT(&g_hdma2d, (uint32_t)srcAddr, (uint32_t)destAddr, (uint32_t)destAddr, dma2d_blending_data->width, dma2d_blending_data->height);
316 }
317 
318 /*
319  * @brief Draws a region of an image at another position.
320  *
321  * This function draws block per block to prevent the overlapping in X.
322  *
323  * @param[in] dma2d_blending_data the blending configuration
324  */
325 static void _drawing_dma2d_overlap_horizontal(DRAWING_DMA2D_blending_t* dma2d_blending_data) {
326 
327  // retrieve band's width
328  jint width = dma2d_blending_data->width;
329  dma2d_blending_data->width = dma2d_blending_data->x_dest - dma2d_blending_data->x_src;
330  _drawing_dma2d_blending_configure(dma2d_blending_data);
331 
332  // go to x + band width
333  dma2d_blending_data->x_src += width;
334  dma2d_blending_data->x_dest = dma2d_blending_data->x_src + dma2d_blending_data->width;
335 
336  while (width > 0) {
337 
338  // adjust band's width
339  if (width < dma2d_blending_data->width){
340  dma2d_blending_data->width = width;
341  _drawing_dma2d_blending_configure(dma2d_blending_data);
342  }
343 
344  // adjust src & dest positions
345  dma2d_blending_data->x_src -= dma2d_blending_data->width;
346  dma2d_blending_data->x_dest -= dma2d_blending_data->width;
347 
348  _drawing_dma2d_wait();
349  _drawing_dma2d_blending_start(dma2d_blending_data);
350 
351  width -= dma2d_blending_data->width;
352  }
353 }
354 
355 /*
356  * @brief Draws a region of an image at another position.
357  *
358  * This function draws block per block to prevent the overlapping in Y.
359  *
360  * @param[in] dma2d_blending_data the blending configuration
361  */
362 static void _drawing_dma2d_overlap_vertical(DRAWING_DMA2D_blending_t* dma2d_blending_data) {
363 
364  // retrieve band's height
365  jint height = dma2d_blending_data->height;
366  dma2d_blending_data->height = dma2d_blending_data->y_dest - dma2d_blending_data->y_src;
367  _drawing_dma2d_blending_configure(dma2d_blending_data);
368 
369  // go to x + band height
370  dma2d_blending_data->y_src += height;
371  dma2d_blending_data->y_dest = dma2d_blending_data->y_src + dma2d_blending_data->height;
372 
373  while (height > 0) {
374 
375  // adjust band's height
376  if (height < dma2d_blending_data->height){
377  dma2d_blending_data->height = height;
378  // no need to configure again the DMA2D
379  }
380 
381  // adjust src & dest positions
382  dma2d_blending_data->y_src -= dma2d_blending_data->height;
383  dma2d_blending_data->y_dest -= dma2d_blending_data->height;
384 
385  _drawing_dma2d_wait();
386  _drawing_dma2d_blending_start(dma2d_blending_data);
387 
388  height -= dma2d_blending_data->height;
389  }
390 }
391 
392 /*
393  * @brief Draws a region of an image using the DMA2D.
394  *
395  * @param[in] dma2d_blending_data the blending configuration
396  */
397 static void _drawing_dma2d(DRAWING_DMA2D_blending_t* dma2d_blending_data){
398 
399  _cleanDCache();
400 
401  if (dma2d_blending_data->src_address == dma2d_blending_data->dest_address) {
402  // source and destination target same buffer: have to check the overlapping
403 
404  if ((dma2d_blending_data->y_dest == dma2d_blending_data->y_src) && (dma2d_blending_data->x_dest > dma2d_blending_data->x_src) && (dma2d_blending_data->x_dest < (dma2d_blending_data->x_src + dma2d_blending_data->width))){
405  _drawing_dma2d_overlap_horizontal(dma2d_blending_data);
406  }
407  else if ((dma2d_blending_data->y_dest > dma2d_blending_data->y_src) && (dma2d_blending_data->y_dest < (dma2d_blending_data->y_src + dma2d_blending_data->height))){
408  _drawing_dma2d_overlap_vertical(dma2d_blending_data);
409  }
410  else {
411  _drawing_dma2d_blending_configure(dma2d_blending_data);
412  _drawing_dma2d_blending_start(dma2d_blending_data);
413  }
414  }
415  else {
416  _drawing_dma2d_blending_configure(dma2d_blending_data);
417  _drawing_dma2d_blending_start(dma2d_blending_data);
418  }
419 
420  LLUI_DISPLAY_setDrawingLimits(dma2d_blending_data->x_dest, dma2d_blending_data->y_dest, dma2d_blending_data->x_dest + dma2d_blending_data->width - 1, dma2d_blending_data->y_dest + dma2d_blending_data->height - 1);
421 }
422 
423 
424 #if DRAWING_DMA2D_BPP == 16
425 
430 static void memcpy_16_ltr(uint16_t* destination, const uint16_t* source, uint32_t num) {
431  for (int i = 0; i < (int)num; ++i) {
432  destination[i] = source[i];
433  }
434 }
435 
440 static void memcpy_16_rtl(uint16_t* destination, const uint16_t* source, uint32_t num) {
441  for (int i = (int)num-1; i >= 0; --i) {
442  destination[i] = source[i];
443  }
444 }
445 
450 static void _drawing_soft_copy_pixels(uint8_t* src8, uint32_t src_stride, uint8_t* dst8, uint32_t dst_stride, uint32_t src_x, uint32_t src_y,
451  uint32_t width, uint32_t dst_x, uint32_t dst_y, bool rtl) {
452 
453  // cppcheck-suppress [misra-c2012-11.3] cast 8 to 16 is ensured by the multiplication with stride
454  uint16_t* dst = ((uint16_t*) dst8) + ((dst_y * dst_stride) + dst_x);
455  // cppcheck-suppress [misra-c2012-11.3] cast 8 to 16 is ensured by the multiplication with stride
456  uint16_t* src = ((uint16_t*) src8) + ((src_y * src_stride) + src_x);
457 
458  if (rtl) {
459  memcpy_16_rtl(dst, src, width);
460  } else {
461  memcpy_16_ltr(dst, src, width);
462  }
463 }
464 
468 static void _drawing_soft_copy_region(MICROUI_Image* dest, MICROUI_Image* source, jint x_src, jint y_src, jint width, jint height, jint x_dest, jint y_dest) {
469 
470  uint8_t* src = LLUI_DISPLAY_getBufferAddress(source);
471  uint8_t* dst = LLUI_DISPLAY_getBufferAddress(dest);
472  uint32_t src_stride = LLUI_DISPLAY_getStrideInPixels(source);
473  uint32_t dst_stride = LLUI_DISPLAY_getStrideInPixels(dest);
474 
475  if (y_dest <= y_src) {
476  bool rtl = ((y_dest == y_src) && (x_dest > x_src)); // true when copying to the same rows but to the right
477  for (int dy = 0; dy < height; dy++) { // top to bottom
478  _drawing_soft_copy_pixels(src, src_stride, dst, dst_stride, x_src, y_src+dy, width, x_dest, y_dest+dy, rtl);
479  }
480  } else {
481  for (int dy = height-1; dy >= 0; dy--) { // bottom to top
482  _drawing_soft_copy_pixels(src, src_stride, dst, dst_stride, x_src, y_src+dy, width, x_dest, y_dest+dy, false);
483  }
484  }
485 
486  LLUI_DISPLAY_setDrawingLimits(x_dest, y_dest, x_dest + width - 1, y_dest + height - 1);
487 }
488 
489 #endif // DRAWING_DMA2D_BPP
490 
491 /*
492  * @brief Tells if given image blending is useful to be performed or not.
493  *
494  * @param[in] dest the destination
495  * @param[in] source the image to draw
496  * @param[in] x_src: the source's region X coordinate
497  * @param[in] y_src: the source's region Y coordinate
498  * @param[in] width: the width of the region to draw
499  * @param[in] height: the width of the region to draw
500  * @param[in] x_dest: the destination X coordinate
501  * @param[in] y_dest: the destination Y coordinate
502  * @param[in] alpha the opacity to apply
503  */
504 static inline bool _is_useless_drawing(MICROUI_Image* dest, MICROUI_Image* source, jint x_src, jint y_src, jint x_dest, jint y_dest, jint alpha) {
505  return (dest == source) && (0xff == alpha) && (x_src == x_dest) && (y_src == y_dest);
506 }
507 
508 /* Interrupt functions -------------------------------------------------------*/
509 
510 void DRAWING_DMA2D_IRQHandler(void) {
511  // notify STM32 HAL
512  HAL_DMA2D_IRQHandler(&g_hdma2d);
513 
514  // notify DMA2D users
515  _drawing_dma2d_done();
516 
517  // notify graphical engine
518  g_callback_notification(true);
519 }
520 
521 /* Public functions ----------------------------------------------------------*/
522 
523 void DRAWING_DMA2D_initialize(void* binary_semaphore_handle) {
524  // configure globals
525  g_dma2d_running = false;
526  g_dma2d_semaphore = binary_semaphore_handle;
527 
528  // configure DMA2D IRQ handler
529  HAL_NVIC_SetPriority(DMA2D_IRQn, 5, 3);
530  HAL_NVIC_EnableIRQ(DMA2D_IRQn);
531 
532  // configure DMA2D
533  g_hdma2d.Init.ColorMode = DRAWING_DMA2D_FORMAT;
534  g_hdma2d.Instance = DMA2D;
535 }
536 
537 void DRAWING_DMA2D_configure_memcpy(uint8_t* srcAddr, uint8_t* destAddr, uint32_t xmin, uint32_t ymin, uint32_t xmax, uint32_t ymax, uint32_t stride, DRAWING_DMA2D_memcpy* memcpy_data) {
538  _drawing_dma2d_wait();
539 
540  uint32_t width = (xmax - xmin + (uint32_t)1);
541  uint32_t height = (ymax - ymin + (uint32_t)1);
542 
543  // de-init DMA2D
544  HAL_DMA2D_DeInit(&g_hdma2d);
545 
546  // configure foreground
547  g_hdma2d.LayerCfg[1].InputOffset = stride - width;
548  g_hdma2d.LayerCfg[1].InputColorMode = DRAWING_DMA2D_FORMAT;
549  HAL_DMA2D_ConfigLayer(&g_hdma2d, 1);
550 
551  // configure DMA2D
552  g_hdma2d.Init.Mode = DMA2D_M2M;
553  g_hdma2d.Init.OutputOffset = stride - width;
554  HAL_DMA2D_Init(&g_hdma2d) ;
555 
556  // configure given structure (to give later to DRAWING_DMA2D_start_memcpy())
557  memcpy_data->src_address = _drawing_dma2d_adjust_address(srcAddr, xmin, ymin, stride, DRAWING_DMA2D_BPP);
558  memcpy_data->dest_address = _drawing_dma2d_adjust_address(destAddr, xmin, ymin, stride, DRAWING_DMA2D_BPP);
559  memcpy_data->width = width;
560  memcpy_data->height = height;
561 
562  // configure environment
563  g_callback_notification = &LLUI_DISPLAY_flushDone;
564  g_dma2d_running = true;
565 }
566 
567 void DRAWING_DMA2D_start_memcpy(DRAWING_DMA2D_memcpy* memcpy_data) {
568  _cleanDCache();
569  HAL_DMA2D_Start_IT(
570  &g_hdma2d,
571  (uint32_t)memcpy_data->src_address,
572  (uint32_t)memcpy_data->dest_address,
573  memcpy_data->width,
574  memcpy_data->height
575  );
576 }
577 
578 /* ui_drawing.h functions --------------------------------------------*/
579 
580 DRAWING_Status UI_DRAWING_fillRectangle(MICROUI_GraphicsContext* gc, jint x1, jint y1, jint x2, jint y2) {
581 
582  DRAWING_Status ret;
583 
584  if (LLUI_DISPLAY_isClipEnabled(gc) && !LLUI_DISPLAY_clipRectangle(gc, &x1, &y1, &x2, &y2)) {
585  // drawing is out of clip: nothing to do
586  ret = DRAWING_DONE;
587  }
588  else {
589  // clip disabled (means drawing is fully in clip) or drawing fits the clip
590 
591 
592  _drawing_dma2d_wait();
593 
594  LLUI_DISPLAY_setDrawingLimits(x1, y1, x2, y2);
595 
596  uint32_t rectangle_width = x2 - x1 + 1;
597  uint32_t rectangle_height = y2 - y1 + 1;
598  uint32_t stride = LLUI_DISPLAY_getStrideInPixels(&gc->image);
599 
600  // de-init DMA2D
601  HAL_DMA2D_DeInit(&g_hdma2d);
602 
603  // configure DMA2D
604  g_hdma2d.Init.Mode = DMA2D_R2M;
605  g_hdma2d.Init.OutputOffset = stride - rectangle_width;
606  HAL_DMA2D_Init(&g_hdma2d);
607 
608  // configure environment
609  g_callback_notification = &LLUI_DISPLAY_notifyAsynchronousDrawingEnd;
610  g_dma2d_running = true;
611 
612  // start DMA2D
613  _cleanDCache();
614  uint8_t* destination_address = _drawing_dma2d_adjust_address(LLUI_DISPLAY_getBufferAddress(&gc->image), x1, y1, stride, DRAWING_DMA2D_BPP);
615  // cppcheck-suppress [misra-c2012-11.4] allow cast address in u32 (see HAL_DMA2D_Start_IT())
616  HAL_DMA2D_Start_IT(&g_hdma2d, gc->foreground_color, (uint32_t)destination_address, rectangle_width, rectangle_height);
617 
618  ret = DRAWING_RUNNING;
619  }
620 
621  return ret;
622 }
623 
624 DRAWING_Status UI_DRAWING_drawImage(MICROUI_GraphicsContext* gc, MICROUI_Image* image, jint x_src, jint y_src, jint width, jint height, jint x_dest, jint y_dest, jint alpha) {
625 
626  DRAWING_Status ret;
627  if (!_is_useless_drawing(&gc->image, image, x_src, y_src, x_dest, y_dest, alpha)){
628 
629 #if DRAWING_DMA2D_BPP == 16
630  if ((0xff == alpha) && (gc->image.format == image->format)) {
631  // source and destination have the same format and no opacity is applied
632  // -> software algorithm is faster than DMA2D
633  _drawing_soft_copy_region(&gc->image, image, x_src, y_src, width, height, x_dest, y_dest);
634  ret = DRAWING_DONE;
635  }
636  else{
637 #endif // DRAWING_DMA2D_BPP
638 
639  DRAWING_DMA2D_blending_t dma2d_blending_data;
640 
641  if (_drawing_dma2d_is_image_compatible_with_dma2d(gc, image, x_src, y_src, width, height, x_dest, y_dest, alpha, &dma2d_blending_data)){
642  _drawing_dma2d(&dma2d_blending_data);
643  ret = DRAWING_RUNNING;
644  }
645  else {
646  UI_DRAWING_SOFT_drawImage(gc, image, x_src, y_src, width, height, x_dest, y_dest, alpha);
647  ret = DRAWING_DONE;
648  }
649 #if DRAWING_DMA2D_BPP == 16
650  }
651 #endif // DRAWING_DMA2D_BPP
652  }
653  else {
654  // nothing to do
655  ret = DRAWING_DONE;
656  }
657 
658  return ret;
659 }
660 
661 /* EOF -----------------------------------------------------------------------*/
662 
663 #ifdef __cplusplus
664 }
665 #endif
666 
667 
Use STM32 DMA2D (ChromART) for MicroEJ ui_drawing.h implementation.