diff --git a/components/esp_driver_ppa/src/ppa_blend.c b/components/esp_driver_ppa/src/ppa_blend.c index e3cd6816c04..44a1470b427 100644 --- a/components/esp_driver_ppa/src/ppa_blend.c +++ b/components/esp_driver_ppa/src/ppa_blend.c @@ -152,6 +152,8 @@ bool ppa_blend_transaction_on_picked(uint32_t num_chans, const dma2d_trans_chann ppa_ll_blend_set_tx_yuv_range(platform->hal.dev, blend_trans_desc->out.yuv_range); ppa_ll_blend_set_tx_rgb2yuv_std(platform->hal.dev, blend_trans_desc->out.yuv_std); } + // For YUV420/YUV422 background input and output, blend_tx_size.blend_hb/vb must be set to make the Blending engine and 2D-DMA work properly + ppa_ll_blend_set_block_size(platform->hal.dev, blend_trans_desc->in_bg.block_w, blend_trans_desc->in_bg.block_h); // in_bg.block_w == in_fg.block_w && in_bg.block_h == in_fg.block_h // Color keying color_pixel_rgb888_data_t rgb888_min = {.b = 0x00, .g = 0x00, .r = 0x00}; diff --git a/components/esp_driver_ppa/src/ppa_fill.c b/components/esp_driver_ppa/src/ppa_fill.c index 70fe4278d91..29fc939d8d8 100644 --- a/components/esp_driver_ppa/src/ppa_fill.c +++ b/components/esp_driver_ppa/src/ppa_fill.c @@ -74,8 +74,9 @@ bool ppa_fill_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channe dma2d_start(dma2d_rx_chan); // Configure PPA Blending engine - ppa_ll_blend_configure_filling_block(platform->hal.dev, fill_trans_desc->out.fill_cm, (void *)&fill_trans_desc->fill_color_val, fill_trans_desc->fill_block_w, fill_trans_desc->fill_block_h); + ppa_ll_blend_configure_filling_block_color(platform->hal.dev, fill_trans_desc->out.fill_cm, (void *)&fill_trans_desc->fill_color_val); ppa_ll_blend_set_tx_color_mode(platform->hal.dev, fill_trans_desc->out.fill_cm); + ppa_ll_blend_set_block_size(platform->hal.dev, fill_trans_desc->fill_block_w, fill_trans_desc->fill_block_h); ppa_ll_blend_start(platform->hal.dev, PPA_LL_BLEND_TRANS_MODE_FILL); diff --git a/components/esp_driver_ppa/test_apps/main/test_ppa.c b/components/esp_driver_ppa/test_apps/main/test_ppa.c index b9093157b02..6b5a7285e76 100644 --- a/components/esp_driver_ppa/test_apps/main/test_ppa.c +++ b/components/esp_driver_ppa/test_apps/main/test_ppa.c @@ -488,6 +488,82 @@ TEST_CASE("ppa_blend_basic_data_correctness_check", "[PPA]") printf("\n"); TEST_ASSERT_EQUAL_UINT8_ARRAY((void *)out_buf_expected, (void *)out_buf, out_buf_len); +#if !(CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_SELECTS_REV_LESS_V3) + // Test YUV422/YUV420 blend + + // A mid-grey image is achromatic (U = V = 128), so a correct RGB<->YUV path must round-trip + // it back to grey with R == G == B. For each format we run RGB->YUV (exercises YUV as the + // blend output) then YUV->RGB (exercises YUV as the blend background input); both must + // complete without hanging and yield achromatic grey + + // 2 x 2 is the smallest valid YUV block: even w/h satisfies YUV422 (2x1) & YUV420 (2x2) + const uint8_t grey = 0x80; // mid-grey: Y arbitrary, U = V = 128 -> R == G == B after decode + + // RGB888 mid-grey background (12B) and ARGB8888 foreground (16B). The foreground alpha is + // inverted to 0, so it contributes nothing and the blend output equals the background color. + const uint8_t rgb_grey[12] = {[0 ... 11] = grey}; + const uint8_t fg_buf[16] = {[0 ... 15] = 0xFF}; + // DMA outputs require cache-line alignment; yuv_mid is also reused as input for the YUV->RGB pass. + uint8_t yuv_mid[64] __attribute__((aligned(64))) = {[0 ... 63] = 0}; + uint8_t rgb_back[64] __attribute__((aligned(64))) = {[0 ... 63] = 0xCC}; + const uint32_t yuv_buf_size = sizeof(yuv_mid); + + const ppa_blend_color_mode_t yuv_cms[] = { + PPA_BLEND_COLOR_MODE_YUV422_UYVY, + PPA_BLEND_COLOR_MODE_YUV420, + }; + for (int c = 0; c < 2; c++) { + const ppa_blend_color_mode_t yuv_cm = yuv_cms[c]; + + // Foreground contributes nothing: alpha 0xFF inverted to 0, so output == background. + ppa_blend_oper_config_t yuv_oper_config = { + .in_fg.buffer = fg_buf, + .in_fg.pic_w = w, + .in_fg.pic_h = h, + .in_fg.block_w = w, + .in_fg.block_h = h, + .in_fg.blend_cm = PPA_BLEND_COLOR_MODE_ARGB8888, + .bg_alpha_update_mode = PPA_ALPHA_NO_CHANGE, + .fg_alpha_update_mode = PPA_ALPHA_INVERT, + .mode = PPA_TRANS_MODE_BLOCKING, + }; + + // 1) RGB888 grey -> YUV (exercises YUV as blend output; must not hang) + yuv_oper_config.in_bg.buffer = rgb_grey; + yuv_oper_config.in_bg.pic_w = w; + yuv_oper_config.in_bg.pic_h = h; + yuv_oper_config.in_bg.block_w = w; + yuv_oper_config.in_bg.block_h = h; + yuv_oper_config.in_bg.blend_cm = PPA_BLEND_COLOR_MODE_RGB888; + yuv_oper_config.out.buffer = yuv_mid; + yuv_oper_config.out.buffer_size = yuv_buf_size; + yuv_oper_config.out.pic_w = w; + yuv_oper_config.out.pic_h = h; + yuv_oper_config.out.blend_cm = yuv_cm; + TEST_ESP_OK(ppa_do_blend(ppa_client_handle, &yuv_oper_config)); + + // 2) YUV grey -> RGB888 (exercises YUV as blend background input; must not hang) + yuv_oper_config.in_bg.buffer = yuv_mid; + yuv_oper_config.in_bg.blend_cm = yuv_cm; + yuv_oper_config.out.buffer = rgb_back; + yuv_oper_config.out.blend_cm = PPA_BLEND_COLOR_MODE_RGB888; + TEST_ESP_OK(ppa_do_blend(ppa_client_handle, &yuv_oper_config)); + + // Check result + // Mid-grey is achromatic: every RGB888 pixel must stay near-grey, i.e. R ~= G ~= B + // (chroma preserved) and the level must remain mid-grey (luma not driven to + // black/white). A small tolerance covers the +-1 LSB rounding of two YUV conversions. + for (int p = 0; p < w * h; p++) { + const int b = rgb_back[p * 3 + 0]; + const int g = rgb_back[p * 3 + 1]; + const int r = rgb_back[p * 3 + 2]; + TEST_ASSERT_INT_WITHIN(2, b, g); // achromatic: channels stay together + TEST_ASSERT_INT_WITHIN(2, g, r); + TEST_ASSERT_INT_WITHIN(16, grey, b); // round-trips back to ~mid-grey + } + } +#endif // !(CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_SELECTS_REV_LESS_V3) + TEST_ESP_OK(ppa_unregister_client(ppa_client_handle)); } diff --git a/components/esp_hal_ppa/esp32p4/include/hal/ppa_ll.h b/components/esp_hal_ppa/esp32p4/include/hal/ppa_ll.h index c45e66806ed..001946b47f4 100644 --- a/components/esp_hal_ppa/esp32p4/include/hal/ppa_ll.h +++ b/components/esp_hal_ppa/esp32p4/include/hal/ppa_ll.h @@ -1083,7 +1083,7 @@ static inline void ppa_ll_blend_configure_rx_fg_alpha(ppa_dev_t *dev, ppa_alpha_ } /** - * @brief Configure PPA blending pixel filling image block + * @brief Configure PPA blending pixel filling image block color * * The color to be filled is directly relying on the blend_tx_fix_pixel register field value. * For fill operation, the data does not go through any color space conversion in the blending engine. @@ -1091,12 +1091,9 @@ static inline void ppa_ll_blend_configure_rx_fg_alpha(ppa_dev_t *dev, ppa_alpha_ * @param dev Peripheral instance address * @param color_mode One of the values in ppa_fill_color_mode_t * @param data The point of the fix data to be filled to the image block pixels - * @param hb The horizontal width of image block that would be filled in fix pixel filling mode. The unit is pixel. - * @param vb The vertical height of image block that would be filled in fix pixel filling mode. The unit is pixel. */ -static inline void ppa_ll_blend_configure_filling_block(ppa_dev_t *dev, ppa_fill_color_mode_t color_mode, void *data, uint32_t hb, uint32_t vb) +static inline void ppa_ll_blend_configure_filling_block_color(ppa_dev_t *dev, ppa_fill_color_mode_t color_mode, void *data) { - HAL_ASSERT(hb <= PPA_BLEND_HB_V && vb <= PPA_BLEND_VB_V); uint32_t fill_color_data = 0; switch (color_mode) { case PPA_FILL_COLOR_MODE_ARGB8888: @@ -1123,6 +1120,18 @@ static inline void ppa_ll_blend_configure_filling_block(ppa_dev_t *dev, ppa_fill abort(); } dev->blend_fix_pixel.blend_tx_fix_pixel = fill_color_data; +} + +/** + * @brief Set PPA blending block size + * + * @param dev Peripheral instance address + * @param hb The horizontal width of image block that would be filled in fix pixel filling mode or blend mode. The unit is pixel. + * @param vb The vertical height of image block that would be filled in fix pixel filling mode or blend mode. The unit is pixel. + */ +static inline void ppa_ll_blend_set_block_size(ppa_dev_t *dev, uint32_t hb, uint32_t vb) +{ + HAL_ASSERT(hb <= PPA_BLEND_HB_V && vb <= PPA_BLEND_VB_V); dev->blend_tx_size.blend_hb = hb; dev->blend_tx_size.blend_vb = vb; }