mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(ppa): add PPA driver support for ESP32P4
Remove the check for in_accepting_trans_state Add color_pixel_xxxx_data_t structures to color_types.h Fix PM lock protection (Tested, now works well) * CPU_MAX, PM lock and semaphore order * Remove ppa_driver PM lock Modify concurrency (queue, trans recycle, semaphore, ...) Add programming guide Add test apps
This commit is contained in:
parent
916c0ef8d1
commit
8464fac845
@ -21,7 +21,7 @@ typedef enum {
|
||||
PPA_OPERATION_SRM, /*!< Do scale-rotate-mirror operation */
|
||||
PPA_OPERATION_BLEND, /*!< Do blend operation */
|
||||
PPA_OPERATION_FILL, /*!< Do fill operation, use one constant pixel to fill a target window */
|
||||
PPA_OPERATION_NUM, /*!< Quantity of PPA operations */
|
||||
PPA_OPERATION_INVALID, /*!< Invalid PPA operations, indicates the quantity of available PPA operations */
|
||||
} ppa_operation_t;
|
||||
|
||||
/**
|
||||
@ -89,7 +89,7 @@ typedef bool (*ppa_event_callback_t)(ppa_client_handle_t ppa_client, ppa_event_d
|
||||
* @brief Group of supported PPA callbacks
|
||||
*/
|
||||
typedef struct {
|
||||
ppa_event_callback_t on_trans_done; /*! Invoked when a PPA transaction finishes */
|
||||
ppa_event_callback_t on_trans_done; /*!< Invoked when a PPA transaction finishes */
|
||||
} ppa_event_callbacks_t;
|
||||
|
||||
/**
|
||||
@ -111,7 +111,7 @@ esp_err_t ppa_client_register_event_callbacks(ppa_client_handle_t ppa_client, co
|
||||
* @brief A collection of configuration items for an input picture and the target block inside the picture
|
||||
*/
|
||||
typedef struct {
|
||||
void *buffer; /*!< Pointer to the input picture buffer */
|
||||
const void *buffer; /*!< Pointer to the input picture buffer */
|
||||
uint32_t pic_w; /*!< Input picture width (unit: pixel) */
|
||||
uint32_t pic_h; /*!< Input picture height (unit: pixel) */
|
||||
uint32_t block_w; /*!< Target block width (unit: pixel) */
|
||||
@ -123,8 +123,8 @@ typedef struct {
|
||||
ppa_blend_color_mode_t blend_cm; /*!< Color mode of the picture in a PPA blend operation. Supported color mode in `ppa_blend_color_mode_t` */
|
||||
ppa_fill_color_mode_t fill_cm; /*!< Color mode of the picture in a PPA fill operation. Supported color mode in `ppa_fill_color_mode_t` */
|
||||
};
|
||||
color_range_t yuv_range; /*!< When the color mode is any YUV color space, this field is to describe its color range */
|
||||
color_conv_std_rgb_yuv_t yuv_std; /*!< When the color mode is any YUV color space, this field is to describe its YUV<->RGB conversion standard */
|
||||
ppa_color_range_t yuv_range; /*!< When the color mode is any YUV color space, this field is to describe its color range */
|
||||
ppa_color_conv_std_rgb_yuv_t yuv_std; /*!< When the color mode is any YUV color space, this field is to describe its YUV<->RGB conversion standard */
|
||||
} ppa_in_pic_blk_config_t;
|
||||
|
||||
/**
|
||||
@ -142,8 +142,8 @@ typedef struct {
|
||||
ppa_blend_color_mode_t blend_cm; /*!< Color mode of the picture in a PPA blend operation. Supported color mode in `ppa_blend_color_mode_t` */
|
||||
ppa_fill_color_mode_t fill_cm; /*!< Color mode of the picture in a PPA fill operation. Supported color mode in `ppa_fill_color_mode_t` */
|
||||
};
|
||||
color_range_t yuv_range; /*!< When the color mode is any YUV color space, this field is to describe its color range */
|
||||
color_conv_std_rgb_yuv_t yuv_std; /*!< When the color mode is any YUV color space, this field is to describe its YUV<->RGB conversion standard */
|
||||
ppa_color_range_t yuv_range; /*!< When the color mode is any YUV color space, this field is to describe its color range */
|
||||
ppa_color_conv_std_rgb_yuv_t yuv_std; /*!< When the color mode is any YUV color space, this field is to describe its YUV<->RGB conversion standard */
|
||||
} ppa_out_pic_blk_config_t;
|
||||
|
||||
/**
|
||||
@ -193,8 +193,7 @@ typedef struct {
|
||||
* @return
|
||||
* - ESP_OK: Perform a SRM operation successfully
|
||||
* - ESP_ERR_INVALID_ARG: Perform a SRM operation failed because of invalid argument
|
||||
* - ESP_ERR_NO_MEM: Perform a SRM operation failed because out of memory
|
||||
* - ESP_FAIL: Perform a SRM operation failed because the client cannot accept transaction now
|
||||
* - ESP_FAIL: Perform a SRM operation failed because the client's pending transactions has reached its maximum capacity
|
||||
*/
|
||||
esp_err_t ppa_do_scale_rotate_mirror(ppa_client_handle_t ppa_client, const ppa_srm_oper_config_t *config);
|
||||
|
||||
@ -227,7 +226,7 @@ typedef struct {
|
||||
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_pixel_rgb888_data_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 */
|
||||
|
||||
// color-keying
|
||||
// A pixel, where its background element and foreground element are both out of their color-keying ranges, will follow Alpha Blending
|
||||
@ -255,8 +254,7 @@ typedef struct {
|
||||
* @return
|
||||
* - ESP_OK: Perform a blend operation successfully
|
||||
* - ESP_ERR_INVALID_ARG: Perform a blend operation failed because of invalid argument
|
||||
* - ESP_ERR_NO_MEM: Perform a blend operation failed because out of memory
|
||||
* - ESP_FAIL: Perform a blend operation failed because the client cannot accept transaction now
|
||||
* - ESP_FAIL: Perform a blend operation failed because the client's pending transactions has reached its maximum capacity
|
||||
*/
|
||||
esp_err_t ppa_do_blend(ppa_client_handle_t ppa_client, const ppa_blend_oper_config_t *config);
|
||||
|
||||
@ -268,7 +266,7 @@ typedef struct {
|
||||
|
||||
uint32_t fill_block_w; /*!< The width of the block to be filled (unit: pixel) */
|
||||
uint32_t fill_block_h; /*!< The height of the block to be filled (unit: pixel) */
|
||||
uint32_t fill_argb_color; /*!< The color to be filled, in ARGB8888 format ((A[31:24], R[23:16], G[15: 8], B[7:0])) */
|
||||
color_pixel_argb8888_data_t fill_argb_color; /*!< The color to be filled, in ARGB8888 format */
|
||||
|
||||
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 */
|
||||
@ -283,8 +281,7 @@ typedef struct {
|
||||
* @return
|
||||
* - ESP_OK: Perform a fill operation successfully
|
||||
* - ESP_ERR_INVALID_ARG: Perform a fill operation failed because of invalid argument
|
||||
* - ESP_ERR_NO_MEM: Perform a fill operation failed because out of memory
|
||||
* - ESP_FAIL: Perform a fill operation failed because the client cannot accept transaction now
|
||||
* - ESP_FAIL: Perform a fill operation failed because the client's pending transactions has reached its maximum capacity
|
||||
*/
|
||||
esp_err_t ppa_do_fill(ppa_client_handle_t ppa_client, const ppa_fill_oper_config_t *config);
|
||||
|
||||
|
@ -146,7 +146,7 @@ bool ppa_blend_transaction_on_picked(uint32_t num_chans, const dma2d_trans_chann
|
||||
|
||||
ppa_ll_blend_set_rx_fg_color_mode(platform->hal.dev, blend_trans_desc->in_fg.blend_cm);
|
||||
if (COLOR_SPACE_TYPE((uint32_t)blend_trans_desc->in_fg.blend_cm) == COLOR_SPACE_ALPHA) {
|
||||
ppa_ll_blend_set_rx_fg_fix_rgb(platform->hal.dev, blend_trans_desc->fg_fix_rgb_val);
|
||||
ppa_ll_blend_set_rx_fg_fix_rgb(platform->hal.dev, &blend_trans_desc->fg_fix_rgb_val);
|
||||
}
|
||||
ppa_ll_blend_enable_rx_fg_byte_swap(platform->hal.dev, blend_trans_desc->fg_byte_swap);
|
||||
ppa_ll_blend_enable_rx_fg_rgb_swap(platform->hal.dev, blend_trans_desc->fg_rgb_swap);
|
||||
@ -231,18 +231,21 @@ esp_err_t ppa_do_blend(ppa_client_handle_t ppa_client, const ppa_blend_oper_conf
|
||||
.color_type_id = config->in_bg.blend_cm,
|
||||
};
|
||||
uint32_t in_bg_pic_len = config->in_bg.pic_w * config->in_bg.pic_h * color_hal_pixel_format_get_bit_depth(in_bg_pixel_format) / 8;
|
||||
esp_cache_msync(config->in_bg.buffer, in_bg_pic_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED);
|
||||
esp_cache_msync((void *)config->in_bg.buffer, in_bg_pic_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED);
|
||||
color_space_pixel_format_t in_fg_pixel_format = {
|
||||
.color_type_id = config->in_fg.blend_cm,
|
||||
};
|
||||
uint32_t in_fg_pic_len = config->in_fg.pic_w * config->in_fg.pic_h * color_hal_pixel_format_get_bit_depth(in_fg_pixel_format) / 8;
|
||||
esp_cache_msync(config->in_fg.buffer, in_fg_pic_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED);
|
||||
esp_cache_msync((void *)config->in_fg.buffer, in_fg_pic_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED);
|
||||
// Invalidate out_buffer
|
||||
esp_cache_msync(config->out.buffer, config->out.buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
|
||||
esp_cache_msync((void *)config->out.buffer, config->out.buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
ppa_trans_t *trans_elm = NULL;
|
||||
if (xQueueReceive(ppa_client->trans_elm_ptr_queue, (void *)&trans_elm, 0)) {
|
||||
portENTER_CRITICAL(&ppa_client->spinlock);
|
||||
bool trans_elm_acquired = xQueueReceive(ppa_client->trans_elm_ptr_queue, (void *)&trans_elm, 0);
|
||||
portEXIT_CRITICAL(&ppa_client->spinlock);
|
||||
if (trans_elm_acquired) {
|
||||
dma2d_trans_config_t *dma_trans_desc = trans_elm->trans_desc;
|
||||
|
||||
ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = dma_trans_desc->user_config;
|
||||
|
@ -46,10 +46,10 @@ static esp_err_t ppa_engine_release(ppa_engine_t *ppa_engine);
|
||||
static bool ppa_malloc_transaction(QueueHandle_t trans_elm_ptr_queue, uint32_t trans_elm_num, ppa_operation_t oper_type);
|
||||
static void ppa_free_transaction(ppa_trans_t *trans_elm);
|
||||
|
||||
const dma2d_trans_on_picked_callback_t ppa_oper_trans_on_picked_func[PPA_OPERATION_NUM] = {
|
||||
ppa_srm_transaction_on_picked,
|
||||
ppa_blend_transaction_on_picked,
|
||||
ppa_fill_transaction_on_picked,
|
||||
const dma2d_trans_on_picked_callback_t ppa_oper_trans_on_picked_func[PPA_OPERATION_INVALID] = {
|
||||
[PPA_OPERATION_SRM] = ppa_srm_transaction_on_picked,
|
||||
[PPA_OPERATION_BLEND] = ppa_blend_transaction_on_picked,
|
||||
[PPA_OPERATION_FILL] = ppa_fill_transaction_on_picked,
|
||||
};
|
||||
|
||||
static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engine_t **ret_engine)
|
||||
@ -104,9 +104,11 @@ static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engin
|
||||
}
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "ppa_srm", &srm_engine->base.pm_lock);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "create pm lock failed");
|
||||
if (ret == ESP_OK) {
|
||||
ret = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "ppa_srm", &srm_engine->base.pm_lock);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "create pm lock failed");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
@ -147,9 +149,11 @@ static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engin
|
||||
}
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "ppa_blending", &blending_engine->base.pm_lock);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "create pm lock failed");
|
||||
if (ret == ESP_OK) {
|
||||
ret = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "ppa_blending", &blending_engine->base.pm_lock);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "create pm lock failed");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
@ -180,16 +184,6 @@ static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engin
|
||||
ESP_LOGE(TAG, "install 2D-DMA failed");
|
||||
goto wrap_up;
|
||||
}
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
assert(!s_platform.pm_lock);
|
||||
// Create and acquire the PM lock
|
||||
ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "ppa", &s_platform.pm_lock);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "create pm lock failed");
|
||||
goto wrap_up;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
wrap_up:
|
||||
@ -250,14 +244,6 @@ static esp_err_t ppa_engine_release(ppa_engine_t *ppa_engine)
|
||||
if (!s_platform.srm && !s_platform.blending) {
|
||||
assert(s_platform.srm_engine_ref_count == 0 && s_platform.blend_engine_ref_count == 0);
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
if (s_platform.pm_lock) {
|
||||
ret = esp_pm_lock_delete(s_platform.pm_lock);
|
||||
assert(ret == ESP_OK);
|
||||
s_platform.pm_lock = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (s_platform.dma2d_pool_handle) {
|
||||
dma2d_release_pool(s_platform.dma2d_pool_handle); // TODO: check return value. If not ESP_OK, then must be error on other 2D-DMA clients :( Give a warning log?
|
||||
s_platform.dma2d_pool_handle = NULL;
|
||||
@ -278,19 +264,19 @@ esp_err_t ppa_register_client(const ppa_client_config_t *config, ppa_client_hand
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_RETURN_ON_FALSE(config && ret_client, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(config->oper_type < PPA_OPERATION_NUM, ESP_ERR_INVALID_ARG, TAG, "unknown operation");
|
||||
ESP_RETURN_ON_FALSE(config->oper_type < PPA_OPERATION_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown operation");
|
||||
|
||||
ppa_client_t *client = (ppa_client_t *)heap_caps_calloc(1, sizeof(ppa_client_t), PPA_MEM_ALLOC_CAPS);
|
||||
ESP_RETURN_ON_FALSE(client, ESP_ERR_NO_MEM, TAG, "no mem to register client");
|
||||
|
||||
uint32_t ring_buf_size = MAX(1, config->max_pending_trans_num);
|
||||
client->trans_elm_ptr_queue = xQueueCreateWithCaps(ring_buf_size, sizeof(uint32_t), PPA_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(client->trans_elm_ptr_queue && ppa_malloc_transaction(client->trans_elm_ptr_queue, ring_buf_size, config->oper_type),
|
||||
// Allocate memory for storing transaction contexts and create a queue to save these trans_elm_ptr
|
||||
uint32_t queue_size = MAX(1, config->max_pending_trans_num);
|
||||
client->trans_elm_ptr_queue = xQueueCreateWithCaps(queue_size, sizeof(uint32_t), PPA_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(client->trans_elm_ptr_queue && ppa_malloc_transaction(client->trans_elm_ptr_queue, queue_size, config->oper_type),
|
||||
ESP_ERR_NO_MEM, err, TAG, "no mem for transaction storage");
|
||||
|
||||
client->oper_type = config->oper_type;
|
||||
client->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
client->in_accepting_trans_state = true;
|
||||
if (config->oper_type == PPA_OPERATION_SRM) {
|
||||
ppa_engine_config_t engine_config = {
|
||||
.engine = PPA_ENGINE_TYPE_SRM,
|
||||
@ -318,7 +304,6 @@ esp_err_t ppa_unregister_client(ppa_client_handle_t ppa_client)
|
||||
bool do_unregister = false;
|
||||
portENTER_CRITICAL(&ppa_client->spinlock);
|
||||
if (ppa_client->trans_cnt == 0) {
|
||||
ppa_client->in_accepting_trans_state = false;
|
||||
do_unregister = true;
|
||||
}
|
||||
portEXIT_CRITICAL(&ppa_client->spinlock);
|
||||
@ -387,12 +372,12 @@ static bool ppa_malloc_transaction(QueueHandle_t trans_elm_ptr_queue, uint32_t t
|
||||
trans_on_picked_desc->op_desc = ppa_trans_desc;
|
||||
trans_on_picked_desc->trans_elm = new_trans_elm;
|
||||
dma_trans_desc->user_config = (void *)trans_on_picked_desc;
|
||||
dma_trans_desc->on_job_picked = ppa_oper_trans_on_picked_func[oper_type]; // TODO: This maybe better to be in the ppa_do_xxx function
|
||||
dma_trans_desc->on_job_picked = ppa_oper_trans_on_picked_func[oper_type];
|
||||
new_trans_elm->trans_desc = dma_trans_desc;
|
||||
new_trans_elm->dma_trans_placeholder = dma_trans_elm;
|
||||
new_trans_elm->sem = ppa_trans_sem;
|
||||
|
||||
// Fill the ring buffer with allocated transaction element pointer
|
||||
// Fill the queue with allocated transaction element pointer
|
||||
BaseType_t sent = xQueueSend(trans_elm_ptr_queue, &new_trans_elm, 0);
|
||||
assert(sent);
|
||||
}
|
||||
@ -424,27 +409,14 @@ esp_err_t ppa_do_operation(ppa_client_handle_t ppa_client, ppa_engine_t *ppa_eng
|
||||
esp_err_t ret = ESP_OK;
|
||||
esp_err_t pm_lock_ret __attribute__((unused));
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
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);
|
||||
// TODO: Check whether trans_cnt and trans_elm_ptr_queue need in one spinlock!!!
|
||||
if (ppa_client->in_accepting_trans_state) {
|
||||
// Send transaction into PPA engine queue
|
||||
STAILQ_INSERT_TAIL(&ppa_engine_base->trans_stailq, trans_elm, entry);
|
||||
ppa_client->trans_cnt++;
|
||||
} else {
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
// Send transaction into PPA engine queue
|
||||
portENTER_CRITICAL(&ppa_engine_base->spinlock);
|
||||
STAILQ_INSERT_TAIL(&ppa_engine_base->trans_stailq, trans_elm, entry);
|
||||
portEXIT_CRITICAL(&ppa_engine_base->spinlock);
|
||||
ppa_client->trans_cnt++;
|
||||
portEXIT_CRITICAL(&ppa_client->spinlock);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "The client cannot accept transaction now");
|
||||
goto err;
|
||||
}
|
||||
|
||||
TickType_t ticks_to_wait = (mode == PPA_TRANS_MODE_NON_BLOCKING) ? 0 : portMAX_DELAY;
|
||||
if (xSemaphoreTake(ppa_engine_base->sem, ticks_to_wait) == pdTRUE) {
|
||||
// Check if the transaction has already been started from the ISR
|
||||
@ -469,11 +441,11 @@ esp_err_t ppa_do_operation(ppa_client_handle_t ppa_client, ppa_engine_t *ppa_eng
|
||||
portENTER_CRITICAL(&ppa_engine_base->spinlock);
|
||||
STAILQ_REMOVE(&ppa_engine_base->trans_stailq, trans_elm, ppa_trans_s, entry);
|
||||
portEXIT_CRITICAL(&ppa_engine_base->spinlock);
|
||||
xSemaphoreGive(ppa_engine_base->sem);
|
||||
#if CONFIG_PM_ENABLE
|
||||
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);
|
||||
ppa_client->trans_cnt--;
|
||||
portEXIT_CRITICAL(&ppa_client->spinlock);
|
||||
@ -489,15 +461,9 @@ esp_err_t ppa_do_operation(ppa_client_handle_t ppa_client, ppa_engine_t *ppa_eng
|
||||
// printf("ppa intr: %ld\n", PPA.int_raw.val);
|
||||
// }
|
||||
xSemaphoreTake(trans_elm->sem, portMAX_DELAY); // Given in the ISR
|
||||
// Sanity check new_trans_elm not in trans_stailq anymore? (loop takes time tho)
|
||||
// ppa_recycle_transaction(ppa_client, trans_elm); // TODO: Do we need it to be here or can be at the end of done_cb?
|
||||
// TODO: Sanity check new_trans_elm not in trans_stailq anymore? (loop takes time tho)
|
||||
}
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
pm_lock_ret = esp_pm_lock_release(s_platform.pm_lock);
|
||||
assert((pm_lock_ret == ESP_OK) && "release pm_lock failed");
|
||||
#endif
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
@ -510,11 +476,9 @@ bool ppa_transaction_done_cb(dma2d_channel_handle_t dma2d_chan, dma2d_event_data
|
||||
ppa_client_t *client = trans_elm->client;
|
||||
ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = (ppa_dma2d_trans_on_picked_config_t *)trans_elm->trans_desc->user_config;
|
||||
ppa_engine_t *engine_base = trans_on_picked_desc->ppa_engine;
|
||||
|
||||
if (client->done_cb) {
|
||||
ppa_event_data_t edata = {};
|
||||
need_yield |= client->done_cb(client, &edata, trans_elm->user_data);
|
||||
}
|
||||
// Save callback contexts
|
||||
ppa_event_callback_t done_cb = client->done_cb;
|
||||
void *trans_elm_user_data = trans_elm->user_data;
|
||||
|
||||
ppa_trans_t *next_start_trans = NULL;
|
||||
portENTER_CRITICAL_ISR(&engine_base->spinlock);
|
||||
@ -523,28 +487,34 @@ bool ppa_transaction_done_cb(dma2d_channel_handle_t dma2d_chan, dma2d_event_data
|
||||
next_start_trans = STAILQ_FIRST(&engine_base->trans_stailq);
|
||||
portEXIT_CRITICAL_ISR(&engine_base->spinlock);
|
||||
|
||||
portENTER_CRITICAL_ISR(&client->spinlock);
|
||||
// Release transaction semaphore to unblock ppa_do_operation
|
||||
xSemaphoreGiveFromISR(trans_elm->sem, &HPTaskAwoken);
|
||||
need_yield |= (HPTaskAwoken == pdTRUE);
|
||||
|
||||
// Then recycle transaction elm
|
||||
need_yield |= ppa_recycle_transaction(client, trans_elm);
|
||||
|
||||
client->trans_cnt--;
|
||||
portEXIT_CRITICAL_ISR(&client->spinlock);
|
||||
|
||||
// If there is next trans in PPA engine queue, send it to DMA queue; otherwise, release the engine semaphore
|
||||
if (next_start_trans) {
|
||||
ppa_dma2d_enqueue(next_start_trans);
|
||||
} else {
|
||||
xSemaphoreGiveFromISR(engine_base->sem, &HPTaskAwoken);
|
||||
need_yield |= (HPTaskAwoken == pdTRUE);
|
||||
#if CONFIG_PM_ENABLE
|
||||
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);
|
||||
}
|
||||
// Recycle transaction and release transaction semaphore
|
||||
// if (trans_elm->sem != NULL) {
|
||||
xSemaphoreGiveFromISR(trans_elm->sem, &HPTaskAwoken);
|
||||
need_yield |= (HPTaskAwoken == pdTRUE);
|
||||
// }
|
||||
|
||||
// TODO: Check whether trans_cnt and trans_elm_ptr_queue need in one spinlock!!!
|
||||
portENTER_CRITICAL_ISR(&client->spinlock);
|
||||
need_yield |= ppa_recycle_transaction(client, trans_elm);
|
||||
client->trans_cnt--;
|
||||
portEXIT_CRITICAL_ISR(&client->spinlock);
|
||||
// Process last transaction's callback
|
||||
if (done_cb) {
|
||||
ppa_event_data_t edata = {};
|
||||
need_yield |= done_cb(client, &edata, trans_elm_user_data);
|
||||
}
|
||||
|
||||
return need_yield;
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ 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->fill_argb_color, fill_trans_desc->fill_block_w, fill_trans_desc->fill_block_h);
|
||||
ppa_ll_blend_configure_filling_block(platform->hal.dev, &fill_trans_desc->fill_argb_color, fill_trans_desc->fill_block_w, fill_trans_desc->fill_block_h);
|
||||
ppa_ll_blend_set_tx_color_mode(platform->hal.dev, fill_trans_desc->out.fill_cm);
|
||||
|
||||
ppa_ll_blend_start(platform->hal.dev, PPA_LL_BLEND_TRANS_MODE_FILL);
|
||||
@ -104,11 +104,14 @@ esp_err_t ppa_do_fill(ppa_client_handle_t ppa_client, const ppa_fill_oper_config
|
||||
// To reduce complexity, color_mode, fill_block_w/h correctness are checked in their corresponding LL functions
|
||||
|
||||
// Write back and invalidate are performed on the entire picture (the window content is not continuous in the buffer)
|
||||
esp_cache_msync(config->out.buffer, config->out.buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE);
|
||||
esp_cache_msync((void *)config->out.buffer, config->out.buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE);
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
ppa_trans_t *trans_elm = NULL;
|
||||
if (xQueueReceive(ppa_client->trans_elm_ptr_queue, (void *)&trans_elm, 0)) {
|
||||
portENTER_CRITICAL(&ppa_client->spinlock);
|
||||
bool trans_elm_acquired = xQueueReceive(ppa_client->trans_elm_ptr_queue, (void *)&trans_elm, 0);
|
||||
portEXIT_CRITICAL(&ppa_client->spinlock);
|
||||
if (trans_elm_acquired) {
|
||||
dma2d_trans_config_t *dma_trans_desc = trans_elm->trans_desc;
|
||||
|
||||
ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = dma_trans_desc->user_config;
|
||||
|
@ -78,7 +78,6 @@ struct ppa_client_t {
|
||||
ppa_engine_t *engine; // Pointer to the PPA engine that in charge of performing the PPA operation
|
||||
uint32_t trans_cnt; // Number of pending PPA transactions
|
||||
portMUX_TYPE spinlock; // Client level spinlock
|
||||
bool in_accepting_trans_state; // Indicates whether the client can accept new PPA transaction requests now
|
||||
ppa_event_callback_t done_cb; // Transaction done callback
|
||||
QueueHandle_t trans_elm_ptr_queue; // Queue that contains the pointers to the allocated memory to save the transaction contexts
|
||||
};
|
||||
@ -141,7 +140,7 @@ typedef struct {
|
||||
uint32_t fg_alpha_fix_val;
|
||||
float fg_alpha_scale_ratio;
|
||||
};
|
||||
uint32_t fg_fix_rgb_val;
|
||||
color_pixel_rgb888_data_t fg_fix_rgb_val;
|
||||
|
||||
// color-keying
|
||||
bool bg_ck_en;
|
||||
@ -209,9 +208,6 @@ struct ppa_platform_t {
|
||||
uint32_t blend_engine_ref_count; // Reference count used to protect PPA blending engine acquire and release
|
||||
size_t buf_alignment_size; // Alignment requirement for the outgoing buffer addr and size to satisfy cache line size
|
||||
uint32_t dma_desc_mem_size; // Alignment requirement for the 2D-DMA descriptor to satisfy cache line size
|
||||
#if CONFIG_PM_ENABLE
|
||||
esp_pm_lock_handle_t pm_lock; // Power management lock
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -108,7 +108,7 @@ bool ppa_srm_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel
|
||||
if (ppa_in_color_mode == PPA_SRM_COLOR_MODE_YUV444) {
|
||||
ppa_in_color_mode = PPA_SRM_COLOR_MODE_RGB888;
|
||||
dma2d_csc_config_t dma_tx_csc = {0};
|
||||
if (srm_trans_desc->in.yuv_std == COLOR_CONV_STD_RGB_YUV_BT601) {
|
||||
if (srm_trans_desc->in.yuv_std == PPA_COLOR_CONV_STD_RGB_YUV_BT601) {
|
||||
dma_tx_csc.tx_csc_option = DMA2D_CSC_TX_YUV444_TO_RGB888_601;
|
||||
} else {
|
||||
dma_tx_csc.tx_csc_option = DMA2D_CSC_TX_YUV444_TO_RGB888_709;
|
||||
@ -117,7 +117,7 @@ bool ppa_srm_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel
|
||||
} else if (ppa_in_color_mode == PPA_SRM_COLOR_MODE_YUV422) {
|
||||
ppa_in_color_mode = PPA_SRM_COLOR_MODE_RGB888;
|
||||
dma2d_csc_config_t dma_tx_csc = {0};
|
||||
if (srm_trans_desc->in.yuv_std == COLOR_CONV_STD_RGB_YUV_BT601) {
|
||||
if (srm_trans_desc->in.yuv_std == PPA_COLOR_CONV_STD_RGB_YUV_BT601) {
|
||||
dma_tx_csc.tx_csc_option = DMA2D_CSC_TX_YUV422_TO_RGB888_601;
|
||||
} else {
|
||||
dma_tx_csc.tx_csc_option = DMA2D_CSC_TX_YUV422_TO_RGB888_709;
|
||||
@ -227,13 +227,16 @@ esp_err_t ppa_do_scale_rotate_mirror(ppa_client_handle_t ppa_client, const ppa_s
|
||||
.color_type_id = config->in.srm_cm,
|
||||
};
|
||||
uint32_t in_pic_len = config->in.pic_w * config->in.pic_h * color_hal_pixel_format_get_bit_depth(in_pixel_format) / 8;
|
||||
esp_cache_msync(config->in.buffer, in_pic_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED);
|
||||
esp_cache_msync((void *)config->in.buffer, in_pic_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED);
|
||||
// Invalidate out_buffer
|
||||
esp_cache_msync(config->out.buffer, config->out.buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
|
||||
esp_cache_msync((void *)config->out.buffer, config->out.buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
ppa_trans_t *trans_elm = NULL;
|
||||
if (xQueueReceive(ppa_client->trans_elm_ptr_queue, (void *)&trans_elm, 0)) {
|
||||
portENTER_CRITICAL(&ppa_client->spinlock);
|
||||
bool trans_elm_acquired = xQueueReceive(ppa_client->trans_elm_ptr_queue, (void *)&trans_elm, 0);
|
||||
portEXIT_CRITICAL(&ppa_client->spinlock);
|
||||
if (trans_elm_acquired) {
|
||||
dma2d_trans_config_t *dma_trans_desc = trans_elm->trans_desc;
|
||||
|
||||
ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = dma_trans_desc->user_config;
|
||||
|
@ -0,0 +1,7 @@
|
||||
# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
|
||||
|
||||
components/esp_driver_ppa/test_apps:
|
||||
disable:
|
||||
- if: SOC_PPA_SUPPORTED != 1
|
||||
depends_components:
|
||||
- esp_driver_ppa
|
9
components/esp_driver_ppa/test_apps/CMakeLists.txt
Normal file
9
components/esp_driver_ppa/test_apps/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
set(COMPONENTS main)
|
||||
|
||||
project(ppa_test)
|
2
components/esp_driver_ppa/test_apps/README.md
Normal file
2
components/esp_driver_ppa/test_apps/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32-P4 |
|
||||
| ----------------- | -------- |
|
9
components/esp_driver_ppa/test_apps/main/CMakeLists.txt
Normal file
9
components/esp_driver_ppa/test_apps/main/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
set(srcs "test_app_main.c"
|
||||
"test_ppa.c")
|
||||
|
||||
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
||||
# the component can be registered as WHOLE_ARCHIVE
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES esp_driver_ppa esp_psram unity
|
||||
WHOLE_ARCHIVE)
|
@ -0,0 +1,2 @@
|
||||
dependencies:
|
||||
ccomp_timer: "^1.0.0"
|
42
components/esp_driver_ppa/test_apps/main/test_app_main.c
Normal file
42
components/esp_driver_ppa/test_apps/main/test_app_main.c
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "unity_test_utils.h"
|
||||
|
||||
// Some resources are lazy allocated in the driver, the threshold is left for that case
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (300)
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
unity_utils_record_free_mem();
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
esp_reent_cleanup(); //clean up some of the newlib's lazy allocations
|
||||
unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
printf(" ________ \n");
|
||||
printf("|___ ___ \\ \n");
|
||||
printf(" | \\_/ | \n");
|
||||
printf(" '.___.' \n");
|
||||
printf(" ________ \n");
|
||||
printf("|___ ___ \\ \n");
|
||||
printf(" | \\_/ | \n");
|
||||
printf(" '.___.' \n");
|
||||
printf(" _______ \n");
|
||||
printf("|__. _ '. \n");
|
||||
printf(" __||_/ / \n");
|
||||
printf("|______.' \n");
|
||||
|
||||
unity_run_menu();
|
||||
}
|
489
components/esp_driver_ppa/test_apps/main/test_ppa.c
Normal file
489
components/esp_driver_ppa/test_apps/main/test_ppa.c
Normal file
@ -0,0 +1,489 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "unity.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "driver/ppa.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_err.h"
|
||||
#include "ccomp_timer.h"
|
||||
#include "hal/color_hal.h"
|
||||
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
TEST_CASE("ppa_client_do_ppa_operation", "[PPA]")
|
||||
{
|
||||
const uint32_t w = 480;
|
||||
const uint32_t h = 480;
|
||||
const uint32_t buf_1_color_type_id = COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888);
|
||||
const uint32_t buf_2_color_type_id = COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888);
|
||||
|
||||
color_space_pixel_format_t buf_1_cm = {
|
||||
.color_type_id = buf_1_color_type_id,
|
||||
};
|
||||
color_space_pixel_format_t buf_2_cm = {
|
||||
.color_type_id = buf_2_color_type_id,
|
||||
};
|
||||
|
||||
uint32_t buf_1_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(buf_1_cm) / 8, 64);
|
||||
uint32_t buf_2_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(buf_2_cm) / 8, 64);
|
||||
uint8_t *buf_1 = heap_caps_aligned_calloc(64, buf_1_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM);
|
||||
TEST_ASSERT_NOT_NULL(buf_1);
|
||||
uint8_t *buf_2 = heap_caps_aligned_calloc(64, buf_2_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM);
|
||||
TEST_ASSERT_NOT_NULL(buf_2);
|
||||
|
||||
// Register different types of PPA clients
|
||||
ppa_client_handle_t ppa_client_a_handle;
|
||||
ppa_client_handle_t ppa_client_b_handle;
|
||||
ppa_client_handle_t ppa_client_c_handle;
|
||||
ppa_client_handle_t ppa_client_d_handle;
|
||||
ppa_client_config_t ppa_client_config = {
|
||||
.oper_type = PPA_OPERATION_SRM,
|
||||
};
|
||||
TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_a_handle));
|
||||
ppa_client_config.oper_type = PPA_OPERATION_BLEND;
|
||||
TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_b_handle));
|
||||
ppa_client_config.oper_type = PPA_OPERATION_FILL;
|
||||
TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_c_handle));
|
||||
TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_d_handle));
|
||||
|
||||
ppa_srm_oper_config_t srm_oper_config = {
|
||||
.in.buffer = buf_1,
|
||||
.in.pic_w = w,
|
||||
.in.pic_h = h,
|
||||
.in.block_w = w,
|
||||
.in.block_h = h,
|
||||
.in.block_offset_x = 0,
|
||||
.in.block_offset_y = 0,
|
||||
.in.srm_cm = buf_1_color_type_id,
|
||||
|
||||
.out.buffer = buf_2,
|
||||
.out.buffer_size = buf_2_size,
|
||||
.out.pic_w = w,
|
||||
.out.pic_h = h,
|
||||
.out.block_offset_x = 0,
|
||||
.out.block_offset_y = 0,
|
||||
.out.srm_cm = buf_2_color_type_id,
|
||||
|
||||
.rotation_angle = PPA_SRM_ROTATION_ANGLE_0,
|
||||
.scale_x = 1.0,
|
||||
.scale_y = 1.0,
|
||||
|
||||
.mode = PPA_TRANS_MODE_BLOCKING,
|
||||
};
|
||||
// A SRM client can request to do a SRM operation
|
||||
TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_a_handle, &srm_oper_config));
|
||||
// A non-SRM client can not request to do a SRM operation
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, ppa_do_scale_rotate_mirror(ppa_client_b_handle, &srm_oper_config));
|
||||
|
||||
ppa_blend_oper_config_t blend_oper_config = {
|
||||
.in_bg.buffer = buf_1,
|
||||
.in_bg.pic_w = w,
|
||||
.in_bg.pic_h = h,
|
||||
.in_bg.block_w = w,
|
||||
.in_bg.block_h = h,
|
||||
.in_bg.block_offset_x = 0,
|
||||
.in_bg.block_offset_y = 0,
|
||||
.in_bg.blend_cm = buf_1_color_type_id,
|
||||
|
||||
.in_fg.buffer = buf_2,
|
||||
.in_fg.pic_w = w,
|
||||
.in_fg.pic_h = h,
|
||||
.in_fg.block_w = w,
|
||||
.in_fg.block_h = h,
|
||||
.in_fg.block_offset_x = 0,
|
||||
.in_fg.block_offset_y = 0,
|
||||
.in_fg.blend_cm = buf_2_color_type_id,
|
||||
|
||||
.out.buffer = buf_1,
|
||||
.out.buffer_size = buf_1_size,
|
||||
.out.pic_w = w,
|
||||
.out.pic_h = h,
|
||||
.out.block_offset_x = 0,
|
||||
.out.block_offset_y = 0,
|
||||
.out.blend_cm = buf_1_color_type_id,
|
||||
|
||||
.mode = PPA_TRANS_MODE_BLOCKING,
|
||||
};
|
||||
// A blend client can request to do a blend operation
|
||||
TEST_ESP_OK(ppa_do_blend(ppa_client_b_handle, &blend_oper_config));
|
||||
// A non-blend client can not request to do a blend operation
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, ppa_do_blend(ppa_client_d_handle, &blend_oper_config));
|
||||
|
||||
ppa_fill_oper_config_t fill_oper_config = {
|
||||
.out.buffer = buf_1,
|
||||
.out.buffer_size = buf_1_size,
|
||||
.out.pic_w = w,
|
||||
.out.pic_h = h,
|
||||
.out.block_offset_x = 0,
|
||||
.out.block_offset_y = 0,
|
||||
.out.fill_cm = buf_1_color_type_id,
|
||||
|
||||
.fill_block_w = w,
|
||||
.fill_block_h = h,
|
||||
.fill_argb_color = {
|
||||
.val = 0xFF00FF00,
|
||||
},
|
||||
|
||||
.mode = PPA_TRANS_MODE_NON_BLOCKING,
|
||||
};
|
||||
// A fill client can request to do a fill operation
|
||||
TEST_ESP_OK(ppa_do_fill(ppa_client_c_handle, &fill_oper_config));
|
||||
// Another fill client can also request another fill operation at the same time
|
||||
TEST_ESP_OK(ppa_do_fill(ppa_client_d_handle, &fill_oper_config));
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
|
||||
// Unregister all PPA clients
|
||||
TEST_ESP_OK(ppa_unregister_client(ppa_client_a_handle));
|
||||
TEST_ESP_OK(ppa_unregister_client(ppa_client_b_handle));
|
||||
TEST_ESP_OK(ppa_unregister_client(ppa_client_c_handle));
|
||||
TEST_ESP_OK(ppa_unregister_client(ppa_client_d_handle));
|
||||
|
||||
free(buf_1);
|
||||
free(buf_2);
|
||||
}
|
||||
|
||||
static bool ppa_trans_done_cb(ppa_client_handle_t ppa_client, ppa_event_data_t *event_data, void *user_data)
|
||||
{
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
SemaphoreHandle_t sem = (SemaphoreHandle_t)user_data;
|
||||
xSemaphoreGiveFromISR(sem, &xHigherPriorityTaskWoken);
|
||||
return (xHigherPriorityTaskWoken == pdTRUE);
|
||||
}
|
||||
|
||||
TEST_CASE("ppa_pending_transactions_in_queue", "[PPA]")
|
||||
{
|
||||
// A big picture block takes longer time to process, desired for this test case
|
||||
const uint32_t w = 1920;
|
||||
const uint32_t h = 1080;
|
||||
const uint32_t buf_1_color_type_id = COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888);
|
||||
const uint32_t buf_2_color_type_id = COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888);
|
||||
|
||||
color_space_pixel_format_t buf_1_cm = {
|
||||
.color_type_id = buf_1_color_type_id,
|
||||
};
|
||||
color_space_pixel_format_t buf_2_cm = {
|
||||
.color_type_id = buf_2_color_type_id,
|
||||
};
|
||||
|
||||
uint32_t buf_1_size = w * h * color_hal_pixel_format_get_bit_depth(buf_1_cm) / 8;
|
||||
uint32_t buf_2_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(buf_2_cm) / 8, 64);
|
||||
uint8_t *buf_1 = heap_caps_aligned_calloc(64, buf_1_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM);
|
||||
TEST_ASSERT_NOT_NULL(buf_1);
|
||||
uint8_t *buf_2 = heap_caps_aligned_calloc(64, buf_2_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM);
|
||||
TEST_ASSERT_NOT_NULL(buf_2);
|
||||
|
||||
// Register two PPA SRM clients with different max_pending_trans_num
|
||||
ppa_client_handle_t ppa_client_a_handle;
|
||||
ppa_client_handle_t ppa_client_b_handle;
|
||||
ppa_client_config_t ppa_client_config = {
|
||||
.oper_type = PPA_OPERATION_SRM,
|
||||
};
|
||||
TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_a_handle));
|
||||
ppa_client_config.max_pending_trans_num = 3;
|
||||
TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_b_handle));
|
||||
|
||||
ppa_event_callbacks_t cbs = {
|
||||
.on_trans_done = ppa_trans_done_cb,
|
||||
};
|
||||
ppa_client_register_event_callbacks(ppa_client_a_handle, &cbs);
|
||||
|
||||
SemaphoreHandle_t sem = xSemaphoreCreateBinary();
|
||||
|
||||
ppa_srm_oper_config_t oper_config = {
|
||||
.in.buffer = buf_1,
|
||||
.in.pic_w = w,
|
||||
.in.pic_h = h,
|
||||
.in.block_w = w,
|
||||
.in.block_h = h,
|
||||
.in.block_offset_x = 0,
|
||||
.in.block_offset_y = 0,
|
||||
.in.srm_cm = buf_1_color_type_id,
|
||||
|
||||
.out.buffer = buf_2,
|
||||
.out.buffer_size = buf_2_size,
|
||||
.out.pic_w = w,
|
||||
.out.pic_h = h,
|
||||
.out.block_offset_x = 0,
|
||||
.out.block_offset_y = 0,
|
||||
.out.srm_cm = buf_2_color_type_id,
|
||||
|
||||
.rotation_angle = PPA_SRM_ROTATION_ANGLE_0,
|
||||
.scale_x = 1.0,
|
||||
.scale_y = 1.0,
|
||||
|
||||
.user_data = (void *)sem,
|
||||
.mode = PPA_TRANS_MODE_NON_BLOCKING,
|
||||
};
|
||||
TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_a_handle, &oper_config));
|
||||
|
||||
// Another transaction cannot be accept since client_a can only hold one transaction
|
||||
TEST_ESP_ERR(ESP_FAIL, ppa_do_scale_rotate_mirror(ppa_client_a_handle, &oper_config));
|
||||
|
||||
// Wait for the last transaction finishes
|
||||
xSemaphoreTake(sem, portMAX_DELAY);
|
||||
// Then a new transaction can be accepted again
|
||||
TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_a_handle, &oper_config));
|
||||
|
||||
// Client can not be unregistered when there are unfinished transactions
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, ppa_unregister_client(ppa_client_a_handle));
|
||||
|
||||
oper_config.mode = PPA_TRANS_MODE_BLOCKING;
|
||||
TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_b_handle, &oper_config));
|
||||
// Every PPA engine can only process one operation at a time
|
||||
// Transactions are being processed with First-In-First-Out
|
||||
// So, at the moment, the new transaction requested by client_b has finished, the last transaction requested by client_a for sure has finished
|
||||
TEST_ASSERT(xSemaphoreTake(sem, 0) == pdTRUE);
|
||||
// client_b can accept more than one transactions
|
||||
oper_config.mode = PPA_TRANS_MODE_NON_BLOCKING;
|
||||
TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_b_handle, &oper_config));
|
||||
TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_b_handle, &oper_config));
|
||||
oper_config.mode = PPA_TRANS_MODE_BLOCKING;
|
||||
TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_b_handle, &oper_config));
|
||||
// The last transaction requested is with BLOCKING mode, so the last call to ppa_do_scale_rotate_mirror returned means all transactions finished
|
||||
|
||||
// Unregister all PPA clients
|
||||
TEST_ESP_OK(ppa_unregister_client(ppa_client_a_handle));
|
||||
TEST_ESP_OK(ppa_unregister_client(ppa_client_b_handle));
|
||||
|
||||
vSemaphoreDelete(sem);
|
||||
free(buf_1);
|
||||
free(buf_2);
|
||||
}
|
||||
|
||||
TEST_CASE("ppa_srm_performance", "[PPA][ignore]")
|
||||
{
|
||||
const uint32_t w = 1920; // 1920 / 1280 / 800 / 640
|
||||
const uint32_t h = 1080; // 1080 / 720 / 480
|
||||
const uint32_t block_w = w;
|
||||
const uint32_t block_h = h;
|
||||
const ppa_srm_color_mode_t in_cm = PPA_SRM_COLOR_MODE_ARGB8888;
|
||||
const ppa_srm_color_mode_t out_cm = PPA_SRM_COLOR_MODE_YUV420;
|
||||
const ppa_srm_rotation_angle_t rotation = PPA_SRM_ROTATION_ANGLE_0;
|
||||
const float scale_x = 1.0;
|
||||
const float scale_y = 1.0;
|
||||
|
||||
color_space_pixel_format_t in_pixel_format = {
|
||||
.color_type_id = in_cm,
|
||||
};
|
||||
color_space_pixel_format_t out_pixel_format = {
|
||||
.color_type_id = out_cm,
|
||||
};
|
||||
|
||||
uint32_t in_buf_size = w * h * color_hal_pixel_format_get_bit_depth(in_pixel_format) / 8;
|
||||
uint32_t out_buf_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(out_pixel_format) / 8, 64);
|
||||
uint8_t *out_buf = heap_caps_aligned_calloc(64, out_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM);
|
||||
TEST_ASSERT_NOT_NULL(out_buf);
|
||||
uint8_t *in_buf = heap_caps_aligned_calloc(64, in_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM);
|
||||
TEST_ASSERT_NOT_NULL(in_buf);
|
||||
|
||||
uint8_t *ptr = in_buf;
|
||||
for (int x = 0; x < in_buf_size; x++) {
|
||||
ptr[x] = x;
|
||||
}
|
||||
|
||||
ppa_client_handle_t ppa_client_handle;
|
||||
ppa_client_config_t ppa_client_config = {
|
||||
.oper_type = PPA_OPERATION_SRM,
|
||||
.max_pending_trans_num = 1,
|
||||
};
|
||||
TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_handle));
|
||||
|
||||
uint32_t out_pic_w = (rotation == PPA_SRM_ROTATION_ANGLE_0 || rotation == PPA_SRM_ROTATION_ANGLE_180) ? w : h;
|
||||
uint32_t out_pic_h = (rotation == PPA_SRM_ROTATION_ANGLE_0 || rotation == PPA_SRM_ROTATION_ANGLE_180) ? h : w;
|
||||
ppa_srm_oper_config_t oper_config = {
|
||||
.in.buffer = in_buf,
|
||||
.in.pic_w = w,
|
||||
.in.pic_h = h,
|
||||
.in.block_w = block_w,
|
||||
.in.block_h = block_h,
|
||||
.in.block_offset_x = 0,
|
||||
.in.block_offset_y = 0,
|
||||
.in.srm_cm = in_cm,
|
||||
|
||||
.out.buffer = out_buf,
|
||||
.out.buffer_size = out_buf_size,
|
||||
.out.pic_w = out_pic_w,
|
||||
.out.pic_h = out_pic_h,
|
||||
.out.block_offset_x = 0,
|
||||
.out.block_offset_y = 0,
|
||||
.out.srm_cm = out_cm,
|
||||
|
||||
.rotation_angle = rotation,
|
||||
.scale_x = scale_x,
|
||||
.scale_y = scale_y,
|
||||
|
||||
.rgb_swap = 0,
|
||||
.byte_swap = 0,
|
||||
|
||||
.mode = PPA_TRANS_MODE_BLOCKING,
|
||||
};
|
||||
|
||||
ccomp_timer_start();
|
||||
|
||||
TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_handle, &oper_config));
|
||||
|
||||
int64_t oper_time = ccomp_timer_stop();
|
||||
printf("Time passed: %lld us\n", oper_time);
|
||||
|
||||
TEST_ESP_OK(ppa_unregister_client(ppa_client_handle));
|
||||
|
||||
free(in_buf);
|
||||
free(out_buf);
|
||||
}
|
||||
|
||||
TEST_CASE("ppa_blend_performance", "[PPA][ignore]")
|
||||
{
|
||||
const uint32_t w = 1280;
|
||||
const uint32_t h = 720;
|
||||
const uint32_t block_w = w;
|
||||
const uint32_t block_h = h;
|
||||
const ppa_blend_color_mode_t in_bg_cm = PPA_BLEND_COLOR_MODE_ARGB8888;
|
||||
const ppa_blend_color_mode_t in_fg_cm = PPA_BLEND_COLOR_MODE_ARGB8888;
|
||||
const ppa_blend_color_mode_t out_cm = PPA_BLEND_COLOR_MODE_ARGB8888;
|
||||
|
||||
color_space_pixel_format_t in_bg_pixel_format = {
|
||||
.color_type_id = in_bg_cm,
|
||||
};
|
||||
color_space_pixel_format_t in_fg_pixel_format = {
|
||||
.color_type_id = in_fg_cm,
|
||||
};
|
||||
color_space_pixel_format_t out_pixel_format = {
|
||||
.color_type_id = out_cm,
|
||||
};
|
||||
|
||||
uint32_t in_bg_buf_size = w * h * color_hal_pixel_format_get_bit_depth(in_bg_pixel_format) / 8;
|
||||
uint32_t in_fg_buf_size = w * h * color_hal_pixel_format_get_bit_depth(in_fg_pixel_format) / 8;
|
||||
uint32_t out_buf_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(out_pixel_format) / 8, 64);
|
||||
uint8_t *out_buf = heap_caps_aligned_calloc(64, out_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM);
|
||||
TEST_ASSERT_NOT_NULL(out_buf);
|
||||
uint8_t *in_bg_buf = heap_caps_aligned_calloc(64, in_bg_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM);
|
||||
TEST_ASSERT_NOT_NULL(in_bg_buf);
|
||||
uint8_t *in_fg_buf = heap_caps_aligned_calloc(64, in_fg_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM);
|
||||
TEST_ASSERT_NOT_NULL(in_fg_buf);
|
||||
|
||||
uint8_t *ptr = in_bg_buf;
|
||||
for (int x = 0; x < in_bg_buf_size; x++) {
|
||||
ptr[x] = x & 0x55;
|
||||
}
|
||||
ptr = in_fg_buf;
|
||||
for (int x = 0; x < in_fg_buf_size; x++) {
|
||||
ptr[x] = x & 0xAA;
|
||||
}
|
||||
|
||||
ppa_client_handle_t ppa_client_handle;
|
||||
ppa_client_config_t ppa_client_config = {
|
||||
.oper_type = PPA_OPERATION_BLEND,
|
||||
.max_pending_trans_num = 1,
|
||||
};
|
||||
TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_handle));
|
||||
|
||||
ppa_blend_oper_config_t oper_config = {
|
||||
.in_bg.buffer = in_bg_buf,
|
||||
.in_bg.pic_w = w,
|
||||
.in_bg.pic_h = h,
|
||||
.in_bg.block_w = block_w,
|
||||
.in_bg.block_h = block_h,
|
||||
.in_bg.block_offset_x = 0,
|
||||
.in_bg.block_offset_y = 0,
|
||||
.in_bg.blend_cm = in_bg_cm,
|
||||
|
||||
.in_fg.buffer = in_fg_buf,
|
||||
.in_fg.pic_w = w,
|
||||
.in_fg.pic_h = h,
|
||||
.in_fg.block_w = block_w,
|
||||
.in_fg.block_h = block_h,
|
||||
.in_fg.block_offset_x = 0,
|
||||
.in_fg.block_offset_y = 0,
|
||||
.in_fg.blend_cm = in_fg_cm,
|
||||
|
||||
.out.buffer = out_buf,
|
||||
.out.buffer_size = out_buf_size,
|
||||
.out.pic_w = w,
|
||||
.out.pic_h = h,
|
||||
.out.block_offset_x = 0,
|
||||
.out.block_offset_y = 0,
|
||||
.out.blend_cm = out_cm,
|
||||
|
||||
.bg_ck_en = false,
|
||||
.fg_ck_en = false,
|
||||
|
||||
.mode = PPA_TRANS_MODE_BLOCKING,
|
||||
};
|
||||
|
||||
ccomp_timer_start();
|
||||
|
||||
TEST_ESP_OK(ppa_do_blend(ppa_client_handle, &oper_config));
|
||||
|
||||
int64_t oper_time = ccomp_timer_stop();
|
||||
printf("Time passed: %lld us\n", oper_time);
|
||||
|
||||
TEST_ESP_OK(ppa_unregister_client(ppa_client_handle));
|
||||
|
||||
free(in_bg_buf);
|
||||
free(in_fg_buf);
|
||||
free(out_buf);
|
||||
}
|
||||
|
||||
TEST_CASE("ppa_fill_performance", "[PPA][ignore]")
|
||||
{
|
||||
const uint32_t w = 1280;
|
||||
const uint32_t h = 720;
|
||||
const uint32_t block_w = 800;
|
||||
const uint32_t block_h = 480;
|
||||
const ppa_fill_color_mode_t out_cm = PPA_FILL_COLOR_MODE_RGB565;
|
||||
|
||||
color_space_pixel_format_t out_pixel_format = {
|
||||
.color_type_id = out_cm,
|
||||
};
|
||||
|
||||
uint32_t out_buf_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(out_pixel_format) / 8, 64);
|
||||
uint8_t *out_buf = heap_caps_aligned_calloc(64, out_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM);
|
||||
TEST_ASSERT_NOT_NULL(out_buf);
|
||||
|
||||
ppa_client_handle_t ppa_client_handle;
|
||||
ppa_client_config_t ppa_client_config = {
|
||||
.oper_type = PPA_OPERATION_FILL,
|
||||
.max_pending_trans_num = 1,
|
||||
};
|
||||
TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_handle));
|
||||
|
||||
ppa_fill_oper_config_t oper_config = {
|
||||
.out.buffer = out_buf,
|
||||
.out.buffer_size = out_buf_size,
|
||||
.out.pic_w = w,
|
||||
.out.pic_h = h,
|
||||
.out.block_offset_x = 0,
|
||||
.out.block_offset_y = 0,
|
||||
.out.fill_cm = out_cm,
|
||||
|
||||
.fill_block_w = block_w,
|
||||
.fill_block_h = block_h,
|
||||
.fill_argb_color = {
|
||||
.val = 0xFF00FFFF,
|
||||
},
|
||||
|
||||
.mode = PPA_TRANS_MODE_BLOCKING,
|
||||
};
|
||||
|
||||
ccomp_timer_start();
|
||||
|
||||
TEST_ESP_OK(ppa_do_fill(ppa_client_handle, &oper_config));
|
||||
|
||||
int64_t oper_time = ccomp_timer_stop();
|
||||
printf("Time passed: %lld us\n", oper_time);
|
||||
|
||||
TEST_ESP_OK(ppa_unregister_client(ppa_client_handle));
|
||||
|
||||
free(out_buf);
|
||||
}
|
17
components/esp_driver_ppa/test_apps/pytest_ppa.py
Normal file
17
components/esp_driver_ppa/test_apps/pytest_ppa.py
Normal file
@ -0,0 +1,17 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'release',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_ppa(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases()
|
6
components/esp_driver_ppa/test_apps/sdkconfig.ci.release
Normal file
6
components/esp_driver_ppa/test_apps/sdkconfig.ci.release
Normal file
@ -0,0 +1,6 @@
|
||||
CONFIG_PM_ENABLE=y
|
||||
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||
CONFIG_PM_DFS_INIT_AUTO=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
3
components/esp_driver_ppa/test_apps/sdkconfig.defaults
Normal file
3
components/esp_driver_ppa/test_apps/sdkconfig.defaults
Normal file
@ -0,0 +1,3 @@
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
|
@ -0,0 +1,3 @@
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_MODE_HEX=y
|
||||
CONFIG_SPIRAM_SPEED_200M=y
|
@ -230,15 +230,15 @@ static inline void ppa_ll_srm_set_tx_color_mode(ppa_dev_t *dev, ppa_srm_color_mo
|
||||
* @brief Set YUV to RGB protocol when PPA SRM RX pixel color space is YUV
|
||||
*
|
||||
* @param dev Peripheral instance address
|
||||
* @param std One of the RGB-YUV conversion standards in color_conv_std_rgb_yuv_t
|
||||
* @param std One of the RGB-YUV conversion standards in ppa_color_conv_std_rgb_yuv_t
|
||||
*/
|
||||
static inline void ppa_ll_srm_set_rx_yuv2rgb_std(ppa_dev_t *dev, color_conv_std_rgb_yuv_t std)
|
||||
static inline void ppa_ll_srm_set_rx_yuv2rgb_std(ppa_dev_t *dev, ppa_color_conv_std_rgb_yuv_t std)
|
||||
{
|
||||
switch (std) {
|
||||
case COLOR_CONV_STD_RGB_YUV_BT601:
|
||||
case PPA_COLOR_CONV_STD_RGB_YUV_BT601:
|
||||
dev->sr_color_mode.yuv2rgb_protocol = 0;
|
||||
break;
|
||||
case COLOR_CONV_STD_RGB_YUV_BT709:
|
||||
case PPA_COLOR_CONV_STD_RGB_YUV_BT709:
|
||||
dev->sr_color_mode.yuv2rgb_protocol = 1;
|
||||
break;
|
||||
default:
|
||||
@ -251,15 +251,15 @@ static inline void ppa_ll_srm_set_rx_yuv2rgb_std(ppa_dev_t *dev, color_conv_std_
|
||||
* @brief Set RGB to YUV protocol when PPA SRM TX pixel color space is YUV
|
||||
*
|
||||
* @param dev Peripheral instance address
|
||||
* @param std One of the RGB-YUV conversion standards in color_conv_std_rgb_yuv_t
|
||||
* @param std One of the RGB-YUV conversion standards in ppa_color_conv_std_rgb_yuv_t
|
||||
*/
|
||||
static inline void ppa_ll_srm_set_tx_rgb2yuv_std(ppa_dev_t *dev, color_conv_std_rgb_yuv_t std)
|
||||
static inline void ppa_ll_srm_set_tx_rgb2yuv_std(ppa_dev_t *dev, ppa_color_conv_std_rgb_yuv_t std)
|
||||
{
|
||||
switch (std) {
|
||||
case COLOR_CONV_STD_RGB_YUV_BT601:
|
||||
case PPA_COLOR_CONV_STD_RGB_YUV_BT601:
|
||||
dev->sr_color_mode.rgb2yuv_protocol = 0;
|
||||
break;
|
||||
case COLOR_CONV_STD_RGB_YUV_BT709:
|
||||
case PPA_COLOR_CONV_STD_RGB_YUV_BT709:
|
||||
dev->sr_color_mode.rgb2yuv_protocol = 1;
|
||||
break;
|
||||
default:
|
||||
@ -272,15 +272,15 @@ static inline void ppa_ll_srm_set_tx_rgb2yuv_std(ppa_dev_t *dev, color_conv_std_
|
||||
* @brief Set PPA SRM YUV input range
|
||||
*
|
||||
* @param dev Peripheral instance address
|
||||
* @param range One of color range options in color_range_t
|
||||
* @param range One of color range options in ppa_color_range_t
|
||||
*/
|
||||
static inline void ppa_ll_srm_set_rx_yuv_range(ppa_dev_t *dev, color_range_t range)
|
||||
static inline void ppa_ll_srm_set_rx_yuv_range(ppa_dev_t *dev, ppa_color_range_t range)
|
||||
{
|
||||
switch (range) {
|
||||
case COLOR_RANGE_LIMIT:
|
||||
case PPA_COLOR_RANGE_LIMIT:
|
||||
dev->sr_color_mode.yuv_rx_range = 0;
|
||||
break;
|
||||
case COLOR_RANGE_FULL:
|
||||
case PPA_COLOR_RANGE_FULL:
|
||||
dev->sr_color_mode.yuv_rx_range = 1;
|
||||
break;
|
||||
default:
|
||||
@ -293,15 +293,15 @@ static inline void ppa_ll_srm_set_rx_yuv_range(ppa_dev_t *dev, color_range_t ran
|
||||
* @brief Set PPA SRM YUV output range
|
||||
*
|
||||
* @param dev Peripheral instance address
|
||||
* @param range One of color range options in color_range_t
|
||||
* @param range One of color range options in ppa_color_range_t
|
||||
*/
|
||||
static inline void ppa_ll_srm_set_tx_yuv_range(ppa_dev_t *dev, color_range_t range)
|
||||
static inline void ppa_ll_srm_set_tx_yuv_range(ppa_dev_t *dev, ppa_color_range_t range)
|
||||
{
|
||||
switch (range) {
|
||||
case COLOR_RANGE_LIMIT:
|
||||
case PPA_COLOR_RANGE_LIMIT:
|
||||
dev->sr_color_mode.yuv_tx_range = 0;
|
||||
break;
|
||||
case COLOR_RANGE_FULL:
|
||||
case PPA_COLOR_RANGE_FULL:
|
||||
dev->sr_color_mode.yuv_tx_range = 1;
|
||||
break;
|
||||
default:
|
||||
@ -643,10 +643,10 @@ static inline void ppa_ll_blend_configure_rx_fg_alpha(ppa_dev_t *dev, ppa_alpha_
|
||||
* @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, uint32_t data, uint32_t hb, uint32_t vb)
|
||||
static inline void ppa_ll_blend_configure_filling_block(ppa_dev_t *dev, color_pixel_argb8888_data_t *data, uint32_t hb, uint32_t vb)
|
||||
{
|
||||
HAL_ASSERT(hb <= PPA_BLEND_HB_V && vb <= PPA_BLEND_VB_V);
|
||||
dev->blend_fix_pixel.blend_tx_fix_pixel = data;
|
||||
dev->blend_fix_pixel.blend_tx_fix_pixel = data->val;
|
||||
dev->blend_tx_size.blend_hb = hb;
|
||||
dev->blend_tx_size.blend_vb = vb;
|
||||
}
|
||||
@ -657,9 +657,11 @@ static inline void ppa_ll_blend_configure_filling_block(ppa_dev_t *dev, uint32_t
|
||||
* @param dev Peripheral instance address
|
||||
* @param rgb RGB color for A4/A8 mode in RGB888 format
|
||||
*/
|
||||
static inline void ppa_ll_blend_set_rx_fg_fix_rgb(ppa_dev_t *dev, uint32_t rgb)
|
||||
static inline void ppa_ll_blend_set_rx_fg_fix_rgb(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb)
|
||||
{
|
||||
dev->blend_rgb.val = rgb;
|
||||
dev->blend_rgb.blend1_rx_b = rgb->b;
|
||||
dev->blend_rgb.blend1_rx_g = rgb->g;
|
||||
dev->blend_rgb.blend1_rx_r = rgb->r;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -150,6 +150,44 @@ typedef enum {
|
||||
COLOR_RGB_ELEMENT_ORDER_BGR, /*!< RGB element order: BGR */
|
||||
} color_rgb_element_order_t;
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Data Structure for Color Pixel Unit
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Data structure for ARGB8888 pixel unit
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t b: 8; /*!< B component [0, 255] */
|
||||
uint32_t g: 8; /*!< G component [0, 255] */
|
||||
uint32_t r: 8; /*!< R component [0, 255] */
|
||||
uint32_t a: 8; /*!< A component [0, 255] */
|
||||
};
|
||||
uint32_t val; /*!< 32-bit ARGB8888 value */
|
||||
} color_pixel_argb8888_data_t;
|
||||
|
||||
/**
|
||||
* @brief Data structure for RGB888 pixel unit
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t b; /*!< B component [0, 255] */
|
||||
uint8_t g; /*!< G component [0, 255] */
|
||||
uint8_t r; /*!< R component [0, 255] */
|
||||
} color_pixel_rgb888_data_t;
|
||||
|
||||
/**
|
||||
* @brief Data structure for RGB565 pixel unit
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
uint16_t b: 5; /*!< B component [0, 31] */
|
||||
uint16_t g: 6; /*!< G component [0, 63] */
|
||||
uint16_t r: 5; /*!< R component [0, 31] */
|
||||
};
|
||||
uint16_t val; /*!< 16-bit RGB565 value */
|
||||
} color_pixel_rgb565_data_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -81,6 +81,22 @@ typedef enum {
|
||||
If input format does not contain alpha info, A' = 0, i.e. a layer with 0% opacity. */
|
||||
} ppa_alpha_update_mode_t;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of PPA supported color conversion standard between RGB and YUV (determines the YUV<->RGB conversion equation)
|
||||
*/
|
||||
typedef enum {
|
||||
PPA_COLOR_CONV_STD_RGB_YUV_BT601 = COLOR_CONV_STD_RGB_YUV_BT601, /*!< YUV<->RGB conversion standard: BT.601 */
|
||||
PPA_COLOR_CONV_STD_RGB_YUV_BT709 = COLOR_CONV_STD_RGB_YUV_BT709, /*!< YUV<->RGB conversion standard: BT.709 */
|
||||
} ppa_color_conv_std_rgb_yuv_t;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of PPA supported color range (determines the YUV<->RGB conversion equation)
|
||||
*/
|
||||
typedef enum {
|
||||
PPA_COLOR_RANGE_LIMIT = COLOR_RANGE_LIMIT, /*!< Limited color range, 16 is the darkest black and 235 is the brightest white */
|
||||
PPA_COLOR_RANGE_FULL = COLOR_RANGE_FULL, /*!< Full color range, 0 is the darkest black and 255 is the brightest white */
|
||||
} ppa_color_range_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
BIN
docs/_static/diagrams/ppa/pic_blk_concept.png
vendored
Normal file
BIN
docs/_static/diagrams/ppa/pic_blk_concept.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
@ -176,6 +176,8 @@ SPI_SLAVE_HD_DOCS = ['api-reference/peripherals/spi_slave_hd.rst']
|
||||
|
||||
JPEG_DOCS = ['api-reference/peripherals/jpeg.rst']
|
||||
|
||||
PPA_DOCS = ['api-reference/peripherals/ppa.rst']
|
||||
|
||||
QEMU_DOCS = ['api-guides/tools/qemu.rst']
|
||||
|
||||
ESP32_DOCS = ['api-reference/system/himem.rst',
|
||||
@ -278,6 +280,7 @@ conditional_include_dict = {'SOC_BT_SUPPORTED':BT_DOCS,
|
||||
'SOC_SPI_SUPPORT_SLAVE_HD_VER2':SPI_SLAVE_HD_DOCS,
|
||||
'SOC_WIFI_NAN_SUPPORT':NAN_DOCS,
|
||||
'SOC_JPEG_CODEC_SUPPORTED':JPEG_DOCS,
|
||||
'SOC_PPA_SUPPORTED':PPA_DOCS,
|
||||
'SOC_GP_LDO_SUPPORTED':LDO_DOCS,
|
||||
'esp32':ESP32_DOCS,
|
||||
'esp32s2':ESP32S2_DOCS,
|
||||
|
@ -17,12 +17,14 @@ INPUT += \
|
||||
$(PROJECT_PATH)/components/esp_driver_cam/include/esp_cam_ctlr_types.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_cam/csi/include/esp_cam_ctlr_csi.h \
|
||||
$(PROJECT_PATH)/components/hal/include/hal/jpeg_types.h \
|
||||
$(PROJECT_PATH)/components/hal/include/hal/ppa_types.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_types.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_types.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_af.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_decode.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_encode.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_ppa/include/driver/ppa.h \
|
||||
$(PROJECT_PATH)/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h \
|
||||
$(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/adc_channel.h \
|
||||
$(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/clk_tree_defs.h \
|
||||
|
@ -30,6 +30,7 @@ Peripherals API
|
||||
:SOC_MCPWM_SUPPORTED: mcpwm
|
||||
:SOC_PARLIO_SUPPORTED: parlio
|
||||
:SOC_PCNT_SUPPORTED: pcnt
|
||||
:SOC_PPA_SUPPORTED: ppa
|
||||
:SOC_RMT_SUPPORTED: rmt
|
||||
:SOC_SDMMC_HOST_SUPPORTED or SOC_SDIO_SLAVE_SUPPORTED: sd_pullup_requirements
|
||||
:SOC_SDMMC_HOST_SUPPORTED: sdmmc_host
|
||||
|
149
docs/en/api-reference/peripherals/ppa.rst
Normal file
149
docs/en/api-reference/peripherals/ppa.rst
Normal file
@ -0,0 +1,149 @@
|
||||
Pixel-Processing Accelerator (PPA)
|
||||
==================================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
{IDF_TARGET_NAME} includes a pixel-processing accelerator (PPA) module, to realize hardware-level acceleration of image algorithms, such as image rotation, scaling, mirroring, and blending.
|
||||
|
||||
Terminology
|
||||
-----------
|
||||
|
||||
The terms used in relation to the PPA driver are given in the table and the diagram below.
|
||||
|
||||
.. list-table::
|
||||
:widths: 25 75
|
||||
:header-rows: 1
|
||||
|
||||
* - Term
|
||||
- Definition
|
||||
* - Picture (pic)
|
||||
- A complete image stored in the system memory.
|
||||
* - Block
|
||||
- A portion cropped from a picture at a certain size, with the maximum size equivalent to the entire picture.
|
||||
* - Pixel
|
||||
- The unit to be used in the PPA context.
|
||||
* - PPA Operation
|
||||
- Types of image algorithm accelerations, includes scale-rotate-mirror (SRM), blend, and fill.
|
||||
* - PPA Client
|
||||
- Who wants to do the PPA operations. Typically, every PPA client is hold by a specific task.
|
||||
* - PPA Transaction
|
||||
- One request from a PPA client to do a PPA operation is one PPA transaction.
|
||||
|
||||
.. figure:: ../../../_static/diagrams/ppa/pic_blk_concept.png
|
||||
:align: center
|
||||
:alt: PPA picture/block terminology
|
||||
|
||||
PPA picture/block terminology
|
||||
|
||||
Functional Overview
|
||||
-------------------
|
||||
|
||||
The following sections detail the design of the PPA driver:
|
||||
|
||||
- :ref:`ppa-client-registration` - Covers how to register a PPA client to perform any PPA operations.
|
||||
- :ref:`ppa-register-callback` - Covers how to hook user specific code to PPA driver event callback function.
|
||||
- :ref:`ppa-perform-operation` - Covers how to perform a PPA operation.
|
||||
- :ref:`ppa-thread-safety` - Covers the usage of the PPA operation APIs in thread safety aspect.
|
||||
- :ref:`ppa-performance-overview` - Covers the performance of PPA operations.
|
||||
|
||||
.. _ppa-client-registration:
|
||||
|
||||
Register PPA Client
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Requests to perform PPA operations are made by PPA clients. Therefore, PPA clients need to be registered first before doing any PPA operations. Call :cpp:func:`ppa_register_client` function to register a new client. :cpp:type:`ppa_client_config_t` structure is used to specific the properties of the client.
|
||||
|
||||
- :cpp:member:`ppa_client_config_t::oper_type` - Each PPA operation type corresponds to one PPA client type, a registered PPA client can only request one specific type of PPA operations.
|
||||
- :cpp:member:`ppa_client_config_t::max_pending_trans_num` - Decides the maximum number of pending PPA transactions the client can hold.
|
||||
|
||||
It is recommended that every task to register its own PPA clients. For example, an application contains two tasks: Task A requires both the PPA SRM and the PPA fill functionalities, so one PPA SRM client and one PPA fill client should be registered in Task A; While Task B also requires the PPA SRM functionality, then another PPA SRM client should be registered in Task B.
|
||||
|
||||
If the task no longer needs to do PPA operations, the corresponding PPA clients can be deregistered with :cpp:func:`ppa_unregister_client` function.
|
||||
|
||||
.. _ppa-register-callback:
|
||||
|
||||
Register PPA Event Callbacks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When an event occurs (e.g., a PPA transaction is completed), the CPU is notified of this event via an interrupt. If some specific functions need to be called when a particular event occurs, a callback can be registered for that event by calling :cpp:func:`ppa_client_register_event_callbacks`. This can be specifically useful when ``PPA_TRANS_MODE_NON_BLOCKING`` mode is selected to perform the PPA operations. It is worth noticing that the event callbacks are bound to PPA clients, but the user context is provided per transaction in the call to the PPA operation APIs. This allows the maximum flexibility in utilizing the event callbacks.
|
||||
|
||||
The registered callback functions are called in the interrupt context, therefore, the callback functions should follow common ISR (Interrupt Service Routine) rules.
|
||||
|
||||
.. _ppa-perform-operation:
|
||||
|
||||
Perform PPA Operations
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Once the PPA client is registered, a PPA operation can be requested with the returned :cpp:type:`ppa_client_handle_t`.
|
||||
|
||||
PPA operations includes:
|
||||
|
||||
Scale, Rotate, Mirror (SRM)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Call :cpp:func:`ppa_do_scale_rotate_mirror` to apply one or more of the scaling, rotation, mirroring operations to the target block inside a picture.
|
||||
|
||||
Some notes to avoid confusion in configuring :cpp:type:`ppa_srm_oper_config_t`:
|
||||
|
||||
.. list::
|
||||
- :cpp:member:`ppa_in_pic_blk_config_t::buffer` and :cpp:member:`ppa_out_pic_blk_config_t::buffer` have to be the pointers to different picture buffers for a SRM operation.
|
||||
- The precision of :cpp:member:`ppa_srm_oper_config_t::scale_x` and :cpp:member:`ppa_srm_oper_config_t::scale_y` will be truncated to a step size of 1/16.
|
||||
- Output block's width/height is totally determined by the input block's width/height, scaling factor, and rotation angle, so output block's width/height does not need to be configured. However, please make sure the output block can fit at the offset location in the output picture.
|
||||
- If the color mode of the input or output picture is ``PPA_SRM_COLOR_MODE_YUV420``, then its ``pic_w``, ``pic_h``, ``block_w``, ``block_h``, ``block_offset_x``, ``block_offset_y`` fields must be even.
|
||||
|
||||
Blend
|
||||
~~~~~
|
||||
|
||||
Call :cpp:func:`ppa_do_blend` to blend the two target blocks of two so-called foreground (FG) and background (BG) pictures.
|
||||
|
||||
Blend follows the normal Alpha Blending formula:
|
||||
|
||||
:math:`A_{out} = A_b + A_f - A_b \times A_f`
|
||||
|
||||
:math:`C_{out} = (C_b \times A_b \times (1 - A_f) + C_f \times A_f) / (A_b + A_f - A_b \times A_f)`
|
||||
|
||||
where :math:`A_b` is the Alpha channel of the background layer, :math:`A_f` is the Alpha channel of the foreground layer, :math:`C_b` corresponds to the R, G, B components of the background layer, and :math:`C_f` corresponds to the R, G, B components of the foreground layer.
|
||||
|
||||
Note that this formula is not symmetric to FG and BG. When :math:`A_f = 1`, it calculates :math:`C_{out} = C_f`, :math:`A_{out} = 1`, which means if the color mode of the FG picture is ``PPA_BLEND_COLOR_MODE_RGB565`` or ``PPA_BLEND_COLOR_MODE_RGB888``, since a Alpha value of 255 will be filled by the PPA hardware (i.e. :math:`A_f = 1`), the blended result will be identical to the FG block.
|
||||
|
||||
If :cpp:member:`ppa_blend_oper_config_t::bg_ck_en` or :cpp:member:`ppa_blend_oper_config_t::fg_ck_en` is set to ``true``, the pixels fall into the color-key (also known as Chroma-key) range does not follow Alpha Blending process. Please check **{IDF_TARGET_NAME} Technical Reference Manual** > **Pixel-Processing Accelerator (PPA)** > **Functional Description** > **Layer Blending (BLEND)** [`PDF <{IDF_TARGET_TRM_EN_URL}#ppa>`__] for the detailed rules.
|
||||
|
||||
Similarly, some notes to avoid confusion in configuring :cpp:type:`ppa_blend_oper_config_t`:
|
||||
|
||||
.. list::
|
||||
- :cpp:member:`ppa_out_pic_blk_config_t::buffer` can be the same pointer to one of the input's :cpp:member:`ppa_in_pic_blk_config_t::buffer` for a blend operation.
|
||||
- The blocks' width/height of FG and BG should be identical, and are the width/height values for the output block.
|
||||
- If the color mode of the input picture is ``PPA_BLEND_COLOR_MODE_A4`` or ``PPA_BLEND_COLOR_MODE_L4``, then its ``block_w`` and ``block_offset_x`` fields must be even.
|
||||
|
||||
Fill
|
||||
~~~~
|
||||
|
||||
Call :cpp:func:`ppa_do_fill` to fill a target block inside a picture.
|
||||
|
||||
:cpp:type:`ppa_trans_mode_t` is a field configurable to all the PPA operation APIs. It decides whether you want the call to the PPA operation API to block until the transaction finishes or to return immediately after the transaction is pushed to the internal queue.
|
||||
|
||||
.. _ppa-thread-safety:
|
||||
|
||||
Thread Safety
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
The PPA driver has guaranteed the thread safety of calling the PPA operation APIs in all following situations:
|
||||
|
||||
.. list::
|
||||
- Among clients of different types in one task
|
||||
- Among clients of same type in different tasks
|
||||
- Among clients of different types in different tasks
|
||||
|
||||
.. _ppa-performance-overview:
|
||||
|
||||
Performance Overview
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The PPA operations are acted on the target block of an input picture. Therefore, the time it takes to complete a PPA transaction is proportional to the amount of the data of the block. The size of the entire picture has no influence on the performance. More importantly, the PPA performance highly relies on the PSRAM bandwidth if the pictures are located in the PSRAM section. When there are quite a few peripherals reading and writing to the PSRAM at the same time, the performance of PPA operation will be greatly reduced.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/ppa.inc
|
||||
.. include-build-file:: inc/ppa_types.inc
|
@ -29,6 +29,7 @@
|
||||
:SOC_MCPWM_SUPPORTED: mcpwm
|
||||
:SOC_PARLIO_SUPPORTED: parlio
|
||||
:SOC_PCNT_SUPPORTED: pcnt
|
||||
:SOC_PPA_SUPPORTED: ppa
|
||||
:SOC_RMT_SUPPORTED: rmt
|
||||
:SOC_SDMMC_HOST_SUPPORTED or SOC_SDIO_SLAVE_SUPPORTED: sd_pullup_requirements
|
||||
:SOC_SDMMC_HOST_SUPPORTED: sdmmc_host
|
||||
|
1
docs/zh_CN/api-reference/peripherals/ppa.rst
Normal file
1
docs/zh_CN/api-reference/peripherals/ppa.rst
Normal file
@ -0,0 +1 @@
|
||||
.. include:: ../../../en/api-reference/peripherals/ppa.rst
|
Loading…
x
Reference in New Issue
Block a user