feat(dma2d): rework cache handling to use lv_draw_buf (#9642)

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
Co-authored-by: Alain Volmat <alain.volmat@foss.st.com>
This commit is contained in:
Alain Volmat
2026-06-09 18:55:23 +02:00
committed by André Costa
co-authored by Alain Volmat
parent 261d6fd82b
commit e25eb0d486
4 changed files with 93 additions and 70 deletions
+88 -16
View File
@@ -12,6 +12,7 @@
#include "../sw/lv_draw_sw.h"
#include "../../misc/lv_area_private.h"
#include "../lv_draw_buf_private.h"
#if defined(__ZEPHYR__) && LV_USE_DRAW_DMA2D_INTERRUPT
#include <zephyr/kernel.h>
@@ -46,6 +47,10 @@ static void post_transfer_tasks(lv_draw_dma2d_unit_t * u);
#if defined(__ZEPHYR__) && LV_USE_DRAW_DMA2D_INTERRUPT
static void zephyr_dma2d_irq_handler(void *);
#endif
#if LV_DRAW_DMA2D_CACHE
static void invalidate_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area);
static void flush_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area);
#endif
/**********************
* STATIC VARIABLES
@@ -62,9 +67,24 @@ static void post_transfer_tasks(lv_draw_dma2d_unit_t * u);
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_buf_dma2d_init_handlers(void)
{
#if LV_DRAW_DMA2D_CACHE
lv_draw_buf_handlers_t * handlers = lv_draw_buf_get_handlers();
lv_draw_buf_handlers_t * font_handlers = lv_draw_buf_get_font_handlers();
lv_draw_buf_handlers_t * image_handlers = lv_draw_buf_get_image_handlers();
handlers->invalidate_cache_cb = invalidate_cache;
handlers->flush_cache_cb = flush_cache;
font_handlers->invalidate_cache_cb = invalidate_cache;
font_handlers->flush_cache_cb = flush_cache;
image_handlers->invalidate_cache_cb = invalidate_cache;
image_handlers->flush_cache_cb = flush_cache;
#endif
}
void lv_draw_dma2d_init(void)
{
lv_draw_buf_dma2d_init_handlers();
lv_draw_dma2d_unit_t * draw_dma2d_unit = lv_draw_create_unit(sizeof(lv_draw_dma2d_unit_t));
draw_dma2d_unit->base_unit.evaluate_cb = evaluate_cb;
draw_dma2d_unit->base_unit.dispatch_cb = dispatch_cb;
@@ -255,21 +275,64 @@ void lv_draw_dma2d_configure_and_start_transfer(const lv_draw_dma2d_configuratio
;
}
#if LV_DRAW_DMA2D_CACHE
void lv_draw_dma2d_invalidate_cache(const lv_draw_dma2d_cache_area_t * mem_area)
static void __invalidate_flush_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area,
bool flush)
{
if(SCB->CCR & SCB_CCR_DC_Msk) {
SCB_InvalidateDCache_by_Addr((uint32_t *)mem_area->first_byte,
mem_area->stride * mem_area->height);
LV_ASSERT(draw_buf != NULL);
LV_ASSERT(area != NULL);
const lv_image_header_t * header = &draw_buf->header;
uint32_t stride = header->stride;
lv_color_format_t cf = header->cf;
uint32_t bpp = lv_color_format_get_bpp(cf);
int32_t lines = lv_area_get_height(area);
if(lines <= 0 || bpp == 0U || stride == 0U) {
return;
}
/* As area coordinates, x1, x2 and y1 are always expected to be values > 0 */
LV_ASSERT(area->x1 >= 0);
LV_ASSERT(area->x2 >= 0);
LV_ASSERT(area->y1 >= 0);
LV_ASSERT(area->x2 >= area->x1);
uint64_t start_bit = (uint64_t)(uint32_t)area->x1 * (uint64_t)bpp;
uint64_t end_bit = (uint64_t)((uint32_t)area->x2 + 1U) * (uint64_t)bpp;
uint32_t start_byte = (uint32_t)(start_bit >> 3);
uint32_t end_byte = (uint32_t)((end_bit + 7U) >> 3);
int32_t bytes_to_flush_per_line = (int32_t)(end_byte - start_byte);
uint8_t * address = draw_buf->data + start_byte + (stride * (uint32_t)area->y1);
int32_t i = 0;
if(bytes_to_flush_per_line <= 0) {
return;
}
for(i = 0; i < lines; i++) {
if(SCB->CCR & SCB_CCR_DC_Msk) {
if(flush) {
SCB_CleanDCache_by_Addr(address, bytes_to_flush_per_line);
}
else {
SCB_InvalidateDCache_by_Addr(address, bytes_to_flush_per_line);
}
}
address += stride;
}
}
void lv_draw_dma2d_clean_cache(const lv_draw_dma2d_cache_area_t * mem_area)
static void invalidate_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area)
{
if(SCB->CCR & SCB_CCR_DC_Msk) {
SCB_CleanDCache_by_Addr((uint32_t *)mem_area->first_byte,
mem_area->stride * mem_area->height);
}
__invalidate_flush_cache(draw_buf, area, false);
}
static void flush_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area)
{
__invalidate_flush_cache(draw_buf, area, true);
}
#endif
@@ -372,17 +435,26 @@ static int32_t dispatch_cb(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
return 1;
}
int32_t x = 0 - t->target_layer->buf_area.x1;
int32_t y = 0 - t->target_layer->buf_area.y1;
draw_dma2d_unit->last_clipped_area = clipped_coords;
lv_area_move(&draw_dma2d_unit->last_clipped_area, x, y);
/* Flush cache before drawing. This is a no-op when DMA2D_CACHE is disabled */
lv_draw_buf_flush_cache(layer->draw_buf, &draw_dma2d_unit->last_clipped_area);
if(t->type == LV_DRAW_TASK_TYPE_FILL) {
lv_draw_fill_dsc_t * dsc = t->draw_dsc;
void * dest = lv_draw_layer_go_to_xy(layer,
clipped_coords.x1 - layer->buf_area.x1,
clipped_coords.y1 - layer->buf_area.y1);
void * dest = lv_draw_layer_go_to_xy(layer, draw_dma2d_unit->last_clipped_area.x1,
draw_dma2d_unit->last_clipped_area.y1);
lv_draw_dma2d_fill(t, dest,
lv_area_get_width(&clipped_coords),
lv_area_get_height(&clipped_coords),
lv_draw_buf_width_to_stride(lv_area_get_width(&layer->buf_area), dsc->base.layer->color_format));
lv_draw_buf_width_to_stride(lv_area_get_width(&layer->buf_area),
dsc->base.layer->color_format));
}
else if(t->type == LV_DRAW_TASK_TYPE_IMAGE) {
lv_draw_dma2d_image(t, t->draw_dsc, &t->area);
@@ -425,9 +497,9 @@ static int32_t wait_finish_cb(lv_draw_unit_t * draw_unit)
static void post_transfer_tasks(lv_draw_dma2d_unit_t * u)
{
#if LV_DRAW_DMA2D_CACHE
lv_draw_dma2d_invalidate_cache(&u->writing_area);
#endif
/* Invalidate cache after drawing. This is a no-op when DMA2D_CACHE is disabled */
lv_draw_buf_invalidate_cache(u->task_act->target_layer->draw_buf, &u->last_clipped_area);
u->task_act->state = LV_DRAW_TASK_STATE_FINISHED;
u->task_act = NULL;
}
-16
View File
@@ -43,22 +43,6 @@ void lv_draw_dma2d_fill(lv_draw_task_t * t, void * first_pixel, int32_t w, int32
lv_draw_dma2d_output_cf_t output_cf = lv_draw_dma2d_cf_to_dma2d_output_cf(cf);
uint32_t cf_size = LV_COLOR_FORMAT_GET_SIZE(cf);
#if LV_DRAW_DMA2D_CACHE
lv_draw_dma2d_cache_area_t cache_area = {
.first_byte = first_pixel,
.width_bytes = w * cf_size,
.height = h,
.stride = stride
};
lv_draw_dma2d_unit_t * u = (lv_draw_dma2d_unit_t *) t->draw_unit;
lv_memcpy(&u->writing_area, &cache_area, sizeof(lv_draw_dma2d_cache_area_t));
if(dsc->opa < LV_OPA_MAX) {
/* make sure the background area DMA2D is blending is up-to-date in main memory */
lv_draw_dma2d_clean_cache(&cache_area);
}
#endif
uint32_t output_offset = (stride / cf_size) - w;
lv_draw_dma2d_configuration_t conf = {
-24
View File
@@ -87,34 +87,10 @@ static void lv_draw_dma2d_image_core(lv_draw_task_t * t, const lv_draw_image_dsc
uint32_t image_cf_size = LV_COLOR_FORMAT_GET_SIZE(image_cf);
if(image_stride == 0) image_stride = image_cf_size * decoded->header.w;
#if LV_DRAW_DMA2D_CACHE
lv_draw_dma2d_cache_area_t dest_area = {
.first_byte = dest_first_pixel,
.width_bytes = w * output_cf_size,
.height = h,
.stride = dest_stride
};
lv_draw_dma2d_unit_t * u = (lv_draw_dma2d_unit_t *) t->draw_unit;
lv_memcpy(&u->writing_area, &dest_area, sizeof(lv_draw_dma2d_cache_area_t));
/* make sure the background area DMA2D is blending is up-to-date in main memory */
lv_draw_dma2d_clean_cache(&dest_area);
#endif
const void * image_first_byte = src_buf
+ (image_stride * (clipped_img_area->y1 - draw_dsc->image_area.y1))
+ (image_cf_size * (clipped_img_area->x1 - draw_dsc->image_area.x1));
#if LV_DRAW_DMA2D_CACHE
lv_draw_dma2d_cache_area_t src_area = {
.first_byte = image_first_byte,
.width_bytes = w * image_cf_size,
.height = h,
.stride = image_stride
};
/* make sure the image area is up-to-date in main memory for DMA2D */
lv_draw_dma2d_clean_cache(&src_area);
#endif
uint32_t output_offset = (dest_stride / output_cf_size) - w;
lv_draw_dma2d_configuration_t conf = {
.mode = LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_BLENDING,
+5 -14
View File
@@ -106,19 +106,14 @@ typedef struct {
} lv_draw_dma2d_configuration_t;
typedef struct {
const void * first_byte;
uint32_t width_bytes;
uint32_t height;
uint32_t stride;
} lv_draw_dma2d_cache_area_t;
typedef struct {
lv_draw_unit_t base_unit;
lv_draw_task_t * volatile task_act;
#if LV_DRAW_DMA2D_CACHE
lv_draw_dma2d_cache_area_t writing_area;
#endif
/** Last draw task clipped area, stored here so that we can invalidate
the cache after the drawing operation is done. This can either happen
immediately after the draw operation is done or on the DMA2D IRQ callback */
lv_area_t last_clipped_area;
#if LV_DRAW_DMA2D_ASYNC
lv_thread_sync_t interrupt_signal;
#endif
@@ -134,10 +129,6 @@ void lv_draw_dma2d_image(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_ds
lv_draw_dma2d_output_cf_t lv_draw_dma2d_cf_to_dma2d_output_cf(lv_color_format_t cf);
uint32_t lv_draw_dma2d_color_to_dma2d_color(lv_draw_dma2d_output_cf_t cf, lv_color_t color);
void lv_draw_dma2d_configure_and_start_transfer(const lv_draw_dma2d_configuration_t * conf);
#if LV_DRAW_DMA2D_CACHE
void lv_draw_dma2d_invalidate_cache(const lv_draw_dma2d_cache_area_t * mem_area);
void lv_draw_dma2d_clean_cache(const lv_draw_dma2d_cache_area_t * mem_area);
#endif
/**********************
* MACROS