23 #include "ui_drawing_dma2d.h"
24 #include "ui_drawing_soft.h"
25 #include "ui_image_drawing.h"
26 #include "ui_display_brs.h"
41 #if !defined DMA2D_CONFIGURATION_VERSION
42 #error "Undefined DMA2D_CONFIGURATION_VERSION, it must be defined in ui_drawing_nema_configuration.h"
45 #if defined DMA2D_CONFIGURATION_VERSION && DMA2D_CONFIGURATION_VERSION != 1
46 #error "Version of the configuration file ui_drawing_dma2d_configuration.h is not compatible with this implementation."
56 #if DRAWING_DMA2D_BPP == 16
57 #define DRAWING_DMA2D_FORMAT DMA2D_RGB565
58 #elif DRAWING_DMA2D_BPP == 24
59 #define DRAWING_DMA2D_FORMAT DMA2D_RGB888
60 #elif DRAWING_DMA2D_BPP == 32
61 #define DRAWING_DMA2D_FORMAT DMA2D_ARGB8888
63 #error "Define 'DRAWING_DMA2D_BPP' is required (16, 24 or 32)"
69 #ifndef DRAWING_DMA2D_CACHE_MANAGEMENT
70 #error "Please define the DRAWING_DMA2D_CACHE_MANAGEMENT in ui_drawing_dma2d_configuration.h"
80 typedef void (*t_drawing_notification)(
bool under_isr);
87 uint8_t* dest_address;
99 uint32_t src_dma2d_format;
110 static DMA2D_HandleTypeDef g_hdma2d;
115 static t_drawing_notification g_callback_notification;
121 static bool g_dma2d_running;
126 static void* g_dma2d_semaphore;
135 static inline void _drawing_dma2d_wait(
void) {
136 while(g_dma2d_running) {
137 LLUI_DISPLAY_IMPL_binarySemaphoreTake(g_dma2d_semaphore);
151 static inline void _invalidateDCache(
void) {
152 #if DRAWING_DMA2D_CACHE_MANAGEMENT == DRAWING_DMA2D_CACHE_MANAGEMENT_ENABLED
153 SCB_InvalidateDCache();
166 static inline void _cleanDCache(
void) {
167 #if DRAWING_DMA2D_CACHE_MANAGEMENT == DRAWING_DMA2D_CACHE_MANAGEMENT_ENABLED
175 static inline void _drawing_dma2d_done(
void) {
176 g_dma2d_running =
false;
178 LLUI_DISPLAY_IMPL_binarySemaphoreGive(g_dma2d_semaphore,
true);
184 static inline uint8_t* _drawing_dma2d_adjust_address(uint8_t* address, uint32_t x, uint32_t y, uint32_t stride, uint32_t bpp) {
186 return address + ((((y * stride) + x) * bpp) / (uint32_t)8);
192 static inline void _drawing_dma2d_configure_alpha_image_data(MICROUI_GraphicsContext* gc, jint* alphaAndColor) {
194 *(alphaAndColor) <<= 24;
195 *(alphaAndColor) |= (gc->foreground_color & 0xffffff);
217 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){
219 bool is_dma2d_compatible =
true;
220 jint data_width = width;
221 jint data_x_src = x_src;
222 jint data_x_dest = x_dest;
224 switch(image->format) {
225 case MICROUI_IMAGE_FORMAT_RGB565:
226 dma2d_blending_data->src_dma2d_format = CM_RGB565;
227 dma2d_blending_data->src_bpp = 16;
229 case MICROUI_IMAGE_FORMAT_ARGB8888:
230 dma2d_blending_data->src_dma2d_format = CM_ARGB8888;
231 dma2d_blending_data->src_bpp = 32;
233 case MICROUI_IMAGE_FORMAT_RGB888:
234 dma2d_blending_data->src_dma2d_format = CM_RGB888;
235 dma2d_blending_data->src_bpp = 24;
237 case MICROUI_IMAGE_FORMAT_ARGB1555:
238 dma2d_blending_data->src_dma2d_format = CM_ARGB1555;
239 dma2d_blending_data->src_bpp = 16;
241 case MICROUI_IMAGE_FORMAT_ARGB4444:
242 dma2d_blending_data->src_dma2d_format = CM_ARGB4444;
243 dma2d_blending_data->src_bpp = 16;
245 case MICROUI_IMAGE_FORMAT_A4: {
248 jint xAlign = data_x_src & 1;
249 jint wAlign = data_width & 1;
255 UI_DRAWING_SOFT_drawImage(gc, image, data_x_src + data_width, y_src, 1, height, data_x_dest + data_width, y_dest, alpha);
264 UI_DRAWING_SOFT_drawImage(gc, image, data_x_src, y_src, 1, height, data_x_dest, y_dest, alpha);
268 UI_DRAWING_SOFT_drawImage(gc, image, data_x_src + data_width, y_src, 1, height, data_x_dest + data_width, y_dest, alpha);
276 UI_DRAWING_SOFT_drawImage(gc, image, data_x_src, y_src, 1, height, data_x_dest, y_dest, alpha);
283 _drawing_dma2d_configure_alpha_image_data(gc, &alpha);
284 dma2d_blending_data->src_dma2d_format = CM_A4;
285 dma2d_blending_data->src_bpp = 4;
288 case MICROUI_IMAGE_FORMAT_A8:
289 _drawing_dma2d_configure_alpha_image_data(gc, &alpha);
290 dma2d_blending_data->src_dma2d_format = CM_A8;
291 dma2d_blending_data->src_bpp = 8;
295 is_dma2d_compatible =
false;
299 if (is_dma2d_compatible){
300 MICROUI_Image* dest = &gc->image;
301 dma2d_blending_data->src_address = LLUI_DISPLAY_getBufferAddress(image);
302 dma2d_blending_data->dest_address = LLUI_DISPLAY_getBufferAddress(dest);
303 dma2d_blending_data->src_stride = LLUI_DISPLAY_getStrideInPixels(image);
304 dma2d_blending_data->dest_stride = LLUI_DISPLAY_getStrideInPixels(dest);
305 dma2d_blending_data->dest_width = dest->width;
306 dma2d_blending_data->dest_height = dest->height;
307 dma2d_blending_data->x_src = data_x_src;
308 dma2d_blending_data->y_src = y_src;
309 dma2d_blending_data->width = data_width;
310 dma2d_blending_data->height = height;
311 dma2d_blending_data->x_dest = data_x_dest;
312 dma2d_blending_data->y_dest = y_dest;
313 dma2d_blending_data->alpha = alpha;
318 return is_dma2d_compatible;
330 _drawing_dma2d_wait();
333 HAL_DMA2D_DeInit(&g_hdma2d);
336 g_hdma2d.LayerCfg[0].InputOffset = dma2d_blending_data->dest_stride - dma2d_blending_data->width;
337 g_hdma2d.LayerCfg[0].InputColorMode = DRAWING_DMA2D_FORMAT;
338 g_hdma2d.LayerCfg[0].AlphaMode = DMA2D_NO_MODIF_ALPHA;
339 g_hdma2d.LayerCfg[0].InputAlpha = 255;
340 HAL_DMA2D_ConfigLayer(&g_hdma2d, 0);
343 HAL_DMA2D_DisableCLUT(&g_hdma2d, 1);
344 g_hdma2d.LayerCfg[1].InputOffset = dma2d_blending_data->src_stride - dma2d_blending_data->width;
345 g_hdma2d.LayerCfg[1].InputColorMode = dma2d_blending_data->src_dma2d_format;
346 g_hdma2d.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA;
347 g_hdma2d.LayerCfg[1].InputAlpha = dma2d_blending_data->alpha;
348 HAL_DMA2D_ConfigLayer(&g_hdma2d, 1);
351 g_hdma2d.Init.Mode = DMA2D_M2M_BLEND;
352 g_hdma2d.Init.OutputOffset = dma2d_blending_data->dest_stride - dma2d_blending_data->width;
353 HAL_DMA2D_Init(&g_hdma2d) ;
356 g_callback_notification = &LLUI_DISPLAY_notifyAsynchronousDrawingEnd;
365 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);
366 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);
367 g_dma2d_running =
true;
370 HAL_DMA2D_BlendingStart_IT(&g_hdma2d, (uint32_t)srcAddr, (uint32_t)destAddr, (uint32_t)destAddr, dma2d_blending_data->width, dma2d_blending_data->height);
383 jint width = dma2d_blending_data->width;
384 dma2d_blending_data->width = dma2d_blending_data->x_dest - dma2d_blending_data->x_src;
385 _drawing_dma2d_blending_configure(dma2d_blending_data);
388 dma2d_blending_data->x_src += width;
389 dma2d_blending_data->x_dest = dma2d_blending_data->x_src + dma2d_blending_data->width;
394 if (width < dma2d_blending_data->width){
395 dma2d_blending_data->width = width;
396 _drawing_dma2d_blending_configure(dma2d_blending_data);
400 dma2d_blending_data->x_src -= dma2d_blending_data->width;
401 dma2d_blending_data->x_dest -= dma2d_blending_data->width;
403 _drawing_dma2d_wait();
404 _drawing_dma2d_blending_start(dma2d_blending_data);
406 width -= dma2d_blending_data->width;
420 jint height = dma2d_blending_data->height;
421 dma2d_blending_data->height = dma2d_blending_data->y_dest - dma2d_blending_data->y_src;
422 _drawing_dma2d_blending_configure(dma2d_blending_data);
425 dma2d_blending_data->y_src += height;
426 dma2d_blending_data->y_dest = dma2d_blending_data->y_src + dma2d_blending_data->height;
431 if (height < dma2d_blending_data->height){
432 dma2d_blending_data->height = height;
437 dma2d_blending_data->y_src -= dma2d_blending_data->height;
438 dma2d_blending_data->y_dest -= dma2d_blending_data->height;
440 _drawing_dma2d_wait();
441 _drawing_dma2d_blending_start(dma2d_blending_data);
443 height -= dma2d_blending_data->height;
447 static void _drawing_dma2d_restore_callback(
bool from_isr) {
449 UI_DRAWING_DMA2D_memcpy_callback(from_isr);
451 LLUI_DISPLAY_notifyAsynchronousDrawingEnd(from_isr);
459 void UI_DRAWING_DMA2D_IRQHandler(
void) {
461 HAL_DMA2D_IRQHandler(&g_hdma2d);
464 _drawing_dma2d_done();
467 g_callback_notification(
true);
475 void UI_DRAWING_DMA2D_initialize(
void* binary_semaphore_handle) {
477 g_dma2d_running =
false;
478 g_dma2d_semaphore = binary_semaphore_handle;
481 HAL_NVIC_SetPriority(DMA2D_IRQn, 5, 3);
482 HAL_NVIC_EnableIRQ(DMA2D_IRQn);
485 g_hdma2d.Init.ColorMode = DRAWING_DMA2D_FORMAT;
486 g_hdma2d.Instance = DMA2D;
490 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) {
491 _drawing_dma2d_wait();
493 uint32_t width = (xmax - xmin + (uint32_t)1);
494 uint32_t height = (ymax - ymin + (uint32_t)1);
497 HAL_DMA2D_DeInit(&g_hdma2d);
500 g_hdma2d.LayerCfg[1].InputOffset = stride - width;
501 g_hdma2d.LayerCfg[1].InputColorMode = DRAWING_DMA2D_FORMAT;
502 HAL_DMA2D_ConfigLayer(&g_hdma2d, 1);
505 g_hdma2d.Init.Mode = DMA2D_M2M;
506 g_hdma2d.Init.OutputOffset = stride - width;
507 HAL_DMA2D_Init(&g_hdma2d) ;
510 memcpy_data->src_address = _drawing_dma2d_adjust_address(srcAddr, xmin, ymin, stride, DRAWING_DMA2D_BPP);
511 memcpy_data->dest_address = _drawing_dma2d_adjust_address(destAddr, xmin, ymin, stride, DRAWING_DMA2D_BPP);
512 memcpy_data->width = width;
513 memcpy_data->height = height;
516 g_callback_notification = &UI_DRAWING_DMA2D_memcpy_callback;
517 g_dma2d_running =
true;
526 (uint32_t)(memcpy_data->src_address),
528 (uint32_t)(memcpy_data->dest_address),
535 BSP_DECLARE_WEAK_FCNT
void UI_DRAWING_DMA2D_memcpy_callback(
bool from_isr) {
545 DRAWING_Status UI_DISPLAY_BRS_restore(MICROUI_GraphicsContext* gc, MICROUI_Image* old_back_buffer, ui_rect_t* rect) {
547 UI_DRAWING_DMA2D_configure_memcpy(LLUI_DISPLAY_getBufferAddress(old_back_buffer), LLUI_DISPLAY_getBufferAddress(&gc->image), rect->x1, rect->y1, rect->x2, rect->y2, LLUI_DISPLAY_getStrideInPixels(&gc->image), &memcpy_data);
548 g_callback_notification = &_drawing_dma2d_restore_callback;
549 UI_DRAWING_DMA2D_start_memcpy(&memcpy_data);
550 return DRAWING_RUNNING;
559 DRAWING_Status UI_DRAWING_DMA2D_fillRectangle(MICROUI_GraphicsContext* gc, jint x1, jint y1, jint x2, jint y2) {
561 _drawing_dma2d_wait();
563 uint32_t rectangle_width = x2 - x1 + 1;
564 uint32_t rectangle_height = y2 - y1 + 1;
565 uint32_t stride = LLUI_DISPLAY_getStrideInPixels(&gc->image);
568 HAL_DMA2D_DeInit(&g_hdma2d);
571 g_hdma2d.Init.Mode = DMA2D_R2M;
572 g_hdma2d.Init.OutputOffset = stride - rectangle_width;
573 HAL_DMA2D_Init(&g_hdma2d);
576 g_callback_notification = &LLUI_DISPLAY_notifyAsynchronousDrawingEnd;
577 g_dma2d_running =
true;
581 uint8_t* destination_address = _drawing_dma2d_adjust_address(LLUI_DISPLAY_getBufferAddress(&gc->image), x1, y1, stride, DRAWING_DMA2D_BPP);
583 HAL_DMA2D_Start_IT(&g_hdma2d, gc->foreground_color, (uint32_t)destination_address, rectangle_width, rectangle_height);
585 return DRAWING_RUNNING;
589 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) {
594 if (_drawing_dma2d_is_image_compatible_with_dma2d(gc, image, x_src, y_src, width, height, x_dest, y_dest, alpha, &dma2d_blending_data)){
595 _drawing_dma2d_blending_configure(&dma2d_blending_data);
596 _drawing_dma2d_blending_start(&dma2d_blending_data);
597 ret = DRAWING_RUNNING;
600 #if !defined(LLUI_IMAGE_CUSTOM_FORMATS)
601 UI_DRAWING_SOFT_drawImage(gc, image, x_src, y_src, width, height, x_dest, y_dest, alpha);
604 ret = UI_IMAGE_DRAWING_draw(gc, image, x_src, y_src, width, height, x_dest, y_dest, alpha);
612 DRAWING_Status UI_DRAWING_DMA2D_copyImage(MICROUI_GraphicsContext* gc, MICROUI_Image* img, jint regionX, jint regionY, jint width, jint height, jint x, jint y){
613 return (img == &gc->image) ?
615 UI_DRAWING_DMA2D_drawRegion(gc, regionX, regionY, width, height, x, y, 0xff)
617 : UI_DRAWING_DMA2D_drawImage(gc, img, regionX, regionY, width, height, x, y, 0xff);
621 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){
626 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)){
629 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))){
631 _drawing_dma2d_overlap_horizontal(&dma2d_blending_data);
633 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))){
635 _drawing_dma2d_overlap_vertical(&dma2d_blending_data);
639 _drawing_dma2d_blending_configure(&dma2d_blending_data);
640 _drawing_dma2d_blending_start(&dma2d_blending_data);
642 ret = DRAWING_RUNNING;
646 #if !defined(LLUI_IMAGE_CUSTOM_FORMATS)
647 UI_DRAWING_SOFT_drawImage(gc, &gc->image, x_src, y_src, width, height, x_dest, y_dest, alpha);
650 ret = UI_IMAGE_DRAWING_draw(gc, &gc->image, x_src, y_src, width, height, x_dest, y_dest, alpha);