diff --git a/components/esp_driver_ppa/include/driver/ppa.h b/components/esp_driver_ppa/include/driver/ppa.h index 1d783e9555..f903dc49b4 100644 --- a/components/esp_driver_ppa/include/driver/ppa.h +++ b/components/esp_driver_ppa/include/driver/ppa.h @@ -55,6 +55,8 @@ esp_err_t ppa_register_client(const ppa_client_config_t *config, ppa_client_hand /** * @brief Unregister a PPA client * + * @note This will also free the resources occupied by the client + * * @param[in] ppa_client PPA client handle, allocated by `ppa_register_client` * * @return @@ -170,10 +172,13 @@ typedef struct { bool rgb_swap; /*!< Whether to swap the input data in RGB (e.g. ARGB becomes BGRA, RGB becomes BGR) */ bool byte_swap; /*!< Whether to swap the input data in byte. Only available feature if input picture color mode is ARGB8888 or RGB565 */ ppa_alpha_update_mode_t alpha_update_mode; /*!< Select whether the alpha channel of the input picture needs update */ - uint32_t alpha_value; /*!< Range: 0 ~ 255 - When PPA_ALPHA_FIX_VALUE mode is selected, alpha_value is the alpha value to be replaced with (output_alpha = alpha_value) - When PPA_ALPHA_SCALE mode is selected, alpha_value/256 is the multiplier to the input alpha value (output_alpha = input_alpha * alpha_value / 256) - When other alpha modes are selected, this field is not used */ + union { + uint32_t alpha_fix_val; /*!< Range: [0, 255] + When PPA_ALPHA_FIX_VALUE mode is selected, alpha_fix_val is the new alpha value to replace the input alpha value (output_alpha = alpha_fix_val) */ + float alpha_scale_ratio; /*!< Range: (0, 1) + When PPA_ALPHA_SCALE mode is selected, alpha_scale_ratio is the multiplier to the input alpha value (output_alpha = alpha_scale_ratio * input_alpha) + Ratio resolution is 1/256 */ + }; ppa_trans_mode_t mode; /*!< Determines whether to block inside the operation functions, see `ppa_trans_mode_t` */ void *user_data; /*!< User registered data to be passed into `done_cb` callback function */ @@ -205,17 +210,23 @@ typedef struct { bool bg_rgb_swap; /*!< Whether to swap the background input data in RGB (e.g. ARGB becomes BGRA, RGB becomes BGR) */ bool bg_byte_swap; /*!< Whether to swap the background input data in byte. Only available feature if input BG picture color mode is ARGB8888 or RGB565 */ ppa_alpha_update_mode_t bg_alpha_update_mode; /*!< Select whether the alpha channel of the input background picture needs update */ - uint32_t bg_alpha_value; /*!< Range: 0 ~ 255 - When PPA_ALPHA_FIX_VALUE mode is selected, alpha_value is the alpha value to be replaced with (output_alpha = alpha_value) - When PPA_ALPHA_SCALE mode is selected, alpha_value/256 is the multiplier to the input alpha value (output_alpha = input_alpha * alpha_value / 256) - When other alpha modes are selected, this field is not used */ + union { + uint32_t bg_alpha_fix_val; /*!< Range: [0, 255] + When PPA_ALPHA_FIX_VALUE mode is selected, alpha_fix_val is the new alpha value to replace the input alpha value (output_alpha = alpha_fix_val) */ + float bg_alpha_scale_ratio; /*!< Range: (0, 1) + When PPA_ALPHA_SCALE mode is selected, alpha_scale_ratio is the multiplier to the input alpha value (output_alpha = alpha_scale_ratio * input_alpha) + Ratio resolution is 1/256 */ + }; bool fg_rgb_swap; /*!< Whether to swap the foreground input data in RGB (e.g. ARGB becomes BGRA, RGB becomes BGR) */ bool fg_byte_swap; /*!< Whether to swap the foreground input data in byte. Only available feature if input FG picture color mode is ARGB8888 or RGB565 */ ppa_alpha_update_mode_t fg_alpha_update_mode; /*!< Select whether the alpha channel of the input foreground picture needs update */ - uint32_t fg_alpha_value; /*!< Range: 0 ~ 255 - When PPA_ALPHA_FIX_VALUE mode is selected, alpha_value is the alpha value to be replaced with (output_alpha = alpha_value) - When PPA_ALPHA_SCALE mode is selected, alpha_value/256 is the multiplier to the input alpha value (output_alpha = input_alpha * alpha_value / 256) - When other alpha modes are selected, this field is not used */ + union { + uint32_t fg_alpha_fix_val; /*!< Range: [0, 255] + When PPA_ALPHA_FIX_VALUE mode is selected, alpha_fix_val is the new alpha value to replace the input alpha value (output_alpha = alpha_fix_val) */ + float fg_alpha_scale_ratio; /*!< Range: (0, 1) + When PPA_ALPHA_SCALE mode is selected, alpha_scale_ratio is the multiplier to the input alpha value (output_alpha = alpha_scale_ratio * input_alpha) + Ratio resolution is 1/256 */ + }; uint32_t fg_fix_rgb_val; /*!< When in_fg.blend_cm is PPA_BLEND_COLOR_MODE_A8/4, this field can be used to set a fixed color for the foreground, in RGB888 format (R[23:16], G[15: 8], B[7:0]) */ // color-keying diff --git a/components/esp_driver_ppa/src/ppa_blend.c b/components/esp_driver_ppa/src/ppa_blend.c index a7a91200cb..420a091160 100644 --- a/components/esp_driver_ppa/src/ppa_blend.c +++ b/components/esp_driver_ppa/src/ppa_blend.c @@ -199,7 +199,22 @@ esp_err_t ppa_do_blend(ppa_client_handle_t ppa_client, const ppa_blend_oper_conf if (config->fg_rgb_swap) { PPA_CHECK_CM_SUPPORT_RGB_SWAP("in_fg.blend", (uint32_t)config->in_fg.blend_cm); } - ESP_RETURN_ON_FALSE(config->bg_alpha_value <= 0xFF && config->fg_alpha_value <= 0xFF, ESP_ERR_INVALID_ARG, TAG, "invalid bg/fg_alpha_value"); + uint32_t new_bg_alpha_value = 0; + if (config->bg_alpha_update_mode == PPA_ALPHA_FIX_VALUE) { + ESP_RETURN_ON_FALSE(config->bg_alpha_fix_val <= 0xFF, ESP_ERR_INVALID_ARG, TAG, "invalid bg_alpha_fix_val"); + new_bg_alpha_value = config->bg_alpha_fix_val; + } else if (config->bg_alpha_update_mode == PPA_ALPHA_SCALE) { + ESP_RETURN_ON_FALSE(config->bg_alpha_scale_ratio > 0 && config->bg_alpha_scale_ratio < 1, ESP_ERR_INVALID_ARG, TAG, "invalid bg_alpha_scale_ratio"); + new_bg_alpha_value = (uint32_t)(config->bg_alpha_scale_ratio * 256); + } + uint32_t new_fg_alpha_value = 0; + if (config->fg_alpha_update_mode == PPA_ALPHA_FIX_VALUE) { + ESP_RETURN_ON_FALSE(config->fg_alpha_fix_val <= 0xFF, ESP_ERR_INVALID_ARG, TAG, "invalid fg_alpha_fix_val"); + new_fg_alpha_value = config->fg_alpha_fix_val; + } else if (config->fg_alpha_update_mode == PPA_ALPHA_SCALE) { + ESP_RETURN_ON_FALSE(config->fg_alpha_scale_ratio > 0 && config->fg_alpha_scale_ratio < 1, ESP_ERR_INVALID_ARG, TAG, "invalid fg_alpha_scale_ratio"); + new_fg_alpha_value = (uint32_t)(config->fg_alpha_scale_ratio * 256); + } if (config->in_bg.blend_cm == PPA_BLEND_COLOR_MODE_L4) { ESP_RETURN_ON_FALSE(config->in_bg.block_w % 2 == 0 && config->in_bg.block_offset_x % 2 == 0, ESP_ERR_INVALID_ARG, TAG, "in_bg.block_w and in_bg.block_offset_x must be even"); @@ -234,6 +249,8 @@ esp_err_t ppa_do_blend(ppa_client_handle_t ppa_client, const ppa_blend_oper_conf ppa_blend_oper_t *blend_trans_desc = (ppa_blend_oper_t *)trans_on_picked_desc->blend_desc; memcpy(blend_trans_desc, config, sizeof(ppa_blend_oper_config_t)); + blend_trans_desc->bg_alpha_value = new_bg_alpha_value; + blend_trans_desc->fg_alpha_value = new_fg_alpha_value; trans_on_picked_desc->ppa_engine = ppa_client->engine; trans_on_picked_desc->trigger_periph = DMA2D_TRIG_PERIPH_PPA_BLEND; diff --git a/components/esp_driver_ppa/src/ppa_core.c b/components/esp_driver_ppa/src/ppa_core.c index b08b4a3987..dc08fdced7 100644 --- a/components/esp_driver_ppa/src/ppa_core.c +++ b/components/esp_driver_ppa/src/ppa_core.c @@ -220,7 +220,8 @@ static esp_err_t ppa_engine_release(ppa_engine_t *ppa_engine) vSemaphoreDeleteWithCaps(srm_engine->base.sem); #if CONFIG_PM_ENABLE if (srm_engine->base.pm_lock) { - assert(esp_pm_lock_delete(srm_engine->base.pm_lock) == ESP_OK); + ret = esp_pm_lock_delete(srm_engine->base.pm_lock); + assert(ret == ESP_OK); } #endif free(srm_engine); @@ -238,7 +239,8 @@ static esp_err_t ppa_engine_release(ppa_engine_t *ppa_engine) vSemaphoreDeleteWithCaps(blending_engine->base.sem); #if CONFIG_PM_ENABLE if (blending_engine->base.pm_lock) { - assert(esp_pm_lock_delete(blending_engine->base.pm_lock) == ESP_OK); + ret = esp_pm_lock_delete(blending_engine->base.pm_lock); + assert(ret == ESP_OK); } #endif free(blending_engine); @@ -250,7 +252,9 @@ static esp_err_t ppa_engine_release(ppa_engine_t *ppa_engine) #if CONFIG_PM_ENABLE if (s_platform.pm_lock) { - assert(esp_pm_lock_delete(s_platform.pm_lock) == ESP_OK); + ret = esp_pm_lock_delete(s_platform.pm_lock); + assert(ret == ESP_OK); + s_platform.pm_lock = NULL; } #endif @@ -389,7 +393,8 @@ static bool ppa_malloc_transaction(QueueHandle_t trans_elm_ptr_queue, uint32_t t new_trans_elm->sem = ppa_trans_sem; // Fill the ring buffer with allocated transaction element pointer - assert(xQueueSend(trans_elm_ptr_queue, &new_trans_elm, 0)); + BaseType_t sent = xQueueSend(trans_elm_ptr_queue, &new_trans_elm, 0); + assert(sent); } return res; } @@ -409,16 +414,19 @@ bool ppa_recycle_transaction(ppa_client_handle_t ppa_client, ppa_trans_t *trans_ // Reset transaction and send back to client's trans_elm_ptr_queue // TODO: To be very safe, we shall memset all to 0, and reconnect necessary pointers? BaseType_t HPTaskAwoken; - assert(xQueueSendFromISR(ppa_client->trans_elm_ptr_queue, &trans_elm, &HPTaskAwoken)); + BaseType_t sent = xQueueSendFromISR(ppa_client->trans_elm_ptr_queue, &trans_elm, &HPTaskAwoken); + assert(sent); return HPTaskAwoken; } esp_err_t ppa_do_operation(ppa_client_handle_t ppa_client, ppa_engine_t *ppa_engine_base, ppa_trans_t *trans_elm, ppa_trans_mode_t mode) { esp_err_t ret = ESP_OK; + esp_err_t pm_lock_ret __attribute__((unused)); #if CONFIG_PM_ENABLE - assert((esp_pm_lock_acquire(s_platform.pm_lock) == ESP_OK) && "acquire pm_lock failed"); + pm_lock_ret = esp_pm_lock_acquire(s_platform.pm_lock); + assert((pm_lock_ret == ESP_OK) && "acquire pm_lock failed"); #endif portENTER_CRITICAL(&ppa_client->spinlock); @@ -453,7 +461,8 @@ esp_err_t ppa_do_operation(ppa_client_handle_t ppa_client, ppa_engine_t *ppa_eng portEXIT_CRITICAL(&ppa_engine_base->spinlock); if (found) { #if CONFIG_PM_ENABLE - assert((esp_pm_lock_acquire(ppa_engine_base->pm_lock) == ESP_OK) && "acquire pm_lock failed"); + pm_lock_ret = esp_pm_lock_acquire(ppa_engine_base->pm_lock); + assert((pm_lock_ret == ESP_OK) && "acquire pm_lock failed"); #endif ret = ppa_dma2d_enqueue(trans_elm); if (ret != ESP_OK) { @@ -461,7 +470,8 @@ esp_err_t ppa_do_operation(ppa_client_handle_t ppa_client, ppa_engine_t *ppa_eng STAILQ_REMOVE(&ppa_engine_base->trans_stailq, trans_elm, ppa_trans_s, entry); portEXIT_CRITICAL(&ppa_engine_base->spinlock); #if CONFIG_PM_ENABLE - assert((esp_pm_lock_release(ppa_engine_base->pm_lock) == ESP_OK) && "release pm_lock failed"); + pm_lock_ret = esp_pm_lock_release(ppa_engine_base->pm_lock); + assert((pm_lock_ret == ESP_OK) && "release pm_lock failed"); #endif xSemaphoreGive(ppa_engine_base->sem); portENTER_CRITICAL(&ppa_client->spinlock); @@ -484,7 +494,8 @@ esp_err_t ppa_do_operation(ppa_client_handle_t ppa_client, ppa_engine_t *ppa_eng } #if CONFIG_PM_ENABLE - assert((esp_pm_lock_release(s_platform.pm_lock) == ESP_OK) && "release pm_lock failed"); + pm_lock_ret = esp_pm_lock_release(s_platform.pm_lock); + assert((pm_lock_ret == ESP_OK) && "release pm_lock failed"); #endif err: @@ -517,7 +528,8 @@ bool ppa_transaction_done_cb(dma2d_channel_handle_t dma2d_chan, dma2d_event_data ppa_dma2d_enqueue(next_start_trans); } else { #if CONFIG_PM_ENABLE - assert((esp_pm_lock_release(engine_base->pm_lock) == ESP_OK)); + esp_err_t pm_lock_ret = esp_pm_lock_release(engine_base->pm_lock); + assert(pm_lock_ret == ESP_OK); #endif xSemaphoreGiveFromISR(engine_base->sem, &HPTaskAwoken); need_yield |= (HPTaskAwoken == pdTRUE); diff --git a/components/esp_driver_ppa/src/ppa_priv.h b/components/esp_driver_ppa/src/ppa_priv.h index e55fa89954..827276b238 100644 --- a/components/esp_driver_ppa/src/ppa_priv.h +++ b/components/esp_driver_ppa/src/ppa_priv.h @@ -86,7 +86,7 @@ struct ppa_client_t { /****************************** OPERATION ************************************/ // The elements in this structure listed first are identical to the elements in structure `ppa_srm_oper_config_t` -// With adding a few extra elements in the end +// With adding a few extra elements at the end // This allows memcpy typedef struct { ppa_in_pic_blk_config_t in; @@ -103,19 +103,62 @@ typedef struct { bool rgb_swap; bool byte_swap; ppa_alpha_update_mode_t alpha_update_mode; - uint32_t alpha_value; + union { + uint32_t alpha_fix_val; + float alpha_scale_ratio; + }; ppa_trans_mode_t mode; - // uint32_t timeout; void *user_data; - uint32_t scale_x_int; - uint32_t scale_x_frag; - uint32_t scale_y_int; - uint32_t scale_y_frag; + uint32_t scale_x_int; // Calculation result for the integral part of the scale_x to be directly written to register + uint32_t scale_x_frag; // Calculation result for the fractional part of the scale_x to be directly written to register + uint32_t scale_y_int; // Calculation result for the integral part of the scale_y to be directly written to register + uint32_t scale_y_frag; // Calculation result for the fractional part of the scale_y to be directly written to register + uint32_t alpha_value; // Calculation result for the fix alpha value to be directly written to register } ppa_srm_oper_t; -typedef ppa_blend_oper_config_t ppa_blend_oper_t; +// The elements in this structure listed first are identical to the elements in structure `ppa_blend_oper_config_t` +// With adding a few extra elements at the end +// This allows memcpy +typedef struct { + ppa_in_pic_blk_config_t in_bg; + ppa_in_pic_blk_config_t in_fg; + ppa_out_pic_blk_config_t out; + + // input data manipulation + bool bg_rgb_swap; + bool bg_byte_swap; + ppa_alpha_update_mode_t bg_alpha_update_mode; + union { + uint32_t bg_alpha_fix_val; + float bg_alpha_scale_ratio; + }; + bool fg_rgb_swap; + bool fg_byte_swap; + ppa_alpha_update_mode_t fg_alpha_update_mode; + union { + uint32_t fg_alpha_fix_val; + float fg_alpha_scale_ratio; + }; + uint32_t fg_fix_rgb_val; + + // color-keying + bool bg_ck_en; + uint32_t bg_ck_rgb_low_thres; + uint32_t bg_ck_rgb_high_thres; + bool fg_ck_en; + uint32_t fg_ck_rgb_low_thres; + uint32_t fg_ck_rgb_high_thres; + uint32_t ck_rgb_default_val; + bool ck_reverse_bg2fg; + + ppa_trans_mode_t mode; + void *user_data; + + uint32_t bg_alpha_value; // Calculation result for the fix alpha value for BG to be directly written to register + uint32_t fg_alpha_value; // Calculation result for the fix alpha value for FG to be directly written to register +} ppa_blend_oper_t; typedef ppa_fill_oper_config_t ppa_fill_oper_t; diff --git a/components/esp_driver_ppa/src/ppa_srm.c b/components/esp_driver_ppa/src/ppa_srm.c index 80b5198aad..bbde15789a 100644 --- a/components/esp_driver_ppa/src/ppa_srm.c +++ b/components/esp_driver_ppa/src/ppa_srm.c @@ -208,7 +208,14 @@ esp_err_t ppa_do_scale_rotate_mirror(ppa_client_handle_t ppa_client, const ppa_s if (config->rgb_swap) { PPA_CHECK_CM_SUPPORT_RGB_SWAP("in.srm", (uint32_t)config->in.srm_cm); } - ESP_RETURN_ON_FALSE(config->alpha_value <= 0xFF, ESP_ERR_INVALID_ARG, TAG, "invalid alpha_value"); + uint32_t new_alpha_value = 0; + if (config->alpha_update_mode == PPA_ALPHA_FIX_VALUE) { + ESP_RETURN_ON_FALSE(config->alpha_fix_val <= 0xFF, ESP_ERR_INVALID_ARG, TAG, "invalid alpha_fix_val"); + new_alpha_value = config->alpha_fix_val; + } else if (config->alpha_update_mode == PPA_ALPHA_SCALE) { + ESP_RETURN_ON_FALSE(config->alpha_scale_ratio > 0 && config->alpha_scale_ratio < 1, ESP_ERR_INVALID_ARG, TAG, "invalid alpha_scale_ratio"); + new_alpha_value = (uint32_t)(config->alpha_scale_ratio * 256); + } // To reduce complexity, rotation_angle, color_mode, alpha_update_mode correctness are checked in their corresponding LL functions // TODO: // YUV420: in desc, ha/hb/va/vb/x/y must be even number @@ -237,6 +244,7 @@ esp_err_t ppa_do_scale_rotate_mirror(ppa_client_handle_t ppa_client, const ppa_s srm_trans_desc->scale_x_frag = (uint32_t)(srm_trans_desc->scale_x * (PPA_LL_SRM_SCALING_FRAG_MAX + 1)) & PPA_LL_SRM_SCALING_FRAG_MAX; srm_trans_desc->scale_y_int = (uint32_t)srm_trans_desc->scale_y; srm_trans_desc->scale_y_frag = (uint32_t)(srm_trans_desc->scale_y * (PPA_LL_SRM_SCALING_FRAG_MAX + 1)) & PPA_LL_SRM_SCALING_FRAG_MAX; + srm_trans_desc->alpha_value = new_alpha_value; trans_on_picked_desc->ppa_engine = ppa_client->engine; trans_on_picked_desc->trigger_periph = DMA2D_TRIG_PERIPH_PPA_SRM;