feat(dma2d): rework cache handling to use lv_draw_buf (#9642)
Arduino Lint / lint (push) Has been cancelled
Build Examples with C++ Compiler / build-examples (push) Has been cancelled
MicroPython CI / Build esp32 port (push) Has been cancelled
MicroPython CI / Build rp2 port (push) Has been cancelled
MicroPython CI / Build stm32 port (push) Has been cancelled
MicroPython CI / Build unix port (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_NORMAL_8BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_SDL - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build ESP IDF ESP32S3 (push) Has been cancelled
C/C++ CI / Run tests with 32bit build (push) Has been cancelled
C/C++ CI / Run tests with 64bit build (push) Has been cancelled
BOM Check / bom-check (push) Has been cancelled
Verify that lv_conf_internal.h matches repository state / verify-conf-internal (push) Has been cancelled
Verify GDB constants are up-to-date / verify-gdb-consts (push) Has been cancelled
Verify the widget property name / verify-property-name (push) Has been cancelled
Verify code formatting / verify-formatting (push) Has been cancelled
Compare file templates with file names / template-check (push) Has been cancelled
Build Docs / build-and-deploy (push) Has been cancelled
Build .deb packages / build (push) Has been cancelled
Test API JSON generator / Test API JSON (push) Has been cancelled
Install LVGL using CMake / build-examples (private) (push) Has been cancelled
Install LVGL using CMake / build-examples (public) (push) Has been cancelled
Check Makefile / Build using Makefile (push) Has been cancelled
Check Makefile for UEFI / Build using Makefile for UEFI (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/benchmark_results_comment/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/filter_docker_logs/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/serialize_results/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark 32b - lv_conf_perf32b (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark 64b - lv_conf_perf64b (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Save PR Number (push) Has been cancelled
Performance Tests CI / Perf Tests OPTIONS_TEST_PERF_32B - Ubuntu (push) Has been cancelled
Performance Tests CI / Perf Tests OPTIONS_TEST_PERF_64B - Ubuntu (push) Has been cancelled
Port repo release update / run-release-branch-updater (push) Has been cancelled
Static Checks / Static Checks (push) Has been cancelled
Verify Font License / verify-font-license (push) Has been cancelled
Verify Kconfig / verify-kconfig (push) Has been cancelled
Hardware Performance Test / Hardware Performance Benchmark (push) Has been cancelled
Hardware Performance Test / HW Benchmark - Save PR Number (push) Has been cancelled

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-03 23:07:27 +02:00
committed by GitHub
co-authored by Alain Volmat
parent c0967f93ec
commit fc2ea9a053
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