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 720ffa7656d..976a962401e 100644 --- a/components/esp_driver_dma/src/async_color_convert_dma2d.c +++ b/components/esp_driver_dma/src/async_color_convert_dma2d.c @@ -35,7 +35,8 @@ struct async_color_convert_transaction { dma2d_trans_config_t dma2d_trans_config; // Per-request DMA2D transaction configuration async_color_convert_request_t request; // Cached user request used to build DMA2D transaction - dma2d_csc_config_t tx_csc; // Cached DMA2D CSC configuration resolved in task context + dma2d_csc_config_t tx_csc; // Cached DMA2D TX CSC configuration resolved in task context + dma2d_csc_config_t rx_csc; // Cached DMA2D RX CSC configuration resolved in task context async_color_convert_isr_cb_t cb_isr; // User ISR callback for this request void *cb_args; // User callback argument async_color_convert_dma2d_context_t *ctx; // Back pointer to parent context @@ -62,34 +63,65 @@ static esp_err_t async_color_convert_dma2d_convert(async_color_convert_context_t async_color_convert_isr_cb_t cb_isr, void *cb_args); -static bool try_convert_request_to_dma2d_csc(const async_color_convert_request_t *request, - dma2d_csc_config_t *out_tx_csc) +static bool is_rgb24_or_bgr24_fourcc(esp_color_fourcc_t fourcc) +{ + return fourcc == ESP_COLOR_FOURCC_BGR24 || fourcc == ESP_COLOR_FOURCC_RGB24; +} + +static dma2d_csc_config_t default_tx_csc_config(void) +{ + return (dma2d_csc_config_t) { + .tx_csc_option = DMA2D_CSC_TX_NONE, + .pre_scramble = DMA2D_SCRAMBLE_ORDER_BYTE2_1_0, + .post_scramble = DMA2D_SCRAMBLE_ORDER_BYTE2_1_0, + }; +} + +static dma2d_csc_config_t default_rx_csc_config(void) +{ + return (dma2d_csc_config_t) { + .rx_csc_option = DMA2D_CSC_RX_NONE, + .pre_scramble = DMA2D_SCRAMBLE_ORDER_BYTE2_1_0, + .post_scramble = DMA2D_SCRAMBLE_ORDER_BYTE2_1_0, + }; +} + +static bool resolve_dma2d_csc_configs(const async_color_convert_request_t *request, + dma2d_csc_config_t *out_tx_csc, + dma2d_csc_config_t *out_rx_csc) { esp_color_fourcc_t src_fourcc = request->src_color_format; esp_color_fourcc_t dst_fourcc = request->dst_color_format; + bool src_is_rgb24_or_bgr24 = is_rgb24_or_bgr24_fourcc(src_fourcc); + bool dst_is_rgb24_or_bgr24 = is_rgb24_or_bgr24_fourcc(dst_fourcc); + + *out_tx_csc = default_tx_csc_config(); + *out_rx_csc = default_rx_csc_config(); if (src_fourcc == dst_fourcc) { - out_tx_csc->tx_csc_option = DMA2D_CSC_TX_NONE; - out_tx_csc->pre_scramble = DMA2D_SCRAMBLE_ORDER_BYTE2_1_0; - out_tx_csc->post_scramble = DMA2D_SCRAMBLE_ORDER_BYTE2_1_0; + return true; + } + + if (src_is_rgb24_or_bgr24 && dst_is_rgb24_or_bgr24) { + out_tx_csc->tx_csc_option = DMA2D_CSC_TX_SCRAMBLE; // RGB<->BGR conversion is just a scramble operation + out_tx_csc->pre_scramble = DMA2D_SCRAMBLE_ORDER_BYTE0_1_2; return true; } if (src_fourcc == ESP_COLOR_FOURCC_RGB16 && dst_fourcc == ESP_COLOR_FOURCC_BGR24) { out_tx_csc->tx_csc_option = DMA2D_CSC_TX_RGB565_TO_RGB888; - out_tx_csc->pre_scramble = DMA2D_SCRAMBLE_ORDER_BYTE2_1_0; - out_tx_csc->post_scramble = DMA2D_SCRAMBLE_ORDER_BYTE2_1_0; return true; } - if (src_fourcc == ESP_COLOR_FOURCC_BGR24 && dst_fourcc == ESP_COLOR_FOURCC_RGB16) { + if (src_is_rgb24_or_bgr24 && dst_fourcc == ESP_COLOR_FOURCC_RGB16) { out_tx_csc->tx_csc_option = DMA2D_CSC_TX_RGB888_TO_RGB565; - out_tx_csc->pre_scramble = DMA2D_SCRAMBLE_ORDER_BYTE2_1_0; - out_tx_csc->post_scramble = DMA2D_SCRAMBLE_ORDER_BYTE2_1_0; + if (src_fourcc == ESP_COLOR_FOURCC_RGB24) { + out_tx_csc->pre_scramble = DMA2D_SCRAMBLE_ORDER_BYTE0_1_2; + } return true; } - if (src_fourcc == ESP_COLOR_FOURCC_BGR24 && dst_fourcc == ESP_COLOR_FOURCC_UYVY) { + if (src_is_rgb24_or_bgr24 && dst_fourcc == ESP_COLOR_FOURCC_UYVY) { if (request->color_conv_std == COLOR_CONV_STD_RGB_YUV_BT601) { out_tx_csc->tx_csc_option = DMA2D_CSC_TX_RGB888_TO_YUV422_601; } else if (request->color_conv_std == COLOR_CONV_STD_RGB_YUV_BT709) { @@ -97,8 +129,9 @@ static bool try_convert_request_to_dma2d_csc(const async_color_convert_request_t } else { return false; } - out_tx_csc->pre_scramble = DMA2D_SCRAMBLE_ORDER_BYTE2_1_0; - out_tx_csc->post_scramble = DMA2D_SCRAMBLE_ORDER_BYTE2_1_0; + if (src_fourcc == ESP_COLOR_FOURCC_RGB24) { + out_tx_csc->pre_scramble = DMA2D_SCRAMBLE_ORDER_BYTE0_1_2; + } return true; } @@ -110,8 +143,6 @@ static bool try_convert_request_to_dma2d_csc(const async_color_convert_request_t } else { return false; } - out_tx_csc->pre_scramble = DMA2D_SCRAMBLE_ORDER_BYTE2_1_0; - out_tx_csc->post_scramble = DMA2D_SCRAMBLE_ORDER_BYTE2_1_0; return true; } @@ -123,6 +154,11 @@ static inline bool needs_tx_csc(const dma2d_csc_config_t *tx_csc) return tx_csc->tx_csc_option != DMA2D_CSC_TX_NONE; } +static inline bool needs_rx_csc(const dma2d_csc_config_t *rx_csc) +{ + return rx_csc->rx_csc_option != DMA2D_CSC_RX_NONE; +} + 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; @@ -239,9 +275,8 @@ static bool async_color_convert_on_job_picked(uint32_t channel_num, dma2d_set_transfer_ability(tx_chan, &transfer_ability); dma2d_set_transfer_ability(rx_chan, &transfer_ability); - if (needs_tx_csc(&trans->tx_csc)) { - dma2d_configure_color_space_conversion(tx_chan, &trans->tx_csc); - } + dma2d_configure_color_space_conversion(tx_chan, &trans->tx_csc); + dma2d_configure_color_space_conversion(rx_chan, &trans->rx_csc); dma2d_rx_event_callbacks_t cbs = { .on_recv_eof = async_color_convert_done_cb, @@ -301,16 +336,18 @@ static esp_err_t async_color_convert_dma2d_convert(async_color_convert_context_t esp_color_fourcc_t src_fourcc = request->src_color_format; esp_color_fourcc_t dst_fourcc = request->dst_color_format; - trans->tx_csc = (dma2d_csc_config_t) {}; - ESP_GOTO_ON_FALSE(try_convert_request_to_dma2d_csc(request, &trans->tx_csc), + trans->tx_csc = default_tx_csc_config(); + trans->rx_csc = default_rx_csc_config(); + ESP_GOTO_ON_FALSE(resolve_dma2d_csc_configs(request, &trans->tx_csc, &trans->rx_csc), ESP_ERR_INVALID_ARG, recycle_and_out, TAG, "unsupported color conversion mode"); + trans->dma2d_trans_config.channel_flags = DMA2D_CHANNEL_FUNCTION_FLAG_SIBLING; if (needs_tx_csc(&trans->tx_csc)) { - trans->dma2d_trans_config.channel_flags = DMA2D_CHANNEL_FUNCTION_FLAG_SIBLING | DMA2D_CHANNEL_FUNCTION_FLAG_TX_CSC; - } else { - trans->dma2d_trans_config.channel_flags = DMA2D_CHANNEL_FUNCTION_FLAG_SIBLING; + trans->dma2d_trans_config.channel_flags |= DMA2D_CHANNEL_FUNCTION_FLAG_TX_CSC; + } + if (needs_rx_csc(&trans->rx_csc)) { + trans->dma2d_trans_config.channel_flags |= DMA2D_CHANNEL_FUNCTION_FLAG_RX_CSC; } - setup_desc(trans->tx_desc, (void *)request->src_buffer, request->src_stride, @@ -342,7 +379,7 @@ static esp_err_t async_color_convert_dma2d_convert(async_color_convert_context_t recycle_and_out, TAG, "source cache sync failed"); ESP_GOTO_ON_ERROR(sync_if_cacheable(request->dst_buffer, dst_total_size, - ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE), + ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE | ESP_CACHE_MSYNC_FLAG_UNALIGNED), recycle_and_out, TAG, "destination cache sync failed"); ESP_GOTO_ON_ERROR(sync_if_cacheable(trans->tx_desc, color_ctx->desc_alloc_size, diff --git a/components/esp_driver_dma/test_apps/dma2d/main/test_async_color_convert.c b/components/esp_driver_dma/test_apps/dma2d/main/test_async_color_convert.c index ee2c500aa6f..01dd14ae605 100644 --- a/components/esp_driver_dma/test_apps/dma2d/main/test_async_color_convert.c +++ b/components/esp_driver_dma/test_apps/dma2d/main/test_async_color_convert.c @@ -48,10 +48,10 @@ TEST_CASE("async color convert basic callback", "[async_color_convert]") uint16_t *src565 = heap_caps_aligned_calloc(64, pixel_num, sizeof(uint16_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); - uint8_t *dst888 = heap_caps_aligned_calloc(64, pixel_num, 3, - MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); + uint8_t *dst_bgr24 = heap_caps_aligned_calloc(64, pixel_num, 3, + MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); TEST_ASSERT_NOT_NULL(src565); - TEST_ASSERT_NOT_NULL(dst888); + TEST_ASSERT_NOT_NULL(dst_bgr24); for (uint32_t i = 0; i < pixel_num; i++) { src565[i] = (uint16_t)((i * 13) ^ 0x5AA5); @@ -71,7 +71,7 @@ TEST_CASE("async color convert basic callback", "[async_color_convert]") .src_height = height, .src_x = 0, .src_y = 0, - .dst_buffer = dst888, + .dst_buffer = dst_bgr24, .dst_stride = width, .dst_height = height, .dst_x = 0, @@ -96,10 +96,10 @@ TEST_CASE("async color convert basic callback", "[async_color_convert]") TEST_ESP_OK(esp_async_color_convert_uninstall(conv_hdl)); free(src565); - free(dst888); + free(dst_bgr24); } -TEST_CASE("async color convert roundtrip: RGB565<->RGB888", "[async_color_convert]") +TEST_CASE("async color convert roundtrip: RGB16<->BGR24", "[async_color_convert]") { const uint32_t width = 32; const uint32_t height = 20; @@ -107,12 +107,12 @@ TEST_CASE("async color convert roundtrip: RGB565<->RGB888", "[async_color_conver uint16_t *src565 = heap_caps_aligned_calloc(64, pixel_num, sizeof(uint16_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); - uint8_t *mid888 = heap_caps_aligned_calloc(64, pixel_num, 3, - MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); + uint8_t *mid_bgr24 = heap_caps_aligned_calloc(64, pixel_num, 3, + MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); uint16_t *dst565 = heap_caps_aligned_calloc(64, pixel_num, sizeof(uint16_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); TEST_ASSERT_NOT_NULL(src565); - TEST_ASSERT_NOT_NULL(mid888); + TEST_ASSERT_NOT_NULL(mid_bgr24); TEST_ASSERT_NOT_NULL(dst565); for (uint32_t i = 0; i < pixel_num; i++) { @@ -127,13 +127,13 @@ TEST_CASE("async color convert roundtrip: RGB565<->RGB888", "[async_color_conver async_color_convert_handle_t conv_hdl = NULL; TEST_ESP_OK(esp_async_color_convert_install_dma2d(&config, &conv_hdl)); - async_color_convert_request_t req_565_to_888 = { + async_color_convert_request_t req_565_to_bgr24 = { .src_buffer = src565, .src_stride = width, .src_height = height, .src_x = 0, .src_y = 0, - .dst_buffer = mid888, + .dst_buffer = mid_bgr24, .dst_stride = width, .dst_height = height, .dst_x = 0, @@ -144,8 +144,8 @@ TEST_CASE("async color convert roundtrip: RGB565<->RGB888", "[async_color_conver .dst_color_format = ESP_COLOR_FOURCC_BGR24, }; - async_color_convert_request_t req_888_to_565 = { - .src_buffer = mid888, + async_color_convert_request_t req_bgr24_to_565 = { + .src_buffer = mid_bgr24, .src_stride = width, .src_height = height, .src_x = 0, @@ -161,8 +161,8 @@ TEST_CASE("async color convert roundtrip: RGB565<->RGB888", "[async_color_conver .dst_color_format = ESP_COLOR_FOURCC_RGB16, }; - TEST_ESP_OK(esp_color_convert_blocking(conv_hdl, &req_565_to_888, -1)); - TEST_ESP_OK(esp_color_convert_blocking(conv_hdl, &req_888_to_565, -1)); + TEST_ESP_OK(esp_color_convert_blocking(conv_hdl, &req_565_to_bgr24, -1)); + TEST_ESP_OK(esp_color_convert_blocking(conv_hdl, &req_bgr24_to_565, -1)); // The final dst565 should be the same as the original src565 after round-trip conversion TEST_ASSERT_EQUAL_MEMORY(src565, dst565, pixel_num * sizeof(uint16_t)); @@ -170,7 +170,7 @@ TEST_CASE("async color convert roundtrip: RGB565<->RGB888", "[async_color_conver TEST_ESP_OK(esp_async_color_convert_uninstall(conv_hdl)); free(src565); - free(mid888); + free(mid_bgr24); free(dst565); } @@ -305,7 +305,189 @@ static void uyvy_to_bgr24_reference_image(const uint8_t *src_uyvy, uint8_t *dst_ } } -TEST_CASE("async color convert UYVY->RGB888 matches reference", "[async_color_convert]") +TEST_CASE("async color convert swaps RGB24 and BGR24 byte order", "[async_color_convert]") +{ + const uint32_t width = 4; + const uint32_t height = 2; + const size_t pixel_count = width * height; + const size_t buf_size = pixel_count * 3; + static const uint8_t src_rgb24[] = { + 0x10, 0x20, 0x30, 0x7F, 0x80, 0x81, 0xAA, 0x55, 0xFE, 0x01, 0xC0, 0x99, + 0xDE, 0xAD, 0xBE, 0x00, 0x11, 0x22, 0x44, 0x88, 0xCC, 0xF0, 0x0D, 0x42, + }; + static const uint8_t src_bgr24[] = { + 0x30, 0x20, 0x10, 0x81, 0x80, 0x7F, 0xFE, 0x55, 0xAA, 0x99, 0xC0, 0x01, + 0xBE, 0xAD, 0xDE, 0x22, 0x11, 0x00, 0xCC, 0x88, 0x44, 0x42, 0x0D, 0xF0, + }; + + TEST_ASSERT_EQUAL(sizeof(src_rgb24), buf_size); + TEST_ASSERT_EQUAL(sizeof(src_bgr24), buf_size); + + uint8_t *rgb24 = heap_caps_aligned_calloc(64, 1, buf_size, + MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); + uint8_t *bgr24 = heap_caps_aligned_calloc(64, 1, buf_size, + MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); + uint8_t *dst_bgr24 = heap_caps_aligned_calloc(64, 1, buf_size, + MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); + uint8_t *dst_rgb24 = heap_caps_aligned_calloc(64, 1, buf_size, + MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); + TEST_ASSERT_NOT_NULL(rgb24); + TEST_ASSERT_NOT_NULL(bgr24); + TEST_ASSERT_NOT_NULL(dst_bgr24); + TEST_ASSERT_NOT_NULL(dst_rgb24); + memcpy(rgb24, src_rgb24, buf_size); + memcpy(bgr24, src_bgr24, buf_size); + memset(dst_bgr24, 0xA5, buf_size); + memset(dst_rgb24, 0x5A, buf_size); + + async_color_convert_config_t config = { + .backlog = 1, + .intr_priority = 0, + .dma_burst_size = 16, + }; + async_color_convert_handle_t conv_hdl = NULL; + TEST_ESP_OK(esp_async_color_convert_install_dma2d(&config, &conv_hdl)); + + async_color_convert_request_t req_rgb_to_bgr = { + .src_buffer = rgb24, + .src_stride = width, + .src_height = height, + .src_x = 0, + .src_y = 0, + .dst_buffer = dst_bgr24, + .dst_stride = width, + .dst_height = height, + .dst_x = 0, + .dst_y = 0, + .copy_width = width, + .copy_height = height, + .src_color_format = ESP_COLOR_FOURCC_RGB24, + .dst_color_format = ESP_COLOR_FOURCC_BGR24, + }; + async_color_convert_request_t req_bgr_to_rgb = { + .src_buffer = bgr24, + .src_stride = width, + .src_height = height, + .src_x = 0, + .src_y = 0, + .dst_buffer = dst_rgb24, + .dst_stride = width, + .dst_height = height, + .dst_x = 0, + .dst_y = 0, + .copy_width = width, + .copy_height = height, + .src_color_format = ESP_COLOR_FOURCC_BGR24, + .dst_color_format = ESP_COLOR_FOURCC_RGB24, + }; + + TEST_ESP_OK(esp_color_convert_blocking(conv_hdl, &req_rgb_to_bgr, -1)); + TEST_ASSERT_EQUAL_MEMORY(src_bgr24, dst_bgr24, buf_size); + + TEST_ESP_OK(esp_color_convert_blocking(conv_hdl, &req_bgr_to_rgb, -1)); + TEST_ASSERT_EQUAL_MEMORY(src_rgb24, dst_rgb24, buf_size); + + TEST_ESP_OK(esp_async_color_convert_uninstall(conv_hdl)); + free(rgb24); + free(bgr24); + free(dst_bgr24); + free(dst_rgb24); +} + +// Verifies the scramble route and BGR24/RGB24->UYVY conversion compose correctly. +TEST_CASE("async color convert RGB24 and BGR24 inputs produce identical UYVY output", "[async_color_convert]") +{ + const uint32_t width = 4; + const uint32_t height = 2; + const size_t pixel_count = width * height; + const size_t rgb_size = pixel_count * 3; + const size_t uyvy_size = pixel_count * 2; + static const uint8_t src_rgb24[] = { + 0x10, 0x20, 0x30, 0x7F, 0x80, 0x81, 0xAA, 0x55, 0xFE, 0x01, 0xC0, 0x99, + 0xDE, 0xAD, 0xBE, 0x00, 0x11, 0x22, 0x44, 0x88, 0xCC, 0xF0, 0x0D, 0x42, + }; + static const uint8_t src_bgr24[] = { + 0x30, 0x20, 0x10, 0x81, 0x80, 0x7F, 0xFE, 0x55, 0xAA, 0x99, 0xC0, 0x01, + 0xBE, 0xAD, 0xDE, 0x22, 0x11, 0x00, 0xCC, 0x88, 0x44, 0x42, 0x0D, 0xF0, + }; + const color_conv_std_rgb_yuv_t conv_std = COLOR_CONV_STD_RGB_YUV_BT601; + + TEST_ASSERT_EQUAL(sizeof(src_rgb24), rgb_size); + TEST_ASSERT_EQUAL(sizeof(src_bgr24), rgb_size); + + uint8_t *rgb24 = heap_caps_aligned_calloc(64, 1, rgb_size, + MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); + uint8_t *bgr24 = heap_caps_aligned_calloc(64, 1, rgb_size, + MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); + uint8_t *dst_from_rgb24 = heap_caps_aligned_calloc(64, 1, uyvy_size, + MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); + uint8_t *dst_from_bgr24 = heap_caps_aligned_calloc(64, 1, uyvy_size, + MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); + TEST_ASSERT_NOT_NULL(rgb24); + TEST_ASSERT_NOT_NULL(bgr24); + TEST_ASSERT_NOT_NULL(dst_from_rgb24); + TEST_ASSERT_NOT_NULL(dst_from_bgr24); + memcpy(rgb24, src_rgb24, rgb_size); + memcpy(bgr24, src_bgr24, rgb_size); + + async_color_convert_config_t config = { + .backlog = 2, + .intr_priority = 0, + .dma_burst_size = 16, + }; + async_color_convert_handle_t conv_hdl = NULL; + TEST_ESP_OK(esp_async_color_convert_install_dma2d(&config, &conv_hdl)); + + memset(dst_from_rgb24, 0xA5, uyvy_size); + memset(dst_from_bgr24, 0x5A, uyvy_size); + + async_color_convert_request_t req_rgb24_to_uyvy = { + .src_buffer = rgb24, + .src_stride = width, + .src_height = height, + .src_x = 0, + .src_y = 0, + .dst_buffer = dst_from_rgb24, + .dst_stride = width, + .dst_height = height, + .dst_x = 0, + .dst_y = 0, + .copy_width = width, + .copy_height = height, + .src_color_format = ESP_COLOR_FOURCC_RGB24, + .dst_color_format = ESP_COLOR_FOURCC_UYVY, + .color_conv_std = conv_std, + }; + async_color_convert_request_t req_bgr24_to_uyvy = { + .src_buffer = bgr24, + .src_stride = width, + .src_height = height, + .src_x = 0, + .src_y = 0, + .dst_buffer = dst_from_bgr24, + .dst_stride = width, + .dst_height = height, + .dst_x = 0, + .dst_y = 0, + .copy_width = width, + .copy_height = height, + .src_color_format = ESP_COLOR_FOURCC_BGR24, + .dst_color_format = ESP_COLOR_FOURCC_UYVY, + .color_conv_std = conv_std, + }; + + TEST_ESP_OK(esp_color_convert_blocking(conv_hdl, &req_rgb24_to_uyvy, -1)); + TEST_ESP_OK(esp_color_convert_blocking(conv_hdl, &req_bgr24_to_uyvy, -1)); + TEST_ASSERT_EQUAL_MEMORY(dst_from_bgr24, dst_from_rgb24, uyvy_size); + + TEST_ESP_OK(esp_async_color_convert_uninstall(conv_hdl)); + free(rgb24); + free(bgr24); + free(dst_from_rgb24); + free(dst_from_bgr24); +} + +TEST_CASE("async color convert UYVY->BGR24 matches reference", "[async_color_convert]") { const uint32_t src_stride = 32; const uint32_t dst_stride = 64; diff --git a/components/esp_hal_dma/esp32p4/include/hal/dma2d_ll.h b/components/esp_hal_dma/esp32p4/include/hal/dma2d_ll.h index f96263f8e61..4eb70c39136 100644 --- a/components/esp_hal_dma/esp32p4/include/hal/dma2d_ll.h +++ b/components/esp_hal_dma/esp32p4/include/hal/dma2d_ll.h @@ -1054,7 +1054,7 @@ static inline void dma2d_ll_tx_configure_color_space_conv(dma2d_dev_t *dev, uint input_sel = 7; break; case DMA2D_CSC_TX_SCRAMBLE: - input_sel = 2; // Or 3 + input_sel = 3; // Other 3-byte/pixel input path proc_en = false; output_sel = 2; break; diff --git a/components/esp_hal_dma/esp32s31/include/hal/dma2d_ll.h b/components/esp_hal_dma/esp32s31/include/hal/dma2d_ll.h index 27970ecf257..9e8921d447f 100644 --- a/components/esp_hal_dma/esp32s31/include/hal/dma2d_ll.h +++ b/components/esp_hal_dma/esp32s31/include/hal/dma2d_ll.h @@ -1031,7 +1031,7 @@ static inline void dma2d_ll_tx_configure_color_space_conv(dma2d_dev_t *dev, uint input_sel = 7; break; case DMA2D_CSC_TX_SCRAMBLE: - input_sel = 2; // Or 3 + input_sel = 3; // Other 3-byte/pixel input path proc_en = false; output_sel = 2; break; diff --git a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c index 3c38f45aca2..14ec95ec3b3 100644 --- a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c +++ b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c @@ -533,7 +533,9 @@ esp_err_t esp_lcd_dpi_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, &dpi_panel->fbcpy_handle), TAG, "install async frame buffer copy backend failed"); // Register the DMA2D draw bitmap hook diff --git a/docs/en/api-reference/peripherals/async_color_convert.rst b/docs/en/api-reference/peripherals/async_color_convert.rst index 548468053ab..7980144afa6 100644 --- a/docs/en/api-reference/peripherals/async_color_convert.rst +++ b/docs/en/api-reference/peripherals/async_color_convert.rst @@ -148,7 +148,7 @@ Both the source window and destination window must stay within the bounds of the Supported Conversions --------------------- -The following format pairs are supported by this driver: +The following format pairs are currently supported by this driver: .. list-table:: :header-rows: 1 @@ -156,32 +156,54 @@ The following format pairs are supported by this driver: * - Source format - Destination format - Conversion standard - * - same as destination (skip conversion) - - same as source (skip conversion) + * - ``ESP_COLOR_FOURCC_RGB16`` + - ``ESP_COLOR_FOURCC_RGB16`` - N/A - * - RGB565 - - RGB888 + * - ``ESP_COLOR_FOURCC_BGR24`` + - ``ESP_COLOR_FOURCC_BGR24`` - N/A - * - RGB888 - - RGB565 + * - ``ESP_COLOR_FOURCC_RGB24`` + - ``ESP_COLOR_FOURCC_RGB24`` - N/A - * - RGB888 - - UYVY422 + * - ``ESP_COLOR_FOURCC_UYVY`` + - ``ESP_COLOR_FOURCC_UYVY`` + - N/A + * - ``ESP_COLOR_FOURCC_BGR24`` + - ``ESP_COLOR_FOURCC_RGB24`` + - N/A + * - ``ESP_COLOR_FOURCC_RGB24`` + - ``ESP_COLOR_FOURCC_BGR24`` + - N/A + * - ``ESP_COLOR_FOURCC_RGB16`` + - ``ESP_COLOR_FOURCC_BGR24`` + - N/A + * - ``ESP_COLOR_FOURCC_BGR24`` + - ``ESP_COLOR_FOURCC_RGB16`` + - N/A + * - ``ESP_COLOR_FOURCC_RGB24`` + - ``ESP_COLOR_FOURCC_RGB16`` + - N/A + * - ``ESP_COLOR_FOURCC_BGR24`` + - ``ESP_COLOR_FOURCC_UYVY`` - BT.601 - * - RGB888 - - UYVY422 + * - ``ESP_COLOR_FOURCC_BGR24`` + - ``ESP_COLOR_FOURCC_UYVY`` - BT.709 - * - UYVY422 - - RGB888 + * - ``ESP_COLOR_FOURCC_RGB24`` + - ``ESP_COLOR_FOURCC_UYVY`` - BT.601 - * - UYVY422 - - RGB888 + * - ``ESP_COLOR_FOURCC_RGB24`` + - ``ESP_COLOR_FOURCC_UYVY`` + - BT.709 + * - ``ESP_COLOR_FOURCC_UYVY`` + - ``ESP_COLOR_FOURCC_BGR24`` + - BT.601 + * - ``ESP_COLOR_FOURCC_UYVY`` + - ``ESP_COLOR_FOURCC_BGR24`` - BT.709 .. note:: - In this driver, RGB888 uses ``ESP_COLOR_FOURCC_BGR24`` and UYVY422 uses ``ESP_COLOR_FOURCC_UYVY``. - Always set :cpp:member:`async_color_convert_request_t::src_color_format` and :cpp:member:`async_color_convert_request_t::dst_color_format`. Set :cpp:member:`async_color_convert_request_t::color_conv_std` when converting between RGB and YUV. diff --git a/docs/zh_CN/api-reference/peripherals/async_color_convert.rst b/docs/zh_CN/api-reference/peripherals/async_color_convert.rst index 21041f6b634..32a62dd9aee 100644 --- a/docs/zh_CN/api-reference/peripherals/async_color_convert.rst +++ b/docs/zh_CN/api-reference/peripherals/async_color_convert.rst @@ -148,7 +148,7 @@ 支持的转换格式 -------------- -本驱动支持以下格式组合: +本驱动当前支持以下格式组合: .. list-table:: :header-rows: 1 @@ -156,32 +156,54 @@ * - 源格式 - 目标格式 - 转换标准 - * - 与目标格式相同(跳过转换) - - 与源格式相同(跳过转换) + * - ``ESP_COLOR_FOURCC_RGB16`` + - ``ESP_COLOR_FOURCC_RGB16`` - 不适用 - * - RGB565 - - RGB888 + * - ``ESP_COLOR_FOURCC_BGR24`` + - ``ESP_COLOR_FOURCC_BGR24`` - 不适用 - * - RGB888 - - RGB565 + * - ``ESP_COLOR_FOURCC_RGB24`` + - ``ESP_COLOR_FOURCC_RGB24`` - 不适用 - * - RGB888 - - UYVY422 + * - ``ESP_COLOR_FOURCC_UYVY`` + - ``ESP_COLOR_FOURCC_UYVY`` + - 不适用 + * - ``ESP_COLOR_FOURCC_BGR24`` + - ``ESP_COLOR_FOURCC_RGB24`` + - 不适用 + * - ``ESP_COLOR_FOURCC_RGB24`` + - ``ESP_COLOR_FOURCC_BGR24`` + - 不适用 + * - ``ESP_COLOR_FOURCC_RGB16`` + - ``ESP_COLOR_FOURCC_BGR24`` + - 不适用 + * - ``ESP_COLOR_FOURCC_BGR24`` + - ``ESP_COLOR_FOURCC_RGB16`` + - 不适用 + * - ``ESP_COLOR_FOURCC_RGB24`` + - ``ESP_COLOR_FOURCC_RGB16`` + - 不适用 + * - ``ESP_COLOR_FOURCC_BGR24`` + - ``ESP_COLOR_FOURCC_UYVY`` - BT.601 - * - RGB888 - - UYVY422 + * - ``ESP_COLOR_FOURCC_BGR24`` + - ``ESP_COLOR_FOURCC_UYVY`` - BT.709 - * - UYVY422 - - RGB888 + * - ``ESP_COLOR_FOURCC_RGB24`` + - ``ESP_COLOR_FOURCC_UYVY`` - BT.601 - * - UYVY422 - - RGB888 + * - ``ESP_COLOR_FOURCC_RGB24`` + - ``ESP_COLOR_FOURCC_UYVY`` + - BT.709 + * - ``ESP_COLOR_FOURCC_UYVY`` + - ``ESP_COLOR_FOURCC_BGR24`` + - BT.601 + * - ``ESP_COLOR_FOURCC_UYVY`` + - ``ESP_COLOR_FOURCC_BGR24`` - BT.709 .. note:: - 在本驱动中,RGB888 使用 ``ESP_COLOR_FOURCC_BGR24``,UYVY422 使用 ``ESP_COLOR_FOURCC_UYVY``。 - 所有请求都需要设置 :cpp:member:`async_color_convert_request_t::src_color_format` 和 :cpp:member:`async_color_convert_request_t::dst_color_format`。 当在 RGB 和 YUV 之间转换时,还需要设置 :cpp:member:`async_color_convert_request_t::color_conv_std`。