refactor(lcd): add async dma2d copy wrapper

This commit is contained in:
Chen Jichang
2026-09-15 15:09:48 +08:00
parent 7706587bb2
commit 7a02ede3dc
5 changed files with 253 additions and 49 deletions
+17 -24
View File
@@ -6,12 +6,12 @@
#include <sys/param.h>
#include "esp_lcd_panel_interface.h"
#include "esp_lcd_mipi_dsi.h"
#include "esp_async_color_convert.h"
#include "esp_intr_alloc.h"
#include "esp_clk_tree.h"
#include "esp_cache.h"
#include "mipi_dsi_priv.h"
#include "esp_memory_utils.h"
#include "esp_private/async_memcpy_dma2d.h"
#include "esp_private/dw_gdma.h"
#include "hal/color_hal.h"
@@ -44,7 +44,7 @@ struct esp_lcd_dpi_panel_t {
esp_lcd_panel_draw_bitmap_hook_t draw_bitmap_hook; // Draw bitmap hook function
void* hook_ctx; // Hook context
bool (*on_hook_end)(esp_lcd_panel_handle_t panel); // Callback to be invoked when the draw bitmap hook completes its operation
async_color_convert_handle_t fbcpy_handle; // Async color convert handle used for same-format DMA2D frame buffer copy
async_memcpy_dma2d_handle_t fbcpy_handle; // DMA2D async 2D memcpy handle used for same-format frame buffer copy
#if CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock; // Power management lock
@@ -64,11 +64,11 @@ static bool dpi_panel_draw_bitmap_hook_end(esp_lcd_panel_t *panel)
return false;
}
static bool async_fbcpy_done_cb(async_color_convert_handle_t conv_hdl, async_color_convert_event_data_t *event, void *cb_args)
static bool async_fbcpy_done_cb(async_memcpy_dma2d_handle_t mcp, async_memcpy_dma2d_event_data_t *event, void *cb_args)
{
bool need_yield = false;
esp_lcd_dpi_panel_t *dpi_panel = (esp_lcd_dpi_panel_t *)cb_args;
(void)conv_hdl;
(void)mcp;
(void)event;
if (dpi_panel->on_hook_end) {
@@ -470,7 +470,9 @@ static esp_err_t dpi_panel_draw_bitmap_dma2d_hook(esp_lcd_panel_t *panel, const
esp_lcd_dpi_panel_t *dpi_panel = __containerof(panel, esp_lcd_dpi_panel_t, base);
(void)hook_ctx;
async_color_convert_request_t fbcpy_trans_config = {
// Built-in DMA2D draw hook only needs same-format 2D window copy.
// Use the private DMA2D async memcpy wrapper (thin layer over color convert).
async_memcpy_dma2d_trans_desc_t fbcpy_trans_config = {
.src_buffer = hook_data->src_data,
.dst_buffer = hook_data->dst_data,
.src_stride = hook_data->src_x_size,
@@ -483,16 +485,13 @@ static esp_err_t dpi_panel_draw_bitmap_dma2d_hook(esp_lcd_panel_t *panel, const
.dst_y = hook_data->dst_y_start,
.copy_width = hook_data->src_x_end - hook_data->src_x_start,
.copy_height = hook_data->src_y_end - hook_data->src_y_start,
// For this DMA2D hook we only do window copy from draw buffer to frame buffer.
// Source and destination color formats are intentionally set to the same value to disable CSC.
.src_color_format = dpi_panel->in_color_format,
.dst_color_format = dpi_panel->in_color_format,
.pixel_format = dpi_panel->in_color_format,
};
// The async color convert backend owns source/destination cache sync for the
// DMA2D copy path, so the LCD driver should not perform extra cache sync here.
// The DMA2D async 2D memcpy backend owns source/destination cache sync for the
// copy path, so the LCD driver should not perform extra cache sync here.
// Save the completion callback and invoke it when the async frame buffer copy finishes.
dpi_panel->on_hook_end = hook_data->on_hook_end;
ESP_RETURN_ON_ERROR(esp_async_color_convert(dpi_panel->fbcpy_handle, &fbcpy_trans_config, async_fbcpy_done_cb, dpi_panel), TAG, "async frame buffer copy failed");
ESP_RETURN_ON_ERROR(esp_async_memcpy_dma2d(dpi_panel->fbcpy_handle, &fbcpy_trans_config, async_fbcpy_done_cb, dpi_panel), TAG, "async frame buffer copy failed");
return ESP_OK;
}
@@ -517,12 +516,12 @@ esp_err_t esp_lcd_dpi_panel_enable_dma2d(esp_lcd_panel_handle_t panel)
// Check if built-in DMA2D draw bitmap hook is registered
ESP_RETURN_ON_FALSE(!dpi_panel->fbcpy_handle, ESP_ERR_INVALID_STATE, TAG, "draw bitmap DMA2D hook is already registered");
// Initialize the async color convert backend used by the built-in DMA2D copy hook.
// Initialize the DMA2D async 2D memcpy backend used by the built-in copy hook.
// Use its default backlog to queue multiple frame buffer copy requests.
async_color_convert_config_t fbcpy_config = {
async_memcpy_dma2d_config_t fbcpy_config = {
.dma_burst_size = 128, // for better performance
};
ESP_RETURN_ON_ERROR(esp_async_color_convert_install_dma2d(&fbcpy_config, &dpi_panel->fbcpy_handle), TAG, "install async frame buffer copy backend failed");
ESP_RETURN_ON_ERROR(esp_async_memcpy_install_dma2d(&fbcpy_config, &dpi_panel->fbcpy_handle), TAG, "install async frame buffer copy backend failed");
// Register the DMA2D draw bitmap hook
esp_lcd_panel_hooks_t hooks = {
@@ -534,7 +533,7 @@ esp_err_t esp_lcd_dpi_panel_enable_dma2d(esp_lcd_panel_handle_t panel)
err:
if (dpi_panel->fbcpy_handle) {
esp_async_color_convert_uninstall(dpi_panel->fbcpy_handle);
esp_async_memcpy_uninstall_dma2d(dpi_panel->fbcpy_handle);
dpi_panel->fbcpy_handle = NULL;
}
dpi_panel->on_hook_end = NULL;
@@ -554,13 +553,7 @@ esp_err_t esp_lcd_dpi_panel_disable_dma2d(esp_lcd_panel_handle_t panel)
.draw_bitmap_hook = NULL,
};
ESP_RETURN_ON_ERROR(esp_lcd_dpi_panel_register_hooks(panel, &hooks, NULL), TAG, "unregister DMA2D draw bitmap hook failed");
esp_err_t ret = esp_async_color_convert_uninstall(dpi_panel->fbcpy_handle);
if (ret != ESP_OK) {
// Restore the hook so draw_bitmap_hook and fbcpy_handle stay consistent on failure
hooks.draw_bitmap_hook = dpi_panel_draw_bitmap_dma2d_hook;
esp_lcd_dpi_panel_register_hooks(panel, &hooks, NULL);
ESP_RETURN_ON_ERROR(ret, TAG, "uninstall DMA2D failed");
}
ESP_RETURN_ON_ERROR(esp_async_memcpy_uninstall_dma2d(dpi_panel->fbcpy_handle), TAG, "uninstall DMA2D failed");
dpi_panel->fbcpy_handle = NULL;
dpi_panel->on_hook_end = NULL;
@@ -651,7 +644,7 @@ static esp_err_t dpi_panel_draw_bitmap_2d(esp_lcd_panel_t *panel, int x_start, i
ESP_LOGV(TAG, "copy draw buffer by draw bitmap hook");
// Note, whether the previous draw operation is finished should be ensured by the hook.
// For the built-in DMA2D hook, cache maintenance of the source and destination
// buffers is handled inside the async color convert driver.
// buffers is handled inside the DMA2D async 2D memcpy driver.
esp_lcd_draw_bitmap_hook_data_t hook_data = {
.dst_data = frame_buffer,
+17 -24
View File
@@ -49,7 +49,7 @@
#include "hal/color_hal.h"
#include "rgb_lcd_rotation_sw.h"
#include "esp_private/sleep_retention.h"
#include "esp_async_color_convert.h"
#include "esp_private/async_memcpy_dma2d.h"
#if SOC_HAS(AXI_GDMA)
#include "hal/axi_dma_ll.h"
@@ -174,7 +174,7 @@ struct esp_rgb_panel_t {
esp_lcd_panel_draw_bitmap_hook_t draw_bitmap_hook; // Draw bitmap hook function
void* hook_ctx; // Hook context
bool (*on_hook_end)(esp_lcd_panel_handle_t panel); // Callback to be invoked when the draw bitmap hook completes its operation
async_color_convert_handle_t fbcpy_handle; // Async color convert handle used for same-format DMA2D frame buffer copy
async_memcpy_dma2d_handle_t fbcpy_handle; // DMA2D async 2D memcpy handle used for same-format frame buffer copy
};
static esp_err_t lcd_rgb_panel_alloc_frame_buffers(esp_rgb_panel_t *rgb_panel, const esp_lcd_rgb_panel_config_t *panel_config)
@@ -708,11 +708,11 @@ static bool rgb_panel_draw_bitmap_hook_end(esp_lcd_panel_t *panel)
}
#if SOC_HAS(DMA2D)
static bool async_fbcpy_done_cb(async_color_convert_handle_t conv_hdl, async_color_convert_event_data_t *event, void *cb_args)
static bool async_fbcpy_done_cb(async_memcpy_dma2d_handle_t mcp, async_memcpy_dma2d_event_data_t *event, void *cb_args)
{
bool need_yield = false;
esp_rgb_panel_t *rgb_panel = (esp_rgb_panel_t *)cb_args;
(void)conv_hdl;
(void)mcp;
(void)event;
if (rgb_panel->on_hook_end) {
@@ -800,7 +800,7 @@ static esp_err_t rgb_panel_draw_bitmap_2d(esp_lcd_panel_t *panel, int x_start, i
ESP_LOGV(TAG, "copy draw buffer by draw bitmap hook");
// Note, whether the previous draw operation is finished should be ensured by the hook.
// For the built-in DMA2D hook, cache maintenance of the source and destination
// buffers is handled inside the async color convert driver.
// buffers is handled inside the DMA2D async 2D memcpy driver.
esp_lcd_draw_bitmap_hook_data_t hook_data = {
.dst_data = frame_buffer,
@@ -1447,7 +1447,9 @@ static esp_err_t rgb_panel_draw_bitmap_dma2d_hook(esp_lcd_panel_t *panel, const
esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base);
(void)hook_ctx;
async_color_convert_request_t fbcpy_trans_config = {
// Built-in DMA2D draw hook only needs same-format 2D window copy.
// Use the private DMA2D async memcpy wrapper (thin layer over color convert).
async_memcpy_dma2d_trans_desc_t fbcpy_trans_config = {
.src_buffer = hook_data->src_data,
.dst_buffer = hook_data->dst_data,
.src_stride = hook_data->src_x_size,
@@ -1460,16 +1462,13 @@ static esp_err_t rgb_panel_draw_bitmap_dma2d_hook(esp_lcd_panel_t *panel, const
.dst_y = hook_data->dst_y_start,
.copy_width = hook_data->src_x_end - hook_data->src_x_start,
.copy_height = hook_data->src_y_end - hook_data->src_y_start,
// For this DMA2D hook we only do window copy from draw buffer to frame buffer.
// Source and destination color formats are intentionally set to the same value to disable CSC.
.src_color_format = rgb_panel->in_color_format,
.dst_color_format = rgb_panel->in_color_format,
.pixel_format = rgb_panel->in_color_format,
};
// The async color convert backend owns source/destination cache sync for the
// DMA2D copy path, so the LCD driver should not perform extra cache sync here.
// The DMA2D async 2D memcpy backend owns source/destination cache sync for the
// copy path, so the LCD driver should not perform extra cache sync here.
// Save the completion callback and invoke it when the async frame buffer copy finishes.
rgb_panel->on_hook_end = hook_data->on_hook_end;
ESP_RETURN_ON_ERROR(esp_async_color_convert(rgb_panel->fbcpy_handle, &fbcpy_trans_config, async_fbcpy_done_cb, rgb_panel), TAG, "async frame buffer copy failed");
ESP_RETURN_ON_ERROR(esp_async_memcpy_dma2d(rgb_panel->fbcpy_handle, &fbcpy_trans_config, async_fbcpy_done_cb, rgb_panel), TAG, "async frame buffer copy failed");
return ESP_OK;
}
@@ -1482,12 +1481,12 @@ esp_err_t esp_lcd_rgb_panel_enable_dma2d(esp_lcd_panel_handle_t panel)
// Check if built-in DMA2D draw bitmap hook is registered
ESP_RETURN_ON_FALSE(!rgb_panel->fbcpy_handle, ESP_ERR_INVALID_STATE, TAG, "draw bitmap DMA2D hook is already registered");
// Initialize the async color convert backend used by the built-in DMA2D copy hook.
// Initialize the DMA2D async 2D memcpy backend used by the built-in copy hook.
// Use its default backlog to queue multiple frame buffer copy requests.
async_color_convert_config_t fbcpy_config = {
async_memcpy_dma2d_config_t fbcpy_config = {
.dma_burst_size = 128, // for better performance
};
ESP_RETURN_ON_ERROR(esp_async_color_convert_install_dma2d(&fbcpy_config, &rgb_panel->fbcpy_handle), TAG, "install async frame buffer copy backend failed");
ESP_RETURN_ON_ERROR(esp_async_memcpy_install_dma2d(&fbcpy_config, &rgb_panel->fbcpy_handle), TAG, "install async frame buffer copy backend failed");
// Register the DMA2D draw bitmap hook
esp_lcd_panel_hooks_t hooks = {
@@ -1499,7 +1498,7 @@ esp_err_t esp_lcd_rgb_panel_enable_dma2d(esp_lcd_panel_handle_t panel)
err:
if (rgb_panel->fbcpy_handle) {
esp_async_color_convert_uninstall(rgb_panel->fbcpy_handle);
esp_async_memcpy_uninstall_dma2d(rgb_panel->fbcpy_handle);
rgb_panel->fbcpy_handle = NULL;
}
rgb_panel->on_hook_end = NULL;
@@ -1519,13 +1518,7 @@ esp_err_t esp_lcd_rgb_panel_disable_dma2d(esp_lcd_panel_handle_t panel)
.draw_bitmap_hook = NULL,
};
ESP_RETURN_ON_ERROR(esp_lcd_rgb_panel_register_hooks(panel, &hooks, NULL), TAG, "unregister DMA2D draw bitmap hook failed");
esp_err_t ret = esp_async_color_convert_uninstall(rgb_panel->fbcpy_handle);
if (ret != ESP_OK) {
// Restore the hook so draw_bitmap_hook and fbcpy_handle stay consistent on failure
hooks.draw_bitmap_hook = rgb_panel_draw_bitmap_dma2d_hook;
esp_lcd_rgb_panel_register_hooks(panel, &hooks, NULL);
ESP_RETURN_ON_ERROR(ret, TAG, "uninstall DMA2D failed");
}
ESP_RETURN_ON_ERROR(esp_async_memcpy_uninstall_dma2d(rgb_panel->fbcpy_handle), TAG, "uninstall DMA2D failed");
rgb_panel->fbcpy_handle = NULL;
rgb_panel->on_hook_end = NULL;