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