diff --git a/components/esp_driver_jpeg/test_apps/.build-test-rules.yml b/components/esp_driver_jpeg/test_apps/.build-test-rules.yml new file mode 100644 index 0000000000..e3c04dbafc --- /dev/null +++ b/components/esp_driver_jpeg/test_apps/.build-test-rules.yml @@ -0,0 +1,7 @@ +# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps + +components/esp_driver_jpeg/test_apps/jpeg_test_apps: + disable: + - if: SOC_JPEG_CODEC_SUPPORTED != 1 + depends_components: + - esp_driver_jpeg diff --git a/components/esp_driver_jpeg/test_apps/jpeg_test_apps/CMakeLists.txt b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/CMakeLists.txt new file mode 100644 index 0000000000..51ee562b69 --- /dev/null +++ b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/CMakeLists.txt @@ -0,0 +1,13 @@ +# This is the project CMakeLists.txt file for the test subproject +cmake_minimum_required(VERSION 3.16) + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + +set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(jpeg_test) + +target_add_binary_data(jpeg_test.elf "${IDF_PATH}/examples/peripherals/jpeg/jpeg_decode/resources/esp720.jpg" BINARY) +target_add_binary_data(jpeg_test.elf "${IDF_PATH}/examples/peripherals/jpeg/jpeg_decode/resources/esp1080.jpg" BINARY) diff --git a/components/esp_driver_jpeg/test_apps/jpeg_test_apps/README.md b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/README.md new file mode 100644 index 0000000000..6373a3ce6f --- /dev/null +++ b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32-P4 | +| ----------------- | -------- | diff --git a/components/esp_driver_jpeg/test_apps/jpeg_test_apps/main/CMakeLists.txt b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/main/CMakeLists.txt new file mode 100644 index 0000000000..b654cb7197 --- /dev/null +++ b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/main/CMakeLists.txt @@ -0,0 +1,7 @@ +set(srcs "test_app_main.c" + "test_jpeg_decode.c" + ) + +idf_component_register(SRCS ${srcs} + PRIV_REQUIRES esp_driver_jpeg unity esp_psram test_utils + WHOLE_ARCHIVE) diff --git a/components/esp_driver_jpeg/test_apps/jpeg_test_apps/main/idf_component.yml b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/main/idf_component.yml new file mode 100644 index 0000000000..2ae836a935 --- /dev/null +++ b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/main/idf_component.yml @@ -0,0 +1,2 @@ +dependencies: + ccomp_timer: "^1.0.0" diff --git a/components/esp_driver_jpeg/test_apps/jpeg_test_apps/main/test_app_main.c b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/main/test_app_main.c new file mode 100644 index 0000000000..0864b60cda --- /dev/null +++ b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/main/test_app_main.c @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "unity.h" +#include "unity_test_runner.h" +#include "unity_test_utils_memory.h" +#include "esp_heap_caps.h" + +// Some resources are lazy allocated in JPEG driver, so we reserved this threshold when checking memory leak +// A better way to check a potential memory leak is running a same case by twice, for the second time, the memory usage delta should be zero +#define LEAKS (400) + +void setUp(void) +{ + unity_utils_record_free_mem(); +} + +void tearDown(void) +{ + unity_utils_evaluate_leaks_direct(LEAKS); +} + +void app_main(void) +{ + // _ ____ _____ ____ _____ _____ ____ _____ + // | | _ \| ____/ ___| |_ _| ____/ ___|_ _| + // _ | | |_) | _|| | _ | | | _| \___ \ | | + // | |_| | __/| |__| |_| | | | | |___ ___) || | + // \___/|_| |_____\____| |_| |_____|____/ |_| + + printf(" _ ____ _____ ____ _____ _____ ____ _____ \n"); + printf(" | | _ \\| ____/ ___| |_ _| ____/ ___|_ _|\n"); + printf(" _ | | |_) | _|| | _ | | | _| \\___ \\ | | \n"); + printf("| |_| | __/| |__| |_| | | | | |___ ___) || | \n"); + printf(" \\___/|_| |_____\\____| |_| |_____|____/ |_| \n"); + + unity_run_menu(); +} diff --git a/components/esp_driver_jpeg/test_apps/jpeg_test_apps/main/test_jpeg_decode.c b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/main/test_jpeg_decode.c new file mode 100644 index 0000000000..d450d5d149 --- /dev/null +++ b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/main/test_jpeg_decode.c @@ -0,0 +1,77 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#include "sdkconfig.h" +#include "unity.h" +#include "test_utils.h" +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "esp_private/periph_ctrl.h" +#include "driver/jpeg_decode.h" +#include "esp_log.h" +#include "test_jpeg_performance.h" +#include "esp_system.h" +#include "ccomp_timer.h" + +extern const uint8_t image_esp1080_jpg_start[] asm("_binary_esp1080_jpg_start"); +extern const uint8_t image_esp1080_jpg_end[] asm("_binary_esp1080_jpg_end"); + +TEST_CASE("JPEG decode driver memory leaking check", "[jpeg]") +{ + jpeg_decoder_handle_t jpgd_handle; + + jpeg_decode_engine_cfg_t decode_eng_cfg = { + }; + + int size = esp_get_free_heap_size(); + for (uint32_t i = 0; i <= 5; i++) { + TEST_ESP_OK(jpeg_new_decoder_engine(&decode_eng_cfg, &jpgd_handle)); + vTaskDelay(10 / portTICK_PERIOD_MS); + TEST_ESP_OK(jpeg_del_decoder_engine(jpgd_handle)); + } + + TEST_ASSERT_INT_WITHIN(400, size, esp_get_free_heap_size()); +} + +TEST_CASE("JPEG decode performance test for 1080*1920 YUV->RGB picture", "[jpeg]") +{ + jpeg_decoder_handle_t jpgd_handle; + + jpeg_decode_engine_cfg_t decode_eng_cfg = { + .intr_priority = 0, + }; + + jpeg_decode_cfg_t decode_cfg = { + .output_format = JPEG_DECODE_OUT_FORMAT_RGB565, + }; + + uint8_t *rx_buf_1080p = (uint8_t*)jpeg_alloc_decoder_mem(1080 * 1920 * 3); + uint32_t out_size_1080p = 0; + + size_t bit_stream_length = (size_t)image_esp1080_jpg_end - (size_t)image_esp1080_jpg_start; + + uint8_t *tx_buf_1080p = (uint8_t*)jpeg_alloc_decoder_mem(bit_stream_length); + // Copy bit stream to psram + memcpy(tx_buf_1080p, image_esp1080_jpg_start, bit_stream_length); + TEST_ESP_OK(jpeg_new_decoder_engine(&decode_eng_cfg, &jpgd_handle)); + + ccomp_timer_start(); + + // Decode picture for 50 times, and get the average + uint8_t cnt = 50; + for (int i = 0; i < cnt; i++) { + TEST_ESP_OK(jpeg_decoder_process(jpgd_handle, &decode_cfg, tx_buf_1080p, bit_stream_length, rx_buf_1080p, &out_size_1080p)); + } + int64_t decode_time = ccomp_timer_stop(); + + TEST_PERFORMANCE_GREATER_THAN(JPEG_DECODE_1080P_2_RGB565_PERFORMANCE, "1080p from *jpg -> rgb565 speed is %lld fps", 1 * 1000 * 1000 / (decode_time / cnt)); + + free(rx_buf_1080p); + free(tx_buf_1080p); + TEST_ESP_OK(jpeg_del_decoder_engine(jpgd_handle)); +} diff --git a/components/esp_driver_jpeg/test_apps/jpeg_test_apps/main/test_jpeg_performance.h b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/main/test_jpeg_performance.h new file mode 100644 index 0000000000..5d597dcbae --- /dev/null +++ b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/main/test_jpeg_performance.h @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define IDF_PERFORMANCE_MIN_JPEG_DECODE_1080P_2_RGB565_PERFORMANCE 40 // 40 fps for 1080p decoder. + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_jpeg/test_apps/jpeg_test_apps/pytest_jpeg.py b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/pytest_jpeg.py new file mode 100644 index 0000000000..cdd75ead6a --- /dev/null +++ b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/pytest_jpeg.py @@ -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_jpeg(dut: Dut) -> None: + dut.run_all_single_board_cases() diff --git a/components/esp_driver_jpeg/test_apps/jpeg_test_apps/sdkconfig.ci.release b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/sdkconfig.ci.release new file mode 100644 index 0000000000..91d93f163e --- /dev/null +++ b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/sdkconfig.ci.release @@ -0,0 +1,5 @@ +CONFIG_PM_ENABLE=y +CONFIG_FREERTOS_USE_TICKLESS_IDLE=y +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/components/esp_driver_jpeg/test_apps/jpeg_test_apps/sdkconfig.defaults b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/sdkconfig.defaults new file mode 100644 index 0000000000..b229aa86ed --- /dev/null +++ b/components/esp_driver_jpeg/test_apps/jpeg_test_apps/sdkconfig.defaults @@ -0,0 +1,9 @@ +CONFIG_FREERTOS_HZ=1000 +CONFIG_ESP_TASK_WDT=n + +# SPIRAM configurations + +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MODE_HEX=y +CONFIG_SPIRAM_SPEED_200M=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y