diff --git a/components/esp_driver_dma/src/async_color_convert_dma2d.c b/components/esp_driver_dma/src/async_color_convert_dma2d.c index 976a962401e..5bb403c6ff1 100644 --- a/components/esp_driver_dma/src/async_color_convert_dma2d.c +++ b/components/esp_driver_dma/src/async_color_convert_dma2d.c @@ -164,9 +164,24 @@ static esp_err_t sync_if_cacheable(void *addr, size_t size, int flags) return esp_cache_get_line_size_by_addr(addr) > 0 ? esp_cache_msync(addr, size, flags) : ESP_OK; } -static size_t get_picture_size_bytes(uint32_t stride, uint32_t height, uint32_t bit_depth) +static void get_picture_window_bytes(uint32_t stride, + uint32_t x, + uint32_t y, + uint32_t window_width, + uint32_t window_height, + uint32_t bit_depth, + size_t *out_offset, + size_t *out_size) { - return (((size_t)stride * height * bit_depth) + 7) / 8; + size_t start_bit = ((size_t)y * stride + x) * bit_depth; + size_t end_bit = (((size_t)(y + window_height - 1) * stride + x + window_width) * bit_depth); + // Floor-divide start so the range begins at the first byte that contains start_bit. + // Ceil-divide end ((end_bit + 7) / 8) so any partial trailing byte is included. + size_t start_byte = start_bit / 8; + size_t end_byte = (end_bit + 7) / 8; + + *out_offset = start_byte; + *out_size = end_byte - start_byte; } static esp_err_t validate_request(const async_color_convert_request_t *request) @@ -371,14 +386,28 @@ static esp_err_t async_color_convert_dma2d_convert(async_color_convert_context_t uint32_t src_bpp = color_hal_pixel_format_fourcc_get_bit_depth(src_fourcc); uint32_t dst_bpp = color_hal_pixel_format_fourcc_get_bit_depth(dst_fourcc); - size_t src_total_size = get_picture_size_bytes(request->src_stride, request->src_height, src_bpp); - size_t dst_total_size = get_picture_size_bytes(request->dst_stride, request->dst_height, dst_bpp); + size_t src_window_offset = 0; + size_t src_window_size = 0; + get_picture_window_bytes(request->src_stride, request->src_x, request->src_y, + request->copy_width, request->copy_height, src_bpp, + &src_window_offset, &src_window_size); - ESP_GOTO_ON_ERROR(sync_if_cacheable((void *)request->src_buffer, src_total_size, + size_t dst_window_offset = 0; + size_t dst_window_size = 0; + get_picture_window_bytes(request->dst_stride, request->dst_x, request->dst_y, + request->copy_width, request->copy_height, dst_bpp, + &dst_window_offset, &dst_window_size); + + uint8_t *src_window_addr = (uint8_t *)request->src_buffer + src_window_offset; + uint8_t *dst_window_addr = (uint8_t *)request->dst_buffer + dst_window_offset; + + ESP_GOTO_ON_ERROR(sync_if_cacheable(src_window_addr, src_window_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED), recycle_and_out, TAG, "source cache sync failed"); - ESP_GOTO_ON_ERROR(sync_if_cacheable(request->dst_buffer, dst_total_size, + // UNALIGNED is safe here because C2M writes back partial cache lines before invalidating them + // Callers must not access the destination buffer until the async operation completes. + ESP_GOTO_ON_ERROR(sync_if_cacheable(dst_window_addr, dst_window_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE | ESP_CACHE_MSYNC_FLAG_UNALIGNED), recycle_and_out, TAG, "destination cache sync failed"); diff --git a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c index 58684f12149..283a6d62c56 100644 --- a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c +++ b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c @@ -1484,7 +1484,9 @@ esp_err_t esp_lcd_rgb_panel_enable_dma2d(esp_lcd_panel_handle_t panel) // Initialize the async color convert backend used by the built-in DMA2D copy hook. // Use its default backlog to queue multiple frame buffer copy requests. - async_color_convert_config_t fbcpy_config = {}; + async_color_convert_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"); // Register the DMA2D draw bitmap hook