From f941dfcf138131aadb04a63b98fec1b608f4dda1 Mon Sep 17 00:00:00 2001 From: Frogrey <1170401156@qq.com> Date: Wed, 20 Sep 2023 17:00:30 +0800 Subject: [PATCH] fix uart1 pin bug, delete and update wrong icf files, add vglite support for rt1170 in IAR environment. --- bsp/imxrt/imxrt1170-nxp-evk/m7/.config | 98 +- bsp/imxrt/imxrt1170-nxp-evk/m7/board/Kconfig | 36 + bsp/imxrt/imxrt1170-nxp-evk/m7/board/board.c | 44 +- .../m7/board/linker_scripts/link.icf | 98 - .../m7/board/linker_scripts/link_ram.icf | 40 +- bsp/imxrt/imxrt1170-nxp-evk/m7/project.ewd | 107 +- bsp/imxrt/imxrt1170-nxp-evk/m7/project.ewp | 73 +- bsp/imxrt/imxrt1170-nxp-evk/m7/rtconfig.h | 35 +- bsp/imxrt/imxrt1170-nxp-evk/m7/rtconfig.py | 4 +- bsp/imxrt/imxrt1170-nxp-evk/m7/template.ewd | 87 +- bsp/imxrt/imxrt1170-nxp-evk/m7/template.ewp | 50 +- .../MIMXRT1170/MIMXRT1176/drivers/Elm.h | 681 + .../MIMXRT1176/drivers/buf_reader.c | 221 + .../MIMXRT1176/drivers/buf_reader.h | 63 + .../MIMXRT1176/drivers/display_support.c | 474 + .../MIMXRT1176/drivers/display_support.h | 189 + .../MIMXRT1176/drivers/elm_buffer.c | 321 + .../MIMXRT1170/MIMXRT1176/drivers/elm_draw.c | 483 + .../MIMXRT1176/drivers/elm_headers.h | 158 + .../MIMXRT1170/MIMXRT1176/drivers/elm_init.c | 160 + .../MIMXRT1176/drivers/elm_object.c | 2238 ++++ .../MIMXRT1170/MIMXRT1176/drivers/elm_os.c | 43 + .../MIMXRT1170/MIMXRT1176/drivers/elm_os.h | 13 + .../MIMXRT1176/drivers/elm_precom.h | 55 + .../MIMXRT1170/MIMXRT1176/drivers/elm_text.c | 732 ++ .../MIMXRT1170/MIMXRT1176/drivers/elm_text.h | 207 + .../MIMXRT1170/MIMXRT1176/drivers/fonts.h | 30 + .../MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb.h | 81 + .../MIMXRT1176/drivers/fsl_dc_fb_elcdif.c | 264 + .../MIMXRT1176/drivers/fsl_dc_fb_elcdif.h | 101 + .../MIMXRT1176/drivers/fsl_dc_fb_lcdifv2.c | 288 + .../MIMXRT1176/drivers/fsl_dc_fb_lcdifv2.h | 109 + .../MIMXRT1176/drivers/fsl_display.h | 140 + .../MIMXRT1170/MIMXRT1176/drivers/fsl_fbdev.c | 243 + .../MIMXRT1170/MIMXRT1176/drivers/fsl_fbdev.h | 227 + .../MIMXRT1176/drivers/fsl_hx8394.c | 187 + .../MIMXRT1176/drivers/fsl_hx8394.h | 57 + .../MIMXRT1176/drivers/fsl_mipi_dsi_cmd.c | 351 + .../MIMXRT1176/drivers/fsl_mipi_dsi_cmd.h | 354 + .../MIMXRT1176/drivers/fsl_rm68191.c | 251 + .../MIMXRT1176/drivers/fsl_rm68191.h | 62 + .../MIMXRT1176/drivers/fsl_rm68200.c | 409 + .../MIMXRT1176/drivers/fsl_rm68200.h | 67 + .../MIMXRT1176/drivers/fsl_video_common.c | 301 + .../MIMXRT1176/drivers/fsl_video_common.h | 364 + .../MIMXRT1170/MIMXRT1176/drivers/mcufont.h | 14 + .../MIMXRT1170/MIMXRT1176/drivers/mf_bwfont.c | 134 + .../MIMXRT1170/MIMXRT1176/drivers/mf_bwfont.h | 77 + .../MIMXRT1170/MIMXRT1176/drivers/mf_config.h | 144 + .../MIMXRT1176/drivers/mf_encoding.c | 84 + .../MIMXRT1176/drivers/mf_encoding.h | 45 + .../MIMXRT1170/MIMXRT1176/drivers/mf_font.c | 122 + .../MIMXRT1170/MIMXRT1176/drivers/mf_font.h | 137 + .../MIMXRT1176/drivers/mf_justify.c | 332 + .../MIMXRT1176/drivers/mf_justify.h | 74 + .../MIMXRT1176/drivers/mf_kerning.c | 118 + .../MIMXRT1176/drivers/mf_kerning.h | 27 + .../MIMXRT1176/drivers/mf_rlefont.c | 286 + .../MIMXRT1176/drivers/mf_rlefont.h | 82 + .../MIMXRT1176/drivers/mf_scaledfont.c | 83 + .../MIMXRT1176/drivers/mf_scaledfont.h | 23 + .../MIMXRT1176/drivers/mf_wordwrap.c | 357 + .../MIMXRT1176/drivers/mf_wordwrap.h | 35 + .../MIMXRT1176/drivers/rle_font_read.c | 716 + .../MIMXRT1170/MIMXRT1176/drivers/velm.h | 351 + .../MIMXRT1170/MIMXRT1176/drivers/vft_debug.c | 317 + .../MIMXRT1170/MIMXRT1176/drivers/vft_debug.h | 111 + .../MIMXRT1170/MIMXRT1176/drivers/vft_draw.c | 463 + .../MIMXRT1170/MIMXRT1176/drivers/vft_draw.h | 119 + .../MIMXRT1170/MIMXRT1176/drivers/vg_lite.c | 10894 ++++++++++++++++ .../MIMXRT1170/MIMXRT1176/drivers/vg_lite.h | 2060 +++ .../MIMXRT1176/drivers/vg_lite_flat.c | 535 + .../MIMXRT1176/drivers/vg_lite_flat.h | 55 + .../MIMXRT1176/drivers/vg_lite_hal.c | 499 + .../MIMXRT1176/drivers/vg_lite_hal.h | 272 + .../MIMXRT1176/drivers/vg_lite_hw.h | 64 + .../MIMXRT1176/drivers/vg_lite_image.c | 160 + .../MIMXRT1176/drivers/vg_lite_kernel.c | 1020 ++ .../MIMXRT1176/drivers/vg_lite_kernel.h | 444 + .../MIMXRT1176/drivers/vg_lite_matrix.c | 113 + .../MIMXRT1176/drivers/vg_lite_os.c | 473 + .../MIMXRT1176/drivers/vg_lite_os.h | 134 + .../MIMXRT1176/drivers/vg_lite_path.c | 353 + .../MIMXRT1176/drivers/vg_lite_platform.h | 48 + .../MIMXRT1176/drivers/vg_lite_text.c | 359 + .../MIMXRT1176/drivers/vg_lite_text.h | 372 + .../MIMXRT1176/drivers/vglite_support.c | 87 + .../MIMXRT1176/drivers/vglite_support.h | 36 + .../MIMXRT1176/drivers/vglite_window.c | 181 + .../MIMXRT1176/drivers/vglite_window.h | 62 + bsp/imxrt/libraries/MIMXRT1170/SConscript | 58 + 91 files changed, 32890 insertions(+), 236 deletions(-) delete mode 100644 bsp/imxrt/imxrt1170-nxp-evk/m7/board/linker_scripts/link.icf create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/Elm.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/buf_reader.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/buf_reader.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/display_support.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/display_support.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_buffer.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_draw.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_headers.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_init.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_object.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_os.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_os.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_precom.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_text.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_text.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fonts.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_elcdif.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_elcdif.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_lcdifv2.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_lcdifv2.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_display.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_fbdev.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_fbdev.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_hx8394.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_hx8394.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_mipi_dsi_cmd.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_mipi_dsi_cmd.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68191.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68191.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68200.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68200.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_video_common.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_video_common.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mcufont.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_bwfont.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_bwfont.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_config.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_encoding.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_encoding.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_font.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_font.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_justify.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_justify.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_kerning.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_kerning.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_rlefont.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_rlefont.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_scaledfont.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_scaledfont.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_wordwrap.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_wordwrap.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/rle_font_read.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/velm.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_debug.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_debug.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_draw.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_draw.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_flat.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_flat.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hal.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hal.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hw.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_image.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_kernel.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_kernel.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_matrix.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_os.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_os.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_path.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_platform.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_text.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_text.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_support.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_support.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_window.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_window.h diff --git a/bsp/imxrt/imxrt1170-nxp-evk/m7/.config b/bsp/imxrt/imxrt1170-nxp-evk/m7/.config index eb60e9ca11..56f0a7137c 100644 --- a/bsp/imxrt/imxrt1170-nxp-evk/m7/.config +++ b/bsp/imxrt/imxrt1170-nxp-evk/m7/.config @@ -8,6 +8,8 @@ # CONFIG_RT_NAME_MAX=8 # CONFIG_RT_USING_ARCH_DATA_TYPE is not set +# CONFIG_RT_USING_SMART is not set +# CONFIG_RT_USING_AMP is not set # CONFIG_RT_USING_SMP is not set CONFIG_RT_ALIGN_SIZE=8 # CONFIG_RT_THREAD_PRIORITY_8 is not set @@ -30,18 +32,10 @@ CONFIG_IDLE_THREAD_STACK_SIZE=256 # CONFIG_RT_KSERVICE_USING_TINY_SIZE is not set # CONFIG_RT_USING_TINY_FFS is not set # CONFIG_RT_KPRINTF_USING_LONGLONG is not set -CONFIG_RT_DEBUG=y -CONFIG_RT_DEBUG_COLOR=y -# CONFIG_RT_DEBUG_INIT_CONFIG is not set -# CONFIG_RT_DEBUG_THREAD_CONFIG is not set -# CONFIG_RT_DEBUG_SCHEDULER_CONFIG is not set -# CONFIG_RT_DEBUG_IPC_CONFIG is not set -# CONFIG_RT_DEBUG_TIMER_CONFIG is not set -# CONFIG_RT_DEBUG_IRQ_CONFIG is not set -# CONFIG_RT_DEBUG_MEM_CONFIG is not set -# CONFIG_RT_DEBUG_SLAB_CONFIG is not set -# CONFIG_RT_DEBUG_MEMHEAP_CONFIG is not set -# CONFIG_RT_DEBUG_MODULE_CONFIG is not set +CONFIG_RT_USING_DEBUG=y +CONFIG_RT_DEBUGING_COLOR=y +CONFIG_RT_DEBUGING_CONTEXT=y +CONFIG_RT_DEBUGING_INIT=y # # Inter-Thread communication @@ -51,12 +45,12 @@ CONFIG_RT_USING_MUTEX=y CONFIG_RT_USING_EVENT=y CONFIG_RT_USING_MAILBOX=y CONFIG_RT_USING_MESSAGEQUEUE=y +# CONFIG_RT_USING_MESSAGEQUEUE_PRIORITY is not set # CONFIG_RT_USING_SIGNALS is not set # # Memory Management # -CONFIG_RT_PAGE_MAX_ORDER=11 CONFIG_RT_USING_MEMPOOL=y # CONFIG_RT_USING_SMALL_MEM is not set # CONFIG_RT_USING_SLAB is not set @@ -83,13 +77,17 @@ CONFIG_RT_USING_DEVICE=y CONFIG_RT_USING_CONSOLE=y CONFIG_RT_CONSOLEBUF_SIZE=128 CONFIG_RT_CONSOLE_DEVICE_NAME="uart1" -CONFIG_RT_VER_NUM=0x50000 +CONFIG_RT_VER_NUM=0x50001 # CONFIG_RT_USING_STDC_ATOMIC is not set -# CONFIG_RT_USING_CACHE is not set -# CONFIG_RT_USING_HW_ATOMIC is not set +CONFIG_RT_USING_CACHE=y +CONFIG_RT_USING_HW_ATOMIC=y # CONFIG_ARCH_ARM_BOOTWITH_FLUSH_CACHE is not set # CONFIG_ARCH_CPU_STACK_GROWS_UPWARD is not set -# CONFIG_RT_USING_CPU_FFS is not set +CONFIG_RT_USING_CPU_FFS=y +CONFIG_ARCH_ARM=y +CONFIG_ARCH_ARM_CORTEX_M=y +CONFIG_ARCH_ARM_CORTEX_FPU=y +CONFIG_ARCH_ARM_CORTEX_M7=y # # RT-Thread Components @@ -114,6 +112,10 @@ CONFIG_FINSH_USING_DESCRIPTION=y # CONFIG_FINSH_ECHO_DISABLE_DEFAULT is not set # CONFIG_FINSH_USING_AUTH is not set CONFIG_FINSH_ARG_MAX=10 + +# +# DFS: device virtual file system +# # CONFIG_RT_USING_DFS is not set # CONFIG_RT_USING_FAL is not set @@ -172,7 +174,19 @@ CONFIG_RT_USBD_THREAD_STACK_SZ=4096 # # C/C++ and POSIX layer # -CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8 + +# +# ISO-ANSI C layer +# + +# +# Timezone and Daylight Saving Time +# +# CONFIG_RT_LIBC_USING_FULL_TZ_DST is not set +CONFIG_RT_LIBC_USING_LIGHT_TZ_DST=y +CONFIG_RT_LIBC_TZ_DEFAULT_HOUR=8 +CONFIG_RT_LIBC_TZ_DEFAULT_MIN=0 +CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0 # # POSIX (Portable Operating System Interface) layer @@ -219,9 +233,11 @@ CONFIG_NETDEV_IPV6=0 # CONFIG_RT_USING_ULOG is not set # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set +# CONFIG_RT_USING_RESOURCE_ID is not set # CONFIG_RT_USING_ADT is not set # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set +# CONFIG_RT_USING_KTIME is not set # # RT-Thread Utestcases @@ -246,7 +262,6 @@ CONFIG_NETDEV_IPV6=0 # CONFIG_PKG_USING_KAWAII_MQTT is not set # CONFIG_PKG_USING_BC28_MQTT is not set # CONFIG_PKG_USING_WEBTERMINAL is not set -# CONFIG_PKG_USING_LIBMODBUS is not set # CONFIG_PKG_USING_FREEMODBUS is not set # CONFIG_PKG_USING_NANOPB is not set @@ -264,6 +279,11 @@ CONFIG_NETDEV_IPV6=0 # # CONFIG_PKG_USING_WLAN_WICED is not set # CONFIG_PKG_USING_RW007 is not set + +# +# CYW43012 WiFi +# +# CONFIG_PKG_USING_WLAN_CYW43012 is not set # CONFIG_PKG_USING_COAP is not set # CONFIG_PKG_USING_NOPOLL is not set # CONFIG_PKG_USING_NETUTILS is not set @@ -325,6 +345,7 @@ CONFIG_NETDEV_IPV6=0 # CONFIG_PKG_USING_ZFTP is not set # CONFIG_PKG_USING_WOL is not set # CONFIG_PKG_USING_ZEPHYR_POLLING is not set +# CONFIG_PKG_USING_MATTER_ADAPTATION_LAYER is not set # # security packages @@ -371,7 +392,6 @@ CONFIG_NETDEV_IPV6=0 # LVGL: powerful and easy-to-use embedded GUI library # # CONFIG_PKG_USING_LVGL is not set -# CONFIG_PKG_USING_LITTLEVGL2RTT is not set # CONFIG_PKG_USING_LV_MUSIC_DEMO is not set # CONFIG_PKG_USING_GUI_GUIDER_DEMO is not set @@ -398,6 +418,7 @@ CONFIG_NETDEV_IPV6=0 # CONFIG_PKG_USING_VT100 is not set # CONFIG_PKG_USING_QRCODE is not set # CONFIG_PKG_USING_GUIENGINE is not set +# CONFIG_PKG_USING_PERSIMMON is not set # CONFIG_PKG_USING_3GPP_AMRNB is not set # @@ -446,6 +467,8 @@ CONFIG_NETDEV_IPV6=0 # CONFIG_PKG_USING_HASH_MATCH is not set # CONFIG_PKG_USING_ARMV7M_DWT_TOOL is not set # CONFIG_PKG_USING_VOFA_PLUS is not set +# CONFIG_PKG_USING_RT_TRACE is not set +# CONFIG_PKG_USING_ZDEBUG is not set # # system packages @@ -482,6 +505,8 @@ CONFIG_NETDEV_IPV6=0 # CONFIG_PKG_USING_UC_COMMON is not set # CONFIG_PKG_USING_UC_MODBUS is not set # CONFIG_PKG_USING_FREERTOS_WRAPPER is not set +# CONFIG_PKG_USING_LITEOS_SDK is not set +# CONFIG_PKG_USING_TZ_DATABASE is not set # CONFIG_PKG_USING_CAIRO is not set # CONFIG_PKG_USING_PIXMAN is not set # CONFIG_PKG_USING_PARTITION is not set @@ -505,6 +530,7 @@ CONFIG_NETDEV_IPV6=0 # CONFIG_PKG_USING_QBOOT is not set # CONFIG_PKG_USING_PPOOL is not set # CONFIG_PKG_USING_OPENAMP is not set +# CONFIG_PKG_USING_RPMSG_LITE is not set # CONFIG_PKG_USING_LPM is not set # CONFIG_PKG_USING_TLSF is not set # CONFIG_PKG_USING_EVENT_RECORDER is not set @@ -517,6 +543,9 @@ CONFIG_NETDEV_IPV6=0 # CONFIG_PKG_USING_QPC is not set # CONFIG_PKG_USING_AGILE_UPGRADE is not set # CONFIG_PKG_USING_FLASH_BLOB is not set +# CONFIG_PKG_USING_MLIBC is not set +# CONFIG_PKG_USING_TASK_MSG_BUS is not set +# CONFIG_PKG_USING_SFDB is not set # # peripheral libraries and drivers @@ -581,6 +610,7 @@ CONFIG_NETDEV_IPV6=0 # CONFIG_PKG_USING_BALANCE is not set # CONFIG_PKG_USING_SHT2X is not set # CONFIG_PKG_USING_SHT3X is not set +# CONFIG_PKG_USING_SHT4X is not set # CONFIG_PKG_USING_AD7746 is not set # CONFIG_PKG_USING_ADT74XX is not set # CONFIG_PKG_USING_MAX17048 is not set @@ -601,6 +631,7 @@ CONFIG_NETDEV_IPV6=0 # CONFIG_PKG_USING_FT5426 is not set # CONFIG_PKG_USING_FT6236 is not set # CONFIG_PKG_USING_XPT2046_TOUCH is not set +# CONFIG_PKG_USING_CST816X is not set # CONFIG_PKG_USING_REALTEK_AMEBA is not set # CONFIG_PKG_USING_STM32_SDIO is not set # CONFIG_PKG_USING_ESP_IDF is not set @@ -613,7 +644,6 @@ CONFIG_NETDEV_IPV6=0 # CONFIG_PKG_USING_LKDGUI is not set # CONFIG_PKG_USING_NRF5X_SDK is not set # CONFIG_PKG_USING_NRFX is not set -# CONFIG_PKG_USING_WM_LIBRARIES is not set # # Kendryte SDK @@ -671,14 +701,18 @@ CONFIG_NETDEV_IPV6=0 # CONFIG_PKG_USING_MISAKA_AT24CXX is not set # CONFIG_PKG_USING_MISAKA_RGB_BLING is not set # CONFIG_PKG_USING_LORA_MODEM_DRIVER is not set -# CONFIG_PKG_USING_BL_MCU_SDK is not set # CONFIG_PKG_USING_SOFT_SERIAL is not set # CONFIG_PKG_USING_MB85RS16 is not set # CONFIG_PKG_USING_RFM300 is not set # CONFIG_PKG_USING_IO_INPUT_FILTER is not set # CONFIG_PKG_USING_RASPBERRYPI_PICO_SDK is not set # CONFIG_PKG_USING_LRF_NV7LIDAR is not set +# CONFIG_PKG_USING_AIP650 is not set # CONFIG_PKG_USING_FINGERPRINT is not set +# CONFIG_PKG_USING_BT_ECB02C is not set +# CONFIG_PKG_USING_UAT is not set +# CONFIG_PKG_USING_ST7789 is not set +# CONFIG_PKG_USING_SPI_TOOLS is not set # # AI packages @@ -697,7 +731,11 @@ CONFIG_NETDEV_IPV6=0 # Signal Processing and Control Algorithm Packages # # CONFIG_PKG_USING_FIRE_PID_CURVE is not set +# CONFIG_PKG_USING_QPID is not set # CONFIG_PKG_USING_UKAL is not set +# CONFIG_PKG_USING_DIGITALCTRL is not set +# CONFIG_PKG_USING_KISSFFT is not set +# CONFIG_PKG_USING_CMSIS_DSP is not set # # miscellaneous packages @@ -744,7 +782,6 @@ CONFIG_NETDEV_IPV6=0 # CONFIG_PKG_USING_DSTR is not set # CONFIG_PKG_USING_TINYFRAME is not set # CONFIG_PKG_USING_KENDRYTE_DEMO is not set -# CONFIG_PKG_USING_DIGITALCTRL is not set # CONFIG_PKG_USING_UPACKER is not set # CONFIG_PKG_USING_UPARAM is not set # CONFIG_PKG_USING_HELLO is not set @@ -769,8 +806,9 @@ CONFIG_NETDEV_IPV6=0 # CONFIG_PKG_USING_RTDUINO is not set # -# Projects +# Projects and Demos # +# CONFIG_PKG_USING_ARDUINO_MSGQ_C_CPP_DEMO is not set # CONFIG_PKG_USING_ARDUINO_ULTRASOUND_RADAR is not set # CONFIG_PKG_USING_ARDUINO_SENSOR_KIT is not set # CONFIG_PKG_USING_ARDUINO_MATLAB_SUPPORT is not set @@ -917,14 +955,21 @@ CONFIG_NETDEV_IPV6=0 # # Display # +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_GFX_LIBRARY is not set # CONFIG_PKG_USING_ARDUINO_U8G2 is not set -# CONFIG_PKG_USING_ARDUINO_U8GLIB_ARDUINO is not set +# CONFIG_PKG_USING_ARDUINO_TFT_ESPI is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ST7735 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SSD1306 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ILI9341 is not set # CONFIG_PKG_USING_SEEED_TM1637 is not set # # Timing # +# CONFIG_PKG_USING_ARDUINO_RTCLIB is not set # CONFIG_PKG_USING_ARDUINO_MSTIMER2 is not set +# CONFIG_PKG_USING_ARDUINO_TICKER is not set +# CONFIG_PKG_USING_ARDUINO_TASKSCHEDULER is not set # # Data Processing @@ -958,7 +1003,6 @@ CONFIG_NETDEV_IPV6=0 # # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MFRC630 is not set # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI5351 is not set -# CONFIG_PKG_USING_ARDUINO_RTCLIB is not set # # Signal IO @@ -975,6 +1019,7 @@ CONFIG_NETDEV_IPV6=0 # # Uncategorized # +CONFIG_SOC_IMXRT1170_SERIES=y # # Hardware Drivers Config @@ -997,6 +1042,7 @@ CONFIG_BSP_USING_LPUART1=y # CONFIG_BSP_USING_LPUART3 is not set # CONFIG_BSP_USING_CAN is not set # CONFIG_BSP_USING_FLEXSPI is not set +# CONFIG_BSP_USING_VGLITE is not set # # Onboard Peripheral Drivers diff --git a/bsp/imxrt/imxrt1170-nxp-evk/m7/board/Kconfig b/bsp/imxrt/imxrt1170-nxp-evk/m7/board/Kconfig index 00a2ba6251..1004ec47a7 100644 --- a/bsp/imxrt/imxrt1170-nxp-evk/m7/board/Kconfig +++ b/bsp/imxrt/imxrt1170-nxp-evk/m7/board/Kconfig @@ -141,6 +141,42 @@ menu "On-chip Peripheral Drivers" bool "Enable FLEXSPI2" default n endif + + menuconfig BSP_USING_VGLITE + bool "Enable VGLITE" + select RT_USING_PIN + default n + + if BSP_USING_VGLITE + choice + prompt "Select lcd panel" + default VGLITE_USING_RK055AHD091 + + config VGLITE_USING_RK055AHD091 + bool "RK055AHD091-CTG (RK055HDMIPI4M 720 * 1280)" + + config VGLITE_USING_RK055IQH091 + bool "RK055IQH091-CTG (540 * 960)" + + config VGLITE_USING_RK055MHD091 + bool "RK055MHD091A0-CTG (RK055HDMIPI4MA0 720 * 1280)" + endchoice + + choice + prompt "Select display controller" + default VGLITE_USING_LCDIFV2 + + config VGLITE_USING_ELCDIF + bool "ELCDIF" + + config VGLITE_USING_LCDIFV2 + bool "LCDIFV2" + endchoice + + config VGLITE_USING_ELM + bool "Enable Elementary" + default y + endif endmenu menu "Onboard Peripheral Drivers" diff --git a/bsp/imxrt/imxrt1170-nxp-evk/m7/board/board.c b/bsp/imxrt/imxrt1170-nxp-evk/m7/board/board.c index e9f0b90ad2..a785cd618f 100644 --- a/bsp/imxrt/imxrt1170-nxp-evk/m7/board/board.c +++ b/bsp/imxrt/imxrt1170-nxp-evk/m7/board/board.c @@ -258,26 +258,7 @@ void imxrt_uart_pins_init(void) IOMUXC_SetPinMux( IOMUXC_GPIO_AD_25_LPUART1_RXD, /* GPIO_AD_B0_13 is configured as LPUART1_RX */ 0U); /* Software Input On Field: Input Path is determined by functionality */ - IOMUXC_SetPinConfig( - IOMUXC_GPIO_AD_24_LPUART1_TXD, /* GPIO_AD_B0_12 PAD functional properties : */ - 0x10B0u); /* Slew Rate Field: Slow Slew Rate - Drive Strength Field: R0/6 - Speed Field: medium(100MHz) - Open Drain Enable Field: Open Drain Disabled - Pull / Keep Enable Field: Pull/Keeper Enabled - Pull / Keep Select Field: Keeper - Pull Up / Down Config. Field: 100K Ohm Pull Down - Hyst. Enable Field: Hysteresis Disabled */ - IOMUXC_SetPinConfig( - IOMUXC_GPIO_AD_25_LPUART1_RXD, /* GPIO_AD_B0_13 PAD functional properties : */ - 0x10B0u); /* Slew Rate Field: Slow Slew Rate - Drive Strength Field: R0/6 - Speed Field: medium(100MHz) - Open Drain Enable Field: Open Drain Disabled - Pull / Keep Enable Field: Pull/Keeper Enabled - Pull / Keep Select Field: Keeper - Pull Up / Down Config. Field: 100K Ohm Pull Down - Hyst. Enable Field: Hysteresis Disabled */ + #endif #ifdef BSP_USING_LPUART2 @@ -1334,6 +1315,25 @@ void imxrt_flexspi_pins_init(void) } #endif +#ifdef BSP_USING_VGLITE +void imxrt_lcd_pins_init(void) +{ +#ifdef BSP_USING_VGLITE + CLOCK_EnableClock(kCLOCK_Iomuxc); /* LPCG on: LPCG is ON. */ + + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_02_GPIO9_IO01, /* GPIO_AD_02 is configured as GPIO9_IO01 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_30_GPIO9_IO29, /* GPIO_AD_30 is configured as GPIO9_IO29 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B2_15_GPIO11_IO16, /* GPIO_DISP_B2_15 is configured as GPIO11_IO16 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ +#endif +} +#endif + void rt_hw_board_init() { BOARD_ConfigMPU(); @@ -1378,5 +1378,9 @@ void rt_hw_board_init() #ifdef BSP_USING_FLEXSPI imxrt_flexspi_pins_init(); #endif + +#ifdef BSP_USING_VGLITE + imxrt_lcd_pins_init(); +#endif } diff --git a/bsp/imxrt/imxrt1170-nxp-evk/m7/board/linker_scripts/link.icf b/bsp/imxrt/imxrt1170-nxp-evk/m7/board/linker_scripts/link.icf deleted file mode 100644 index f7053b54a9..0000000000 --- a/bsp/imxrt/imxrt1170-nxp-evk/m7/board/linker_scripts/link.icf +++ /dev/null @@ -1,98 +0,0 @@ -/* -** ################################################################### -** Processors: MIMXRT1052CVJ5B -** MIMXRT1052CVL5B -** MIMXRT1052DVJ6B -** MIMXRT1052DVL6B -** -** Compiler: IAR ANSI C/C++ Compiler for ARM -** Reference manual: IMXRT1050RM Rev.1, 03/2018 -** Version: rev. 1.0, 2018-09-21 -** Build: b180921 -** -** Abstract: -** Linker file for the IAR ANSI C/C++ Compiler for ARM -** -** Copyright 2016 Freescale Semiconductor, Inc. -** Copyright 2016-2018 NXP -** All rights reserved. -** -** SPDX-License-Identifier: BSD-3-Clause -** -** http: www.nxp.com -** mail: support@nxp.com -** -** ################################################################### -*/ - -define symbol m_interrupts_start = 0x30002000; -define symbol m_interrupts_end = 0x300023FF; - -define symbol m_text_start = 0x30002400; -define symbol m_text_end = 0x30FBFFFF; - -define symbol m_data_start = 0x20000000; -define symbol m_data_end = 0x2003FFFF; - -define symbol m_data2_start = 0x202C0000; -define symbol m_data2_end = 0x2033FFFF; - -define exported symbol __NCACHE_REGION_START = m_data2_start; -define exported symbol __NCACHE_REGION_SIZE = 0x0; - -define exported symbol m_boot_hdr_conf_start = 0x30000400; -define symbol m_boot_hdr_ivt_start = 0x30001000; -define symbol m_boot_hdr_boot_data_start = 0x30001020; -define symbol m_boot_hdr_dcd_data_start = 0x30001030; - -/* Sizes */ -if (isdefinedsymbol(__stack_size__)) { - define symbol __size_cstack__ = __stack_size__; -} else { - define symbol __size_cstack__ = 0x0400; -} - -if (isdefinedsymbol(__heap_size__)) { - define symbol __size_heap__ = __heap_size__; -} else { - define symbol __size_heap__ = 0x0400; -} - -define exported symbol __VECTOR_TABLE = m_interrupts_start; -define exported symbol __VECTOR_RAM = m_interrupts_start; -define exported symbol __RAM_VECTOR_TABLE_SIZE = 0x0; -define exported symbol __RTT_HEAP_END = m_data2_end; - -define memory mem with size = 4G; -define region TEXT_region = mem:[from m_interrupts_start to m_interrupts_end] - | mem:[from m_text_start to m_text_end]; - -define region DATA_region = mem:[from m_data_start to m_data_end-__size_cstack__]; -define region DATA2_region = mem:[from m_data2_start to m_data2_end]; -define region CSTACK_region = mem:[from m_data_end-__size_cstack__+1 to m_data_end]; - -define block CSTACK with alignment = 8, size = __size_cstack__ { }; -define block HEAP with alignment = 8, size = __size_heap__ { }; -define block RW { readwrite }; -define block ZI { zi }; -define block NCACHE_VAR { section NonCacheable , section NonCacheable.init }; - -initialize by copy { readwrite, section .textrw }; -do not initialize { section .noinit }; - -place at address mem: m_interrupts_start { readonly section .intvec }; - -place at address mem:m_boot_hdr_conf_start { section .boot_hdr.conf }; -place at address mem:m_boot_hdr_ivt_start { section .boot_hdr.ivt }; -place at address mem:m_boot_hdr_boot_data_start { readonly section .boot_hdr.boot_data }; -place at address mem:m_boot_hdr_dcd_data_start { readonly section .boot_hdr.dcd_data }; - -keep{ section .boot_hdr.conf, section .boot_hdr.ivt, section .boot_hdr.boot_data, section .boot_hdr.dcd_data }; - -place in TEXT_region { readonly }; -place in DATA_region { block RW }; -place in DATA_region { block ZI }; -place in DATA_region { last block HEAP }; -place in DATA_region { block NCACHE_VAR }; -place in CSTACK_region { block CSTACK }; - diff --git a/bsp/imxrt/imxrt1170-nxp-evk/m7/board/linker_scripts/link_ram.icf b/bsp/imxrt/imxrt1170-nxp-evk/m7/board/linker_scripts/link_ram.icf index 45f02d0390..54dc0cd5d2 100644 --- a/bsp/imxrt/imxrt1170-nxp-evk/m7/board/linker_scripts/link_ram.icf +++ b/bsp/imxrt/imxrt1170-nxp-evk/m7/board/linker_scripts/link_ram.icf @@ -24,10 +24,10 @@ ** ################################################################### */ -define symbol m_interrupts_start = 0x00002000; -define symbol m_interrupts_end = 0x000023FF; +define symbol m_interrupts_start = 0x00000000; +define symbol m_interrupts_end = 0x000003FF; -define symbol m_text_start = 0x00002400; +define symbol m_text_start = 0x00000400; define symbol m_text_end = 0x0003FFFF; define symbol m_data_start = 0x20000000; @@ -36,8 +36,14 @@ define symbol m_data_end = 0x2003FFFF; define symbol m_data2_start = 0x202C0000; define symbol m_data2_end = 0x2033FFFF; -define exported symbol __NCACHE_REGION_START = m_data2_start; -define exported symbol __NCACHE_REGION_SIZE = 0x0; +define symbol m_data3_start = 0x80000000; +define symbol m_data3_end = 0x82FFFFFF; + +define symbol m_ncache_start = 0x83000000; +define symbol m_ncache_end = 0x83FFFFFF; + +define exported symbol __NCACHE_REGION_START = m_ncache_start; +define exported symbol __NCACHE_REGION_SIZE = m_ncache_end - m_ncache_start + 1; /* Sizes */ if (isdefinedsymbol(__stack_size__)) { @@ -55,19 +61,21 @@ if (isdefinedsymbol(__heap_size__)) { define exported symbol __VECTOR_TABLE = m_interrupts_start; define exported symbol __VECTOR_RAM = m_interrupts_start; define exported symbol __RAM_VECTOR_TABLE_SIZE = 0x0; -define exported symbol __RTT_HEAP_END = m_data2_end; +define exported symbol __RTT_HEAP_END = m_data3_end-__size_cstack__; define memory mem with size = 4G; define region TEXT_region = mem:[from m_interrupts_start to m_interrupts_end] | mem:[from m_text_start to m_text_end]; -define region DATA_region = mem:[from m_data_start to m_data_end-__size_cstack__]; +define region DATA_region = mem:[from m_data_start to m_data_end]; define region DATA2_region = mem:[from m_data2_start to m_data2_end]; -define region CSTACK_region = mem:[from m_data_end-__size_cstack__+1 to m_data_end]; +define region DATA3_region = mem:[from m_data3_start to m_data3_end-__size_cstack__]; +define region CSTACK_region = mem:[from m_data3_end-__size_cstack__+1 to m_data3_end]; +define region NCACHE_region = mem:[from m_ncache_start to m_ncache_end]; define block CSTACK with alignment = 8, size = __size_cstack__ { }; define block HEAP with alignment = 8, size = __size_heap__ { }; -define block RW { readwrite }; -define block ZI { zi }; +define block RW { first readwrite, section m_usb_dma_init_data }; +define block ZI with alignment = 32 { first zi, section m_usb_dma_noninit_data }; define block NCACHE_VAR { section NonCacheable , section NonCacheable.init }; define block QACCESS_CODE { section CodeQuickAccess }; define block QACCESS_DATA { section DataQuickAccess }; @@ -78,10 +86,14 @@ do not initialize { section .noinit }; place at address mem: m_interrupts_start { readonly section .intvec }; place in TEXT_region { readonly }; -place in DATA_region { block RW }; -place in DATA_region { block ZI }; -place in DATA_region { last block HEAP }; -place in DATA_region { block NCACHE_VAR }; +place in DATA3_region { block RW }; +place in DATA3_region { block ZI }; +if (isdefinedsymbol(__heap_noncacheable__)) { + place in NCACHE_region { last block HEAP }; +} else { + place in DATA3_region { last block HEAP }; +} +place in NCACHE_region { block NCACHE_VAR }; place in TEXT_region { block QACCESS_CODE }; place in DATA_region { block QACCESS_DATA }; place in CSTACK_region { block CSTACK }; diff --git a/bsp/imxrt/imxrt1170-nxp-evk/m7/project.ewd b/bsp/imxrt/imxrt1170-nxp-evk/m7/project.ewd index 09d4a99002..ba36411f77 100644 --- a/bsp/imxrt/imxrt1170-nxp-evk/m7/project.ewd +++ b/bsp/imxrt/imxrt1170-nxp-evk/m7/project.ewd @@ -1,6 +1,6 @@ - 3 + 4 rtthread @@ -11,7 +11,7 @@ C-SPY 2 - 32 + 33 1 1 + + + + + + + + @@ -296,7 +328,7 @@ + + E2_ID + 2 + + 0 + 1 + 1 + + + + + + + + GDBSERVER_ID 2 @@ -1072,7 +1137,7 @@ STLINK_ID 2 - 7 + 8 1 1 + + @@ -1417,7 +1490,7 @@ ICCARM 2 - 37 + 38 1 1 + + AARM 2 - 11 + 12 1 1 + @@ -704,18 +721,10 @@ - 208 + 1 inputOutputBased - - BUILDACTION - 1 - - - - - ILINK 0 @@ -797,7 +806,7 @@ + + BUILDACTION + 2 + + Applications @@ -1126,9 +1140,6 @@ $PROJ_DIR$\..\..\..\..\components\libc\compilers\common\cctype.c - - $PROJ_DIR$\..\..\..\..\components\libc\compilers\common\cstdio.c - $PROJ_DIR$\..\..\..\..\components\libc\compilers\common\cstdlib.c @@ -1138,6 +1149,9 @@ $PROJ_DIR$\..\..\..\..\components\libc\compilers\common\ctime.c + + $PROJ_DIR$\..\..\..\..\components\libc\compilers\common\cunistd.c + $PROJ_DIR$\..\..\..\..\components\libc\compilers\common\cwchar.c @@ -1171,6 +1185,9 @@ CPU + + $PROJ_DIR$\..\..\..\..\libcpu\arm\common\atomic_arm.c + $PROJ_DIR$\..\..\..\..\libcpu\arm\common\div0.c @@ -1189,6 +1206,9 @@ DeviceDrivers + + $PROJ_DIR$\..\..\..\..\components\drivers\core\device.c + $PROJ_DIR$\..\..\..\..\components\drivers\ipc\completion.c @@ -1285,9 +1305,6 @@ $PROJ_DIR$\..\..\..\..\src\components.c - - $PROJ_DIR$\..\..\..\..\src\device.c - $PROJ_DIR$\..\..\..\..\src\idle.c @@ -1382,10 +1399,10 @@ SAL - $PROJ_DIR$\..\..\..\..\components\net\netdev\src\netdev_ipaddr.c + $PROJ_DIR$\..\..\..\..\components\net\netdev\src\netdev.c - $PROJ_DIR$\..\..\..\..\components\net\netdev\src\netdev.c + $PROJ_DIR$\..\..\..\..\components\net\netdev\src\netdev_ipaddr.c diff --git a/bsp/imxrt/imxrt1170-nxp-evk/m7/rtconfig.h b/bsp/imxrt/imxrt1170-nxp-evk/m7/rtconfig.h index 0d214b3550..f1364c646a 100644 --- a/bsp/imxrt/imxrt1170-nxp-evk/m7/rtconfig.h +++ b/bsp/imxrt/imxrt1170-nxp-evk/m7/rtconfig.h @@ -20,8 +20,10 @@ /* kservice optimization */ -#define RT_DEBUG -#define RT_DEBUG_COLOR +#define RT_USING_DEBUG +#define RT_DEBUGING_COLOR +#define RT_DEBUGING_CONTEXT +#define RT_DEBUGING_INIT /* Inter-Thread communication */ @@ -33,7 +35,6 @@ /* Memory Management */ -#define RT_PAGE_MAX_ORDER 11 #define RT_USING_MEMPOOL #define RT_USING_MEMHEAP #define RT_MEMHEAP_FAST_MODE @@ -47,7 +48,14 @@ #define RT_USING_CONSOLE #define RT_CONSOLEBUF_SIZE 128 #define RT_CONSOLE_DEVICE_NAME "uart1" -#define RT_VER_NUM 0x50000 +#define RT_VER_NUM 0x50001 +#define RT_USING_CACHE +#define RT_USING_HW_ATOMIC +#define RT_USING_CPU_FFS +#define ARCH_ARM +#define ARCH_ARM_CORTEX_M +#define ARCH_ARM_CORTEX_FPU +#define ARCH_ARM_CORTEX_M7 /* RT-Thread Components */ @@ -69,6 +77,9 @@ #define FINSH_USING_DESCRIPTION #define FINSH_ARG_MAX 10 +/* DFS: device virtual file system */ + + /* Device Drivers */ #define RT_USING_DEVICE_IPC @@ -87,7 +98,14 @@ /* C/C++ and POSIX layer */ -#define RT_LIBC_DEFAULT_TIMEZONE 8 +/* ISO-ANSI C layer */ + +/* Timezone and Daylight Saving Time */ + +#define RT_LIBC_USING_LIGHT_TZ_DST +#define RT_LIBC_TZ_DEFAULT_HOUR 8 +#define RT_LIBC_TZ_DEFAULT_MIN 0 +#define RT_LIBC_TZ_DEFAULT_SEC 0 /* POSIX (Portable Operating System Interface) layer */ @@ -127,6 +145,9 @@ /* Wiced WiFi */ +/* CYW43012 WiFi */ + + /* IoT Cloud */ @@ -196,7 +217,7 @@ /* Arduino libraries */ -/* Projects */ +/* Projects and Demos */ /* Sensors */ @@ -227,6 +248,8 @@ /* Uncategorized */ +#define SOC_IMXRT1170_SERIES + /* Hardware Drivers Config */ #define BSP_USING_QSPIFLASH diff --git a/bsp/imxrt/imxrt1170-nxp-evk/m7/rtconfig.py b/bsp/imxrt/imxrt1170-nxp-evk/m7/rtconfig.py index 456c1f9267..61528410ea 100644 --- a/bsp/imxrt/imxrt1170-nxp-evk/m7/rtconfig.py +++ b/bsp/imxrt/imxrt1170-nxp-evk/m7/rtconfig.py @@ -24,7 +24,7 @@ elif CROSS_TOOL == 'keil': EXEC_PATH = r'C:/Keil_v5' elif CROSS_TOOL == 'iar': PLATFORM = 'iccarm' - EXEC_PATH = r'C:/Program Files (x86)/IAR Systems/Embedded Workbench 8.3' + EXEC_PATH = r'C:/Program Files/IAR Systems/Embedded Workbench 9.2' if os.getenv('RTT_EXEC_PATH'): EXEC_PATH = os.getenv('RTT_EXEC_PATH') @@ -145,7 +145,7 @@ elif PLATFORM == 'iccarm': else: CFLAGS += ' -Oh' - LFLAGS = ' --config "board/linker_scripts/link.icf"' + LFLAGS = ' --config "board/linker_scripts/link_ram.icf"' LFLAGS += ' --redirect _Printf=_PrintfTiny' LFLAGS += ' --redirect _Scanf=_ScanfSmall' LFLAGS += ' --entry __iar_program_start' diff --git a/bsp/imxrt/imxrt1170-nxp-evk/m7/template.ewd b/bsp/imxrt/imxrt1170-nxp-evk/m7/template.ewd index 0d43f6d913..00bb429d70 100644 --- a/bsp/imxrt/imxrt1170-nxp-evk/m7/template.ewd +++ b/bsp/imxrt/imxrt1170-nxp-evk/m7/template.ewd @@ -1,6 +1,6 @@ - 3 + 4 rtthread @@ -11,7 +11,7 @@ C-SPY 2 - 32 + 33 1 1 + + + + + + + + @@ -457,6 +489,39 @@ + + E2_ID + 2 + + 0 + 1 + 1 + + + + + + + + GDBSERVER_ID 2 @@ -1072,7 +1137,7 @@ STLINK_ID 2 - 7 + 8 1 1 + + @@ -1417,7 +1490,7 @@ ICCARM 2 - 37 + 38 1 1 + + AARM 2 - 11 + 12 1 1 + @@ -663,18 +680,10 @@ - 208 + 1 inputOutputBased - - BUILDACTION - 1 - - - - - ILINK 0 @@ -756,7 +765,7 @@ + + BUILDACTION + 2 + + diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/Elm.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/Elm.h new file mode 100644 index 0000000000..cb8c91f435 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/Elm.h @@ -0,0 +1,681 @@ +/**************************************************************************** +* +* Copyright 2012 - 2020 Vivante Corporation, Santa Clara, California. +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#ifndef ELM_H_ +#define ELM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ELM_VERSION 0x00010000 /* Current Version: 1.0. */ +#define ELM_NULL_HANDLE 0 /*! NULL object handle, represent a void object. */ + + /*! + @typedef ELM_EVO_PROP_BIT + evo property bits to control evo manipulation. + */ + typedef enum { + ELM_PROP_ROTATE_BIT = 1 << 0, /*! rotate bit of evo/ego/ebo transformation property. */ + ELM_PROP_TRANSFER_BIT = 1 << 1, /*! transfer bit of evo/ego/ebo transformation property. */ + ELM_PROP_SCALE_BIT = 1 << 2, /*! scale bit of evo/ego/ebo transformation property. */ + ELM_PROP_BLEND_BIT = 1 << 3, /*! blending bit of evo/ebo rendering property. */ + ELM_PROP_QUALITY_BIT = 1 << 4, /*! quality bit of evo/ebo rendering property. */ + ELM_PROP_FILL_BIT = 1 << 5, /*! fill rule bit of evo rendering property. */ + ELM_PROP_COLOR_BIT = 1 << 6, /*! fill color bit of evo rendering property. */ + ELM_PROP_PAINT_BIT = 1 << 7, /*! paint type bit of evo. */ + ELM_PROP_ALL_BIT = 0xFFFFFFFF, /*! all transformation property bits of evo. */ + } ELM_EVO_PROP_BIT; + + /*! + @typedef ELM_EVO_BLEND + The blending property of the evo object when it's drawn. + D is Destination color, S is Source color; + Da is Destination alpha, S is Source alpha. + */ + typedef enum { + ELM_BLEND_NONE = 0, /*! D = S. */ + ELM_BLEND_SRC_OVER, /*! D = S + (1 - Sa) * D */ + ELM_BLEND_DST_OVER, /*! D = (1 - Da) * S + D */ + ELM_BLEND_SRC_IN, /*! D = Da * S */ + ELM_BLEND_DST_IN, /*! D = Sa * D */ + ELM_BLEND_SCR, /*! D = S + D - S * D */ + ELM_BLEND_MUL, /*! D = S * (1 - Da) + D * (1 - Sa) + S * D */ + ELM_BLEND_ADD, /*! S + D */ + ELM_BLEND_SUB /*! D * (1 - S) */ + } ELM_BLEND; + + /*! + @typedef ELM_EVO_QUALITY + The drawing quality of the evo object. + */ + typedef enum { + ELM_QUALITY_LOW = 0, /*! NOAA for evo, POINT SAMPLE for ebo. */ + ELM_QUALITY_MED = 1, /*! 2XAA for evo, LINEAR SAMPLE for ebo. */ + ELM_QULIATY_HI = 2, /*! 4XAA for evo, BI-LINEAR SAMPLE for ebo. */ + } ELM_QUALITY; + + /*! + @typedef ELM_PAINT_TYPE + Those are types for evo fill paint. + COLOR means solid color fill; + PATTERN means fill with an image (evo); + GRADIENT means fill with linear gradient. + */ + typedef enum { + ELM_PAINT_COLOR = 0, /*! Paint evo with solid color */ + ELM_PAINT_PATTERN = 1, /*! Paint evo with ebo */ + ELM_PAINT_GRADIENT = 2, /*! Paint evo with a linear gradient built-in evo object */ + ELM_PAINT_RADIAL_GRADIENT = 3, /*! Paint evo with a radial gradient built-in evo object */ + ELM_PAINT_TEXT = 4, /*! Paint evo-text */ + } ELM_PAINT_TYPE; + + /*! + @typedef ELM_PATTERN_MODE + Those are enum types for pattern fill mode. + COLOR means fill the area outside the pattern with a solid color; + PAD means extend the border color to the area outside the pattern. + */ + typedef enum { + ELM_PATTERN_MODE_COLOR = 0, + ELM_PATTERN_MODE_PAD = 1, + } ELM_PATTERN_MODE; + + /*! + @typedef ELM_EVO_FILL + The filling rule of for an evo object. + EO = EVEN_ODD; + NZ = NONE_ZERO; + */ + typedef enum { + ELM_EVO_FILL_NZ = 0, /*! none-zero fill rule */ + ELM_EVO_FILL_EO = 1, /*! Even-odd fill rule */ + } ELM_EVO_FILL; + + /*! + @typedef ELM_EVO_TYPE + the type of an evo object. could be pathes, images, or a group which contains other EVOs. + */ + typedef enum { + ELM_OBJECT_TYPE_EVO = 0, /*! elementary vector object, representing a path object. */ + ELM_OBJECT_TYPE_EGO = 1, /*! elementary group object, containing multiple path objects. */ + ELM_OBJECT_TYPE_EBO = 2, /*! elementary bitmap object, representing image data. */ + ELM_OBJECT_TYPE_BUF = 3, /*! rendering buffer object, created by application. */ + ELM_OBJECT_TYPE_FONT = 4, /*! elementary font object, representing character data. */ + ELM_OBJECT_TYPE_TEXT = 5, /*! elementary text object, representing text data. */ + } ELM_OBJECT_TYPE; + + /*! + @typedef ELM_BUFFER_FORMAT + Enumeration for buffer format, all format name definiton is sequenced from LSB to MSB. + */ + typedef enum { + ELM_BUFFER_FORMAT_RGBA8888, /*! 32-bit RGBA format with 8 bits per color channel. Red is in bits 7:0, green in bits 15:8, blue in + bits 23:16, and the alpha channel is in bits 31:24. */ + ELM_BUFFER_FORMAT_BGRA8888, /*! 32-bit RGBA format with 8 bits per color channel. Red is in bits 23:16, green in bits 15:8, blue in + bits 7:0, and the alpha channel is in bits 31:24. */ + ELM_BUFFER_FORMAT_RGBX8888, /*! 32-bit RGBX format with 8 bits per color channel. Red is in bits 7:0, green in bits 15:8, blue in + bits 23:16, and the x channel is in bits 31:24. */ + ELM_BUFFER_FORMAT_BGRX8888, /*! 32-bit RGBX format with 8 bits per color channel. Red is in bits 23:16, green in bits 15:8, blue in + bits 7:0, and the x channel is in bits 31:24. */ + ELM_BUFFER_FORMAT_RGB565, /*! 16-bit RGB format with 5 and 6 bits per color channel. Red is in bits 4:0, green in bits 10:5, and + the blue color channel is in bits 15:11. */ + ELM_BUFFER_FORMAT_BGR565, /*! 16-bit RGB format with 5 and 6 bits per color channel. Red is in bits 15:11, green in bits 10:5, + and the blue color channel is in bits 4:0. */ + ELM_BUFFER_FORMAT_RGBA4444, /*! 16-bit RGBA format with 4 bits per color channel. Red is in bits 3:0, green in bits 7:4, blue in + bits 11:8 and the alpha channel is in bits 15:12. */ + ELM_BUFFER_FORMAT_BGRA4444, /*! 16-bit RGBA format with 4 bits per color channel. Red is in bits 11:8, green in bits 7:4, blue in + bits 3:0 and the alpha channel is in bits 15:12. */ + ELM_BUFFER_FORMAT_BGRA5551, /*! 16-bit RGBA format with 4 bits per color channel. Red is in bits 14:10, green in bits 9:5, blue in + bits 4:0 and the alpha channel is in bit 15:15. */ + ELM_BUFFER_FORMAT_INDEX_1, /*! 1-bit indexed format. */ + ELM_BUFFER_FORMAT_INDEX_2, /*! 2-bits indexed format. */ + ELM_BUFFER_FORMAT_INDEX_4, /*! 4-bits indexed format. */ + ELM_BUFFER_FORMAT_INDEX_8, /*! 8-bits indexed format. */ + } ELM_BUFFER_FORMAT; + + /*! + @typedef ElmHandle + common handle type for object reference. + */ + typedef unsigned int ElmHandle; + + /*! + @typedef ElmVecObj + evo object handle (elemtry vector object). Created from an external binary evo file. + */ + typedef ElmHandle ElmVecObj; + + /*! + @typedef ElmBitmapObj + ebo object handle (elementry image object). Created from an external ebo file. + */ + typedef ElmHandle ElmBitmapObj; + + /*! + @typedef ElmGroupObj + group object handle. Create from an external ego file. + */ + typedef ElmHandle ElmGroupObj; + + /*! + @typedef ElmBuffer + render buffer object handle. + */ + typedef ElmHandle ElmBuffer; + + #define TRUE 1 + #define FALSE 0 + /*! + @typedef BOOL + boolean type define. + */ + typedef unsigned int BOOL; + + /*! + @abstract Initialize Elementary context. + + @discussion + It should be called as the first function of Elemenatary libary, which initializes the library. Currently + Elementary library doesn't support context concept, neigher multi-threading. Elementary library defines + origin of coordinate system is at top-left. + + @param none + + @return none + */ + BOOL ElmInitialize(uint32_t width, uint32_t height); + + /*! + @abstract Terminate Elementary context. + + @discussion + This should be called when an app exits. It frees all the resource. + + @param none + + @return none + */ + void ElmTerminate(void); + + /*! + @abstract Create an elementary object from an existing binary file. + + @discussion + This function creates an elementary object from the file whose file name is specified by param name. + Caller must match type with the binary file, otherwise create mail fail by returning ELM_NULL_HANDLE. + + @param type + Specify what type of object to be created. + + @param name + The name of the binary resource file. + + @return ElmHandle + An object handle depending on the corresponding type. If type mismatches, it + returns ELM_NULL_HANDLE. + */ + ElmHandle ElmCreateObjectFromFile(ELM_OBJECT_TYPE type, const char *name); + + /*! + @abstract Create an elementary object from build-in data within the appplication. + + @discussion + This function creates an elementar object from local data pointer, which is specially useful for environment without filesystem support. + + @param type + Specify what type of object to be created. + + @param data + The pointer to the binary data which has exactly same layout as external resource file. + + @return ElmHandle + An object handle depending on the corresponding type. If type mismatches with the binary data, it + returns ELM_NULL_HANDLE. + */ + ElmHandle ElmCreateObjectFromData(ELM_OBJECT_TYPE type, void *data, int size); + + /*! + @abstract Rotate a graphics object with centain degree + + @discussion + This function sets an evo/ebo/ego object rotated with specified angle. Without reset, these setting will be + accumulated. + + @param obj + The graphics object will be rotated. + + @param angle + A radian value to be applied on the evo object. + + @return bool + Rotate is set successfully. + */ + BOOL ElmRotate(ElmHandle obj, float angle); + + /*! + @abstract Transfer an graphics object at different directions. + + @discussion + This function put an evo/ebo/ego object away at different directions. Without reset, the setting will be + accumulated. + + @param obj + The graphics object will be transfered. + + @param x + The units in pixel of X direction. + + @param y + The units in pixel of Y direction. + + @return bool + Transfer is set successfully. + */ + BOOL ElmTransfer(ElmHandle obj, int x, int y); + + /*! + @abstract Scale an graphics object at different directions. + + @discussion + This function scale up or down an evo/ego/ebo object at different directions. Without reset, the setting will + be accumateled. + + @param obj + The graphics object which is targeted to manipulate. + + @param x + The scale ratio in X direction. + + @param y + The scale ratio in Y direction. + + @return bool + Scale is set succefully. + */ + BOOL ElmScale(ElmHandle obj, float x, float y); + + /*! + @abstract Reset the attribute of a graphics object for specified property bit. + + @discussion + This funcion resets specified property for an elementary object. It can be applied all types of objects. + But some properties are only valid for centain types of objects. If the function is called to reset an invalid + property for this type of object, it will be siliently ignored. + After reset, the specifed property of an evo/ebo/ego object is set to the initial state. The initial states are decided + by the binary resource file. The resource creator should set right value for all properties if they want to directly render + the object without any adjustment in application. There is one issue, at present, application has no way to query current value + of each property, is it required? + + @param obj + The graphics object which is targeted to manipulate. + + @param mask + Specify which property or properties need to reset to initial value. + + @return bool + Reset is done successfully. If some mask is not valid for this type of object, it would return false. + */ + BOOL ElmReset(ElmHandle obj, ELM_EVO_PROP_BIT mask); + + /*! + @abstract Draw a graphics object onto current render target + + @discussion + This is an enssentail function to do the real job, it takes all current setting of the elementary object and + render into theb buffer target. + + @param buffer + The render target that an elmentary object will be rendered into. + + @param obj + The elmentary object will be draw into render target. + + @return bool + The draw operation for this elmentary object is sucessful. + */ + BOOL ElmDraw(ElmBuffer buffer, ElmHandle object); + + /*! + @abstract Set the rendering quality of an graphics object. + + @discussion + This function sets the rendering quality of an evo/ebo object. Avaliable quality setting contains: + ELM_EVO_QUALITY_LOW, ELM_EVO_QUALITY_MED, ELM_EVO_QUALITY_HI. This function is only applied to an evo or an ebo. + Group object can't be set quality. It always use the setting from its binary. + + @param obj + The elementary object. + + @param quality + The quality enum. + + @return bool + The operation for this object is sucessful, for group object and invalid enum, would return false. + */ + BOOL ElmSetQuality(ElmHandle obj, ELM_QUALITY quality); + + /*! + @abstract Set the fill rule of an evo object. + + @discussion + This function sets the fill rule of an elementary object. Avaliable quality setting contains: + ELM_EVO_EO, ELM_EVO_NZ. It only applies to evo object. + + @param evo + The evo object. + + @param fill + The fill rule enum. + + @return bool + The operation for this evo is sucessful. For non-evo object an ENUM is not a valid enum, would return false. + */ + BOOL ElmSetFill(ElmVecObj evo, ELM_EVO_FILL fill); + + /*! + @abstract Set the blending mode of an evo/ebo object. + + @discussion + This function sets the blending mode of an evo/ebo object. It's not applied to group object. + + @param obj + The graphics object. + + @param blend + The blending mode enum. + + @return bool + The operation for this evo/ebo is sucessful. If object is a group object or blend mode is not a legal one, it would return false. + */ + BOOL ElmSetBlend(ElmHandle obj, ELM_BLEND blend); + + /*! + @abstract Set the solid fill color of an evo object. + + @discussion + This function sets the solid fill color of an evo object. + + @param evo + The evo object. + + @param color + The uint32 color value in rgba order. + + @return bool + The operation for this evo is sucessful. If the object is not a evo object, it would return false. + */ + BOOL ElmSetColor(ElmVecObj evo, uint32_t color); + + /*! + @abstract Set the image paint fill of an evo. + + @discussion + This function sets the image pattern for filling an evo. The image pattern + is a loaded ebo. The ebo's transformation is applied when drawing the evo. + + @param evo + The evo object. + + @param pattern + The image pattern to be set for the evo. + + @return bool + The operation is successful or not. + */ + BOOL ElmSetPattern(ElmVecObj evo, ElmBitmapObj pattern); + + /*! + @abstract Set the image paint fill of an evo. + + @discussion + This function sets the image pattern for filling an evo. The image pattern + is a loaded ebo. The ebo's transformation is applied when drawing the evo. + + @param evo + The evo object. + + @param pattern + The image pattern to be set for the evo. + + @return bool + The operation is successful or not. + */ + BOOL ElmSetPatternMode(ElmVecObj evo, ELM_PATTERN_MODE mode, uint32_t color); + + /*! + @abstract Set the paint type of an evo. + + @discussion + This function selects the paint type for evo to use. An evo may have 3 types + of paint: COLOR, PATTERN, and LINEAR GRADIENT. The Linear graident is always + a built-in resource, which can not be altered. If a binary resource doesn't + have built-in gradient paint resource, it can't be selected as the paint source. + Solid color is also a built-in attribute, but it can be changed by ElmSetColor(). + Paint with a pattern always need an external ebo object, which is impossible + to be embedded in resource file,i.e. ebo object. Before select paint type to + be PATTERN, ElmSetPattern() must be called to attach an EBO to an EVO. + + @param evo + The evo object. + + @param type + The paint type to be set for the evo. + + @return bool + The operation is successful or not. + If the corresponding type is not avaiable for the evo, it returns false and + type paint type falls back to COLOR. + */ + BOOL ElmSetPaintType(ElmVecObj evo, ELM_PAINT_TYPE type); + + /*! + @abstract Create internal render buffer. + + @discussion + This functiois is to create an internal render buffer for Elementary rendering, ussually it's not for direct display. + The buffer which is displayed on pannel is wrapped up by another API, whose address is managed by display controller side. + + @param width + The buffer's width. + + @param height + The buffer's height. + + @param format + The buffer's format, check enumeration of ELM_BUFFER_FORMAT. + + @return + The buffer handle. + */ + ElmBuffer ElmCreateBuffer(unsigned int width, unsigned int height, ELM_BUFFER_FORMAT format); + + /*! + @abstract Wrap a customized buffer. + + @discussion + The application may wrap a user created buffer by giving the information of + the buffer including the size, the memory addresses and format. E.g., the + application can wrap a system framebuffer thus ELM can directly render onto + the screen. + + @return + The buffer handle. + */ + ElmBuffer ElmWrapBuffer(int width, int height, int stride, + void *logical, uint32_t physical, + ELM_BUFFER_FORMAT format); + + /*! + @abstract Get buffer address. + + @discussion + The function is to get the address of ElmBuffer. + + @return + The buffer address. + */ + + uint32_t ElmGetBufferAddress(ElmBuffer buffer); + + /*! + @abstract Destroy a render buffer. + + @discussion + This function is to release all internal resource inside Elementary libary belonging to this buffer. + Applicatoin need make sure the buffer is not being used by elmentary library any more when calling this function. + + @param buffer + The render buffer handle + + @return + If destroying is completed successfully. + */ + BOOL ElmDestroyBuffer(ElmBuffer buffer); + + /*! + @abstract Save a buffer to PNG file. + + @discussion + This function can save the buffer into a PNG file. + + @param buffer + The render buffer handle. + + @param name + The name of the PNG file to sve. + + @return + Save OK or NOT. + + */ + BOOL ElmSaveBuffer(ElmBuffer buffer, const char *name); + + /*! + @abstract Clear a render buffer with specified color and dimension. + + @discussion + This function is called to clear full or partial of the buffer. If the rectangle is out of buffer space, the intersect portion will be cleared. + + @param buffer + A render buffer handle. + + @param color + Clear color value. + + @param x + x origin of partical clear rectangle. + + @param y + y origin of partial clear rectangle. + + @param width + width of partical clear rectangle. + + @param height + height of partical clear rectangle. + + @param full + Flag to indicate a full buffer clear. If true, the dimension parameters will be ignored. + + @return bool + Indicate the clear operation is set up correctly. + */ + BOOL ElmClear(ElmBuffer buffer, uint32_t color, uint32_t x, uint32_t y, uint32_t width, uint32_t height, BOOL full); + + /*! + @abstract Destroy an ELM object. + + @discussion + This function is to release all internal resource inside Elementary libary belonging to this object. + Applicatoin need make sure the object is not being used by elmentary library any more when calling this function. + If an EBO is being destroyed and it's attached to one EVO, it need to guarantee that EVO is not being used by elementary library too. + + @param object + The object handle + + @return + If destroying is completed successfully. + */ + BOOL ElmDestroyObject(ElmHandle object); + + /*! + @abstract Finish all rendering on GPU issued before this call. + + @discussion + This function tells the engine that it has finished the frame data and GPU can draw it now. It's blocked until GPU rendering done. + + @return + If the opeartion is successfully done or not. + */ + BOOL ElmFinish(); + + /*! + @abstract Flush all rendering command to GPU issued before this call. + + @discussion + This function tells the engine to start kicking off command to GPU side, it will return immediately after firing off GPU. + + @return + If the opeartion is successfully done or not. + */ + BOOL ElmFlush(); + + /*! + @abstract Query the paint color of an evo object. + */ + BOOL ElmGetColor(ElmVecObj evoHandle,uint32_t *color); + + /*! + @abstract Query the vectory path count of an EGO object. If the given object + is an evo/ebo, the count is 0. + */ + uint32_t ElmGetVectorCount(ElmHandle handle); + + /*! + @abstract Query the type of an object (by handle). + */ + ELM_OBJECT_TYPE ElmGetObjectType(ElmHandle handle); + + /*! + @abstract Set the current vectory object index to operate on. + */ + BOOL ElmSetCurrentVector(int32_t id); + + BOOL ElmScalePaint(ElmHandle handle, float sx, float sy); + BOOL ElmRotatePaint(ElmHandle handle, float degrees); + BOOL ElmTranslatePaint(ElmHandle handle, float tx, float ty); + + /*! + @abstract Get handle of the framebuffer. + */ + ElmBuffer ElmGetBuffer(vg_lite_buffer_t *buffer); + +#ifdef __cplusplus +} +#endif +#endif /* ELM_H_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/buf_reader.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/buf_reader.c new file mode 100644 index 0000000000..7fa832c6f5 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/buf_reader.c @@ -0,0 +1,221 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright 2020 NXP +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ +#include "buf_reader.h" +#include "stdio.h" +#include "string.h" + +#define DBG_TRACE(x) printf x + +static int _is_buffered_handle_valid(bufferred_reader_t *fd) +{ + if (fd == NULL) + return E_BUF_INVALID_HANDLE; + if ( fd->data_buf == NULL ) + return E_BUF_INVALID_HANDLE; + if ( fd->size < 0 ) + return E_BUF_INVALID_HANDLE; + if ( fd->index > fd->size ) + return E_BUF_INVALID_HANDLE; + + return 0; +} + +/* Write buffered IO operations */ +int bufferred_fopen(bufferred_reader_t *fd, char *buf, int size) +{ + if (fd == NULL) + return E_BUF_INVALID_HANDLE; + + fd->data_buf = buf; + fd->size = size; + fd->index = 0; + + if ( _is_buffered_handle_valid(fd)) { + return E_BUF_INVALID_HANDLE; + } + + fd->is_valid = 1; + + return 0; +} + +int bufferred_ftell(bufferred_reader_t *fd) +{ + if ( _is_buffered_handle_valid(fd)) { + return E_BUF_INVALID_HANDLE; + } + + return fd->index; +} + +int bufferred_fread( + void *ptr, + int size, + int nmemb, + bufferred_reader_t *fd +) +{ + int to_copy = 0; + char *data_ptr = NULL; + char *buff = (char *)ptr; + int byte_to_read = size * nmemb; + + if ( _is_buffered_handle_valid(fd)) { + return E_BUF_INVALID_HANDLE; + } + + if ( buff == NULL ) { + return E_BUF_IO_INVALID_PARAMETERS; + } + + if ( byte_to_read < 0 ) { + return E_BUF_IO_INVALID_PARAMETERS; + } + + to_copy = (fd->size - fd->index); + data_ptr = fd->data_buf + fd->index; + + if ( to_copy > byte_to_read ) + to_copy = byte_to_read; + + if (to_copy <= 0) + return -1; //EOF + + memcpy(buff, data_ptr, to_copy); + + fd->index += to_copy; + + return 0; +} + +int bufferred_fseek( + bufferred_reader_t *fd, + int offset, + int direction +) +{ + if ( _is_buffered_handle_valid(fd)) { + return E_BUF_INVALID_HANDLE; + } + + switch(direction) + { + case SEEK_SET: + fd->index = offset; + break; + case SEEK_CUR: + fd->index += offset; + break; + case SEEK_END: + fd->index = fd->size - offset; + break; + } + + /* Clamp current offset */ + if ( fd->index > fd->size ) { + DBG_TRACE(("WARNING: seeking beyond buffer size\n")); + fd->index = fd->size; + } + if ( fd->index < 0 ) { + DBG_TRACE(("WARNING: seeking beyond buffer size\n")); + fd->index = 0; + } + + return 0; +} + +int bufferred_fclose(bufferred_reader_t *fd) +{ + if ( _is_buffered_handle_valid(fd)) { + return E_BUF_INVALID_HANDLE; + } + + fd->size = -1; + fd->is_valid = 0; + + return 0; +} + +char *bufferred_fgets(char* buff, int len, bufferred_reader_t *fd) +{ + char *ptr; + int i, j, valid_bytes; + + if ( buff == NULL ) { + return NULL; + } + + if ( len <= 0 ) { + return NULL; + } + + if ( _is_buffered_handle_valid(fd)) { + return NULL; + } + + /* Check how many bytes are available to read */ + valid_bytes = fd->size - fd->index; + if ( len > 0 ) + len -=1; /* fgets read one character less than buffer length */ + if ( len > valid_bytes ) + len = valid_bytes; + + if ( valid_bytes <= 0 ) + return NULL; + + ptr = fd->data_buf + fd->index; + for(i=0; ptr[i] != '\0' && i < len; i++) + { + if ( ptr[i] == '\n' ) + break; + if ( ptr[i] == '\r' ) + break; + buff[i] = ptr[i]; + } + buff[i] = '\0'; + j = i; + /* skip trailing newline from file buffer */ + if ( ptr[i] == '\r' ) + i++; + if ( ptr[i] == '\n' ) + i++; + fd->index += i; + + /* Trim trailing spaces from output buffer */ + for (i = j-1 ; i>0; i--) { + if (buff[i] == ' ') + buff[i] = '\0'; + else + break; + } + + + return ptr; + +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/buf_reader.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/buf_reader.h new file mode 100644 index 0000000000..85c5247ce2 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/buf_reader.h @@ -0,0 +1,63 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright 2020 NXP +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +/* Bufferred reader interface */ +#ifndef _BUFFERRED_READER_ +#define _BUFFERRED_READER_ + +typedef struct buffered_reader { + char *data_buf; + int size; + int index; + int is_valid; +} bufferred_reader_t; + +#define E_BUF_IO_OUT_OF_MEMORY -10 +#define E_BUF_IO_READ_ERROR -11 +#define E_BUF_INVALID_HANDLE -12 +#define E_BUF_IO_INVALID_PARAMETERS -13 + +int is_buffered_handle_valid(bufferred_reader_t *fd); +int bufferred_fopen(bufferred_reader_t *fd, char *buf, int size); +int bufferred_ftell(bufferred_reader_t *fd); +int bufferred_fread( + void *ptr, + int size, + int nmemb, + bufferred_reader_t *fd +); +int bufferred_fseek( + bufferred_reader_t *fd, + int offset, + int direction +); +int bufferred_fclose(bufferred_reader_t *fd); +char *bufferred_fgets(char* buff, int len, bufferred_reader_t *fd); + +#endif //!_BUFFERRED_READER_ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/display_support.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/display_support.c new file mode 100644 index 0000000000..fb549f5632 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/display_support.c @@ -0,0 +1,474 @@ +/* + * Copyright 2019-2021, 2023 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include "display_support.h" +#include "fsl_gpio.h" +#include "fsl_mipi_dsi.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* + * The DPHY bit clock must be fast enough to send out the pixels, it should be + * larger than: + * + * (Pixel clock * bit per output pixel) / number of MIPI data lane + * + * Here the desired DPHY bit clock multiplied by ( 9 / 8 = 1.125) to ensure + * it is fast enough. + */ +#define DEMO_MIPI_DPHY_BIT_CLK_ENLARGE(origin) (((origin) / 8) * 9) + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +static void BOARD_PullPanelResetPin(bool pullUp); +static void BOARD_PullPanelPowerPin(bool pullUp); +static void BOARD_InitLcdifClock(void); +static void BOARD_InitMipiDsiClock(void); +static status_t BOARD_DSI_Transfer(dsi_transfer_t *xfer); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +static uint32_t mipiDsiTxEscClkFreq_Hz; +static uint32_t mipiDsiDphyBitClkFreq_Hz; +static uint32_t mipiDsiDphyRefClkFreq_Hz; +static uint32_t mipiDsiDpiClkFreq_Hz; + +const MIPI_DSI_Type g_mipiDsi = { + .host = DSI_HOST, + .apb = DSI_HOST_APB_PKT_IF, + .dpi = DSI_HOST_DPI_INTFC, + .dphy = DSI_HOST_DPHY_INTFC, +}; + +#if defined(VGLITE_USING_RK055AHD091) + +static mipi_dsi_device_t dsiDevice = { + .virtualChannel = 0, + .xferFunc = BOARD_DSI_Transfer, +}; + +static const rm68200_resource_t rm68200Resource = { + .dsiDevice = &dsiDevice, + .pullResetPin = BOARD_PullPanelResetPin, + .pullPowerPin = BOARD_PullPanelPowerPin, +}; + +static display_handle_t rm68200Handle = { + .resource = &rm68200Resource, + .ops = &rm68200_ops, +}; + +#elif defined(VGLITE_USING_RK055MHD091) + +static mipi_dsi_device_t dsiDevice = { + .virtualChannel = 0, + .xferFunc = BOARD_DSI_Transfer, +}; + +static const hx8394_resource_t hx8394Resource = { + .dsiDevice = &dsiDevice, + .pullResetPin = BOARD_PullPanelResetPin, + .pullPowerPin = BOARD_PullPanelPowerPin, +}; + +static display_handle_t hx8394Handle = { + .resource = &hx8394Resource, + .ops = &hx8394_ops, +}; + +#else + +static mipi_dsi_device_t dsiDevice = { + .virtualChannel = 0, + .xferFunc = BOARD_DSI_Transfer, +}; + +static const rm68191_resource_t rm68191Resource = { + .dsiDevice = &dsiDevice, + .pullResetPin = BOARD_PullPanelResetPin, + .pullPowerPin = BOARD_PullPanelPowerPin, +}; + +static display_handle_t rm68191Handle = { + .resource = &rm68191Resource, + .ops = &rm68191_ops, +}; + +#endif + +#if defined(VGLITE_USING_LCDIFV2) + +static dc_fb_lcdifv2_handle_t s_dcFbLcdifv2Handle = {0}; + +static const dc_fb_lcdifv2_config_t s_dcFbLcdifv2Config = { + .lcdifv2 = DEMO_LCDIF, + .width = LCD_WIDTH, + .height = LCD_HEIGHT, + .hsw = LCD_HSW, + .hfp = LCD_HFP, + .hbp = LCD_HBP, + .vsw = LCD_VSW, + .vfp = LCD_VFP, + .vbp = LCD_VBP, + .polarityFlags = DEMO_LCDIF_POL_FLAGS, + .lineOrder = kLCDIFV2_LineOrderRGB, +/* CM4 is domain 1, CM7 is domain 0. */ +#if (__CORTEX_M <= 4) + .domain = 1, +#else + .domain = 0, +#endif +}; + +const dc_fb_t g_dc = { + .ops = &g_dcFbOpsLcdifv2, + .prvData = &s_dcFbLcdifv2Handle, + .config = &s_dcFbLcdifv2Config, +}; + +#else + +dc_fb_elcdif_handle_t s_dcFbElcdifHandle = {0}; /* The handle must be initialized to 0. */ + +const dc_fb_elcdif_config_t s_dcFbElcdifConfig = { + .elcdif = DEMO_LCDIF, + .width = LCD_WIDTH, + .height = LCD_HEIGHT, + .hsw = LCD_HSW, + .hfp = LCD_HFP, + .hbp = LCD_HBP, + .vsw = LCD_VSW, + .vfp = LCD_VFP, + .vbp = LCD_VBP, + .polarityFlags = DEMO_LCDIF_POL_FLAGS, +#if (!DEMO_USE_XRGB8888) && (DEMO_USE_LUT8) + .dataBus = kELCDIF_DataBus8Bit, +#else + .dataBus = kELCDIF_DataBus24Bit, +#endif +}; + +const dc_fb_t g_dc = { + .ops = &g_dcFbOpsElcdif, + .prvData = &s_dcFbElcdifHandle, + .config = &s_dcFbElcdifConfig, +}; +#endif + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void BOARD_PullPanelResetPin(bool pullUp) +{ + if (pullUp) + { + GPIO_PinWrite(BOARD_MIPI_PANEL_RST_GPIO, BOARD_MIPI_PANEL_RST_PIN, 1); + } + else + { + GPIO_PinWrite(BOARD_MIPI_PANEL_RST_GPIO, BOARD_MIPI_PANEL_RST_PIN, 0); + } +} + +static void BOARD_PullPanelPowerPin(bool pullUp) +{ + if (pullUp) + { + GPIO_PinWrite(BOARD_MIPI_PANEL_POWER_GPIO, BOARD_MIPI_PANEL_POWER_PIN, 1); + } + else + { + GPIO_PinWrite(BOARD_MIPI_PANEL_POWER_GPIO, BOARD_MIPI_PANEL_POWER_PIN, 0); + } +} + +static status_t BOARD_DSI_Transfer(dsi_transfer_t *xfer) +{ + return DSI_TransferBlocking(DEMO_MIPI_DSI, xfer); +} + +static void BOARD_InitLcdifClock(void) +{ + /* + * The pixel clock is (height + VSW + VFP + VBP) * (width + HSW + HFP + HBP) * frame rate. + * + * For 60Hz frame rate, the RK055IQH091 pixel clock should be 36MHz. + * the RK055AHD091 pixel clock should be 62MHz. + */ + const clock_root_config_t lcdifClockConfig = { + .clockOff = false, + .mux = 4, /*!< PLL_528. */ +#if (defined(VGLITE_USING_RK055AHD091) || defined(VGLITE_USING_RK055MHD091)) + .div = 9, +#else + .div = 15, +#endif + }; + +#if defined(VGLITE_USING_LCDIFV2) + CLOCK_SetRootClock(kCLOCK_Root_Lcdifv2, &lcdifClockConfig); + + mipiDsiDpiClkFreq_Hz = CLOCK_GetRootClockFreq(kCLOCK_Root_Lcdifv2); + +#else + + CLOCK_SetRootClock(kCLOCK_Root_Lcdif, &lcdifClockConfig); + + mipiDsiDpiClkFreq_Hz = CLOCK_GetRootClockFreq(kCLOCK_Root_Lcdif); +#endif +} + +static void BOARD_InitMipiDsiClock(void) +{ + uint32_t mipiDsiEscClkFreq_Hz; + + /* RxClkEsc max 60MHz, TxClkEsc 12 to 20MHz. */ + /* RxClkEsc = 528MHz / 11 = 48MHz. */ + /* TxClkEsc = 528MHz / 11 / 4 = 16MHz. */ + const clock_root_config_t mipiEscClockConfig = { + .clockOff = false, + .mux = 4, /*!< PLL_528. */ + .div = 11, + }; + + CLOCK_SetRootClock(kCLOCK_Root_Mipi_Esc, &mipiEscClockConfig); + + mipiDsiEscClkFreq_Hz = CLOCK_GetRootClockFreq(kCLOCK_Root_Mipi_Esc); + + const clock_group_config_t mipiEscClockGroupConfig = { + .clockOff = false, .resetDiv = 2, .div0 = 2, /* TX esc clock. */ + }; + + CLOCK_SetGroupConfig(kCLOCK_Group_MipiDsi, &mipiEscClockGroupConfig); + + mipiDsiTxEscClkFreq_Hz = mipiDsiEscClkFreq_Hz / 3; + + /* DPHY reference clock, use OSC 24MHz clock. */ + const clock_root_config_t mipiDphyRefClockConfig = { + .clockOff = false, + .mux = 1, /*!< OSC_24M. */ + .div = 1, + }; + + CLOCK_SetRootClock(kCLOCK_Root_Mipi_Ref, &mipiDphyRefClockConfig); + + mipiDsiDphyRefClkFreq_Hz = BOARD_XTAL0_CLK_HZ; +} + +static status_t BOARD_InitLcdPanel(void) +{ + status_t status; + + const gpio_pin_config_t pinConfig = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode}; + + const display_config_t displayConfig = { + .resolution = FSL_VIDEO_RESOLUTION(LCD_WIDTH, LCD_HEIGHT), + .hsw = LCD_HSW, + .hfp = LCD_HFP, + .hbp = LCD_HBP, + .vsw = LCD_VSW, + .vfp = LCD_VFP, + .vbp = LCD_VBP, + .controlFlags = 0, + .dsiLanes = DEMO_MIPI_DSI_LANE_NUM, + }; + + GPIO_PinInit(BOARD_MIPI_PANEL_POWER_GPIO, BOARD_MIPI_PANEL_POWER_PIN, &pinConfig); + GPIO_PinInit(BOARD_MIPI_PANEL_BL_GPIO, BOARD_MIPI_PANEL_BL_PIN, &pinConfig); + GPIO_PinInit(BOARD_MIPI_PANEL_RST_GPIO, BOARD_MIPI_PANEL_RST_PIN, &pinConfig); + +#if defined(VGLITE_USING_RK055AHD091) + status = RM68200_Init(&rm68200Handle, &displayConfig); + +#elif defined(VGLITE_USING_RK055MHD091) + + status = HX8394_Init(&hx8394Handle, &displayConfig); + +#else + + status = RM68191_Init(&rm68191Handle, &displayConfig); +#endif + + if (status == kStatus_Success) + { + GPIO_PinWrite(BOARD_MIPI_PANEL_BL_GPIO, BOARD_MIPI_PANEL_BL_PIN, 1); + } + + return status; +} + +static void BOARD_SetMipiDsiConfig(void) +{ + dsi_config_t dsiConfig; + dsi_dphy_config_t dphyConfig; + + const dsi_dpi_config_t dpiConfig = {.pixelPayloadSize = LCD_WIDTH, + .dpiColorCoding = kDSI_Dpi24Bit, + .pixelPacket = kDSI_PixelPacket24Bit, + .videoMode = kDSI_DpiBurst, + .bllpMode = kDSI_DpiBllpLowPower, + .polarityFlags = kDSI_DpiVsyncActiveLow | kDSI_DpiHsyncActiveLow, + .hfp = LCD_HFP, + .hbp = LCD_HBP, + .hsw = LCD_HSW, + .vfp = LCD_VFP, + .vbp = LCD_VBP, + .panelHeight = LCD_HEIGHT, + .virtualChannel = 0}; + + /* + * dsiConfig.numLanes = 4; + * dsiConfig.enableNonContinuousHsClk = false; + * dsiConfig.autoInsertEoTp = true; + * dsiConfig.numExtraEoTp = 0; + * dsiConfig.htxTo_ByteClk = 0; + * dsiConfig.lrxHostTo_ByteClk = 0; + * dsiConfig.btaTo_ByteClk = 0; + */ + DSI_GetDefaultConfig(&dsiConfig); + dsiConfig.numLanes = DEMO_MIPI_DSI_LANE_NUM; + dsiConfig.autoInsertEoTp = true; + + /* Init the DSI module. */ + DSI_Init(DEMO_MIPI_DSI, &dsiConfig); + + /* Init DPHY. + * + * The DPHY bit clock must be fast enough to send out the pixels, it should be + * larger than: + * + * (Pixel clock * bit per output pixel) / number of MIPI data lane + * + * Here the desired DPHY bit clock multiplied by ( 9 / 8 = 1.125) to ensure + * it is fast enough. + * + * Note that the DSI output pixel is 24bit per pixel. + */ + mipiDsiDphyBitClkFreq_Hz = mipiDsiDpiClkFreq_Hz * (24 / DEMO_MIPI_DSI_LANE_NUM); + + mipiDsiDphyBitClkFreq_Hz = DEMO_MIPI_DPHY_BIT_CLK_ENLARGE(mipiDsiDphyBitClkFreq_Hz); + + DSI_GetDphyDefaultConfig(&dphyConfig, mipiDsiDphyBitClkFreq_Hz, mipiDsiTxEscClkFreq_Hz); + + mipiDsiDphyBitClkFreq_Hz = DSI_InitDphy(DEMO_MIPI_DSI, &dphyConfig, mipiDsiDphyRefClkFreq_Hz); + + /* Init DPI interface. */ + DSI_SetDpiConfig(DEMO_MIPI_DSI, &dpiConfig, DEMO_MIPI_DSI_LANE_NUM, mipiDsiDpiClkFreq_Hz, mipiDsiDphyBitClkFreq_Hz); +} + +status_t BOARD_InitDisplayInterface(void) +{ + CLOCK_EnableClock(kCLOCK_Video_Mux); + +#if defined(VGLITE_USING_LCDIFV2) + /* LCDIF v2 output to MIPI DSI. */ + VIDEO_MUX->VID_MUX_CTRL.SET = VIDEO_MUX_VID_MUX_CTRL_MIPI_DSI_SEL_MASK; +#else + /* ELCDIF output to MIPI DSI. */ + VIDEO_MUX->VID_MUX_CTRL.CLR = VIDEO_MUX_VID_MUX_CTRL_MIPI_DSI_SEL_MASK; +#endif + + /* 1. Power on and isolation off. */ + PGMC_BPC4->BPC_POWER_CTRL |= (PGMC_BPC_BPC_POWER_CTRL_PSW_ON_SOFT_MASK | PGMC_BPC_BPC_POWER_CTRL_ISO_OFF_SOFT_MASK); + + /* 2. Assert MIPI reset. */ + IOMUXC_GPR->GPR62 &= + ~(IOMUXC_GPR_GPR62_MIPI_DSI_PCLK_SOFT_RESET_N_MASK | IOMUXC_GPR_GPR62_MIPI_DSI_ESC_SOFT_RESET_N_MASK | + IOMUXC_GPR_GPR62_MIPI_DSI_BYTE_SOFT_RESET_N_MASK | IOMUXC_GPR_GPR62_MIPI_DSI_DPI_SOFT_RESET_N_MASK); + + /* 3. Setup clock. */ + BOARD_InitMipiDsiClock(); + + /* 4. Deassert PCLK and ESC reset. */ + IOMUXC_GPR->GPR62 |= + (IOMUXC_GPR_GPR62_MIPI_DSI_PCLK_SOFT_RESET_N_MASK | IOMUXC_GPR_GPR62_MIPI_DSI_ESC_SOFT_RESET_N_MASK); + + /* 5. Configures peripheral. */ + BOARD_SetMipiDsiConfig(); + + /* 6. Deassert BYTE and DBI reset. */ + IOMUXC_GPR->GPR62 |= + (IOMUXC_GPR_GPR62_MIPI_DSI_BYTE_SOFT_RESET_N_MASK | IOMUXC_GPR_GPR62_MIPI_DSI_DPI_SOFT_RESET_N_MASK); + + /* 7. Configure the panel. */ + return BOARD_InitLcdPanel(); +} + +#if defined(VGLITE_USING_LCDIFV2) +void LCDIFv2_IRQHandler(void) +{ + DC_FB_LCDIFV2_IRQHandler(&g_dc); +} +#else +void eLCDIF_IRQHandler(void) +{ + DC_FB_ELCDIF_IRQHandler(&g_dc); +} +#endif + +status_t BOARD_VerifyDisplayClockSource(void) +{ + status_t status; + uint32_t srcClkFreq; + + /* + * In this implementation, the SYSPLL2 (528M) clock is used as the source + * of LCDIFV2 pixel clock and MIPI DSI ESC clock. The OSC24M clock is used + * as the MIPI DSI DPHY PLL reference clock. This function checks the clock + * source are valid. OSC24M is always valid, so only verify the SYSPLL2. + */ + srcClkFreq = CLOCK_GetPllFreq(kCLOCK_PllSys2); + if (528 != (srcClkFreq / 1000000)) + { + status = kStatus_Fail; + } + else + { + status = kStatus_Success; + } + + return status; +} + +status_t BOARD_PrepareDisplayController(void) +{ + status_t status; + + status = BOARD_VerifyDisplayClockSource(); + + if (status != kStatus_Success) + { + // PRINTF("Error: Invalid display clock source.\r\n"); + return status; + } + + BOARD_InitLcdifClock(); + + status = BOARD_InitDisplayInterface(); + + if (kStatus_Success == status) + { +#if defined(VGLITE_USING_LCDIFV2) + NVIC_ClearPendingIRQ(LCDIFv2_IRQn); + NVIC_SetPriority(LCDIFv2_IRQn, 3); + EnableIRQ(LCDIFv2_IRQn); +#else + NVIC_ClearPendingIRQ(eLCDIF_IRQn); + NVIC_SetPriority(eLCDIF_IRQn, 3); + EnableIRQ(eLCDIF_IRQn); +#endif + } + + return kStatus_Success; +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/display_support.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/display_support.h new file mode 100644 index 0000000000..b21be74c98 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/display_support.h @@ -0,0 +1,189 @@ +/* + * Copyright 2019-2021, 2023 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _DISPLAY_SUPPORT_H_ +#define _DISPLAY_SUPPORT_H_ + +#include + +#include "fsl_dc_fb.h" + +#if defined(VGLITE_USING_RK055AHD091) +#include "fsl_rm68200.h" +#elif defined(VGLITE_USING_RK055IQH091) +#include "fsl_rm68191.h" +#elif defined(VGLITE_USING_RK055MHD091) +#include "fsl_hx8394.h" +#else +#error "Please config lcd panel parameters." +#endif +#include "pin_mux.h" +#include "board.h" + +#if defined(VGLITE_USING_LCDIFV2) +#include "fsl_dc_fb_lcdifv2.h" +#else +#include "fsl_dc_fb_elcdif.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* @TEST_ANCHOR */ +#define DEMO_BUFFER_FIXED_ADDRESS 0 + +#if DEMO_BUFFER_FIXED_ADDRESS +#define DEMO_BUFFER0_ADDR 0x80000000 +#define DEMO_BUFFER1_ADDR 0x80200000 +#endif + +/* + * Use the MIPI dumb panel + */ + +/* Definitions for the frame buffer. */ +#define DEMO_BUFFER_COUNT 2 /* 2 is enough for DPI interface display. */ + +#ifndef DEMO_USE_XRGB8888 +#define DEMO_USE_XRGB8888 0 +#endif + +/* Use LCDIF LUT (or named color palette) which is 8-bit per-pixel */ +#ifndef DEMO_USE_LUT8 +#define DEMO_USE_LUT8 0 +#endif + +#if DEMO_USE_XRGB8888 +#define DEMO_BUFFER_PIXEL_FORMAT kVIDEO_PixelFormatXRGB8888 +#define DEMO_BUFFER_BYTE_PER_PIXEL 4 +#elif DEMO_USE_LUT8 +#define DEMO_BUFFER_PIXEL_FORMAT kVIDEO_PixelFormatLUT8 +#define DEMO_BUFFER_BYTE_PER_PIXEL 1 +#else +#define DEMO_BUFFER_PIXEL_FORMAT kVIDEO_PixelFormatRGB565 +#define DEMO_BUFFER_BYTE_PER_PIXEL 2 +#endif + +#if (defined(VGLITE_USING_RK055AHD091) || defined(VGLITE_USING_RK055MHD091)) + +#define LCD_WIDTH (720) +#define LCD_HEIGHT (1280) + +#elif defined(VGLITE_USING_RK055IQH091) + +#define LCD_WIDTH (540) +#define LCD_HEIGHT (960) + +#endif + +#define DEMO_BUFFER_WIDTH LCD_WIDTH +#define DEMO_BUFFER_HEIGHT LCD_HEIGHT + +/* Where the frame buffer is shown in the screen. */ +#define DEMO_BUFFER_START_X 0U +#define DEMO_BUFFER_START_Y 0U + +#define DEMO_BUFFER_STRIDE_BYTE (DEMO_BUFFER_WIDTH * DEMO_BUFFER_BYTE_PER_PIXEL) +/* There is not frame buffer aligned requirement, consider the 64-bit AXI data + * bus width and 32-byte cache line size, the frame buffer alignment is set to + * 32 byte. + */ +#define FRAME_BUFFER_ALIGN 32 + +/* + * MIPI panel pin + */ +#define BOARD_MIPI_PANEL_RST_GPIO GPIO9 +#define BOARD_MIPI_PANEL_RST_PIN 1 +#define BOARD_MIPI_PANEL_POWER_GPIO GPIO11 +#define BOARD_MIPI_PANEL_POWER_PIN 16 +/* Back light pin. */ +#define BOARD_MIPI_PANEL_BL_GPIO GPIO9 +#define BOARD_MIPI_PANEL_BL_PIN 29 + +/* + * MIPI panel pin for RT-Thread + */ +#define GET_PIN(PORTx, PIN) (32 * (PORTx - 1) + (PIN & 31)) /* PORTx:1,2,3,4,5 */ +#define LCD_RST_GPIO_PORT (3U) +#define LCD_RST_GPIO_PIN (1U) +#define LCD_RST_PIN GET_PIN(LCD_RST_GPIO_PORT, LCD_RST_GPIO_PIN) +/* Back light pin. */ +#define LCD_BL_GPIO_PORT (3U) +#define LCD_BL_GPIO_PIN (29U) +#define LCD_BL_PIN GET_PIN(LCD_BL_GPIO_PORT, LCD_BL_GPIO_PIN) + +/* + * RK055AHD091 panel + */ + +#if defined(VGLITE_USING_RK055AHD091) +#define LCD_HSW 8 +#define LCD_HFP 32 +#define LCD_HBP 32 +#define LCD_VSW 2 +#define LCD_VFP 16 +#define LCD_VBP 14 + +#elif defined(VGLITE_USING_RK055IQH091) + +#define LCD_HSW 2 +#define LCD_HFP 32 +#define LCD_HBP 30 +#define LCD_VSW 2 +#define LCD_VFP 16 +#define LCD_VBP 14 + +#elif defined(VGLITE_USING_RK055MHD091) + +#define LCD_HSW 6 +#define LCD_HFP 12 +#define LCD_HBP 24 +#define LCD_VSW 2 +#define LCD_VFP 16 +#define LCD_VBP 14 + +#endif + +#if defined(VGLITE_USING_LCDIFV2) + +#define DEMO_LCDIF_POL_FLAGS \ + (kLCDIFV2_DataEnableActiveHigh | kLCDIFV2_VsyncActiveLow | kLCDIFV2_HsyncActiveLow | \ + kLCDIFV2_DriveDataOnFallingClkEdge) + +#define DEMO_LCDIF LCDIFV2 + +#else + +#define DEMO_LCDIF_POL_FLAGS \ + (kELCDIF_DataEnableActiveHigh | kELCDIF_VsyncActiveLow | kELCDIF_HsyncActiveLow | kELCDIF_DriveDataOnFallingClkEdge) + +#define DEMO_LCDIF LCDIF + +#endif + +/* Definitions for MIPI. */ +#define DEMO_MIPI_DSI (&g_mipiDsi) +#define DEMO_MIPI_DSI_LANE_NUM 2 + +extern const dc_fb_t g_dc; + +/******************************************************************************* + * API + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +status_t BOARD_PrepareDisplayController(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif /* _DISPLAY_SUPPORT_H_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_buffer.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_buffer.c new file mode 100644 index 0000000000..4759b5ec64 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_buffer.c @@ -0,0 +1,321 @@ +/**************************************************************************** +* +* Copyright 2012 - 2020 Vivante Corporation, Santa Clara, California. +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#include "elm_precom.h" +#include "vg_lite.h" +#if !DDRLESS +static vg_lite_buffer_format_t _buffer_format_to_vglite(ELM_BUFFER_FORMAT format) +{ + vg_lite_buffer_format_t fmt; + switch (format) { + case ELM_BUFFER_FORMAT_RGBA8888: + fmt = VG_LITE_RGBA8888; + break; + + case ELM_BUFFER_FORMAT_RGBX8888: + fmt = VG_LITE_RGBX8888; + break; + + case ELM_BUFFER_FORMAT_BGRA8888: + fmt = VG_LITE_BGRA8888; + break; + + case ELM_BUFFER_FORMAT_BGRX8888: + fmt = VG_LITE_BGRX8888; + break; + + case ELM_BUFFER_FORMAT_RGB565: + fmt = VG_LITE_RGB565; + break; + + case ELM_BUFFER_FORMAT_BGR565: + fmt = VG_LITE_BGR565; + break; + + case ELM_BUFFER_FORMAT_RGBA4444: + fmt = VG_LITE_RGBA4444; + break; + + case ELM_BUFFER_FORMAT_BGRA4444: + fmt = VG_LITE_BGRA4444; + break; + + default: + fmt = VG_LITE_RGBA8888; + break; + } + + return fmt; +} +#endif +/*! + @abstract Create internal render buffer. + + @discussion + This functiois is to create an internal render buffer for Elementary rendering, ussually it's not for direct display. + The buffer which is displayed on pannel is wrapped up by another API, whose address is managed by display controller side. + + @param width + The buffer's width. + + @param height + The buffer's height. + + @param format + The buffer's format, check enumeration of ELM_BUFFER_FORMAT. + + @return + The buffer handle. + */ +ElmBuffer ElmCreateBuffer(unsigned int width, unsigned int height, ELM_BUFFER_FORMAT format) +{ +#if !DDRLESS + el_Obj_Buffer *buffer_obj; + vg_lite_buffer_t *buffer; + vg_lite_error_t error; + ElmHandle handle = ELM_NULL_HANDLE; + + do { + /* Allocate ebo object. */ + buffer_obj = (el_Obj_Buffer *)calloc(1,sizeof(el_Obj_Buffer)); + if (buffer_obj != NULL) { + buffer_obj->object.type = ELM_OBJECT_TYPE_BUF; + + /* Allocate the buffer. */ + buffer = &buffer_obj->buffer; + memset(buffer, 0, sizeof(vg_lite_buffer_t)); + buffer->width = width; + buffer->height = height; + buffer->format = (vg_lite_buffer_format_t)format; + error = vg_lite_allocate(buffer); + if (error) + goto error_exit; + + JUMP_IF_NON_ZERO_VALUE(add_object((el_Object *)buffer_obj), error_exit); + handle = buffer_obj->object.handle; + } + } while(0); + + return handle; +error_exit: + vg_lite_free(buffer); + free(buffer_obj); + return ELM_NULL_HANDLE; +#else + return ELM_NULL_HANDLE; +#endif +} + +/*! + @abstract Wrap a customized buffer. + + @discussion + The application may wrap a user created buffer by giving the information of + the buffer including the size, the memory addresses and format. E.g., the + application can wrap a system framebuffer thus ELM can directly render onto + the screen. + + @return + The buffer handle. + */ +ElmBuffer ElmWrapBuffer(int width, int height, int stride, + void *logical, uint32_t physical, + ELM_BUFFER_FORMAT format) +{ +#if !DDRLESS + el_Obj_Buffer *buffer_obj; + vg_lite_buffer_t *buffer; + ElmHandle handle = ELM_NULL_HANDLE; + + do { + /* open framebuffer. */ + buffer_obj = (el_Obj_Buffer *)elm_alloc(1, sizeof(el_Obj_Buffer)); + if (buffer_obj != NULL) { + buffer_obj->object.type = ELM_OBJECT_TYPE_BUF; + buffer = &buffer_obj->buffer; + + buffer->width = width; + buffer->height = height; + buffer->stride = stride; + buffer->memory = logical; + buffer->handle = NULL; + buffer->address = physical; + buffer->format = _buffer_format_to_vglite(format); + buffer->tiled = VG_LITE_LINEAR; + JUMP_IF_NON_ZERO_VALUE(add_object((el_Object *)buffer_obj), error_exit); + handle = buffer_obj->object.handle; + } + } while(0); + + return handle; + +error_exit: + free(buffer_obj); + return ELM_NULL_HANDLE; +#else + return ELM_NULL_HANDLE; +#endif + +} + +/*! + @abstract Get buffer address. + +@discussion +The function is to get the address of ElmBuffer. + +@return +The buffer address. +*/ + +uint32_t ElmGetBufferAddress(ElmBuffer buffer) +{ +#if !DDRLESS + el_Obj_Buffer *buff_obj; + buff_obj = (el_Obj_Buffer *)get_object(buffer); + + if (buff_obj == NULL) + { + return 0; + } + else + { + return buff_obj->buffer.address; + } +#else + return 0; +#endif +} + +/*! + @abstract Destroy a render buffer. + + @discussion + This function is to release all internal resource inside Elementary libary belonging to this buffer. + Applicatoin need make sure the buffer is not being used by elmentary library any more when calling this function. + + @param buffer + The render buffer handle + + @return + If destroying is completed successfully. + */ +BOOL ElmDestroyBuffer(ElmBuffer buffer) +{ +#if !DDRLESS + /* Find the object. */ + el_Obj_Buffer *buff = (el_Obj_Buffer *)get_object(buffer); + + /* If found, delete the vg_lite_buffer object. Otherwise, return FALSE. */ + if (buff != NULL) { + if (buff->buffer.handle != NULL) { + /* Free the buffer memory. */ + vg_lite_free(&buff->buffer); + } + + remove_object((el_Object*)buff); + elm_free(buff); + + return TRUE; + } + else { + return FALSE; + } +#else + return TRUE; +#endif +} + +BOOL ElmSaveBuffer(ElmBuffer buffer, const char *name) +{ +#if !DDRLESS + el_Obj_Buffer *buff = (el_Obj_Buffer *)get_object(buffer); + + /* If found, delete the vg_lite_buffer object. Otherwise, return FALSE. */ + if (buff != NULL) { +#if !RTOS + /* + "vg_lite_save_png" function does not exist (anymore). Probably a left + over from an older driver. + */ + if (buff->buffer.memory != NULL) { + vg_lite_save_png(name, &buff->buffer); + } +#endif + return TRUE; + } + else { + return FALSE; + } +#else + return TRUE; +#endif +} + + /*! + @abstract Convert vglite format to elm format. + */ +ELM_BUFFER_FORMAT _buffer_format_to_Elm(vg_lite_buffer_format_t format) +{ + switch (format) + { + case VG_LITE_RGB565: + return ELM_BUFFER_FORMAT_RGB565; + break; + case VG_LITE_BGR565: + return ELM_BUFFER_FORMAT_BGR565; + break; + default: + return ELM_BUFFER_FORMAT_RGBA8888; + break; + } +} + + /*! + @abstract Get handle of the framebuffer. + */ +ElmBuffer ElmGetBuffer(vg_lite_buffer_t *buffer) +{ + elm_tls_t* elm_tls; + + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return ELM_NULL_HANDLE; + + for (int i = 0; i < APP_BUFFER_COUNT; i++) { + if (elm_tls->gContext.elmFB[i].buffer == NULL) { + elm_tls->gContext.elmFB[i].buffer = buffer; + elm_tls->gContext.elmFB[i].handle = ElmWrapBuffer(buffer->width, buffer->height, buffer->stride, buffer->memory, + buffer->address, _buffer_format_to_Elm(buffer->format)); + vg_lite_clear(buffer, NULL, 0x0); + return elm_tls->gContext.elmFB[i].handle; + } + if (elm_tls->gContext.elmFB[i].buffer == buffer) + return elm_tls->gContext.elmFB[i].handle; + } + return 0; +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_draw.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_draw.c new file mode 100644 index 0000000000..a0ce85f096 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_draw.c @@ -0,0 +1,483 @@ +/**************************************************************************** +* +* Copyright 2012 - 2020 Vivante Corporation, Santa Clara, California. +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#include "elm_precom.h" + +#if (VG_RENDER_TEXT==1) +#include "elm_text.h" +#endif /* VG_RENDER_TEXT */ + +static void multiply(vg_lite_matrix_t * matrix, vg_lite_matrix_t * mult) +{ + vg_lite_matrix_t temp; + int row, column; + + /* Process all rows. */ + for (row = 0; row < 3; row++) { + /* Process all columns. */ + for (column = 0; column < 3; column++) { + /* Compute matrix entry. */ + temp.m[row][column] = (matrix->m[row][0] * mult->m[0][column]) + + (matrix->m[row][1] * mult->m[1][column]) + + (matrix->m[row][2] * mult->m[2][column]); + } + } + + memcpy(matrix, &temp, sizeof(temp)); + +} + +static vg_lite_filter_t quality_to_filter(ELM_QUALITY quality) +{ + switch (quality) { + case ELM_QULIATY_HI: + return VG_LITE_FILTER_BI_LINEAR; + break; + + case ELM_QUALITY_MED: + return VG_LITE_FILTER_LINEAR; + break; + + case ELM_QUALITY_LOW: + default: + return VG_LITE_FILTER_POINT; + break; + } +} + +static vg_lite_pattern_mode_t pat_to_pad(ELM_PATTERN_MODE mode) +{ + switch (mode) { + case ELM_PATTERN_MODE_PAD: + return VG_LITE_PATTERN_PAD; + break; + + default: + return VG_LITE_PATTERN_COLOR; + break; + } +} +static vg_lite_error_t draw_evo_pattern(el_Obj_Buffer *buff, el_Obj_Group *ego,int * index) +{ + el_Obj_EVO *evo; + vg_lite_error_t error = VG_LITE_INVALID_ARGUMENT; + vg_lite_color_t color; + vg_lite_filter_t filter; + vg_lite_blend_t blend; + vg_lite_fill_t rule; + vg_lite_buffer_t *buffer; + vg_lite_matrix_t mat; + vg_lite_pattern_mode_t pat_mode; + int width = 0; + int height = 0; + + int start = *index; + int i = start; + evo = &ego->group.objects[i]; + width = (int)(evo->data.path.bounding_box[2] - evo->data.path.bounding_box[0]); + height = (int)(evo->data.path.bounding_box[3] - evo->data.path.bounding_box[1]); + buffer = (vg_lite_buffer_t *)malloc(sizeof(vg_lite_buffer_t)); + memset(buffer,0,sizeof(vg_lite_buffer_t)); + buffer->width = width; + buffer->height = height; + buffer->format = VG_LITE_RGBA8888; + error = vg_lite_allocate(buffer); + vg_lite_clear(buffer,NULL,0xffffffff); + i++; + evo = &ego->group.objects[i]; + while(evo->is_pattern) + { + blend = (vg_lite_blend_t)evo->attribute.blend; + rule = (vg_lite_fill_t)evo->attribute.fill_rule; + color = (vg_lite_color_t)evo->attribute.paint.color; + memcpy(&mat, &(evo->attribute.transform.matrix), sizeof(mat)); + error = vg_lite_draw(buffer, &evo->data.path, + rule, + &mat, + blend, + color); + if(error) + return error; + i++; + evo = &ego->group.objects[i]; + } + *index = i - 1; + evo = &ego->group.objects[start]; + blend = (vg_lite_blend_t)evo->attribute.blend; + rule = (vg_lite_fill_t)evo->attribute.fill_rule; + color = (vg_lite_color_t)evo->attribute.paint.color; + memcpy(&mat, &(evo->attribute.transform.matrix), sizeof(mat)); + filter = VG_LITE_FILTER_POINT; + pat_mode = VG_LITE_PATTERN_COLOR; + error = vg_lite_draw_pattern(&buff->buffer, &evo->data.path, + rule, + &mat, + buffer, + &mat, + blend, + pat_mode, + color, + filter); + vg_lite_finish(); + vg_lite_free(buffer); + free(buffer); + return error; +} + +static vg_lite_error_t draw_evo(el_Obj_Buffer *buff, el_Obj_EVO *evo, vg_lite_matrix_t *mat) +{ + el_Obj_EBO *pattern; + vg_lite_error_t error = VG_LITE_INVALID_ARGUMENT; + vg_lite_color_t color; + vg_lite_filter_t filter; + vg_lite_matrix_t mat_pattern; + ELM_PAINT_TYPE paint_type = evo->attribute.paint.type; + vg_lite_blend_t blend = (vg_lite_blend_t)evo->attribute.blend; + vg_lite_fill_t rule = (vg_lite_fill_t)evo->attribute.fill_rule; + vg_lite_pattern_mode_t pat_mode = pat_to_pad(evo->attribute.paint.pattern.mode); + + switch (paint_type) { + case ELM_PAINT_GRADIENT: + memcpy(&evo->attribute.paint.grad->data.grad.matrix, + &evo->attribute.paint.grad->data.transform.matrix, + sizeof(evo->attribute.paint.grad->data.transform.matrix)); +#if !DDRLESS + error = vg_lite_draw_gradient(&buff->buffer, &evo->data.path, + rule, + mat, + &evo->attribute.paint.grad->data.grad, + blend); +#else + error = vg_lite_draw_gradient(NULL, &evo->data.path, + rule, + mat, + &evo->attribute.paint.grad->data.grad, + blend); +#endif + break; + case ELM_PAINT_RADIAL_GRADIENT: + memcpy(&evo->attribute.paint.radgrad->data.rad_grad.matrix, + &evo->attribute.paint.radgrad->data.transform.matrix, + sizeof(evo->attribute.paint.radgrad->data.transform.matrix)); + + error = vg_lite_draw_radial_gradient(&buff->buffer, &evo->data.path, + rule, + mat, + &evo->attribute.paint.radgrad->data.rad_grad, + 0, + blend, + VG_LITE_FILTER_LINEAR); + break; + case ELM_PAINT_COLOR: + color = (vg_lite_color_t)evo->attribute.paint.color; + +#if !DDRLESS + error = vg_lite_draw(&buff->buffer, &evo->data.path, + rule, + mat, + blend, + color); +#else + error = vg_lite_draw(NULL, &evo->data.path, + rule, + mat, + blend, + color); +#endif + break; + case ELM_PAINT_PATTERN: + pattern = (el_Obj_EBO *)(evo->attribute.paint.pattern.pattern); + blend = (vg_lite_blend_t)(pattern->attribute.blend); + filter = quality_to_filter(evo->attribute.quality); + color = (vg_lite_color_t)pattern->attribute.paint.color; + memcpy(&mat_pattern, &pattern->attribute.transform.matrix, + sizeof(pattern->attribute.transform.matrix)); + +#if !DDRLESS + error = vg_lite_draw_pattern(&buff->buffer, &evo->data.path, rule, mat, + &pattern->data.buffer, &mat_pattern, blend, + pat_mode, color, filter); +#else + error = vg_lite_draw_pattern(NULL, &evo->data.path, rule, mat, + &pattern->data.buffer, &mat_pattern, blend, + pat_mode, color, filter); +#endif + break; + case ELM_PAINT_TEXT: +#if (VG_RENDER_TEXT==1) + error = draw_text(buff, evo, mat); +#endif /* VG_RENDER_TEXT */ + break; + } + + return error; +} + +static vg_lite_error_t draw_ebo(el_Obj_Buffer *buff, el_Obj_EBO *ebo, vg_lite_matrix_t *mat) +{ + vg_lite_error_t error; + vg_lite_buffer_t *image_buffer = &ebo->data.buffer; + vg_lite_blend_t blend = (vg_lite_blend_t)ebo->attribute.blend; + vg_lite_color_t color = ebo->attribute.paint.color; + vg_lite_filter_t filter = quality_to_filter(ebo->attribute.quality); + + if (image_buffer->format >= VG_LITE_INDEX_1 && image_buffer->format <= VG_LITE_INDEX_8) + { + vg_lite_set_CLUT(ebo->clut_count, ebo->clut); + } + + image_buffer->image_mode = VG_LITE_NORMAL_IMAGE_MODE; +#if !DDRLESS + error = vg_lite_blit(&buff->buffer, image_buffer, mat, blend, color, filter); +#else + error = vg_lite_blit(NULL, image_buffer, mat, blend, color, filter); +#endif + return error; +} +/*! + @abstract Clear a render buffer with specified color and dimension. + + @discussion + This function is called to clear full or partial of the buffer. If the rectangle is out of buffer space, the intersect portion will be cleared. + + @param buffer + A render buffer handle. + + @param color + Clear color value. + + @param x + x origin of partical clear rectangle. + + @param y + y origin of partial clear rectangle. + + @param width + width of partical clear rectangle. + + @param height + height of partical clear rectangle. + + @param full + Flag to indicate a full buffer clear. If true, the dimension parameters will be ignored. + + @return bool + Indicate the clear operation is set up correctly. + */ +BOOL ElmClear(ElmBuffer buffer, uint32_t color, uint32_t x, uint32_t y, uint32_t width, uint32_t height, BOOL full) +{ +#if !DDRLESS + vg_lite_error_t error = VG_LITE_SUCCESS; + el_Obj_Buffer *buff = (el_Obj_Buffer *)get_object(buffer); + vg_lite_rectangle_t rectangle; + rectangle.x = x; + rectangle.y = y; + rectangle.width = width; + rectangle.height = height; + + if (full == 1) + { + error = vg_lite_clear(&buff->buffer, NULL, color); + } + else + { + error = vg_lite_clear(&buff->buffer, &rectangle, color); + } + return ((error == VG_LITE_SUCCESS) ? TRUE : FALSE); +#else + return TRUE; +#endif +} + +/*! + @abstract Finish all rendering on GPU issued before this call. + + @discussion + This function tells the engine that it has finished the frame data and GPU can draw it now. It's blocked until GPU rendering done. + + @return + If the opeartion is successfully done or not. + */ +BOOL ElmFinish() +{ + vg_lite_finish(); + return TRUE; +} + +/*! + @abstract Flush all rendering command to GPU issued before this call. + + @discussion + This function tells the engine to start kicking off command to GPU side, it will return immediately after firing off GPU. + + @return + If the opeartion is successfully done or not. + */ +BOOL ElmFlush() +{ + vg_lite_flush(); + return TRUE; +} + + + +/*! + @abstract Draw a graphics object onto current render target + + @discussion + This is an enssentail function to do the real job, it takes all current setting of the elementary object and + render into theb buffer target. + + @param buffer + The render target that an elmentary object will be rendered into. + + @param obj + The elmentary object will be draw into render target. + + @return bool + The draw operation for this elmentary object is sucessful. + */ +BOOL ElmDraw(ElmBuffer buffer, ElmHandle object) +{ + BOOL status = TRUE; + el_Object *elm; + el_Obj_Buffer *buff; + vg_lite_error_t error; + vg_lite_matrix_t mat; + elm = get_object(object); + + if (!elm) + { + return FALSE; + } + +#if !DDRLESS + buff = (el_Obj_Buffer *)get_object(buffer); + if (buff == NULL) + { + return FALSE; + } +#else + buff = NULL; +#endif + + if (elm->type == ELM_OBJECT_TYPE_EGO) + { + el_Obj_EVO *evo; + el_Obj_Group *ego = (el_Obj_Group *)elm; + vg_lite_matrix_t mat_group, res_mat; + + if (ego->group.count > 0) + { + int i; + memcpy(&mat_group, &(ego->transform.matrix), sizeof(ego->transform.matrix)); + for (i = 0; i < ego->group.count; i++) + { + evo = &ego->group.objects[i]; + + /* Font objects may generate empty objects */ + if (evo->object.handle == ELM_NULL_HANDLE) + continue; + + if(evo->is_image) + { + ElmHandle ebo_handle; + el_Object *elm_ebo; + el_Obj_EBO *ebo; + ebo_handle = ElmCreateObjectFromFile(ELM_OBJECT_TYPE_EBO, evo->eboname); + elm_ebo = get_object(ebo_handle); + ebo = (el_Obj_EBO *)elm_ebo; + memcpy(&mat, &evo->defaultAttrib.transform.matrix, sizeof(mat)); + + error = draw_ebo(buff, ebo, &mat); + if (error) + { + status = FALSE; + } + continue; + } + memcpy(&mat, &(evo->attribute.transform.matrix), sizeof(mat)); + memcpy(&res_mat, &mat_group, sizeof(mat_group)); + multiply(&res_mat, &mat); + + if(evo->has_pattern) + error = draw_evo_pattern(buff,ego,&i); + else + error = draw_evo(buff, evo, &res_mat); + if (error) + { + status = FALSE; + break; + } + } + } + } + else if (elm->type == ELM_OBJECT_TYPE_EVO) + { + el_Obj_EVO *evo = (el_Obj_EVO *)elm; + memcpy(&mat, &(evo->attribute.transform.matrix), sizeof(mat)); + + error = draw_evo(buff, evo, &mat); + if (error) + { + status = FALSE; + } + } + else if (elm->type == ELM_OBJECT_TYPE_EBO) + { + el_Obj_EBO *ebo = (el_Obj_EBO *)elm; + memcpy(&mat, &(ebo->attribute.transform.matrix), sizeof(mat)); + + error = draw_ebo(buff, ebo, &mat); + if (error) + { + status = FALSE; + } + + } + else if (elm->type == ELM_OBJECT_TYPE_BUF) + { + el_Obj_Buffer *src = (el_Obj_Buffer *)elm; + vg_lite_identity(&mat); + +#if !DDRLESS + if (VG_LITE_SUCCESS != + vg_lite_blit(&buff->buffer, &src->buffer, &mat, VG_LITE_BLEND_NONE, 0, + VG_LITE_FILTER_BI_LINEAR) + ) +#else + if (VG_LITE_SUCCESS != + vg_lite_blit(NULL, &src->buffer, &mat, VG_LITE_BLEND_NONE, 0, + VG_LITE_FILTER_BI_LINEAR) + ) +#endif + { + status = FALSE; + } + } + return status; +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_headers.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_headers.h new file mode 100644 index 0000000000..70937c8ad0 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_headers.h @@ -0,0 +1,158 @@ +/**************************************************************************** +* +* Copyright 2021 Vivante Corporation, Santa Clara, California. +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#ifndef __ELM_HEADERS_H__ +#define __ELM_HEADERS_H__ + + +#define ATTR_PACKED __attribute__((packed, aligned(4))) + + +typedef struct { + vg_lite_matrix_t matrix; + uint32_t reserved; + uint32_t stop_count; + uint32_t stop_offset; + uint32_t color_offset; +} el_EVO_GradData; + +typedef struct { + vg_lite_radial_gradient_parameter_t params; + vg_lite_radial_gradient_spreadmode_t spread_mode; +} el_EVO_RadGradDataExt; + +struct el_PaintType_t { + uint32_t paint:28; + uint32_t flags:1; + uint32_t is_image:1; + uint32_t is_pattern:1; + uint32_t has_pattern:1; +}; + +typedef struct ATTR_PACKED { + uint32_t type; + vg_lite_float_t min_x, min_y, max_x, max_y; + uint32_t format; + uint32_t length:31; + uint32_t arc_flag:1; + uint32_t offset; + vg_lite_matrix_t matrix; + uint32_t reserved; + uint32_t quality; + uint32_t fill_rule; + uint32_t blend; + union { + uint32_t paint_data; + struct el_PaintType_t paint_type; + }; + vg_lite_color_t color; + el_EVO_GradData grad; +} el_EVO_Polygon; + +typedef struct ATTR_PACKED { + uint32_t type; + uint32_t namelength; + char eboname[76]; + union { + uint32_t paint_data; + struct el_PaintType_t paint_type; + }; + vg_lite_matrix_t matrix; + uint32_t width; + uint32_t height; +} el_EVO_Image; + +typedef struct ATTR_PACKED { + union { + el_EVO_Polygon polygon; + el_EVO_Image image; + }; +} el_EVO_Header; + +typedef struct ATTR_PACKED { + uint32_t type; + uint32_t size_font_block; + uint32_t num_ttf_fonts; + uint32_t num_vector_fonts; + uint32_t num_text_fonts; + uint32_t ttf_fonts_block_offset; + uint32_t ttf_fonts_block_length; + uint32_t vector_fonts_block_offset; + uint32_t vector_fonts_block_length; + uint32_t text_fonts_block_offset; + uint32_t text_fonts_block_length; + uint32_t property_block_offset; + uint32_t property_block_length; +} el_Font_Header; + +struct el_TextFlags_t { + uint32_t flags1:1; + uint32_t text_anchor:2; + uint32_t flags2:29; +}; + +typedef struct ATTR_PACKED { + uint32_t type; + uint32_t size_text_block; + uint32_t tspan_has_dx_dy; + float x_pos; + float y_pos; + float font_size; + uint32_t font_id; + uint32_t color; + union { + uint32_t flags_data; + struct el_TextFlags_t text_flags; + }; + vg_lite_matrix_t matrix; + uint32_t reserved; + uint16_t data_length; +} el_Text_Header; + +typedef struct ATTR_PACKED { + uint32_t type; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t tiled; + uint32_t format; + uint32_t data_offset; +} el_EBO_Header; + +typedef struct ATTR_PACKED { + uint32_t clut_count; + uint32_t clut_data_offset; +} el_EBO_Palette; + +typedef struct ATTR_PACKED { + uint32_t type; + vg_lite_matrix_t matrix; + uint32_t count; +} el_EGO_Header; + + +#endif /* __ELM_HEADERS_H__ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_init.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_init.c new file mode 100644 index 0000000000..3c5f1688b8 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_init.c @@ -0,0 +1,160 @@ +/**************************************************************************** +* +* Copyright 2012 - 2020 Vivante Corporation, Santa Clara, California. +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#include "elm_precom.h" +#include "elm_os.h" +#include "vg_lite_os.h" +#if (VG_RENDER_TEXT==1) +#include "elm_text.h" +#endif /* VG_RENDER_TEXT */ + +/* Prototypes */ +static int _initialize_elm(uint32_t width, uint32_t height); + +/* Initialize vg_lite related. */ +static int _initialize_vglite(int32_t width, int32_t height) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + + error = vg_lite_init(width, height); + + return (error == VG_LITE_SUCCESS); +} + +/* Initialize elm global objects. */ +static int _initialize_elm(uint32_t width, uint32_t height) +{ + vg_lite_error_t error; + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *)elm_os_get_tls(); + if (elm_tls == NULL) { + elm_tls = (elm_tls_t *)vg_lite_os_malloc(sizeof(elm_tls_t)); + error = elm_os_set_tls((void *) elm_tls); + if(error != VG_LITE_SUCCESS) + return error; + } + + int i; + + elm_tls->gContext.version = VERSION; + elm_tls->gContext.currentHandle = (ELM_NULL_HANDLE + 1); /* Reserve handle 0 for error */ + elm_tls->gContext.objectCount = 0; + elm_tls->gContext.tessellation_width = width; + elm_tls->gContext.tessellation_height = height; + elm_tls->gContext.vector_id = -1; + + for (i = 0; i < SLOT_COUNT; i++) { + elm_tls->gContext.object_slots[i] = NULL; + } + +#if (RTOS && DDRLESS) || BAREMETAL + for (i = 0; i < sizeof(elm_tls->gContext.objmap_ebo) / 4; i++) { + elm_tls->gContext.objmap_ebo[i] = 0; + } + for (i = 0; i < sizeof(elm_tls->gContext.objmap_evo) / 4; i++) { + elm_tls->gContext.objmap_evo[i] = 0; + } + for (i = 0; i < sizeof(elm_tls->gContext.objmap_group) / 4; i++) { + elm_tls->gContext.objmap_group[i] = 0; + } + for (i = 0; i < sizeof(elm_tls->gContext.objmap_grad) / 4; i++) { + elm_tls->gContext.objmap_grad[i] = 0; + } + + elm_tls->gContext.objcounter_grad = 0; + elm_tls->gContext.objcounter_evo = 0; + elm_tls->gContext.objcounter_ebo = 0; + elm_tls->gContext.objcounter_group = 0; +#endif + return 1; +} + +/* Terminate vg_lite related. */ +static void _terminate_vglite(void) +{ + vg_lite_close(); +} + +/* Terminate elm global objects. */ +static void _terminate_elm(void) +{ +#if (VG_RENDER_TEXT==1) + _release_default_text_parameters(); +#endif + elm_os_reset_tls(); +} + +/*! + @abstract Initialize Elementary context. + + @discussion + It should be called as the first function of Elemenatary libary, which initializes the library. Currently + Elementary library doesn't support context concept, neigher multi-threading. Elementary library defines + origin of coordinate system is at top-left. + + @param none + + @return none + */ +BOOL ElmInitialize(uint32_t width, uint32_t height) +{ + BOOL result = TRUE; + + do { + result = _initialize_vglite((int32_t)width, (int32_t)height); + + if (!result) + break; + + result = _initialize_elm(width, height); + + if (!result) + break; + } + while (0); + +#if (VG_RENDER_TEXT==1) + initialize_elm_text(); +#endif /* VG_RENDER_TEXT */ + return result; +} + +/*! + @abstract Terminate Elementary context. + + @discussion + This should be called when an app exits. It frees all the resource. + + @param none + + @return none + */ +void ElmTerminate(void) +{ + _terminate_elm(); + _terminate_vglite(); +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_object.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_object.c new file mode 100644 index 0000000000..742bc14c76 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_object.c @@ -0,0 +1,2238 @@ +/**************************************************************************** +* +* Copyright 2012 - 2021 Vivante Corporation, Santa Clara, California. +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#include "elm_precom.h" +#include "elm_os.h" +#include "vg_lite_text.h" +#include "vft_debug.h" +#include "elm_headers.h" + +#if (VG_RENDER_TEXT==1) +#include "elm_text.h" +#endif /* VG_RENDER_TEXT */ + +#if RTOS +#define BASE_ADDRESS_ALIGNMENT 32 +#else +#define BASE_ADDRESS_ALIGNMENT 4 +# endif +/* #define ENABLE_ELM_CRATE_OBJECT_FROM_FILE */ + +/* + * ANSI APIs are missing so application can use ElmCreateObjectFromData + * This simplifies things since file can be from FATFS, NOR Flash buffer etc. + */ + +#if (RTOS && DDRLESS) || BAREMETAL +/* Find some free objects, return the first index, + * and mark the bits as 1 (allocated). + * Params: + * free_map: the map bits of the objects where 0 is free and 1 is allocated; + * count : the element count of free_map[]; + * obj_count:how many objects to allocate from the pool. + * + * Return: + * The free index of the object in the pool. + * */ +int get_free_objects(int32_t free_map[], int count, int obj_count) +{ + int i, j; + int result = -1; + int counter = 0; + int bit_count = 0; + int32_t bits; + + /* Find a free bit. */ + for (i = 0; i < count; i++) { + bits = free_map[i]; + + for (j = 0; j < 32; j++) { + //Increase the bit counter. + bit_count++; + + if ((bits & 0x80000000) == 0) { + //Free bit is found. then count available free bits. + counter++; + } + else { + //Free bit is not found, reset the counter. + counter = 0; + } + + //Check to see whether enough bits are found. + if (counter >= obj_count) { + result = bit_count - counter; + + //Get out of the two loops. + i = count; + break; + } + + //Shift to next bit. + bits <<= 1; + } + } + + /* Mark the bits as allocated if OK. */ + if (result > -1) { + int bits_set = 1; + int bit_offset = result % 32; + bit_count = result / 32; + + while (obj_count > 0) { + bits_set = ~(0xffffffff << (32 - bit_offset)); + if (obj_count <= 32 - bit_offset) { + //Done. + bits_set = bits_set & (0xffffffff << (32 - bit_offset - obj_count)); + free_map[bit_count] |= bits_set; + break; + } + free_map[bit_count] |= bits_set; + + //Go to next map element. + obj_count -= (32 - bit_offset); + bit_count++; + bit_offset = 0; + } + } + + return result; +} + +/* When an object is "freed", mark the corresponding bits to 0. */ +void mark_free_object(int32_t free_map[], int object) +{ + int index, offset; + + index = object / 32; + offset = object % 32; + + free_map[index] &= ~(1 << (31 - offset)); +} + +/* Check whether an object (with given index) allocated or not. */ +int object_exists(int32_t free_map[], int index) +{ + int32_t bits; + int offset = index % 32; + index /= 32; + + bits = ~(1 << (31 - offset)); + + if (free_map[index] & bits) { + return 1; + } + else { + return 0; + } +} + +/* Allocate an EVO object from pool. */ +static el_Obj_EVO * alloc_evo(int count) +{ + elm_tls_t* elm_tls; + int index; + el_Obj_EVO *object = NULL; + + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return NULL; + + index = get_free_objects(elm_tls->gContext.objmap_evo, COUNT_OF(elm_tls->gContext.objmap_evo), count); + + if (index > -1) { + object = &elm_tls->gContext.objpool_evo[index]; + elm_tls->gContext.objcounter_evo += count; + for (; count > 0; count--) { + object[count - 1].object.index = index + count - 1; + } + } + + return object; +} + +/* Allocate an EBO object from pool. */ +static el_Obj_EBO * alloc_ebo() +{ + elm_tls_t* elm_tls; + int index; + el_Obj_EBO *object = NULL; + + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return NULL; + + index = get_free_objects(elm_tls->gContext.objmap_ebo, COUNT_OF(elm_tls->gContext.objmap_ebo), 1); + + if (index > -1) { + object = &elm_tls->gContext.objpool_ebo[index]; + object->object.index = index; + elm_tls->gContext.objcounter_ebo++; + } + + return object; +} + +/* Allocate an EGO object from pool. */ +static el_Obj_Group * alloc_ego() +{ + elm_tls_t* elm_tls; + int index; + el_Obj_Group *object = NULL; + + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return NULL; + + index = get_free_objects(elm_tls->gContext.objmap_group, COUNT_OF(elm_tls->gContext.objmap_group), 1); + + if (index > -1) { + object = &elm_tls->gContext.objpool_group[index]; + object->object.index = index; + elm_tls->gContext.objcounter_group++; + } + + return object; +} + +/* Mark an EGO object as free: insert it into the free list. */ +static void free_ego(el_Obj_Group *object) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return NULL; + + mark_free_object(elm_tls->gContext.objmap_group, elm_tls->object->object.index); + elm_tls->gContext.objcounter_group--; +} + +/* Allocate a grad object from pool. */ +static el_Obj_Grad * alloc_grad() +{ + elm_tls_t* elm_tls; + int index; + el_Obj_Grad *object = NULL; + + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return NULL; + + index = get_free_objects(elm_tls->gContext.objmap_grad, COUNT_OF(elm_tls->gContext.objmap_grad), 1); + + if (index > -1) { + object = &elm_tls->gContext.objpool_grad[index]; + object->object.index = index; + elm_tls->gContext.objcounter_grad++; + } + + return object; +} + +#endif +/* Internal Implementations *******************************/ +int deref_object(el_Object *object) +{ + object->reference--; + return object->reference; +} + +int ref_object(el_Object *object) +{ + object->reference++; + return object->reference; +} + +int add_object(el_Object *object) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return 0; +#if (RTOS && DDRLESS) || BAREMETAL + /* Assign handle. */ + object->handle = elm_tls->gContext.currentHandle++; + return 1; +#else + int result = 1; + el_ObjList *list = NULL; + + /* Assign handle. */ + object->handle = elm_tls->gContext.currentHandle++; + + /* Get the list slot. */ + list = OBJECT_SLOT(object->handle); + if (list == NULL) { + list = (el_ObjList *) elm_alloc(1, sizeof(el_ObjList)); + if ( list == NULL ) { + return 0; /* Memory allocation failed */ + } +#ifdef ENABLE_STRICT_DEBUG_MEMSET + memset(list, 0, sizeof(el_ObjList)); +#endif + + OBJECT_SLOT(object->handle) = list; + + list->object = object; + list->next = NULL; + + return 1; + } + + /* Insert the object. */ + while (list->next != NULL) { + list = list->next; + } + list->next = (el_ObjList *) elm_alloc(1, sizeof(el_ObjList)); + if ( list->next == NULL ) { + return 0; /* Memory allocation failed */ + } +#ifdef ENABLE_STRICT_DEBUG_MEMSET + memset(list->next, 0, sizeof(el_ObjList)); +#endif + list = list->next; + list->object = object; + list->next = NULL; + + return result; +#endif +} + +int remove_object(el_Object *object) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return 0; + + int result = 0; +#if (!(RTOS && DDRLESS)) && (!BAREMETAL) + el_ObjList *list = NULL, *node = NULL; + + // Get the list slot. + list = OBJECT_SLOT(object->handle); + + // Invalid. + if (list == NULL) + return 0; + + // Find the object. + if (list->object == object) { + OBJECT_SLOT(object->handle) = list->next; + elm_free(list); + return 1; + } + + while (list->next != NULL) { + if (list->next->object == object) { + node = list->next; + list->next = list->next->next; + elm_free(node); + return 1; + } + list = list->next; + } +#endif + + return result; +} + +el_Object *get_object(ElmHandle handle) +{ + elm_tls_t* elm_tls; + el_Object *object = NULL; + + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return NULL; + +#if (RTOS && DDRLESS) || BAREMETAL + int i; + for (i = 0; i < OBJCOUNT_EVO; i++) { + if (object_exists(elm_tls->gContext.objmap_evo, i)) { + if (elm_tls->gContext.objpool_evo[i].object.handle == handle) { + object = (el_Object *)&elm_tls->gContext.objpool_evo[i]; + return object; + } + } + } + for (i = 0; i < OBJCOUNT_EBO; i++) { + if (object_exists(elm_tls->gContext.objmap_ebo, i)) { + if (elm_tls->gContext.objpool_ebo[i].object.handle == handle) { + object = (el_Object *)&elm_tls->gContext.objpool_ebo[i]; + return object; + } + } + } + for (i = 0; i < OBJCOUNT_GRAD; i++) { + if (object_exists(elm_tls->gContext.objmap_grad, i)) { + if (elm_tls->gContext.objpool_grad[i].object.handle == handle) { + object = (el_Object *)&elm_tls->gContext.objpool_grad[i]; + return object; + } + } + } + for (i = 0; i < OBJCOUNT_GROUP; i++) { + if (object_exists(elm_tls->gContext.objmap_group, i)) { + if (elm_tls->gContext.objpool_group[i].object.handle == handle) { + object = (el_Object *)&elm_tls->gContext.objpool_group[i]; + return object; + } + } + } +#else + el_ObjList *list = NULL; + + // Get the slot. + list = OBJECT_SLOT(handle); + + // Find the object. + while (list != NULL) { + if ((list->object != NULL) && + (list->object->handle == handle)) { + object = list->object; + return object; + } + list = list->next; + } +#endif + + DEBUG_ASSERT(0, "Unknown object"); + return NULL; +} + +#if (RTOS && DDRLESS) || BAREMETAL +static void free_grad(el_Obj_Grad *object) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls != NULL) { + mark_free_object(elm_tls->gContext.objmap_grad, object->object.index); + elm_tls->gContext.objcounter_grad--; + } +} +#endif + +/* Destroy an evo object data. */ +int destroy_evo(el_Obj_EVO *evo) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return 0; + +#if (RTOS && DDRLESS) || BAREMETAL + mark_free_object(elm_tls->gContext.objmap_evo, evo->object.index); + elm_tls->gContext.objcounter_evo--; + free_grad(evo->defaultAttrib.paint.grad); +#else + + if ( evo->defaultAttrib.paint.type == ELM_PAINT_TEXT ) { +#if (VG_RENDER_TEXT==1) + _unload_text(evo); +#else + ; +#endif /* VG_RENDER_TEXT */ + } else { + /* TODO: EVO destroy not done yet. */ + if (evo->defaultAttrib.paint.grad != NULL) { + vg_lite_clear_grad(&evo->defaultAttrib.paint.grad->data.grad); + elm_free(evo->defaultAttrib.paint.grad); + evo->defaultAttrib.paint.grad = NULL; + } + + if (evo->data.path.path != NULL) { + vg_lite_clear_path(&evo->data.path); + elm_free(evo->data.path.path); + evo->data.path.path = NULL; + } + } + + remove_object(&evo->object); +#endif + +#if (VG_RENDER_TEXT==1) + destroy_font_data(); +#endif /* VG_RENDER_TEXT */ + return 1; +} + +/* Destroy an ego object data. */ +int destroy_ego(el_Obj_Group *ego) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if(elm_tls == NULL) + return 0; + +#if (RTOS && DDRLESS) || BAREMETAL + mark_free_object(elm_tls->gContext.objmap_group, ego->object.index); + elm_tls->gContext.objcounter_group--; +#else + int i; + for (i = 0; i < ego->group.count; i++) + { + destroy_evo(&ego->group.objects[i]); + } + elm_free(ego->group.objects); + elm_free(ego); +#endif + +#if (VG_RENDER_TEXT==1) + destroy_font_data(); +#endif /* VG_RENDER_TEXT */ + return 1; +} + +/* Destroy an ebo object data. */ +int destroy_ebo(el_Obj_EBO *ebo) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if(elm_tls == NULL) + return 0; + +#if (RTOS && DDRLESS) || BAREMETAL + mark_free_object(elm_tls->gContext.objmap_ebo, ebo->object.index); + elm_tls->gContext.objcounter_ebo--; +#else + if ( ebo != NULL && ebo->data.buffer.handle != NULL) { + vg_lite_free(&ebo->data.buffer); + } + elm_free(ebo); +#endif + return 1; +} + +/* Destroy an object. + return: + -1: any error; + 0: destroyed when reference count is 0; + 1: decreased reference count but still > 0. + */ +int destroy_object(ElmHandle handle) +{ + el_Object *object = NULL; + int ref_count = 0; + + object = get_object(handle); + + // No such object. + if (object == NULL) { + DEBUG_ASSERT(0, "No such object"); + return -1; + } + + // Dereference object, and destroy if it's no more referred. + ref_count = deref_object(object); + if (ref_count == 0) { + remove_object(object); + + switch (object->type) { + case ELM_OBJECT_TYPE_EVO: + destroy_evo((el_Obj_EVO *)object); + elm_free(object); + break; + + case ELM_OBJECT_TYPE_EGO: + destroy_ego((el_Obj_Group *) object); + break; + + case ELM_OBJECT_TYPE_EBO: + destroy_ebo((el_Obj_EBO *) object); + break; + + default: + DEBUG_ASSERT(0, "Unknow object type"); + break; + } + } + + return 1; +} + +void _init_transform(el_Transform *transform) +{ + int i = 0; + transform->rotate = 0.0f; + for (i = 0;i < 2; i++) + { + transform->scale[i] = 1.0f; + transform->translate[i] = 0.0f; + } + vg_lite_identity(&transform->matrix); +} + +/* Static functions. *************************************************/ + +/* Get the specified vector object in a group. */ +static el_Obj_EVO* _get_evo(el_Obj_Group *group, int32_t id) +{ + if ((id >= group->group.count) || + (id < 0)){ + return (el_Obj_EVO*)NULL; + } + else { + return (el_Obj_EVO*)(group->group.objects + id); + } +} + +#if (VG_RENDER_TEXT==1) +static int _load_font(uint8_t *data, + unsigned size) +{ + ElmHandle ret = ELM_NULL_HANDLE; + el_Font_Header *font_header = (el_Font_Header *)data; + + + if (font_header->size_font_block != size) + return ret; + + return _load_font_data(data); +} + +static ElmHandle _load_text(uint8_t *data, + unsigned size, + el_Obj_EVO *evo) +{ + ElmHandle ret = ELM_NULL_HANDLE; + el_Text_Header *text_header = (el_Text_Header *)data; + + + if (text_header->size_text_block != size) + return ret; + + return _load_text_data(data, evo); +} +#endif /* VG_RENDER_TEXT */ + +#if (defined(__ICCARM__)) +/* + * Disable the unaligned structure attribute warning. Due to the packed data + * structures used to interpret ELM objects data the IAR compiler issues a + * number of warnings that certain attributes of the headers might be unaligned. + * This is not true, however, as all atributes are manually aligned to 4 bytes. + */ +#pragma diag_suppress = Pa039 +#endif + +static ElmHandle _load_evo(const uint8_t *data, unsigned size, el_Obj_EVO *evo) +{ + int i = 0; +#if (RTOS && DDRLESS) || BAREMETAL + uint32_t colors[VLC_MAX_GRAD]; + void *path_data; +#else + uint32_t *colors = NULL; + uint8_t *path_data = NULL; +#endif + el_Obj_EVO *local_evo = NULL; + el_EVO_Header *evo_header = (el_EVO_Header *) data; + + if (evo == NULL) { +#if (RTOS && DDRLESS) || BAREMETAL + local_evo = alloc_evo(1); +#else + local_evo = (el_Obj_EVO *)elm_alloc(1, sizeof(el_Obj_EVO)); +#endif + evo = local_evo; + } + JUMP_IF_NULL(evo, error_exit); + memset(evo, 0, sizeof(el_Obj_EVO)); + + /* + * Check if object size is valid. The size parameter + * needs to be a value greater or equal to the + * size of the current object to be loaded. + * This check needs to be done in order to ensure + * that the is_image field is correctly read and + * we do not read from invalid memory. + */ + JUMP_IF_LOWER(size, + MIN(sizeof(el_EVO_Polygon), sizeof(el_EVO_Image)), + error_exit); + + if(evo_header->polygon.paint_type.is_image) + { + /* + * Check if object size is valid + * (greater or equal to el_EVO_Image size). + */ + JUMP_IF_LOWER(size, + sizeof(el_EVO_Image), + error_exit); + memcpy(evo->eboname, + evo_header->image.eboname, + evo_header->image.namelength); + evo->is_image = evo_header->image.paint_type.is_image; + _init_transform(&evo->defaultAttrib.transform); + memcpy(&evo->defaultAttrib.transform.matrix, + &(evo_header->image.matrix), + sizeof(vg_lite_matrix_t)); + evo->img_width = evo_header->image.width; + evo->img_height = evo_header->image.height; + } + else + { + /* + * Check if object size is valid + * (greater or equal to el_EVO_Polygon size). + */ + JUMP_IF_LOWER(size, + sizeof(el_EVO_Polygon), + error_exit); + el_Transform *transform = NULL; + el_Transform *grad_transform = NULL; + el_EVO_Polygon *object_data = (el_EVO_Polygon *) &(evo_header->polygon); + el_EVO_GradData *grad_data = (el_EVO_GradData *) &(evo_header->polygon.grad); + + /* Get path data from the object. */ +#if (RTOS && DDRLESS) || BAREMETAL + path_data = (void *) (data + object_data->offset); +#else + path_data = (uint8_t *)elm_alloc(1, object_data->length); + JUMP_IF_NULL(path_data, error_exit); + +#ifdef ENABLE_STRICT_DEBUG_MEMSET + memset(path_data, 0, object_data->length); +#endif + JUMP_IF_LOWER(size, + object_data->offset + object_data->length, + error_exit); + /* Get path data. */ + memcpy(path_data, (void *)(data + object_data->offset), + object_data->length); +#endif + + if(object_data->paint_type.has_pattern) + evo->has_pattern = 1; + if(object_data->paint_type.is_pattern) + evo->is_pattern = 1; + + _init_transform(&evo->defaultAttrib.transform); + transform = &evo->defaultAttrib.transform; + + evo->object.type = ELM_OBJECT_TYPE_EVO; + evo->object.reference = 0; + + if ((object_data->paint_type.paint == ELM_PAINT_RADIAL_GRADIENT) || + (object_data->paint_type.paint == ELM_PAINT_GRADIENT)) { +#if (RTOS && DDRLESS) || BAREMETAL + evo->defaultAttrib.paint.grad = alloc_grad(); +#else + evo->defaultAttrib.paint.grad = (el_Obj_Grad*)elm_alloc(1, sizeof(el_Obj_Grad)); +#endif + JUMP_IF_NULL(evo->defaultAttrib.paint.grad, error_exit); +#ifdef ENABLE_STRICT_DEBUG_MEMSET + memset(evo->defaultAttrib.paint.grad, 0, sizeof(el_Obj_Grad)); +#endif + evo->defaultAttrib.paint.grad->data.grad.image.width = 0; + evo->defaultAttrib.paint.grad->data.grad.image.height = 0; + evo->defaultAttrib.paint.grad->data.grad.image.stride = 0; + evo->defaultAttrib.paint.grad->data.grad.image.tiled = VG_LITE_LINEAR; + + _init_transform(&evo->defaultAttrib.paint.grad->data.transform); + grad_transform = &evo->defaultAttrib.paint.grad->data.transform; + memcpy(&grad_transform->matrix, &(grad_data->matrix), + sizeof(vg_lite_matrix_t)); + colors = (uint32_t *)elm_alloc(grad_data->stop_count, sizeof(uint32_t)); + JUMP_IF_NULL(colors, error_exit); + memcpy(colors, + data + grad_data->color_offset, + grad_data->stop_count * sizeof(uint32_t)); + } + + if (object_data->arc_flag) + vg_lite_init_arc_path(&evo->data.path, + (vg_lite_format_t) object_data->format, + (vg_lite_quality_t) object_data->quality, + object_data->length, + path_data, + object_data->min_x, + object_data->min_y, + object_data->max_x, + object_data->max_y); + else + vg_lite_init_path(&evo->data.path, + (vg_lite_format_t) object_data->format, + (vg_lite_quality_t) object_data->quality, + object_data->length, + path_data, + object_data->min_x, + object_data->min_y, + object_data->max_x, + object_data->max_y); + + memcpy(&transform->matrix, &(object_data->matrix), sizeof(vg_lite_matrix_t)); + + evo->defaultAttrib.quality = ELM_QUALITY_LOW; + evo->defaultAttrib.fill_rule = (ELM_EVO_FILL) object_data->fill_rule; + evo->defaultAttrib.blend = (ELM_BLEND) object_data->blend; + evo->defaultAttrib.paint.type = (ELM_PAINT_TYPE) object_data->paint_type.paint; + + switch (object_data->paint_type.paint) { + case ELM_PAINT_GRADIENT: + { +#if (RTOS && DDRLESS) || BAREMETAL + uint32_t stops[VLC_MAX_GRAD]; +#else + uint32_t *stops = NULL; + + stops = (uint32_t *)elm_alloc(sizeof(uint32_t), grad_data->stop_count); + JUMP_IF_NULL(stops, error_exit); +#endif + for (i = 0 ;i < grad_data->stop_count; i++) + { + stops[i] = (uint32_t)((*(float *) (data + + grad_data->stop_offset + i * 4)) * 255); + } + + vg_lite_init_grad(&evo->defaultAttrib.paint.grad->data.grad); + vg_lite_set_grad(&evo->defaultAttrib.paint.grad->data.grad, + grad_data->stop_count, colors, stops); + if (grad_data->stop_count > 0) + { + vg_lite_update_grad(&evo->defaultAttrib.paint.grad->data.grad); + } +#if (RTOS && DDRLESS) || BAREMETAL +#else + elm_free(stops); +#endif + break; + } + case ELM_PAINT_RADIAL_GRADIENT: + { + float *stops; + vg_lite_color_ramp_t *vgColorRamp; + el_EVO_RadGradDataExt *rad_grad = (el_EVO_RadGradDataExt *) (data + sizeof(el_EVO_Header)); + + JUMP_IF_LOWER(size, + sizeof(el_EVO_Polygon) + sizeof(el_EVO_RadGradDataExt), + error_exit); + + stops = (float *)elm_alloc(grad_data->stop_count, sizeof(float)); + JUMP_IF_NULL(stops, error_exit); + memset(stops, 0, grad_data->stop_count * sizeof(float)); + vgColorRamp = (vg_lite_color_ramp_t *) elm_alloc(grad_data->stop_count, + sizeof(vg_lite_color_ramp_t)); + if (vgColorRamp == NULL) { + elm_free(stops); + goto error_exit; + } + memset(vgColorRamp, 0, + sizeof(vg_lite_color_ramp_t) * grad_data->stop_count); + for (i = 0; i < grad_data->stop_count; i++) + { + stops[i] = (*(float *) (data + grad_data->stop_offset + i * 4)); + vgColorRamp[i].alpha = (float)(colors[i] >> 24) / 255.0f; + vgColorRamp[i].red = (float)(colors[i] >> 16 & 0xFF) / 255.0f; + vgColorRamp[i].green = (float)(colors[i] >> 8 & 0xFF) / 255.0f; + vgColorRamp[i].blue = (float)(colors[i] & 0xFF) / 255.0f; + vgColorRamp[i].stop = stops[i]; + } + + memset(&evo->defaultAttrib.paint.radgrad->data.rad_grad, 0, sizeof(evo->defaultAttrib.paint.radgrad->data.rad_grad)); + vg_lite_set_rad_grad(&evo->defaultAttrib.paint.radgrad->data.rad_grad, + grad_data->stop_count, + vgColorRamp, + rad_grad->params, + rad_grad->spread_mode, + 0); + vg_lite_update_rad_grad(&evo->defaultAttrib.paint.radgrad->data.rad_grad); + + elm_free(stops); + elm_free(vgColorRamp); + break; + } + default: + /* Do nothing */ + break; + } + + evo->defaultAttrib.paint.color = object_data->color; + evo->attribute = evo->defaultAttrib; + ref_object(&evo->object); + JUMP_IF_NON_ZERO_VALUE(add_object(&evo->object), error_exit); + +#if (RTOS && DDRLESS) || BAREMETAL +#else + elm_free(colors); +#endif + } + + return evo->object.handle; + +error_exit: +#if (RTOS && DDRLESS) || BAREMETAL +#else + if ( colors != NULL ) + elm_free(colors); + if ( path_data != NULL) + elm_free(path_data); +#endif + + if ( (evo != NULL) && (evo->defaultAttrib.paint.grad != NULL) ) + elm_free(evo->defaultAttrib.paint.grad); + if ( (evo != NULL) && (evo->defaultAttrib.paint.radgrad != NULL) ) + elm_free(evo->defaultAttrib.paint.radgrad); + if ( local_evo != NULL ) + elm_free(local_evo); + + return ELM_NULL_HANDLE; +} + +static ElmHandle _load_ebo(const uint8_t *data, int size, uint32_t version) +{ + vg_lite_error_t error; + vg_lite_buffer_t *buffer; + uint32_t *colors, bytes = 0; + + el_EBO_Header *ebo_header = (el_EBO_Header *) data; + +#if (RTOS && DDRLESS) || BAREMETAL + el_Obj_EBO *ebo = alloc_ebo(); +#else + el_Obj_EBO *ebo = (el_Obj_EBO *)elm_alloc(1, (sizeof(el_Obj_EBO))); +#endif + JUMP_IF_NULL(ebo, error_exit); +#ifdef ENABLE_STRICT_DEBUG_MEMSET + memset(ebo, 0, sizeof(el_Obj_EBO)); +#endif + buffer = &ebo->data.buffer; + + /* + * Check if object size is valid. "size" needs to be a value greater than or + * equal to the size of the current object header. + */ + JUMP_IF_LOWER(size, sizeof(el_EBO_Header), error_exit); + bytes += sizeof(el_EBO_Header); + + if(version == 1) + { + el_EBO_Palette *clut_header = (el_EBO_Palette *) (data + sizeof(el_EBO_Header)); + + /* Make sure object size includes the CLUT header */ + bytes += sizeof(el_EBO_Palette); + JUMP_IF_LOWER(size, bytes, error_exit); + + ebo->object.type = (ELM_OBJECT_TYPE) ebo_header->type; + ebo->object.reference = 0; + + buffer->width = ebo_header->width; + buffer->height = ebo_header->height; + buffer->format = (vg_lite_buffer_format_t) ebo_header->format; + buffer->stride = 0; + + error = vg_lite_allocate(buffer); + if (error != VG_LITE_SUCCESS) + { + destroy_ebo(ebo); + return 0; + } + + buffer->stride = ebo_header->stride; + buffer->tiled = (vg_lite_buffer_layout_t) ebo_header->tiled; + colors = (uint32_t *)(data + clut_header->clut_data_offset); + + /* Make sure the object size includes image data */ + JUMP_IF_LOWER(size, + ebo_header->data_offset + + (buffer->stride * buffer->height), + error_exit); + + memcpy(buffer->memory, + data + ebo_header->data_offset, + buffer->stride * buffer->height); + + /* Save CLUT infomation. */ + ebo->clut_count = clut_header->clut_count; + + /* Make sure object size includes CLUT data */ + JUMP_IF_LOWER(size, + clut_header->clut_data_offset + + (sizeof(uint32_t) * clut_header->clut_count), + error_exit); + + memcpy(ebo->clut, colors, sizeof(uint32_t) * clut_header->clut_count); + } + else if(version == 2) + { + ebo->object.type = (ELM_OBJECT_TYPE) ebo_header->type; + ebo->object.reference = 0; + + buffer->width = ebo_header->width; + buffer->height = ebo_header->height; + buffer->format = (vg_lite_buffer_format_t) ebo_header->format; + buffer->stride = 0; + + error = vg_lite_allocate(buffer); + if (error != VG_LITE_SUCCESS) + { + destroy_ebo(ebo); + return 0; + } + + buffer->stride = ebo_header->stride; + buffer->tiled = (vg_lite_buffer_layout_t) ebo_header->tiled; + + /* Make sure the object size includes image data */ + JUMP_IF_LOWER(size, + ebo_header->data_offset + + (buffer->stride * buffer->height), + error_exit); + + memcpy(buffer->memory, + data + ebo_header->data_offset, + buffer->stride * buffer->height); + } + /* Set transformation to identity. */ + ebo->defaultAttrib.transform.dirty = 1; + ebo->defaultAttrib.transform.identity = 1; + + _init_transform(&ebo->defaultAttrib.transform); + ebo->attribute = ebo->defaultAttrib; + + ref_object(&ebo->object); + JUMP_IF_NON_ZERO_VALUE(add_object(&ebo->object), error_exit); + + return ebo->object.handle; + +error_exit: + if (ebo != NULL ) { + elm_free(ebo); + } + + return ELM_NULL_HANDLE; +} + +static ElmHandle _load_ego(const uint8_t *data, int size) +{ + int i; + unsigned int invalid_count = 0; + uint32_t *obj_size, *obj_offset, *obj_type; + void *obj_data; + el_EGO_Header *ego_header = (el_EGO_Header *) data; + +#if (RTOS && DDRLESS) || BAREMETAL + el_Obj_Group *ego = alloc_ego(); +#else + el_Obj_Group *ego = (el_Obj_Group *)elm_alloc(1, sizeof(el_Obj_Group)); +#endif + JUMP_IF_NULL(ego, error_exit); +#ifdef ENABLE_STRICT_DEBUG_MEMSET + memset(ego, 0, sizeof(el_Obj_Group)); +#endif + + ego->object.type = (ELM_OBJECT_TYPE) ego_header->type; + ego->object.reference = 0; + + _init_transform(&ego->defaultTrans); + memcpy(&(ego->defaultTrans.matrix.m), + &(ego_header->matrix), + sizeof(vg_lite_matrix_t)); + ego->group.count = ego_header->count; +#if (RTOS && DDRLESS) || BAREMETAL + ego->group.objects = alloc_evo(ego->group.count); +#else + ego->group.objects = (el_Obj_EVO *)elm_alloc(1, ego->group.count * sizeof(el_Obj_EVO)); +#endif + JUMP_IF_NULL(ego->group.objects, error_exit); +#ifdef ENABLE_STRICT_DEBUG_MEMSET + memset(ego->group.objects, 0, ego->group.count * sizeof(el_Obj_EVO)); +#endif + + obj_size = (uint32_t *)((unsigned)data + sizeof(el_EGO_Header)); + obj_offset = (uint32_t *)((unsigned)obj_size + \ + (ego_header->count * sizeof(uint32_t))); + + for (i = 0; i < ego->group.count && obj_offset[i] < size; i++) + { + if (obj_size[i] == 0) { + invalid_count++; + continue; + } + + /* Check whether EVO object is truncated */ + JUMP_IF_GREATER(obj_offset[i] + obj_size[i], size, error_exit); + + /* Call appropriate object loader according to object type */ + obj_data = (void*)((unsigned)data + obj_offset[i]); + obj_type = obj_data; + switch (*obj_type) { + case ELM_OBJECT_TYPE_EVO: + ego->group.objects[i].object.handle = _load_evo(obj_data, + obj_size[i], + &ego->group.objects[i]); + break; +#if (VG_RENDER_TEXT==1) + case ELM_OBJECT_TYPE_FONT: + _load_font(obj_data, obj_size[i]); + break; + case ELM_OBJECT_TYPE_TEXT: + ego->group.objects[i].object.handle = _load_text(obj_data, + obj_size[i], + &ego->group.objects[i]); + break; +#endif /* VG_RENDER_TEXT */ + default: + break; + } + } + + ego->group.count -= invalid_count; + ego->transform = ego->defaultTrans; + + ref_object(&ego->object); + JUMP_IF_NON_ZERO_VALUE(add_object(&ego->object), error_exit); + + return ego->object.handle; + +error_exit: + if (ego != NULL ) { + if ( ego->group.objects != NULL ) { + elm_free(ego->group.objects); + } + elm_free(ego); + } + + return ELM_NULL_HANDLE; +} + +#if (defined(__ICCARM__)) +/* Restore the unaligned data structure attribute warning */ +#pragma diag_default = Pa039 +#endif + +static BOOL _scale(ElmHandle obj, float x, float y) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return FALSE; + + el_Object *object = get_object(obj); + el_Obj_EBO *ebo = NULL; + el_Obj_EVO *evo = NULL; + el_Obj_Group *ego = NULL; + el_Transform *transform = NULL; + + switch (object->type) { + case ELM_OBJECT_TYPE_EBO: + ebo = (el_Obj_EBO *)object; + transform = &ebo->attribute.transform; + break; + + case ELM_OBJECT_TYPE_EGO: + ego = (el_Obj_Group *)object; + if (elm_tls->gContext.vector_id < 0) { + transform = &ego->transform; + } + else { + evo = _get_evo(ego, elm_tls->gContext.vector_id); + if (evo != NULL) { + transform = &evo->attribute.transform; + } + else { /* No such vector object to set. */ + return FALSE; + } + } + break; + + case ELM_OBJECT_TYPE_EVO: + evo = (el_Obj_EVO *)object; + transform = &evo->attribute.transform; + break; + + default: + DEBUG_ASSERT(0, "Bad object type"); + break; + } + + // Update the transformation params. + transform->scale[0] *= x; + transform->scale[1] *= y; + + vg_lite_scale(x, y, &transform->matrix); + + // Clean dirty. + transform->dirty = FALSE; + + return TRUE; +} + +static BOOL _reset_attrib(ElmHandle obj, ELM_EVO_PROP_BIT mask) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return FALSE; + + el_Object *object = get_object(obj); + el_Obj_EBO *ebo = NULL; + el_Obj_EVO *evo = NULL; + el_Obj_Group *ego = NULL; + el_Attribute *attrib = NULL; + el_Attribute *defaultAttr = NULL; + el_Transform *transform = NULL; + el_Transform *defaultTrans = NULL; + + switch (object->type) { + case ELM_OBJECT_TYPE_EBO: + ebo = (el_Obj_EBO *)object; + attrib = &ebo->attribute; + defaultAttr = &ebo->defaultAttrib; + transform = &attrib->transform; + defaultTrans = &defaultAttr->transform; + break; + + case ELM_OBJECT_TYPE_EGO: + ego = (el_Obj_Group *)object; + if (elm_tls->gContext.vector_id < 0) { + transform = &ego->transform; + defaultTrans = &ego->defaultTrans; + } + else { + evo = _get_evo((el_Obj_Group*)obj, elm_tls->gContext.vector_id); + if (evo != NULL) { + attrib = &evo->attribute; + defaultAttr = &evo->defaultAttrib; + transform = &attrib->transform; + defaultTrans = &defaultAttr->transform; + } + else { + return FALSE; + } + } + break; + + case ELM_OBJECT_TYPE_EVO: + evo = (el_Obj_EVO *)object; + attrib = &evo->attribute; + defaultAttr = &evo->defaultAttrib; + transform = &attrib->transform; + defaultTrans = &defaultAttr->transform; + break; + + default: + DEBUG_ASSERT(0, "Bad object type"); + return FALSE; + break; + } + + // Update the attribute value. When transform is modified, update the matrix. + if (mask & ELM_PROP_ROTATE_BIT) { + transform->rotate = defaultTrans->rotate; + } + + if (mask & ELM_PROP_TRANSFER_BIT) { + transform->translate[0] = defaultTrans->translate[0]; + transform->translate[1] = defaultTrans->translate[1]; + } + + if (mask & ELM_PROP_SCALE_BIT) { + transform->scale[0] = defaultTrans->scale[0]; + transform->scale[1] = defaultTrans->scale[1]; + } + + /* On any bit reset, reset the whole matrix to the default one. */ + if (mask & (ELM_PROP_ROTATE_BIT | ELM_PROP_TRANSFER_BIT | ELM_PROP_SCALE_BIT)) { + memcpy(&(transform->matrix), &(defaultTrans->matrix), sizeof(defaultTrans->matrix)); + transform->dirty = FALSE; + } + + /* Update other rendering attributes. */ + if (mask & ELM_PROP_BLEND_BIT) { + attrib->blend = defaultAttr->blend; + } + + if (mask & ELM_PROP_QUALITY_BIT) { + attrib->quality = defaultAttr->quality; + } + + if (mask & ELM_PROP_FILL_BIT) { + attrib->fill_rule = defaultAttr->fill_rule; + } + + if (mask & ELM_PROP_COLOR_BIT) { + attrib->paint.color = defaultAttr->paint.color; + } + + if (mask & ELM_PROP_PAINT_BIT) { + attrib->paint.type = defaultAttr->paint.type; + } + + return TRUE; +} + +static BOOL _set_quality(ElmHandle obj, ELM_QUALITY quality) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return FALSE; + + el_Object *object = get_object(obj); + el_Obj_EBO *ebo = NULL; + el_Obj_EVO *evo = NULL; + el_Obj_Group *group = NULL; + el_Attribute *attrib = NULL; + + switch (object->type) { + case ELM_OBJECT_TYPE_EBO: + ebo = (el_Obj_EBO *)object; + attrib = &ebo->attribute; + break; + + case ELM_OBJECT_TYPE_EVO: + evo = (el_Obj_EVO *)object; + attrib = &evo->attribute; + break; + + case ELM_OBJECT_TYPE_EGO: + group = (el_Obj_Group *)object; + evo = _get_evo(group, elm_tls->gContext.vector_id); + if (evo != NULL) { + attrib = &evo->attribute; + } + else { + return FALSE; + } + break; + default: + DEBUG_ASSERT(0, "Bad object type"); + return FALSE; + break; + } + + attrib->quality = quality; + + return TRUE; +} + +static BOOL _set_fill(ElmVecObj evo, ELM_EVO_FILL fill) +{ + el_Obj_EVO *object = (el_Obj_EVO *)get_object(evo); + + if (object == NULL) { + DEBUG_ASSERT(0, "Bad object handle"); + return FALSE; + } + + object->attribute.fill_rule = fill; + + return TRUE; +} + +static BOOL _set_blend(ElmHandle obj, ELM_BLEND blend) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return FALSE; + + el_Object *object = get_object(obj); + el_Obj_EBO *ebo = NULL; + el_Obj_EVO *evo = NULL; + el_Obj_Group *group = NULL; + el_Attribute *attrib = NULL; + + switch (object->type) { + case ELM_OBJECT_TYPE_EBO: + ebo = (el_Obj_EBO *)object; + attrib = &ebo->attribute; + break; + + case ELM_OBJECT_TYPE_EVO: + evo = (el_Obj_EVO *)object; + attrib = &evo->attribute; + break; + + case ELM_OBJECT_TYPE_EGO: + group = (el_Obj_Group *)object; + evo = _get_evo(group, elm_tls->gContext.vector_id); + if (evo != NULL) { + attrib = &evo->attribute; + } + else { + return FALSE; + } + break; + default: + DEBUG_ASSERT(0, "Bad object type"); + return FALSE; + break; + } + + attrib->blend = blend; + + return TRUE; +} + +static BOOL _set_color(ElmVecObj evo, uint32_t color) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return FALSE; + + el_Obj_EVO *object = (el_Obj_EVO *)get_object(evo); + el_Obj_Group *group = NULL; + + if (object == NULL) { + DEBUG_ASSERT(0, "Bad object handle"); + return FALSE; + } + + switch (object->object.type) { + case ELM_OBJECT_TYPE_EVO: + break; + + case ELM_OBJECT_TYPE_EGO: + group = (el_Obj_Group *)object; + object = _get_evo(group, elm_tls->gContext.vector_id); + if (object == NULL) { + return FALSE; + } + break; + case ELM_OBJECT_TYPE_EBO: + default: + DEBUG_ASSERT(0, "Bad object type"); + return FALSE; + break; + } + + object->attribute.paint.color = color; + + return TRUE; +} + +static BOOL _set_pattern(ElmVecObj evo, ElmBitmapObj pattern) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return FALSE; + + el_Obj_EVO *object = (el_Obj_EVO *)get_object(evo); + el_Obj_EBO *ebo_obj = (el_Obj_EBO *) get_object(pattern); + el_Obj_Group *group = NULL; + + if ((object == NULL) || + (ebo_obj == NULL)){ + DEBUG_ASSERT(0, "Bad object handle"); + return FALSE; + } + + switch (object->object.type) { + case ELM_OBJECT_TYPE_EVO: + break; + + case ELM_OBJECT_TYPE_EGO: + group = (el_Obj_Group *)object; + object = _get_evo(group, elm_tls->gContext.vector_id); + if (object == NULL) { + return FALSE; + } + break; + + default: + break; + } + + object->attribute.paint.pattern.pattern = ebo_obj; + ref_object((el_Object *)ebo_obj); + + return TRUE; +} + +static BOOL _set_pattern_mode(ElmVecObj evo, ELM_PATTERN_MODE mode, uint32_t color) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return FALSE; + + el_Obj_EVO *object = (el_Obj_EVO *)get_object(evo); + el_Obj_Group *group = NULL; + + if (object == NULL){ + DEBUG_ASSERT(0, "Bad object handle"); + return FALSE; + } + + switch (object->object.type) { + case ELM_OBJECT_TYPE_EVO: + break; + + case ELM_OBJECT_TYPE_EGO: + group = (el_Obj_Group *)object; + object = _get_evo(group, elm_tls->gContext.vector_id); + if (object == NULL) { + return FALSE; + } + break; + + default: + break; + } + + object->attribute.paint.pattern.mode = mode; + object->attribute.paint.pattern.color = color; + + return TRUE; +} + +static BOOL _set_paintType(ElmVecObj evo, ELM_PAINT_TYPE type) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return FALSE; + + el_Obj_EVO *object = (el_Obj_EVO *)get_object(evo); + el_Obj_Group *group = NULL; + + if (object == NULL) { + DEBUG_ASSERT(0, "Bad object handle"); + return FALSE; + } + switch (object->object.type) { + case ELM_OBJECT_TYPE_EVO: + break; + + case ELM_OBJECT_TYPE_EGO: + group = (el_Obj_Group *)object; + object = _get_evo(group, elm_tls->gContext.vector_id); + if (object == NULL) { + return FALSE; + } + break; + + default: + break; + } + + object->attribute.paint.type = type; + + return TRUE; +} + +static BOOL _rotate(ElmHandle obj, float angle) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return FALSE; + + el_Object *object = get_object(obj); + el_Obj_EBO *ebo = NULL; + el_Obj_EVO *evo = NULL; + el_Obj_Group *ego = NULL; + el_Transform *transform = NULL; + + switch (object->type) { + case ELM_OBJECT_TYPE_EBO: + ebo = (el_Obj_EBO *)object; + transform = &ebo->attribute.transform; + break; + + case ELM_OBJECT_TYPE_EGO: + ego = (el_Obj_Group *)object; + if (elm_tls->gContext.vector_id < 0) { + transform = &ego->transform; + } + else { + evo = _get_evo(ego, elm_tls->gContext.vector_id); + if (evo != NULL) { + transform = &evo->attribute.transform; + } + else { + return FALSE; + } + } + break; + + case ELM_OBJECT_TYPE_EVO: + evo = (el_Obj_EVO *)object; + transform = &evo->attribute.transform; + break; + + default: + DEBUG_ASSERT(0, "Bad object type"); + break; + } + + // Update the transformation params. + transform->rotate += angle; + + // Upate the matrix. + vg_lite_rotate(angle, &transform->matrix); + + // Clean dirty. + transform->dirty = FALSE; + + return TRUE; +} +static BOOL _translate(ElmHandle obj, float x, float y) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return FALSE; + + el_Object *object = get_object(obj); + el_Obj_EBO *ebo = NULL; + el_Obj_EVO *evo = NULL; + el_Obj_Group *ego = NULL; + el_Transform *transform = NULL; + + switch (object->type) { + case ELM_OBJECT_TYPE_EBO: + ebo = (el_Obj_EBO *)object; + transform = &ebo->attribute.transform; + break; + + case ELM_OBJECT_TYPE_EGO: + ego = (el_Obj_Group *)object; + if (elm_tls->gContext.vector_id < 0) { + transform = &ego->transform; + } + else { + evo = _get_evo(ego, elm_tls->gContext.vector_id); + if (evo != NULL) { + transform = &evo->attribute.transform; + } + else { + return FALSE; + } + } + break; + + case ELM_OBJECT_TYPE_EVO: + evo = (el_Obj_EVO *)object; + transform = &evo->attribute.transform; + break; + + default: + DEBUG_ASSERT(0, "Bad object type"); + break; + } + + // Update the transformation params. + transform->translate[0] += x; + transform->translate[1] += y; + + // Update the matrix. + vg_lite_translate(x, y, &transform->matrix); + + // Clean dirty. + transform->dirty = FALSE; + + return TRUE; +} + +static BOOL _verify_header(ELM_OBJECT_TYPE *type, uint32_t *version, void *data) +{ + uint32_t *p32_data = (uint32_t *)data; + + if (type != NULL) { + *type = (ELM_OBJECT_TYPE)(*(p32_data + 1)); + } + + if (version != NULL) { + *version = *p32_data; + + if (*version <= ELM_VERSION) { + return TRUE; /* Verified OK, compatible. */ + } + else { + return FALSE; /* Verified Failed, API version is lower. */ + } + } + + return TRUE; +} + +/* + Load the specified object from the data. + */ +static ElmHandle _create_object_from_data(ELM_OBJECT_TYPE type, void *data, int size) +{ + ELM_OBJECT_TYPE real_type; + uint32_t p_data = (uint32_t)data; + uint32_t version; + + if(p_data % BASE_ADDRESS_ALIGNMENT != 0) { + DEBUG_ASSERT(0, "Error: data address don't align with 32 bytes!"); + return ELM_NULL_HANDLE; + } + + if (FALSE == _verify_header(&real_type, &version, data)) { + DEBUG_ASSERT(0, "Error: Incompatible file."); + return ELM_NULL_HANDLE; + } + + if (real_type != type) { + DEBUG_ASSERT(0, "Warning: Specified type mismatched.\n"); + } + + /* Jump over the version field to get to the start of the first ELM object */ + data = (void *)((unsigned)data + sizeof(uint32_t)); + + switch (real_type) { + case ELM_OBJECT_TYPE_EVO: + return _load_evo(data, size, NULL); + break; + + case ELM_OBJECT_TYPE_EGO: + return _load_ego(data, size); + + case ELM_OBJECT_TYPE_EBO: + return _load_ebo(data, size, version); +#if (VG_RENDER_TEXT==1) + case ELM_OBJECT_TYPE_FONT: + return _load_font(data, size); + + case ELM_OBJECT_TYPE_TEXT: + return _load_text(data, size, NULL); +#endif + default: + DEBUG_ASSERT(0, "Bad object type"); + break; + } + + return ELM_NULL_HANDLE; +} + +static el_Transform *_get_paint_transform(ElmHandle handle) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return FALSE; + + el_Transform *transform = NULL; + el_Obj_Group *group = NULL; + el_Obj_EVO *evo = NULL; + + evo = (el_Obj_EVO *)get_object(handle); + + if (evo == NULL) { + DEBUG_ASSERT(0, "Bad object handle.\n"); + return NULL; + } + + /* Find the corresponding evo object. */ + switch (evo->object.type) { + case ELM_OBJECT_TYPE_EVO: + break; + + case ELM_OBJECT_TYPE_EGO: + group = (el_Obj_Group *)evo; + evo = _get_evo(group, elm_tls->gContext.vector_id); + if (evo == NULL) { + return NULL; + } + break; + + case ELM_OBJECT_TYPE_EBO: + default: + DEBUG_ASSERT(0, "Incorrect object tyoe.\n"); + return NULL; + break; + } + + /* Get the correct transformation based on the paint type. */ + if (evo->attribute.paint.type == ELM_PAINT_PATTERN) { + transform = &((el_Obj_EBO*)evo->attribute.paint.pattern.pattern)->attribute.transform; + } + else if (evo->attribute.paint.type == ELM_PAINT_GRADIENT) { + transform = &evo->attribute.paint.grad->data.transform; + } + + return transform; +} + +/*********************** ELM API *********************/ +#if !RTOS +/*! + @abstract Create an elementary object from an existing binary file. + + @discussion + This function creates an elementary object from the file whose file name is specified by param name. + Caller must match type with the binary file, otherwise create mail fail by returning ELM_NULL_HANDLE. + + @param type + Specify what type of object to be created. + + @param name + The name of the binary resource file. + + @return ElmHandle + An object handle depending on the corresponding type. If type mismatches, it + returns ELM_NULL_HANDLE. + */ +ElmHandle ElmCreateObjectFromFile(ELM_OBJECT_TYPE type, const char *name) +{ +#if RTOS || BAREMETAL + return ELM_NULL_HANDLE; +#else + void *data = NULL; + long size = 0; + FILE *fp = fopen(name, "rb"); + ElmHandle handle = ELM_NULL_HANDLE; + + if (fp != NULL) { + fseek(fp, 0, SEEK_END); + size = ftell(fp); + + data = elm_alloc(1, size); + if (data != NULL) { + fseek(fp, 0, SEEK_SET); + fread(data, size, 1, fp); + + handle = _create_object_from_data(type, data, size); + } + else { + printf("open %s failed!\n", name); + } + elm_free(data); + fclose(fp); + } + + return handle; +#endif +} +#else +ElmHandle ElmCreateObjectFromFile(ELM_OBJECT_TYPE type, const char *name) +{ + return ELM_NULL_HANDLE; +} +#endif /*!ENABLE_ELM_CRATE_OBJECT_FROM_FILE*/ +/*! + @abstract Create an elementary object from build-in data within the appplication. + + @discussion + This function creates an elementar object from local data pointer, which is specially useful for environment without filesystem support. + + @param type + Specify what type of object to be created. + + @param data + The pointer to the binary data which has exactly same layout as external resource file. + + @return ElmHandle + An object handle depending on the corresponding type. If type mismatches with the binary data, it + returns ELM_NULL_HANDLE. + */ +ElmHandle ElmCreateObjectFromData(ELM_OBJECT_TYPE type, void *data, int size) +{ + return _create_object_from_data(type, data, size); +} + +/*! + @abstract Destroy an ELM object. + + @discussion + This function is to release all internal resource inside Elementary libary belonging to this object. + Applicatoin need make sure the object is not being used by elmentary library any more when calling this function. + If an EBO is being destroyed and it's attached to one EVO, it need to guarantee that EVO is not being used by elementary library too. + + @param object + The object handle + + @return + If destroying is completed successfully. + */ +BOOL ElmDestroyObject(ElmHandle object) +{ + int result = destroy_object(object); + return (result >= 0); +} + +/*! + @abstract Rotate a graphics object with centain degree + + @discussion + This function sets an evo/ebo/ego object rotated with specified angle. Without reset, these setting will be + accumulated. + + @param obj + The graphics object will be rotated. + + @param angle + A radian value to be applied on the evo object. + + @return bool + Rotate is set successfully. + */ +BOOL ElmRotate(ElmHandle obj, float angle) +{ + return _rotate(obj, angle); +} + +/*! + @abstract Transfer an graphics object at different directions. + + @discussion + This function put an evo/ebo/ego object away at different directions. Without reset, the setting will be + accumulated. + + @param obj + The graphics object will be transfered. + + @param x + The units in pixel of X direction. + + @param y + The units in pixel of Y direction. + + @return bool + Transfer is set successfully. + */ +BOOL ElmTransfer(ElmHandle obj, int x, int y) +{ + return _translate(obj, x, y); +} + +/*! + @abstract Scale an graphics object at different directions. + + @discussion + This function scale up or down an evo/ego/ebo object at different directions. Without reset, the setting will + be accumateled. + + @param obj + The graphics object which is targeted to manipulate. + + @param x + The scale ratio in X direction. + + @param y + The scale ratio in Y direction. + + @return bool + Scale is set succefully. + */ +BOOL ElmScale(ElmHandle obj, float x, float y) +{ + return _scale(obj, x, y); +} + +/*! + @abstract Reset the attribute of a graphics object for specified property bit. + + @discussion + This funcion resets specified property for an elementary object. It can be applied all types of objects. + But some properties are only valid for centain types of objects. If the function is called to reset an invalid + property for this type of object, it will be siliently ignored. + After reset, the specifed property of an evo/ebo/ego object is set to the initial state. The initial states are decided + by the binary resource file. The resource creator should set right value for all properties if they want to directly render + the object without any adjustment in application. There is one issue, at present, application has no way to query current value + of each property, is it required? + + @param obj + The graphics object which is targeted to manipulate. + + @param mask + Specify which property or properties need to reset to initial value. + + @return bool + Reset is done successfully. If some mask is not valid for this type of object, it would return false. + */ +BOOL ElmReset(ElmHandle obj, ELM_EVO_PROP_BIT mask) +{ + return _reset_attrib(obj, mask); +} + +/*! + @abstract Set the rendering quality of an graphics object. + + @discussion + This function sets the rendering quality of an evo/ebo object. Avaliable quality setting contains: + ELM_EVO_QUALITY_LOW, ELM_EVO_QUALITY_MED, ELM_EVO_QUALITY_HI. This function is only applied to an evo or an ebo. + Group object can't be set quality. It always use the setting from its binary. + + @param obj + The elementary object. + + @param quality + The quality enum. + + @return bool + The operation for this object is sucessful, for group object and invalid enum, would return false. + */ +BOOL ElmSetQuality(ElmHandle obj, ELM_QUALITY quality) +{ + return _set_quality(obj, quality); +} + +/*! + @abstract Set the fill rule of an evo object. + + @discussion + This function sets the fill rule of an elementary object. Avaliable quality setting contains: + ELM_EVO_EO, ELM_EVO_NZ. It only applies to evo object. + + @param evo + The evo object. + + @param fill + The fill rule enum. + + @return bool + The operation for this evo is sucessful. For non-evo object an ENUM is not a valid enum, would return false. + */ +BOOL ElmSetFill(ElmVecObj evo, ELM_EVO_FILL fill) +{ + return _set_fill(evo, fill); +} + +/*! + @abstract Set the blending mode of an evo/ebo object. + + @discussion + This function sets the blending mode of an evo/ebo object. It's not applied to group object. + + @param obj + The graphics object. + + @param blend + The blending mode enum. + + @return bool + The operation for this evo/ebo is sucessful. If object is a group object or blend mode is not a legal one, it would return false. + */ +BOOL ElmSetBlend(ElmHandle obj, ELM_BLEND blend) +{ + return _set_blend(obj, blend); +} + +/*! + @abstract Set the solid fill color of an evo object. + + @discussion + This function sets the solid fill color of an evo object. + + @param evo + The evo object. + + @param color + The uint32 color value in rgba order. + + @return bool + The operation for this evo is sucessful. If the object is not a evo object, it would return false. + */ +BOOL ElmSetColor(ElmVecObj evo, uint32_t color) +{ + return _set_color(evo, color); +} + +/*! + @abstract Set the image paint fill of an evo. + + @discussion + This function sets the image pattern for filling an evo. The image pattern + is a loaded ebo. The ebo's transformation is applied when drawing the evo. + + @param evo + The evo object. + + @param pattern + The image pattern to be set for the evo. + + @return bool + The operation is successful or not. + */ +BOOL ElmSetPattern(ElmVecObj evo, ElmBitmapObj pattern) +{ + return _set_pattern(evo, pattern); +} + +/*! + @abstract Set the image paint fill of an evo. + + @discussion + This function sets the image pattern for filling an evo. The image pattern + is a loaded ebo. The ebo's transformation is applied when drawing the evo. + + @param evo + The evo object. + + @param pattern + The image pattern to be set for the evo. + + @return bool + The operation is successful or not. + */ +BOOL ElmSetPatternMode(ElmVecObj evo, ELM_PATTERN_MODE mode, uint32_t color) +{ + return _set_pattern_mode(evo, mode, color); +} + +/*! + @abstract Set the paint type of an evo. + + @discussion + This function selects the paint type for evo to use. An evo may have 3 types + of paint: COLOR, PATTERN, and LINEAR GRADIENT. The Linear graident is always + a built-in resource, which can not be altered. If a binary resource doesn't + have built-in gradient paint resource, it can't be selected as the paint source. + Solid color is also a built-in attribute, but it can be changed by ElmSetColor(). + Paint with a pattern always need an external ebo object, which is impossible + to be embedded in resource file,i.e. ebo object. Before select paint type to + be PATTERN, ElmSetPattern() must be called to attach an EBO to an EVO. + + @param evo + The evo object. + + @param type + The paint type to be set for the evo. + + @return bool + The operation is successful or not. + If the corresponding type is not avaiable for the evo, it returns false and + type paint type falls back to COLOR. + */ +BOOL ElmSetPaintType(ElmVecObj evo, ELM_PAINT_TYPE type) +{ + return _set_paintType(evo, type); +} + +/*! + @abstract Get the solid fill color of an evo object. + + @discussion + This function Get the solid fill color of an evo object. + + @param evo + The evo object. + + @return uint32_t + The uint32 color value in rgba order. + */ +BOOL ElmGetColor(ElmGroupObj handle,uint32_t *color) +{ + elm_tls_t* elm_tls; + el_Obj_EVO *evo; + + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return FALSE; + + el_Obj_Group *ego = (el_Obj_Group*) get_object(handle); + evo = _get_evo(ego, elm_tls->gContext.vector_id); + *color = evo->attribute.paint.color; + + return TRUE; +} + +/*! + @abstract Query the vectory path count of an EGO object. If the given object + is an evo/ebo, the count is 0. + */ +uint32_t ElmGetVectorCount(ElmHandle handle) +{ + el_Obj_Group *ego = (el_Obj_Group*) get_object(handle); + if (ego->object.type != ELM_OBJECT_TYPE_EGO) { + return 0; + } + else { + return ego->group.count; + } +} + +/*! + @abstract Query the type of an object (by handle). + */ +ELM_OBJECT_TYPE ElmGetObjectType(ElmHandle handle) +{ + el_Object *object = get_object(handle); + return object->type; +} + +/*! + @abstract Set the current vectory object index to operate on. + */ +BOOL ElmSetCurrentVector(int32_t id) +{ + elm_tls_t* elm_tls; + elm_tls = (elm_tls_t *) elm_os_get_tls(); + if (elm_tls == NULL) + return FALSE; + + elm_tls->gContext.vector_id = id; + + return TRUE; +} + +BOOL ElmScalePaint(ElmHandle handle, float sx, float sy) +{ + el_Transform *transform = NULL; + + transform = _get_paint_transform(handle); + + if (transform != NULL) { + vg_lite_scale(sx, sy, &transform->matrix); + transform->dirty = FALSE; + return TRUE; + } + else { + return FALSE; + } +} +BOOL ElmRotatePaint(ElmHandle handle, float degrees) +{ + el_Transform *transform = NULL; + + transform = _get_paint_transform(handle); + + if (transform != NULL) { + vg_lite_rotate(degrees, &transform->matrix); + transform->dirty = FALSE; + return TRUE; + } + else { + return FALSE; + } +} + +BOOL ElmTranslatePaint(ElmHandle handle, float tx, float ty) +{ + el_Transform *transform = NULL; + + transform = _get_paint_transform(handle); + + if (transform != NULL) { + vg_lite_translate(tx, ty, &transform->matrix); + transform->dirty = FALSE; + return TRUE; + } + else { + return FALSE; + } +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_os.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_os.c new file mode 100644 index 0000000000..b2415fa875 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_os.c @@ -0,0 +1,43 @@ +#include "elm_os.h" +#include "rtthread.h" + +vg_lite_error_t elm_os_set_tls(void* tls) +{ + if(tls == NULL) + return VG_LITE_INVALID_ARGUMENT; + + rt_thread_t rt_TCB; + + rt_TCB = rt_thread_self(); + RT_ASSERT( rt_TCB != NULL ); + + + rt_uint32_t * tls_ptr = (rt_uint32_t *)rt_TCB->user_data; + *(tls_ptr + 1) = (rt_uint32_t) tls; + return VG_LITE_SUCCESS; +} + +void * elm_os_get_tls(void) +{ + rt_thread_t rt_TCB; + + void * pvReturn = NULL; + + rt_TCB = rt_thread_self(); + + rt_uint32_t * tls_ptr = (rt_uint32_t *)rt_TCB->user_data; + pvReturn = (void *) *(tls_ptr + 1); + + return pvReturn; +} + +void elm_os_reset_tls(void) +{ + rt_thread_t rt_TCB; + + rt_TCB = rt_thread_self(); + RT_ASSERT( rt_TCB != NULL ); + + rt_uint32_t * tls_ptr = (rt_uint32_t *)rt_TCB->user_data; + *(tls_ptr + 1) = NULL; +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_os.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_os.h new file mode 100644 index 0000000000..fb3a0607bb --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_os.h @@ -0,0 +1,13 @@ +#ifndef ELM_OS_H_ +#define ELM_OS_H_ + +#include +#include"vg_lite.h" + +vg_lite_error_t elm_os_set_tls(void* tls); + +void * elm_os_get_tls(void); + +void elm_os_reset_tls(void); + +#endif diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_precom.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_precom.h new file mode 100644 index 0000000000..0ef71a34e8 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_precom.h @@ -0,0 +1,55 @@ +/**************************************************************************** +* +* Copyright 2012 - 2021 Vivante Corporation, Santa Clara, California. +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#ifndef elm_precom_h +#define elm_precom_h + +/* System headers. */ +#include +#include +#include + +/* VGLite hdaders. */ +#include "vg_lite.h" + +/* Project headers. */ +#include "Elm.h" +#include "velm.h" +#include "elm_os.h" + +#define JUMP_IF_NON_ZERO_VALUE(x, label) { int ret = x; if ( (ret) != 1 ) { goto label; } } +#define JUMP_IF_NULL(x, label) { if (x == NULL) { goto label;} } +#define JUMP_IF_LOWER(x, y, label) {if (x < y) {goto label;} } +#define JUMP_IF_GREATER(x, y, label) {if (x > y) {goto label;} } +#define JUMP_IF_EQUAL(x, y, label) {if (x == y) {goto label;} } +#define JUMP_IF_LOWER_OR_EQUAL(x, y, label) {if (x <= y) {goto label;} } +#define JUMP_IF_GREATER_OR_EQUAL(x, y, label) {if (x => y) {goto label;} } + +#define MIN(a, b) ((a) > (b) ? (b) : (a)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +#endif /* elm_precom_h */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_text.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_text.c new file mode 100644 index 0000000000..0e7bf06e27 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_text.c @@ -0,0 +1,732 @@ +/**************************************************************************** +* +* Copyright 2020 NXP +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +/* + ElmDrawText API + */ +/** Include Files */ +#include // for snprintf +#include +#include + +#include "vg_lite.h" +#include "Elm.h" +#include "velm.h" +#include "vg_lite_text.h" +#include "elm_headers.h" +#include "elm_text.h" +#include "elm_precom.h" +#include "vft_draw.h" + +/** Macros */ +#ifndef VECTOR_DEFAULT_FONT +#define VECTOR_DEFAULT_FONT 1 +#endif + +#if VECTOR_DEFAULT_FONT /* Use vector font as default font */ +#define DEFAULT_FONT_NAME "SVGFreeSansASCII" +#define DEFAULT_FONT_WEIGHT eFontWeightRegular +#define DEFAULT_FONT_STRETCH eFontStretchNormal +#define DEFAULT_FONT_STYLE eFontStyleNormal +#define DEFAULT_FONT_HEIGHT 35 +#define DEFAULT_TEXT_FG_COLOR 0xff000000 +#define DEFAULT_TEXT_ALIGN (eTextAlignLeft) + +#else /* Use raster font as default font */ +#define DEFAULT_FONT_NAME "DejaVuSans_Oblique" +#define DEFAULT_FONT_WEIGHT eFontWeightRegular +#define DEFAULT_FONT_STRETCH eFontStretchNormal +#define DEFAULT_FONT_STYLE eFontStyleItalic +#define DEFAULT_FONT_HEIGHT 35 +#define DEFAULT_TEXT_FG_COLOR 0xff000000 +#define DEFAULT_TEXT_ALIGN (eTextAlignLeft) + +#endif + +/* Maximum font properties from EVO file */ +#define MAX_FONT_ATTRIB_COMBINATIONS (32) + +#define TRANSPARENT_VGLITE_COLOUR(a, r, g, b) \ + ((uint32_t)(a) << 24) | ((uint32_t)(b) << 16) | ((uint32_t)(g) << 8) | \ + (uint32_t)r + +#define OPAQUE_VGLITE_COLOUR(r, g, b) TRANSPARENT_VGLITE_COLOUR(0xff, r, g, b) + +/** Data structures */ + +/** Internal or external API prototypes */ +int vg_lite_is_font_valid(vg_lite_font_t font); +char *vg_lite_get_font_name(vg_lite_font_t font); +vg_lite_error_t vg_lite_free_font_memory(vg_lite_font_t font); +int ref_object (el_Object *object); + +/** Globals */ +int g_total_system_font = 0; +static font_field_info_t g_default_font_properties[eMaxFontProperties]; +static font_field_info_t g_font_properties[MAX_FONT_ATTRIB_COMBINATIONS][eMaxFontProperties]; + +/** Externs if any */ +extern vg_lite_font_attributes_t g_font_attribs; +extern vg_lite_font_t g_last_font; +extern int g_last_font_attrib_idx; + +void initialize_elm_text(void) +{ + font_field_info_t *font_fields = NULL; + /* internal parameters of mcufont library */ + g_font_attribs.alignment = 0; + g_font_attribs.scale = 1; + g_font_attribs.width = 1200; /* Describes drawing area */ + g_font_attribs.margin = 5; /* Left margin in drawing area */ + g_font_attribs.bg_color = OPAQUE_VGLITE_COLOUR(0xff,0xff,0xff); // white + g_font_attribs.last_y = 0; + g_font_attribs.last_x =0; + g_font_attribs.last_dx = 0; + + /* Initialize default properties */ + font_fields = &g_default_font_properties[0]; + + char *font_name = (char *)elm_alloc(1, strlen(DEFAULT_FONT_NAME)+1); + strcpy(font_name, DEFAULT_FONT_NAME); + font_fields[eFontNameProperty].value.data = font_name; + font_fields[eFontWeightProperty].value.i_value = DEFAULT_FONT_WEIGHT; + font_fields[eFontStretchProperty].value.i_value = DEFAULT_FONT_STRETCH; + font_fields[eFontStyleProperty].value.i_value = DEFAULT_FONT_STYLE; + font_fields[eFontHeightProperty].value.i_value = DEFAULT_FONT_HEIGHT; + font_fields[eTextColorProperty].value.i_value = DEFAULT_TEXT_FG_COLOR; + font_fields[eTextAlignProperty].value.i_value = DEFAULT_TEXT_ALIGN; +} + +static int get_property(font_field_info_t *dst_font_fields, font_fields_t *src_font_fields, int num_fields) +{ + int i=0; + int len; + + /* Initialize default values */ + dst_font_fields[eFontWeightProperty].value.i_value = DEFAULT_FONT_WEIGHT; + dst_font_fields[eFontStretchProperty].value.i_value = DEFAULT_FONT_STRETCH; + dst_font_fields[eFontStyleProperty].value.i_value = eFontStyleNormal; + dst_font_fields[eTextAlignProperty].value.i_value = DEFAULT_TEXT_ALIGN; + + dst_font_fields[eFontNameProperty].value.data = NULL; + dst_font_fields[eFontHeightProperty].value.i_value = DEFAULT_FONT_HEIGHT; + dst_font_fields[eTextColorProperty].value.i_value = DEFAULT_TEXT_FG_COLOR; + + for(i=0; iattribute.blend; + vg_lite_font_t curr_font = VG_LITE_INVALID_FONT; + int curr_font_attrib_idx = INVALID_FONT_PROPERTY_IDX; + + vg_lite_font_attributes_t *font_attribs = &g_font_attribs; + font_field_info_t *font_fields = NULL; + + curr_font_attrib_idx = text->font_id; + + /* Single font caching can be done here (No caching for now) + Release last font object if it is different + */ + if ( vg_lite_is_font_valid(g_last_font) == 1 ) { + /* recycle font objects */ + vg_lite_free_font_memory(g_last_font); + g_last_font = VG_LITE_INVALID_FONT; + } + + if(curr_font_attrib_idx != INVALID_FONT_PROPERTY_IDX) + { + font_fields = &g_font_properties[curr_font_attrib_idx][0]; + font_fields[eFontHeightProperty].value.i_value = text->font_size; + + curr_font = vg_lite_find_font( + font_fields[eFontNameProperty].value.data, + (eFontWeight_t)font_fields[eFontWeightProperty].value.i_value, + (eFontStretch_t)font_fields[eFontStretchProperty].value.i_value, + (eFontStyle_t)font_fields[eFontStyleProperty].value.i_value, + font_fields[eFontHeightProperty].value.i_value + ); + } + + if (curr_font == VG_LITE_INVALID_FONT) { + //printf("ERROR: Font not found. Rendering with default configuration\n"); + font_fields = &g_default_font_properties[0]; + curr_font = vg_lite_find_font( + font_fields[eFontNameProperty].value.data, + (eFontWeight_t)font_fields[eFontWeightProperty].value.i_value, + (eFontStretch_t)font_fields[eFontStretchProperty].value.i_value, + (eFontStyle_t)font_fields[eFontStyleProperty].value.i_value, + font_fields[eFontHeightProperty].value.i_value); + } + if (curr_font == VG_LITE_INVALID_FONT) { + printf("Font[%s] not found\n", font_fields[eFontNameProperty].value.data); + return VG_LITE_INVALID_ARGUMENT; + } + font_attribs->is_vector_font = vg_lite_is_vector_font(curr_font); + /* Properties that changes over time */ + font_attribs->text_color = text->attribute.paint.color; + font_attribs->alignment = (eTextAlign_t)text->text_anchor; + font_attribs->font_height = font_fields[eFontHeightProperty].value.i_value; + font_attribs->tspan_has_dx_dy = text->tspan_has_dx_dy; + + error = vg_lite_draw_text(&buff->buffer, + (char *)text->msg, + curr_font, + text->x_pos, text->y_pos, + &text->attribute.transform.matrix, + blend, + font_attribs); + + g_last_font = curr_font; + g_last_font_attrib_idx = curr_font_attrib_idx; + return error; +} + +/* process font-field data */ +static int _process_font_field_data( uint8_t *data_start, uint8_t *data, int num_fields, font_fields_t* fields) +{ + eFontFields_t eName; + + if (g_total_system_font >= MAX_FONT_ATTRIB_COMBINATIONS) { + printf("WARNING: Font property buffer overflowing...\n" + "Increase MAX_FONT_ATTRIB_COMBINATIONS\n"); + return -1; + } + + for(int i=0; ittf_fonts[id].id = *(uint32_t *)(data); + fontblockobj->ttf_fonts[id].type = (eElemType_t)*(uint32_t *)(data + 1 * 4); + num_fields = *(uint32_t *)(data + 2 * 4); + fontblockobj->ttf_fonts[id].num_fields = num_fields; + fontblockobj->ttf_fonts[id].fields = (font_fields_t *)elm_alloc(1, num_fields * sizeof(font_fields_t)); + + _process_font_field_data(data_start, (uint8_t*)(data + 3 * 4), num_fields, fontblockobj->ttf_fonts[id].fields); + return 0; +} + +/* process vector-type font data */ +static int _process_vector_font_data(uint8_t *data_start, uint8_t *data, font_block_t *fontblockobj, int id) +{ + unsigned int num_fields = 0; + + fontblockobj->vector_fonts[id].id = *(uint32_t *)(data); + fontblockobj->vector_fonts[id].type = (eElemType_t)*(uint32_t *)(data + 1 * 4); + num_fields = *(uint32_t *)(data + 2 * 4); + fontblockobj->vector_fonts[id].num_fields = num_fields; + fontblockobj->vector_fonts[id].fields = (font_fields_t *)elm_alloc(1, num_fields * sizeof(font_fields_t)); + + _process_font_field_data(data_start, (uint8_t*)(data + 3 * 4), num_fields, fontblockobj->vector_fonts[id].fields); + + return 0; +} + +static int _process_text_font_data(uint8_t *data_start, uint8_t *void_data, font_block_t *fontblockobj, int id) +{ + unsigned int num_fields; + uint8_t * data = (uint8_t *) void_data; + + fontblockobj->text_fonts[id].id = *(uint32_t *)(data); + fontblockobj->text_fonts[id].type = (eElemType_t)*(uint32_t *)(data + 1 * 4); + num_fields = *(uint32_t *)(data + 2 * 4); + fontblockobj->text_fonts[id].num_fields = num_fields; + fontblockobj->text_fonts[id].fields = (font_fields_t *)elm_alloc(1, num_fields * sizeof(font_fields_t)); + + _process_font_field_data(data_start, (uint8_t*)(data + 3 * 4), num_fields, fontblockobj->text_fonts[id].fields); + return 0; +} + +static uint32_t *alloc_mem(uint32_t size) +{ + uint32_t *data = NULL; + data = (uint32_t *)elm_alloc(1, size); + JUMP_IF_NULL(data, error_exit); +#ifdef ENABLE_STRICT_DEBUG_MEMSET + memset(data, 0, size); +#endif + return data; +error_exit: + return NULL; +} + +font_block_t *fontblockobj = NULL; + +/* load font-data */ +int _load_font_data(uint8_t *data) +{ + el_Font_Header *font_header = (el_Font_Header *)data; + + if ( fontblockobj != NULL ) + { + return -1; + } + + fontblockobj = (font_block_t *)elm_alloc(1, sizeof(font_block_t)); + memset(fontblockobj, 0, sizeof(font_block_t)); + + fontblockobj->size = font_header->size_font_block; + fontblockobj->type = eElemTypeFont; + fontblockobj->num_ttf_fonts = font_header->num_ttf_fonts; + fontblockobj->num_vector_fonts = font_header->num_vector_fonts; + fontblockobj->num_text_fonts = font_header->num_text_fonts; + fontblockobj->ttf_fonts_block_offset = font_header->ttf_fonts_block_offset; + fontblockobj->ttf_fonts_block_length = font_header->ttf_fonts_block_length; + fontblockobj->vector_fonts_block_offset = font_header->vector_fonts_block_offset; + fontblockobj->vector_fonts_block_length = font_header->vector_fonts_block_length; + fontblockobj->text_fonts_block_offset = font_header->text_fonts_block_offset; + fontblockobj->text_fonts_block_length = font_header->text_fonts_block_length; + fontblockobj->property_block_offset = font_header->property_block_offset; + fontblockobj->property_block_length = font_header->property_block_length; +#ifdef ENABLE_DEBUG_TRACE + printf("size: %d(%0x)\n", fontblockobj->size, fontblockobj->size); + printf("type: %d\n", fontblockobj->type); + printf("num_ttf_fonts: %d\n", fontblockobj->num_ttf_fonts); + printf("num_vector_fonts: %d\n", fontblockobj->num_vector_fonts); + printf("num_text_fonts: %d\n", fontblockobj->num_text_fonts); + printf("ttf_fonts_block_offset: %d(%0x)\n", fontblockobj->ttf_fonts_block_offset, + fontblockobj->ttf_fonts_block_offset); + printf("ttf_fonts_block_length: %d(%0x)\n", fontblockobj->ttf_fonts_block_length, + fontblockobj->ttf_fonts_block_length); + printf("vector_fonts_block_offset: %d(%0x)\n", fontblockobj->vector_fonts_block_offset, + fontblockobj->vector_fonts_block_offset); + printf("vector_fonts_block_length: %d(%0x)\n", fontblockobj->vector_fonts_block_length, + fontblockobj->vector_fonts_block_length); + printf("text_fonts_block_offset: %d(%0x)\n", fontblockobj->text_fonts_block_offset, + fontblockobj->text_fonts_block_offset); + printf("text_fonts_block_length: %d(%0x)\n", fontblockobj->text_fonts_block_length, + fontblockobj->text_fonts_block_length); + printf("property_block_offset: %d(%0x)\n", fontblockobj->property_block_offset, + fontblockobj->property_block_offset); + printf("property_block_length: %d(%0x)\n", fontblockobj->property_block_length, + fontblockobj->property_block_length); +#endif + + g_total_system_font = 0; + + if ( fontblockobj->num_ttf_fonts > 0 ) { + fontblockobj->sizes_of_ttf_data = + (unsigned int *)alloc_mem(4 * fontblockobj->num_ttf_fonts); + fontblockobj->offsets_of_ttf_data = + (unsigned int *)alloc_mem(4 * fontblockobj->num_ttf_fonts); + fontblockobj->ttf_fonts = NULL; + fontblockobj->ttf_fonts = (ttf_font_t *)elm_alloc(1, fontblockobj->num_ttf_fonts * sizeof(ttf_font_t)); + JUMP_IF_NULL(fontblockobj->sizes_of_ttf_data, error_exit); + JUMP_IF_NULL(fontblockobj->offsets_of_ttf_data, error_exit); + JUMP_IF_NULL(fontblockobj->ttf_fonts, error_exit); + + memset(fontblockobj->ttf_fonts, 0, fontblockobj->num_ttf_fonts * sizeof(ttf_font_t)); + for(int i=0; inum_ttf_fonts; i++) + { + fontblockobj->sizes_of_ttf_data[i] = *(uint32_t *)(data + (i) * 4 + fontblockobj->ttf_fonts_block_offset); + printf("ttf-DataSize: %d(%0x)\n", fontblockobj->sizes_of_ttf_data[i], + fontblockobj->sizes_of_ttf_data[i]); + fontblockobj->offsets_of_ttf_data[i] = *(uint32_t *)(data + (i + fontblockobj->num_ttf_fonts) * 4 + fontblockobj->ttf_fonts_block_offset); + printf("ttf-offset: %d(%0x)\n", fontblockobj->offsets_of_ttf_data[i], + fontblockobj->offsets_of_ttf_data[i]); + + if (fontblockobj->sizes_of_ttf_data[i] == 0) + { + continue; + } + + _process_ttf_font_data(data, (uint8_t *)(data + fontblockobj->offsets_of_ttf_data[i]), fontblockobj, i); + } + } + + if ( fontblockobj->num_vector_fonts > 0 ) { + fontblockobj->sizes_of_vector_data = + (unsigned int *)alloc_mem(4 * fontblockobj->num_vector_fonts); + fontblockobj->offsets_of_vector_data = + (unsigned int *)alloc_mem(4 * fontblockobj->num_vector_fonts); + fontblockobj->vector_fonts = NULL; + fontblockobj->vector_fonts = (vector_font_t *)elm_alloc(1, fontblockobj->num_vector_fonts * sizeof(vector_font_t)); + JUMP_IF_NULL(fontblockobj->sizes_of_vector_data, error_exit); + JUMP_IF_NULL(fontblockobj->offsets_of_vector_data, error_exit); + JUMP_IF_NULL(fontblockobj->vector_fonts, error_exit); + + memset(fontblockobj->vector_fonts, 0, fontblockobj->num_vector_fonts * sizeof(vector_font_t)); + for(int i=0; inum_vector_fonts; i++) + { + fontblockobj->sizes_of_vector_data[i] = *(uint32_t *)(data + (i) * 4 + fontblockobj->vector_fonts_block_offset); +#ifdef ENABLE_DEBUG_TRACE + printf("vector-DataSize: %d(%0x)\n", fontblockobj->sizes_of_vector_data[i], + fontblockobj->sizes_of_vector_data[i]); +#endif + fontblockobj->offsets_of_vector_data[i] = *(uint32_t *)(data + (i + fontblockobj->num_vector_fonts) * 4 + fontblockobj->vector_fonts_block_offset); +#ifdef ENABLE_DEBUG_TRACE + printf("vector-offset: %d(%0x)\n", fontblockobj->offsets_of_vector_data[i], + fontblockobj->offsets_of_vector_data[i]); +#endif + + if (fontblockobj->sizes_of_vector_data[i] == 0) + { + continue; + } + + _process_vector_font_data(data, (uint8_t *)(data + fontblockobj->offsets_of_vector_data[i]), fontblockobj, i); + } + } + + if ( fontblockobj->num_text_fonts > 0 ) { + fontblockobj->sizes_of_text_font_data = + (unsigned int *)alloc_mem(4 * fontblockobj->num_text_fonts); + fontblockobj->offsets_of_text_font_data = + (unsigned int *)alloc_mem(4 * fontblockobj->num_text_fonts); + fontblockobj->text_fonts = NULL; + fontblockobj->text_fonts = (ttf_font_t *)elm_alloc(1, fontblockobj->num_text_fonts * sizeof(ttf_font_t)); + JUMP_IF_NULL(fontblockobj->sizes_of_text_font_data, error_exit); + JUMP_IF_NULL(fontblockobj->offsets_of_text_font_data, error_exit); + JUMP_IF_NULL(fontblockobj->text_fonts, error_exit); + memset(fontblockobj->text_fonts, 0, fontblockobj->num_text_fonts * sizeof(ttf_font_t)); + for(int i=0; inum_text_fonts; i++) + { + fontblockobj->sizes_of_text_font_data[i] = *(uint32_t *)(data + (i) * 4 + fontblockobj->text_fonts_block_offset); +#ifdef ENABLE_DEBUG_TRACE + printf("textfont-DataSize: %d(%0x)\n", fontblockobj->sizes_of_text_font_data[i], + fontblockobj->sizes_of_text_font_data[i]); +#endif + fontblockobj->offsets_of_text_font_data[i] = *(uint32_t *)(data + (i + fontblockobj->num_text_fonts) * 4 + fontblockobj->text_fonts_block_offset); +#ifdef ENABLE_DEBUG_TRACE + printf("textfont-offset: %d(%0x)\n", fontblockobj->offsets_of_text_font_data[i], + fontblockobj->offsets_of_text_font_data[i]); +#endif + + if (fontblockobj->sizes_of_text_font_data[i] == 0) + { + continue; + } + + _process_text_font_data(data, (uint8_t *)(data + fontblockobj->offsets_of_text_font_data[i]), fontblockobj, i); + } + } + + return 0; + +error_exit: + destroy_font_data(); + + return -1; +} + +#if (defined(__ICCARM__)) +/* + * Disable the unaligned structure attribute warning. Due to the packed data + * structures used to interpret ELM objects data the IAR compiler issues a + * number of warnings that certain attributes of the headers might be unaligned. + * This is not true, however, as all atributes are manually aligned to 4 bytes. + */ +#pragma diag_suppress = Pa039 +#endif + +#define TEXT_CONTENT_OFFSET_WITHOUT_TRANSFORM 9 * 4 +#define TRANSFORM_MATRIX_LENGTH 9 * 4 +ElmHandle _load_text_data(uint8_t *data, el_Obj_EVO *evo) +{ + el_Obj_TEXT *evo_text = NULL; + uint8_t *text_data = NULL; + el_Text_Header *text_header = (el_Text_Header *)data; + + if (evo == NULL) { +#if (RTOS && DDRLESS) || BAREMETAL + evo = alloc_evo(1); +#else + evo = (el_Obj_EVO *)elm_alloc(1, sizeof(el_Obj_TEXT)); +#endif + } + JUMP_IF_NULL(evo, error_exit); +#ifdef ENABLE_STRICT_DEBUG_MEMSET + memset(evo, 0, sizeof(el_Obj_EVO)); +#endif + evo_text = (el_Obj_TEXT *)evo; + + /* + Default transform matrix is, + identity matrix + no-scaling + zero-translate + */ + _init_transform(&evo_text->defaultAttrib.transform); + memcpy(&evo_text->defaultAttrib.transform.matrix, &text_header->matrix, + sizeof(vg_lite_matrix_t)); + + text_data = (uint8_t *)elm_alloc(1, text_header->data_length); + + memcpy(text_data, (void *)(data + sizeof(el_Text_Header)), text_header->data_length); + + evo_text->tspan_has_dx_dy = text_header->tspan_has_dx_dy; + evo_text->x_pos = (int)text_header->x_pos; + evo_text->y_pos = (int)text_header->y_pos; + evo_text->text_anchor = text_header->text_flags.text_anchor; + evo_text->font_id = (int)text_header->font_id; + evo_text->font_size = (int)text_header->font_size; + evo_text->msg = text_data; + + evo_text->defaultAttrib.quality = (ELM_QUALITY)VG_LITE_HIGH; + evo_text->defaultAttrib.fill_rule = ELM_EVO_FILL_NZ; + evo_text->defaultAttrib.blend = ELM_BLEND_SRC_OVER; + evo_text->defaultAttrib.paint.type = ELM_PAINT_TEXT; + evo_text->defaultAttrib.paint.color = text_header->color; + + evo_text->object.type = ELM_OBJECT_TYPE_EVO; + evo_text->object.reference = 0; + evo_text->attribute = evo_text->defaultAttrib; + + ref_object(&evo_text->object); + JUMP_IF_NON_ZERO_VALUE(add_object(&evo_text->object), error_exit); + + return evo_text->object.handle; + +error_exit: + if ( (evo_text) && (evo_text->msg != NULL) ) { + elm_free(evo_text->msg); + evo_text->msg = NULL; + } + if ( evo != NULL ) { + elm_free(evo); + } + + return ELM_NULL_HANDLE; +} + +#if (defined(__ICCARM__)) +/* Restore the unaligned data structure attribute warning */ +#pragma diag_default = Pa039 +#endif + +void _unload_text(el_Obj_EVO *evo) +{ + el_Obj_TEXT *evo_text = (el_Obj_TEXT *)evo; + if(evo_text->msg != NULL) + { + elm_free(evo_text->msg); + evo_text->msg = NULL; + } +} +void destroy_font_data() +{ + int i=0, j = 0; + if(fontblockobj != NULL) { + if(fontblockobj->sizes_of_ttf_data != NULL){ + elm_free(fontblockobj->sizes_of_ttf_data); + fontblockobj->sizes_of_ttf_data = NULL; + } + if(fontblockobj->offsets_of_ttf_data != NULL){ + elm_free(fontblockobj->offsets_of_ttf_data); + fontblockobj->offsets_of_ttf_data = NULL; + } + if(fontblockobj->sizes_of_vector_data != NULL){ + elm_free(fontblockobj->sizes_of_vector_data); + fontblockobj->sizes_of_vector_data = NULL; + } + if(fontblockobj->offsets_of_vector_data != NULL){ + elm_free(fontblockobj->offsets_of_vector_data); + fontblockobj->offsets_of_vector_data = NULL; + } + if(fontblockobj->sizes_of_text_font_data != NULL){ + elm_free(fontblockobj->sizes_of_text_font_data); + fontblockobj->sizes_of_text_font_data = NULL; + } + if(fontblockobj->offsets_of_text_font_data != NULL){ + elm_free(fontblockobj->offsets_of_text_font_data); + fontblockobj->offsets_of_text_font_data = NULL; + } + for(i=0; inum_ttf_fonts; i++) + { + if(fontblockobj->ttf_fonts[i].fields != NULL){ + for(j=0; jttf_fonts[i].num_fields; j++) + { + if(fontblockobj->ttf_fonts[i].fields[j].data != NULL) { + elm_free(fontblockobj->ttf_fonts[i].fields[j].data); + fontblockobj->ttf_fonts[i].fields[j].data = NULL; + } + } + elm_free(fontblockobj->ttf_fonts[i].fields); + fontblockobj->ttf_fonts[i].fields = NULL; + } + } + if(fontblockobj->ttf_fonts != NULL){ + elm_free(fontblockobj->ttf_fonts); + fontblockobj->ttf_fonts = NULL; + } + for(i=0; inum_vector_fonts; i++) + { + if(fontblockobj->vector_fonts[i].fields != NULL){ + for(j=0; jvector_fonts[i].num_fields; j++) + { + if(fontblockobj->vector_fonts[i].fields[j].data != NULL) { + elm_free(fontblockobj->vector_fonts[i].fields[j].data); + fontblockobj->vector_fonts[i].fields[j].data = NULL; + } + } + elm_free(fontblockobj->vector_fonts[i].fields); + fontblockobj->vector_fonts[i].fields = NULL; + } + } + if(fontblockobj->vector_fonts != NULL){ + elm_free(fontblockobj->vector_fonts); + fontblockobj->vector_fonts = NULL; + } + for(i=0; inum_text_fonts; i++) + { + if(fontblockobj->text_fonts[i].fields != NULL){ + for(j=0; jtext_fonts[i].num_fields; j++) + { + if(fontblockobj->text_fonts[i].fields[j].data != NULL) { + elm_free(fontblockobj->text_fonts[i].fields[j].data); + fontblockobj->text_fonts[i].fields[j].data = NULL; + } + } + elm_free(fontblockobj->text_fonts[i].fields); + fontblockobj->text_fonts[i].fields = NULL; + } + } + if(fontblockobj->text_fonts != NULL){ + elm_free(fontblockobj->text_fonts); + fontblockobj->text_fonts = NULL; + } + + elm_free(fontblockobj); + fontblockobj = NULL; + } + + vg_lite_unload_font_data(); + + for(int i=0; iprvData; + + if (0U == dcHandle->initTimes++) + { + dcConfig = (const dc_fb_elcdif_config_t *)(dc->config); + + elcdifConfig.panelWidth = dcConfig->width; + elcdifConfig.panelHeight = dcConfig->height; + elcdifConfig.hsw = (uint8_t)dcConfig->hsw; + elcdifConfig.hfp = (uint8_t)dcConfig->hfp; + elcdifConfig.hbp = (uint8_t)dcConfig->hbp; + elcdifConfig.vsw = (uint8_t)dcConfig->vsw; + elcdifConfig.vfp = (uint8_t)dcConfig->vfp; + elcdifConfig.vbp = (uint8_t)dcConfig->vbp; + elcdifConfig.bufferAddr = 0; + elcdifConfig.dataBus = dcConfig->dataBus; + elcdifConfig.pixelFormat = DC_FB_ELCDIF_DEFAULT_PIXEL_FORMAT_ELCDIF; + elcdifConfig.polarityFlags = dcConfig->polarityFlags; + + dcHandle->height = dcConfig->height; + dcHandle->width = dcConfig->width; + dcHandle->elcdif = dcConfig->elcdif; + + ELCDIF_RgbModeInit(dcHandle->elcdif, &elcdifConfig); + } + + return kStatus_Success; +} + +status_t DC_FB_ELCDIF_Deinit(const dc_fb_t *dc) +{ + dc_fb_elcdif_handle_t *dcHandle = dc->prvData; + + if (dcHandle->initTimes > 0U) + { + if ((--dcHandle->initTimes) == 0U) + { + ELCDIF_Deinit(dcHandle->elcdif); + } + } + + return kStatus_Success; +} + +status_t DC_FB_ELCDIF_EnableLayer(const dc_fb_t *dc, uint8_t layer) +{ + assert(layer < DC_FB_ELCDIF_MAX_LAYER); + + status_t status = kStatus_Success; + dc_fb_elcdif_handle_t *dcHandle = dc->prvData; + + /* If the layer is already started. */ + if (!dcHandle->layers[layer].enabled) + { + /* Must have valid frame buffer to show. */ + if (dcHandle->layers[layer].activeBuffer == NULL) + { + status = kStatus_Fail; + } + else + { + ELCDIF_RgbModeStart(dcHandle->elcdif); + dcHandle->layers[layer].enabled = true; + ELCDIF_EnableInterrupts(dcHandle->elcdif, (uint32_t)kELCDIF_CurFrameDoneInterruptEnable); + } + } + + return status; +} + +status_t DC_FB_ELCDIF_DisableLayer(const dc_fb_t *dc, uint8_t layer) +{ + assert(layer < DC_FB_ELCDIF_MAX_LAYER); + + dc_fb_elcdif_handle_t *dcHandle = dc->prvData; + + if (dcHandle->layers[layer].enabled) + { + ELCDIF_RgbModeStop(dcHandle->elcdif); + dcHandle->layers[layer].enabled = false; + ELCDIF_DisableInterrupts(dcHandle->elcdif, (uint32_t)kELCDIF_CurFrameDoneInterruptEnable); + } + + return kStatus_Success; +} + +status_t DC_FB_ELCDIF_SetLayerConfig(const dc_fb_t *dc, uint8_t layer, dc_fb_info_t *fbInfo) +{ + assert(layer < DC_FB_ELCDIF_MAX_LAYER); + + elcdif_pixel_format_t pixelFormat; + status_t status; + + dc_fb_elcdif_handle_t *dcHandle = (dc_fb_elcdif_handle_t *)(dc->prvData); + + assert(fbInfo->startX == 0U); + assert(fbInfo->startY == 0U); + assert(fbInfo->width == dcHandle->width); + assert(fbInfo->height == dcHandle->height); + assert(fbInfo->strideBytes == VIDEO_GetPixelSizeBits(fbInfo->pixelFormat) * dcHandle->width / 8U); + + status = DC_FB_ELCDIF_GetPixelFormat(fbInfo->pixelFormat, &pixelFormat); + if (kStatus_Success != status) + { + return status; + } + + ELCDIF_RgbModeSetPixelFormat(dcHandle->elcdif, pixelFormat); + + return kStatus_Success; +} + +status_t DC_FB_ELCDIF_GetLayerDefaultConfig(const dc_fb_t *dc, uint8_t layer, dc_fb_info_t *fbInfo) +{ + assert(layer < DC_FB_ELCDIF_MAX_LAYER); + + dc_fb_elcdif_handle_t *dcHandle = (dc_fb_elcdif_handle_t *)(dc->prvData); + + fbInfo->startX = 0; + fbInfo->startY = 0; + fbInfo->width = dcHandle->width; + fbInfo->height = dcHandle->height; + fbInfo->strideBytes = 2U * dcHandle->width; + fbInfo->pixelFormat = DC_FB_ELCDIF_DEFAULT_PIXEL_FORMAT; + + return kStatus_Success; +} + +status_t DC_FB_ELCDIF_SetFrameBuffer(const dc_fb_t *dc, uint8_t layer, void *frameBuffer) +{ + assert(layer < DC_FB_ELCDIF_MAX_LAYER); + dc_fb_elcdif_handle_t *dcHandle = dc->prvData; + + ELCDIF_SetNextBufferAddr(dcHandle->elcdif, (uint32_t)(uint8_t *)frameBuffer); + dcHandle->layers[layer].inactiveBuffer = frameBuffer; + + /* + * If the layer is not started, set the current buffer and next buffer to + * new frame buffer, there is not pending frame. + * If the layer already started, only set the next buffer, and the new frameBuffer + * is pending until current buffer switched out. + */ + if (!dcHandle->layers[layer].enabled) + { + dcHandle->elcdif->CUR_BUF = ELCDIF_ADDR_CPU_2_IP((uint32_t)(uint8_t *)frameBuffer); + dcHandle->layers[layer].activeBuffer = frameBuffer; + } + else + { + dcHandle->layers[layer].framePending = true; + } + + return kStatus_Success; +} + +void DC_FB_ELCDIF_SetCallback(const dc_fb_t *dc, uint8_t layer, dc_fb_callback_t callback, void *param) +{ + assert(layer < DC_FB_ELCDIF_MAX_LAYER); + dc_fb_elcdif_handle_t *dcHandle = dc->prvData; + + dcHandle->layers[layer].callback = callback; + dcHandle->layers[layer].cbParam = param; +} + +uint32_t DC_FB_ELCDIF_GetProperty(const dc_fb_t *dc) +{ + return (uint32_t)kDC_FB_ReserveFrameBuffer; +} + +void DC_FB_ELCDIF_IRQHandler(const dc_fb_t *dc) +{ + dc_fb_elcdif_handle_t *dcHandle = dc->prvData; + dc_fb_elcdif_layer_t *layer; + void *oldActiveBuffer; + ELCDIF_ClearInterruptStatus(dcHandle->elcdif, (uint32_t)kELCDIF_CurFrameDone); + + for (uint8_t i = 0; i < DC_FB_ELCDIF_MAX_LAYER; i++) + { + if (dcHandle->layers[i].framePending) + { + layer = &dcHandle->layers[i]; + + oldActiveBuffer = layer->activeBuffer; + layer->activeBuffer = layer->inactiveBuffer; + dcHandle->layers[i].framePending = false; + + layer->callback(layer->cbParam, oldActiveBuffer); + } + } +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_elcdif.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_elcdif.h new file mode 100644 index 0000000000..09be214052 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_elcdif.h @@ -0,0 +1,101 @@ +/* + * Copyright 2019-2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_DC_FB_ELCDIF_H_ +#define _FSL_DC_FB_ELCDIF_H_ + +#include "fsl_dc_fb.h" +#include "fsl_elcdif.h" + +/* + * Change log: + * + * 1.0.1 + * - Fixed MISRA-C 2012 issues. + * + * 1.0.0 + * - Initial version + */ + +/*! + * @addtogroup dc_fb_elcdif + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#define DC_FB_ELCDIF_MAX_LAYER 1U /* Only support one layer currently. */ +#define DC_FB_ELCDIF_DEFAULT_PIXEL_FORMAT kVIDEO_PixelFormatRGB565 +#define DC_FB_ELCDIF_DEFAULT_PIXEL_FORMAT_ELCDIF kELCDIF_PixelFormatRGB565 + +/*! @brief Data for ELCDIF display controller layer. */ +typedef struct _dc_fb_elcdif_layer +{ + bool enabled; /*!< The layer is enabled. */ + volatile bool framePending; /*!< New frame pending. */ + void *activeBuffer; /*!< The frame buffer which is shown. */ + void *inactiveBuffer; /*!< The frame buffer which will be shown. */ + dc_fb_callback_t callback; /*!< Callback for buffer switch off. */ + void *cbParam; /*!< Callback parameter. */ +} dc_fb_elcdif_layer_t; + +/*! @brief Data for ELCDIF display controller driver handle. */ +typedef struct _dc_fb_elcdif_handle +{ + LCDIF_Type *elcdif; /*!< eLCDIF peripheral. */ + uint8_t initTimes; /*!< How many times the DC is initialized. */ + uint16_t height; /*!< Panel height. */ + uint16_t width; /*!< Panel width. */ + dc_fb_elcdif_layer_t layers[DC_FB_ELCDIF_MAX_LAYER]; /*!< Information of the layer. */ +} dc_fb_elcdif_handle_t; + +/*! @brief Configuration for ELCDIF display controller driver handle. */ +typedef struct _dc_fb_elcdif_config +{ + LCDIF_Type *elcdif; /*!< ELCDIF peripheral. */ + uint16_t width; /*!< Width of the panel. */ + uint16_t height; /*!< Height of the panel. */ + uint16_t hsw; /*!< HSYNC pulse width. */ + uint16_t hfp; /*!< Horizontal front porch. */ + uint16_t hbp; /*!< Horizontal back porch. */ + uint16_t vsw; /*!< VSYNC pulse width. */ + uint16_t vfp; /*!< Vertical front porch. */ + uint16_t vbp; /*!< Vertical back porch. */ + uint32_t polarityFlags; /*!< Control flags, OR'ed value of @ref _elcdif_polarity_flags. */ + elcdif_lcd_data_bus_t dataBus; /*!< LCD data bus. */ +} dc_fb_elcdif_config_t; + +extern const dc_fb_ops_t g_dcFbOpsElcdif; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +status_t DC_FB_ELCDIF_Init(const dc_fb_t *dc); +status_t DC_FB_ELCDIF_Deinit(const dc_fb_t *dc); +status_t DC_FB_ELCDIF_EnableLayer(const dc_fb_t *dc, uint8_t layer); +status_t DC_FB_ELCDIF_DisableLayer(const dc_fb_t *dc, uint8_t layer); +status_t DC_FB_ELCDIF_SetLayerConfig(const dc_fb_t *dc, uint8_t layer, dc_fb_info_t *fbInfo); +status_t DC_FB_ELCDIF_GetLayerDefaultConfig(const dc_fb_t *dc, uint8_t layer, dc_fb_info_t *fbInfo); +status_t DC_FB_ELCDIF_SetFrameBuffer(const dc_fb_t *dc, uint8_t layer, void *frameBuffer); +uint32_t DC_FB_ELCDIF_GetProperty(const dc_fb_t *dc); +void DC_FB_ELCDIF_SetCallback(const dc_fb_t *dc, uint8_t layer, dc_fb_callback_t callback, void *param); +void DC_FB_ELCDIF_IRQHandler(const dc_fb_t *dc); + +#if defined(__cplusplus) +} +#endif + +/*! @} */ + +#endif /* _FSL_DC_FB_ELCDIF_H_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_lcdifv2.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_lcdifv2.c new file mode 100644 index 0000000000..ef299e3906 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_lcdifv2.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2019-2020, 2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_dc_fb_lcdifv2.h" +#if defined(SDK_OS_RTOS) +#include "rtthread.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +const dc_fb_ops_t g_dcFbOpsLcdifv2 = { + .init = DC_FB_LCDIFV2_Init, + .deinit = DC_FB_LCDIFV2_Deinit, + .enableLayer = DC_FB_LCDIFV2_EnableLayer, + .disableLayer = DC_FB_LCDIFV2_DisableLayer, + .setLayerConfig = DC_FB_LCDIFV2_SetLayerConfig, + .getLayerDefaultConfig = DC_FB_LCDIFV2_GetLayerDefaultConfig, + .setFrameBuffer = DC_FB_LCDIFV2_SetFrameBuffer, + .getProperty = DC_FB_LCDIFV2_GetProperty, + .setCallback = DC_FB_LCDIFV2_SetCallback, +}; + +typedef struct +{ + video_pixel_format_t videoFormat; + lcdifv2_pixel_format_t lcdifv2Format; +} dc_fb_lcdifv2_pixel_foramt_map_t; + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +static status_t DC_FB_LCDIFV2_GetPixelFormat(video_pixel_format_t input, lcdifv2_pixel_format_t *output); + +/******************************************************************************* + * Variables + ******************************************************************************/ +static const dc_fb_lcdifv2_pixel_foramt_map_t s_lcdifv2PixelFormatMap[] = { + {kVIDEO_PixelFormatRGB565, kLCDIFV2_PixelFormatRGB565}, + {kVIDEO_PixelFormatRGB888, kLCDIFV2_PixelFormatRGB888}, + {kVIDEO_PixelFormatXRGB8888, kLCDIFV2_PixelFormatARGB8888}, + {kVIDEO_PixelFormatXBGR8888, kLCDIFV2_PixelFormatABGR8888}, + {kVIDEO_PixelFormatLUT8, kLCDIFV2_PixelFormatIndex8BPP}, + {kVIDEO_PixelFormatXRGB4444, kLCDIFV2_PixelFormatARGB4444}, + {kVIDEO_PixelFormatXRGB1555, kLCDIFV2_PixelFormatARGB1555}}; + +/******************************************************************************* + * Code + ******************************************************************************/ +static status_t DC_FB_LCDIFV2_GetPixelFormat(video_pixel_format_t input, lcdifv2_pixel_format_t *output) +{ + uint8_t i; + + for (i = 0; i < ARRAY_SIZE(s_lcdifv2PixelFormatMap); i++) + { + if (s_lcdifv2PixelFormatMap[i].videoFormat == input) + { + *output = s_lcdifv2PixelFormatMap[i].lcdifv2Format; + return kStatus_Success; + } + } + + return kStatus_InvalidArgument; +} + +status_t DC_FB_LCDIFV2_Init(const dc_fb_t *dc) +{ + status_t status = kStatus_Success; + const dc_fb_lcdifv2_config_t *dcConfig; + + lcdifv2_display_config_t lcdifv2Config = {0}; + + dc_fb_lcdifv2_handle_t *dcHandle = dc->prvData; + + if (0U == dcHandle->initTimes++) + { + dcConfig = (const dc_fb_lcdifv2_config_t *)(dc->config); + + LCDIFV2_DisplayGetDefaultConfig(&lcdifv2Config); + + lcdifv2Config.panelWidth = dcConfig->width; + lcdifv2Config.panelHeight = dcConfig->height; + lcdifv2Config.hsw = (uint8_t)dcConfig->hsw; + lcdifv2Config.hfp = (uint8_t)dcConfig->hfp; + lcdifv2Config.hbp = (uint8_t)dcConfig->hbp; + lcdifv2Config.vsw = (uint8_t)dcConfig->vsw; + lcdifv2Config.vfp = (uint8_t)dcConfig->vfp; + lcdifv2Config.vbp = (uint8_t)dcConfig->vbp; + lcdifv2Config.polarityFlags = dcConfig->polarityFlags; + lcdifv2Config.lineOrder = dcConfig->lineOrder; + + dcHandle->height = dcConfig->height; + dcHandle->width = dcConfig->width; + dcHandle->lcdifv2 = dcConfig->lcdifv2; + dcHandle->domain = dcConfig->domain; + + LCDIFV2_Init(dcHandle->lcdifv2); + + LCDIFV2_SetDisplayConfig(dcHandle->lcdifv2, &lcdifv2Config); + + LCDIFV2_EnableInterrupts(dcHandle->lcdifv2, dcHandle->domain, (uint32_t)kLCDIFV2_VerticalBlankingInterrupt); + + LCDIFV2_EnableDisplay(dcHandle->lcdifv2, true); + } + + return status; +} + +status_t DC_FB_LCDIFV2_Deinit(const dc_fb_t *dc) +{ + dc_fb_lcdifv2_handle_t *dcHandle = dc->prvData; + + if (dcHandle->initTimes > 0U) + { + if (--dcHandle->initTimes == 0U) + { + LCDIFV2_DisableInterrupts(dcHandle->lcdifv2, dcHandle->domain, + (uint32_t)kLCDIFV2_VerticalBlankingInterrupt); + LCDIFV2_Deinit(dcHandle->lcdifv2); + } + } + + return kStatus_Success; +} + +status_t DC_FB_LCDIFV2_EnableLayer(const dc_fb_t *dc, uint8_t layer) +{ + assert(layer < DC_FB_LCDIFV2_MAX_LAYER); + + status_t status = kStatus_Success; + dc_fb_lcdifv2_handle_t *dcHandle = dc->prvData; + + /* If the layer is not started. */ + if (!dcHandle->layers[layer].enabled) + { + LCDIFV2_SetLayerBackGroundColor(dcHandle->lcdifv2, layer, 0U); + LCDIFV2_EnableLayer(dcHandle->lcdifv2, layer, true); + LCDIFV2_TriggerLayerShadowLoad(dcHandle->lcdifv2, layer); + dcHandle->layers[layer].shadowLoadPending = true; + + while (true == dcHandle->layers[layer].shadowLoadPending) + { +#if defined(SDK_OS_RTOS) + rt_thread_delay(1); +#endif + } + + dcHandle->layers[layer].activeBuffer = dcHandle->layers[layer].inactiveBuffer; + dcHandle->layers[layer].enabled = true; + } + + return status; +} + +status_t DC_FB_LCDIFV2_DisableLayer(const dc_fb_t *dc, uint8_t layer) +{ + assert(layer < DC_FB_LCDIFV2_MAX_LAYER); + + dc_fb_lcdifv2_handle_t *dcHandle = dc->prvData; + + if (dcHandle->layers[layer].enabled) + { + LCDIFV2_EnableLayer(dcHandle->lcdifv2, layer, false); + LCDIFV2_TriggerLayerShadowLoad(dcHandle->lcdifv2, layer); + dcHandle->layers[layer].enabled = false; + } + + return kStatus_Success; +} + +status_t DC_FB_LCDIFV2_SetLayerConfig(const dc_fb_t *dc, uint8_t layer, dc_fb_info_t *fbInfo) +{ + assert(layer < DC_FB_LCDIFV2_MAX_LAYER); + + lcdifv2_buffer_config_t bufferConfig = {0}; + lcdifv2_pixel_format_t pixelFormat; + LCDIFV2_Type *lcdifv2; + status_t status; + + dc_fb_lcdifv2_handle_t *dcHandle = (dc_fb_lcdifv2_handle_t *)(dc->prvData); + + lcdifv2 = dcHandle->lcdifv2; + + status = DC_FB_LCDIFV2_GetPixelFormat(fbInfo->pixelFormat, &pixelFormat); + if (kStatus_Success != status) + { + return status; + } + + LCDIFV2_SetLayerSize(lcdifv2, layer, fbInfo->width, fbInfo->height); + LCDIFV2_SetLayerOffset(lcdifv2, layer, fbInfo->startX, fbInfo->startY); + + bufferConfig.strideBytes = fbInfo->strideBytes; + bufferConfig.pixelFormat = pixelFormat; + LCDIFV2_SetLayerBufferConfig(lcdifv2, layer, &bufferConfig); + + return kStatus_Success; +} + +status_t DC_FB_LCDIFV2_GetLayerDefaultConfig(const dc_fb_t *dc, uint8_t layer, dc_fb_info_t *fbInfo) +{ + assert(layer < DC_FB_LCDIFV2_MAX_LAYER); + + dc_fb_lcdifv2_handle_t *dcHandle = (dc_fb_lcdifv2_handle_t *)(dc->prvData); + + fbInfo->startX = 0; + fbInfo->startY = 0; + fbInfo->width = dcHandle->width; + fbInfo->height = dcHandle->height; + fbInfo->strideBytes = DC_FB_LCDIFV2_DEFAULT_BYTE_PER_PIXEL * dcHandle->width; + fbInfo->pixelFormat = DC_FB_LCDIFV2_DEFAULT_PIXEL_FORMAT; + + return kStatus_Success; +} + +status_t DC_FB_LCDIFV2_SetFrameBuffer(const dc_fb_t *dc, uint8_t layer, void *frameBuffer) +{ + assert(layer < DC_FB_LCDIFV2_MAX_LAYER); + dc_fb_lcdifv2_handle_t *dcHandle = dc->prvData; + + LCDIFV2_SetLayerBufferAddr(dcHandle->lcdifv2, layer, (uint32_t)(uint8_t *)frameBuffer); + dcHandle->layers[layer].inactiveBuffer = frameBuffer; + + if (dcHandle->layers[layer].enabled) + { + LCDIFV2_TriggerLayerShadowLoad(dcHandle->lcdifv2, layer); + dcHandle->layers[layer].shadowLoadPending = true; + dcHandle->layers[layer].framePending = true; + } + else + { + } + + return kStatus_Success; +} + +void DC_FB_LCDIFV2_SetCallback(const dc_fb_t *dc, uint8_t layer, dc_fb_callback_t callback, void *param) +{ + assert(layer < DC_FB_LCDIFV2_MAX_LAYER); + dc_fb_lcdifv2_handle_t *dcHandle = dc->prvData; + + dcHandle->layers[layer].callback = callback; + dcHandle->layers[layer].cbParam = param; +} + +uint32_t DC_FB_LCDIFV2_GetProperty(const dc_fb_t *dc) +{ + return (uint32_t)kDC_FB_ReserveFrameBuffer; +} + +void DC_FB_LCDIFV2_IRQHandler(const dc_fb_t *dc) +{ + uint32_t intStatus; + dc_fb_lcdifv2_handle_t *dcHandle = dc->prvData; + dc_fb_lcdifv2_layer_t *layer; + void *oldActiveBuffer; + + intStatus = LCDIFV2_GetInterruptStatus(dcHandle->lcdifv2, dcHandle->domain); + LCDIFV2_ClearInterruptStatus(dcHandle->lcdifv2, dcHandle->domain, intStatus); + + if (0U == (intStatus & (uint32_t)kLCDIFV2_VerticalBlankingInterrupt)) + { + return; + } + + for (uint8_t i = 0; i < DC_FB_LCDIFV2_MAX_LAYER; i++) + { + if (dcHandle->layers[i].shadowLoadPending) + { + dcHandle->layers[i].shadowLoadPending = false; + } + + if (dcHandle->layers[i].framePending) + { + layer = &dcHandle->layers[i]; + + oldActiveBuffer = layer->activeBuffer; + layer->activeBuffer = layer->inactiveBuffer; + dcHandle->layers[i].framePending = false; + + layer->callback(layer->cbParam, oldActiveBuffer); + } + } +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_lcdifv2.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_lcdifv2.h new file mode 100644 index 0000000000..190437e54d --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_lcdifv2.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2019-2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_DC_FB_LCDIFV2_H_ +#define _FSL_DC_FB_LCDIFV2_H_ + +#include "fsl_dc_fb.h" +#include "fsl_lcdifv2.h" + +/* + * Change log: + * + * 1.0.2 + * - Add more pixel format support. + * + * 1.0.1 + * - Fix MISRA-C 2012 issues. + * + * 1.0.0 + * - Initial version + */ + +/*! + * @addtogroup dc_fb_lcdifv2 + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#define DC_FB_LCDIFV2_MAX_LAYER ((uint32_t)LCDIFV2_LAYER_COUNT) +#define DC_FB_LCDIFV2_DEFAULT_BUF_PER_LAYER 3U +#define DC_FB_LCDIFV2_DEFAULT_PIXEL_FORMAT kVIDEO_PixelFormatRGB565 +#define DC_FB_LCDIFV2_DEFAULT_PIXEL_FORMAT_LCDIFV2 kLCDIFV2_PixelFormatRGB565 +#define DC_FB_LCDIFV2_DEFAULT_BYTE_PER_PIXEL 2U + +/*! @brief Data for LCDIFV2 display controller layer. */ +typedef struct _dc_fb_lcdifv2_layer +{ + bool enabled; /*!< The layer is enabled. */ + volatile bool framePending; /*!< New frame pending. */ + volatile bool shadowLoadPending; /*!< Shadow load pending. */ + void *activeBuffer; /*!< The frame buffer which is shown. */ + void *inactiveBuffer; /*!< The frame buffer which will be shown. */ + dc_fb_callback_t callback; /*!< Callback for buffer switch off. */ + void *cbParam; /*!< Callback parameter. */ +} dc_fb_lcdifv2_layer_t; + +/*! @brief Data for LCDIFV2 display controller driver handle. */ +typedef struct _dc_fb_lcdifv2_handle +{ + LCDIFV2_Type *lcdifv2; /*!< LCDIFV2 peripheral. */ + uint8_t initTimes; /*!< How many times the DC is initialized. */ + uint16_t height; /*!< Panel height. */ + uint16_t width; /*!< Panel width. */ + uint8_t domain; /*!< Domain used for interrupt. */ + dc_fb_lcdifv2_layer_t layers[DC_FB_LCDIFV2_MAX_LAYER]; /*!< Information of the layer. */ +} dc_fb_lcdifv2_handle_t; + +/*! @brief Configuration for LCDIFV2 display controller driver handle. */ +typedef struct _dc_fb_lcdifv2_config +{ + LCDIFV2_Type *lcdifv2; /*!< LCDIFV2 peripheral. */ + uint16_t width; /*!< Width of the panel. */ + uint16_t height; /*!< Height of the panel. */ + uint16_t hsw; /*!< HSYNC pulse width. */ + uint16_t hfp; /*!< Horizontal front porch. */ + uint16_t hbp; /*!< Horizontal back porch. */ + uint16_t vsw; /*!< VSYNC pulse width. */ + uint16_t vfp; /*!< Vertical front porch. */ + uint16_t vbp; /*!< Vertical back porch. */ + uint32_t polarityFlags; /*!< Control flags, OR'ed value of @ref _lcdifv2_polarity_flags. */ + lcdifv2_line_order_t lineOrder; /*!< Line order. */ + uint8_t domain; /*!< Domain used to for interrupt. */ +} dc_fb_lcdifv2_config_t; + +extern const dc_fb_ops_t g_dcFbOpsLcdifv2; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +status_t DC_FB_LCDIFV2_Init(const dc_fb_t *dc); +status_t DC_FB_LCDIFV2_Deinit(const dc_fb_t *dc); +status_t DC_FB_LCDIFV2_EnableLayer(const dc_fb_t *dc, uint8_t layer); +status_t DC_FB_LCDIFV2_DisableLayer(const dc_fb_t *dc, uint8_t layer); +status_t DC_FB_LCDIFV2_SetLayerConfig(const dc_fb_t *dc, uint8_t layer, dc_fb_info_t *fbInfo); +status_t DC_FB_LCDIFV2_GetLayerDefaultConfig(const dc_fb_t *dc, uint8_t layer, dc_fb_info_t *fbInfo); +status_t DC_FB_LCDIFV2_SetFrameBuffer(const dc_fb_t *dc, uint8_t layer, void *frameBuffer); +uint32_t DC_FB_LCDIFV2_GetProperty(const dc_fb_t *dc); +void DC_FB_LCDIFV2_SetCallback(const dc_fb_t *dc, uint8_t layer, dc_fb_callback_t callback, void *param); +void DC_FB_LCDIFV2_IRQHandler(const dc_fb_t *dc); + +#if defined(__cplusplus) +} +#endif + +/*! @} */ + +#endif /* _FSL_DC_FB_LCDIFV2_H_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_display.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_display.h new file mode 100644 index 0000000000..c285cf7ab6 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_display.h @@ -0,0 +1,140 @@ +/* + * Copyright 2017-2018 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_DISPLAY_H_ +#define _FSL_DISPLAY_H_ + +#include "fsl_video_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Display common configuration. */ +typedef struct _display_common_cfg_t +{ + uint16_t width; + uint16_t height; + uint16_t hsw; /*!< HSYNC pulse width. */ + uint16_t hfp; /*!< Horizontal front porch. */ + uint16_t hbp; /*!< Horizontal back porch. */ + uint16_t vsw; /*!< VSYNC pulse width. */ + uint16_t vfp; /*!< Vrtical front porch. */ + uint16_t vbp; /*!< Vertical back porch. */ + uint32_t clock; /* !< pixecl clock in kHz>. */ +} display_common_cfg; + +/*! @brief Display control flags. */ +enum _display_flags +{ + kDISPLAY_VsyncActiveLow = 0U, /*!< VSYNC active low. */ + kDISPLAY_VsyncActiveHigh = (1U << 0U), /*!< VSYNC active high. */ + kDISPLAY_HsyncActiveLow = 0U, /*!< HSYNC active low. */ + kDISPLAY_HsyncActiveHigh = (1U << 1U), /*!< HSYNC active high. */ + kDISPLAY_DataEnableActiveHigh = 0U, /*!< Data enable line active high. */ + kDISPLAY_DataEnableActiveLow = (1U << 2U), /*!< Data enable line active low. */ + kDISPLAY_DataLatchOnRisingEdge = 0U, /*!< Latch data on rising clock edge. */ + kDISPLAY_DataLatchOnFallingEdge = (1U << 3U), /*!< Latch data on falling clock edge. */ +}; + +/*! @brief Display configuration. */ +typedef struct _display_config +{ + uint32_t resolution; /*!< Resolution, see @ref video_resolution_t and @ref FSL_VIDEO_RESOLUTION. */ + uint16_t hsw; /*!< HSYNC pulse width. */ + uint16_t hfp; /*!< Horizontal front porch. */ + uint16_t hbp; /*!< Horizontal back porch. */ + uint16_t vsw; /*!< VSYNC pulse width. */ + uint16_t vfp; /*!< Vrtical front porch. */ + uint16_t vbp; /*!< Vertical back porch. */ + uint32_t controlFlags; /*!< Control flags, OR'ed value of @ref _display_flags. */ + uint8_t dsiLanes; /*!< MIPI DSI data lanes number. */ + uint32_t pixelClock_Hz; /*!< Pixel clock in Hz. */ + video_pixel_format_t pixelFormat; /*!< Pixel format. */ +} display_config_t; + +typedef struct _display_handle display_handle_t; + +/*! @brief Display device operations. */ +typedef struct _display_operations +{ + status_t (*init)(display_handle_t *handle, const display_config_t *config); /*!< Init the device. */ + status_t (*deinit)(display_handle_t *handle); /*!< Deinit the device. */ + status_t (*start)(display_handle_t *handle); /*!< Start the device. */ + status_t (*stop)(display_handle_t *handle); /*!< Stop the device. */ +} display_operations_t; + +/*! @brief Display handle. */ +struct _display_handle +{ + const void *resource; + const display_operations_t *ops; + uint16_t width; + uint16_t height; + video_pixel_format_t pixelFormat; +}; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @brief Initializes the display device with user defined configuration. + * + * @param handle Display device handle. + * @param config Pointer to the user-defined configuration structure. + * @return Returns @ref kStatus_Success if initialize success, otherwise returns + * error code. + */ +static inline status_t DISPLAY_Init(display_handle_t *handle, const display_config_t *config) +{ + return handle->ops->init(handle, config); +} + +/*! + * @brief Deinitialize the display device. + * + * @param handle Display device handle. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +static inline status_t DISPLAY_Deinit(display_handle_t *handle) +{ + return handle->ops->deinit(handle); +} + +/*! + * @brief Start the display device. + * + * @param handle Display device handle. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +static inline status_t DISPLAY_Start(display_handle_t *handle) +{ + return handle->ops->start(handle); +} + +/*! + * @brief Stop the display device. + * + * @param handle Display device handle. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +static inline status_t DISPLAY_Stop(display_handle_t *handle) +{ + return handle->ops->stop(handle); +} + +#if defined(__cplusplus) +} +#endif + +#endif /* _FSL_DISPLAY_H_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_fbdev.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_fbdev.c new file mode 100644 index 0000000000..a2a182d9fa --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_fbdev.c @@ -0,0 +1,243 @@ +/* + * Copyright 2019-2021, 2023 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_fbdev.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +static void FBDEV_BufferSwitchOffCallback(void *param, void *switchOffBuffer); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +status_t FBDEV_Open(fbdev_t *fbdev, const dc_fb_t *dc, uint8_t layer) +{ + status_t status; + + assert(NULL != fbdev); + + (void)memset(fbdev, 0, sizeof(fbdev_t)); + + fbdev->dc = dc; + + (void)VIDEO_STACK_Init(&fbdev->fbManager, fbdev->buffers, FBDEV_MAX_FRAME_BUFFER); + + /* Initialize the display controller. */ + status = dc->ops->init(dc); + if (kStatus_Success != status) + { + return status; + } + + fbdev->layer = layer; + + /* Initializes the dc_fb_info_t to the display controller default setting. */ + status = dc->ops->getLayerDefaultConfig(dc, layer, &fbdev->fbInfo.bufInfo); + if (kStatus_Success != status) + { + return status; + } + + fbdev->semaFramePending = rt_sem_create("fsfp", 0, RT_IPC_FLAG_PRIO); + if (NULL == fbdev->semaFramePending) + { + return kStatus_Fail; + } + + /* No frame pending. */ + (void)rt_sem_release(fbdev->semaFramePending); + + dc->ops->setCallback(dc, layer, FBDEV_BufferSwitchOffCallback, (void *)fbdev); + + return kStatus_Success; +} + +status_t FBDEV_Close(fbdev_t *fbdev) +{ + const dc_fb_t *dc = fbdev->dc; + + (void)dc->ops->deinit(dc); + + if (NULL != fbdev->semaFbManager) + { + rt_sem_delete(fbdev->semaFbManager); + fbdev->semaFbManager = NULL; + } + + if (NULL != fbdev->semaFramePending) + { + rt_sem_delete(fbdev->semaFramePending); + fbdev->semaFramePending = NULL; + } + + return kStatus_Success; +} + +status_t FBDEV_Enable(fbdev_t *fbdev) +{ + status_t status = kStatus_Success; + + const dc_fb_t *dc = fbdev->dc; + + if (!fbdev->enabled) + { + /* Wait for frame buffer sent to display controller video memory. */ + if ((dc->ops->getProperty(dc) & (uint32_t)kDC_FB_ReserveFrameBuffer) == 0U) + { + if (RT_EOK != rt_sem_take(fbdev->semaFramePending, RT_WAITING_FOREVER)) + { + status = kStatus_Fail; + } + } + + if (kStatus_Success == status) + { + /* No frame is pending. */ + (void)rt_sem_release(fbdev->semaFramePending); + + status = dc->ops->enableLayer(dc, fbdev->layer); + + if (kStatus_Success == status) + { + fbdev->enabled = true; + } + } + } + + return status; +} + +status_t FBDEV_Disable(fbdev_t *fbdev) +{ + status_t status = kStatus_Success; + + const dc_fb_t *dc = fbdev->dc; + + if (!fbdev->enabled) + { + /* Wait until no frame pending. */ + if (RT_EOK != rt_sem_take(fbdev->semaFramePending, RT_WAITING_FOREVER)) + { + status = kStatus_Fail; + } + + if (kStatus_Success == status) + { + (void)rt_sem_release(fbdev->semaFramePending); + + (void)dc->ops->disableLayer(dc, fbdev->layer); + + fbdev->enabled = false; + } + } + + return status; +} + +void FBDEV_GetFrameBufferInfo(fbdev_t *fbdev, fbdev_fb_info_t *info) +{ + *info = fbdev->fbInfo; +} + +status_t FBDEV_SetFrameBufferInfo(fbdev_t *fbdev, fbdev_fb_info_t *info) +{ + status_t status; + const dc_fb_t *dc = fbdev->dc; + + /* Should only change the frame buffer setting before enabling the fbdev. */ + if (fbdev->enabled) + { + return kStatus_Fail; + } + + fbdev->fbInfo = *info; + + status = dc->ops->setLayerConfig(dc, fbdev->layer, &fbdev->fbInfo.bufInfo); + + if (kStatus_Success != status) + { + return status; + } + + fbdev->semaFbManager = rt_sem_create("fsfm", 0, RT_IPC_FLAG_PRIO); + if (NULL == fbdev->semaFbManager) + { + return kStatus_Fail; + } + + for (uint8_t i = 0; i < info->bufferCount; i++) + { + /* Don't need to disable interrupt for the FB stack operation, because + the fbdev is not working, this is the only function to access FB stack. + */ + (void)VIDEO_STACK_Push(&fbdev->fbManager, info->buffers[i]); + (void)rt_sem_release(fbdev->semaFbManager); + } + + return kStatus_Success; +} + +void *FBDEV_GetFrameBuffer(fbdev_t *fbdev, uint32_t flags) +{ + rt_uint32_t tick; + void *fb; + + tick = ((flags & (uint32_t)kFBDEV_NoWait) != 0U) ? 0U : RT_WAITING_FOREVER; + + if (RT_EOK == rt_sem_take(fbdev->semaFbManager, tick)) + { + /* Disable interrupt to protect the FB stack. */ + rt_enter_critical(); + (void)VIDEO_STACK_Pop(&fbdev->fbManager, &fb); + rt_exit_critical(); + } + else + { + fb = NULL; + } + + return fb; +} + +status_t FBDEV_SetFrameBuffer(fbdev_t *fbdev, void *frameBuffer, uint32_t flags) +{ + rt_uint32_t tick; + const dc_fb_t *dc = fbdev->dc; + + tick = ((flags & (uint32_t)kFBDEV_NoWait) != 0U) ? 0U : RT_WAITING_FOREVER; + + if (RT_EOK == rt_sem_take(fbdev->semaFramePending, tick)) + { + return dc->ops->setFrameBuffer(dc, fbdev->layer, frameBuffer); + } + else + { + return kStatus_Fail; + } +} + +static void FBDEV_BufferSwitchOffCallback(void *param, void *switchOffBuffer) +{ + fbdev_t *fbdev = (fbdev_t *)param; + + /* This function should only be called in ISR, so don't need to protect the FB stack */ + (void)VIDEO_STACK_Push(&fbdev->fbManager, switchOffBuffer); + rt_sem_release(fbdev->semaFbManager); + + rt_sem_release(fbdev->semaFramePending); +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_fbdev.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_fbdev.h new file mode 100644 index 0000000000..556efa7486 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_fbdev.h @@ -0,0 +1,227 @@ +/* + * Copyright 2019-2021, 2023 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_FBDEV_H_ +#define _FSL_FBDEV_H_ + +#include "fsl_video_common.h" +#include "fsl_dc_fb.h" +#include "rtthread.h" + +/* + * Change Log: + * + * 1.0.3: + * - Bug Fixes: + * - Fixed the issue that frame buffer content changed when saved + * to free frame buffer list. + * + * 1.0.2: + * - Bug Fixes: + * - Fixed MISRA 2012 issues. + * + * 1.0.1: + * - Bug Fixes: + * - Fixed coverity warnings that return values unchedked. + * + * 1.0.0: + * - Initial version. + */ + +/*! + * @addtogroup fbdev + * @{ + * + * To use the fbdev, follow the workflow: + * + @code + uint8_t layer = 0; + fbdev_t fbdev; + fbdev_fb_info_t fbInfo; + extern const dc_fb_t dc; + + FBDEV_Open(&fbdev, &dc, layer); + + fbInfo.bufInfo.pixelFormat = DEMO_BUFFER_PIXEL_FORMAT; + fbInfo.bufInfo.width = DEMO_BUFFER_WIDTH; + fbInfo.bufInfo.height = DEMO_BUFFER_HEIGHT; + fbInfo.bufInfo.strideBytes = DEMO_BUFFER_STRIDE_BYTE; + fbInfo.buffers[0] = DEMO_BUFFER0_ADDR; + fbInfo.buffers[1] = DEMO_BUFFER1_ADDR; + + FBDEV_SetFrameBufferInfo(&fbdev, &fbInfo); + + buffer = FBDEV_GetFrameBuffer(&fbdev, 0); + + fill the buffer here. + + FBDEV_SetFrameBuffer(&fbdev, buffer, 0); + + FBDEV_Enable(&fbdev); + + buffer = FBDEV_GetFrameBuffer(&fbdev, 0); + + fill the buffer here. + + FBDEV_SetFrameBuffer(&fbdev, buffer, 0); + + ... + + @endcode + * + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief How many frame buffers used in each fbdev. */ +#ifndef FBDEV_MAX_FRAME_BUFFER +#define FBDEV_MAX_FRAME_BUFFER 3 +#endif + +#define FBDEV_DEFAULT_FRAME_BUFFER 2 + +/*! @brief Frame buffer information. */ +typedef struct _fbdev_fb_info +{ + uint8_t bufferCount; /*!< How many frame buffers used. */ + void *buffers[FBDEV_MAX_FRAME_BUFFER]; /*!< Address of the frame buffers */ + dc_fb_info_t bufInfo; /*!< Frame buffers information */ +} fbdev_fb_info_t; + +/*! @brief FBDEV handle, user should not touch the members directly. */ +typedef struct _fbdev +{ + fbdev_fb_info_t fbInfo; /*!< Frame buffer information. */ + video_stack_t fbManager; /*!< Manage the framebuffers used by this device. */ + void *buffers[FBDEV_MAX_FRAME_BUFFER]; /*!< Memory used by @ref fbManager, to save the free frame buffers. */ + const dc_fb_t *dc; /*!< Display controller handle. */ + uint8_t layer; /*!< Layer in the display controller. */ + bool enabled; /*!< The fbdev is enabled or not by @ref FBDEV_Enable. */ + rt_sem_t semaFbManager; /*!< Semaphore for the @ref fbManager. */ + rt_sem_t semaFramePending; /*!< Semaphore for the @ref framePending. */ +} fbdev_t; + +/*! @brief Flags used for FBDEV operations. */ +enum _fbdev_flag +{ + kFBDEV_NoWait = (1 << 0), /*!< Don't wait until available, but return directly. */ +}; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @brief Open the FBDEV. + * + * @param fbdev The FBDEV handle. + * @param dc The display controller used. + * @param layer The layer in the display controller. + * @return Returns @ref kStatus_Success if success, otherwise returns + * error code. + */ +status_t FBDEV_Open(fbdev_t *fbdev, const dc_fb_t *dc, uint8_t layer); + +/*! + * @brief Close the FBDEV. + * + * @param fbdev The FBDEV handle. + * @return Returns @ref kStatus_Success if success, otherwise returns + * error code. + */ +status_t FBDEV_Close(fbdev_t *fbdev); + +/*! + * @brief Enable the FBDEV. + * + * After enabled, the FBDEV will be shown in the panel. This function should be + * called after @ref FBDEV_SetFrameBufferInfo. + * + * @param fbdev The FBDEV handle. + * @return Returns @ref kStatus_Success if success, otherwise returns + * error code. + */ +status_t FBDEV_Enable(fbdev_t *fbdev); + +/*! + * @brief Disable the FBDEV. + * + * After disabled, the FBDEV will not be shown in the panel. Don't call + * @ref FBDEV_SetFrameBuffer when the FBDEV is disabled. + * + * @param fbdev The FBDEV handle. + * @return Returns @ref kStatus_Success if success, otherwise returns + * error code. + */ +status_t FBDEV_Disable(fbdev_t *fbdev); + +/*! + * @brief Get the frame buffer information of the FBDEV. + * + * @param fbdev The FBDEV handle. + * @param info Pointer to the frame buffer information. + */ +void FBDEV_GetFrameBufferInfo(fbdev_t *fbdev, fbdev_fb_info_t *info); + +/*! + * @brief Set the frame buffer information of the FBDEV. + * + * This function could be used to configure the FRDEV, including set witdh, height, + * pixel format, frame buffers, and so on. This function should only be called once + * after @ref FBDEV_Open and before @ref FBDEV_Enable. + * + * @param fbdev The FBDEV handle. + * @param info Pointer to the frame buffer information. + * @return Returns @ref kStatus_Success if success, otherwise returns + * error code. + */ +status_t FBDEV_SetFrameBufferInfo(fbdev_t *fbdev, fbdev_fb_info_t *info); + +/*! + * @brief Get available frame buffer from the FBDEV. + * + * Upper layer could call this function to get an available frame buffer from + * the FBDEV, render send to show. + * + * @param fbdev The FBDEV handle. + * @param flags OR'ed value of @ref _fbdev_flag. If @ref kFBDEV_NoWait is used, + * the function returns NULL immediately if no available buffer. If @ref kFBDEV_NoWait + * is not used, this function waits until available. + * + * @return Returns the address of the frame buffer. If no available, returns NULL. + */ +void *FBDEV_GetFrameBuffer(fbdev_t *fbdev, uint32_t flags); + +/*! + * @brief Send frame buffer to the FBDEV. + * + * Upper layer could call this function to send a frame buffer to the FBDEV. This + * function should only be used when the FBDEV is enabled. + * + * @param fbdev The FBDEV handle. + * @param flags OR'ed value of @ref _fbdev_flag. If @ref kFBDEV_NoWait is used, + * the function returns NULL immediately if the previous frame buffer is pending. + * If @ref kFBDEV_NoWait is not used, this function waits until previous frame + * buffer not pending. + * + * @return Returns @ref kStatus_Success if success, otherwise returns + * error code. + */ +status_t FBDEV_SetFrameBuffer(fbdev_t *fbdev, void *frameBuffer, uint32_t flags); + +#if defined(__cplusplus) +} +#endif + +/*! @} */ + +#endif /* _FSL_FBDEV_H_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_hx8394.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_hx8394.c new file mode 100644 index 0000000000..91303ce47c --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_hx8394.c @@ -0,0 +1,187 @@ +/* + * Copyright 2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_display.h" +#include "fsl_hx8394.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define HX8394_DelayMs VIDEO_DelayMs + +typedef struct +{ + const uint8_t *cmd; + uint8_t cmdLen; +} hx8394_cmd_t; + +/******************************************************************************* + * Variables + ******************************************************************************/ +const display_operations_t hx8394_ops = { + .init = HX8394_Init, + .deinit = HX8394_Deinit, + .start = HX8394_Start, + .stop = HX8394_Stop, +}; + +static const hx8394_cmd_t s_hx8394Cmds[] = { + {(const uint8_t[]){0x36U, 0x02U}, 2U}, + + {(const uint8_t[]){0xB1U, 0x48U, 0x12U, 0x72U, 0x09U, 0x32U, 0x54U, 0x71U, 0x71U, 0x57U, 0x47U}, 11U}, + + {(const uint8_t[]){0xB2U, 0x00U, 0x80U, 0x64U, 0x0CU, 0x0DU, 0x2FU}, 7U}, + + {(const uint8_t[]){0xB4U, 0x73U, 0x74U, 0x73U, 0x74U, 0x73U, 0x74U, 0x01U, 0x0CU, 0x86U, /* 10 */ + 0x75U, 0x00U, 0x3FU, 0x73U, 0x74U, 0x73U, 0x74U, 0x73U, 0x74U, 0x01U, /* 20 */ + 0x0CU, 0x86U}, + 22U}, + + {(const uint8_t[]){0xD3U, 0x00U, 0x00U, 0x07U, 0x07U, 0x40U, 0x07U, 0x0CU, 0x00U, 0x08U, /* 10 */ + 0x10U, 0x08U, 0x00U, 0x08U, 0x54U, 0x15U, 0x0AU, 0x05U, 0x0AU, 0x02U, /* 20 */ + 0x15U, 0x06U, 0x05U, 0x06U, 0x47U, 0x44U, 0x0AU, 0x0AU, 0x4BU, 0x10U, /* 30 */ + 0x07U, 0x07U, 0x0CU, 0x40U}, + 34U}, + + {(const uint8_t[]){0xD5U, 0x1CU, 0x1CU, 0x1DU, 0x1DU, 0x00U, 0x01U, 0x02U, 0x03U, 0x04U, /* 10 */ + 0x05U, 0x06U, 0x07U, 0x08U, 0x09U, 0x0AU, 0x0BU, 0x24U, 0x25U, 0x18U, /* 20 */ + 0x18U, 0x26U, 0x27U, 0x18U, 0x18U, 0x18U, 0x18U, 0x18U, 0x18U, 0x18U, /* 30 */ + 0x18U, 0x18U, 0x18U, 0x18U, 0x18U, 0x18U, 0x18U, 0x18U, 0x18U, 0x20U, /* 40 */ + 0x21U, 0x18U, 0x18U, 0x18U, 0x18U}, + 45U}, + + {(const uint8_t[]){0xD6U, 0x1CU, 0x1CU, 0x1DU, 0x1DU, 0x07U, 0x06U, 0x05U, 0x04U, 0x03U, /* 10 */ + 0x02U, 0x01U, 0x00U, 0x0BU, 0x0AU, 0x09U, 0x08U, 0x21U, 0x20U, 0x18U, /* 20 */ + 0x18U, 0x27U, 0x26U, 0x18U, 0x18U, 0x18U, 0x18U, 0x18U, 0x18U, 0x18U, /* 30 */ + 0x18U, 0x18U, 0x18U, 0x18U, 0x18U, 0x18U, 0x18U, 0x18U, 0x18U, 0x25U, /* 40 */ + 0x24U, 0x18U, 0x18U, 0x18U, 0x18U}, + 45U}, + + {(const uint8_t[]){0xB6U, 0x92U, 0x92U}, 3U}, + + {(const uint8_t[]){0xE0U, 0x00U, 0x0AU, 0x15U, 0x1BU, 0x1EU, 0x21U, 0x24U, 0x22U, 0x47U, /* 10 */ + 0x56U, 0x65U, 0x66U, 0x6EU, 0x82U, 0x88U, 0x8BU, 0x9AU, 0x9DU, 0x98U, /* 20 */ + 0xA8U, 0xB9U, 0x5DU, 0x5CU, 0x61U, 0x66U, 0x6AU, 0x6FU, 0x7FU, 0x7FU, /* 30 */ + 0x00U, 0x0AU, 0x15U, 0x1BU, 0x1EU, 0x21U, 0x24U, 0x22U, 0x47U, 0x56U, /* 40 */ + 0x65U, 0x65U, 0x6EU, 0x81U, 0x87U, 0x8BU, 0x98U, 0x9DU, 0x99U, 0xA8U, /* 50 */ + 0xBAU, 0x5DU, 0x5DU, 0x62U, 0x67U, 0x6BU, 0x72U, 0x7FU, 0x7FU}, + 59U}, + + {(const uint8_t[]){0xC0U, 0x1FU, 0x31U}, 3U}, + {(const uint8_t[]){0xCCU, 0x03U}, 2U}, + {(const uint8_t[]){0xD4U, 0x02U}, 2U}, + {(const uint8_t[]){0xBDU, 0x02U}, 2U}, + + {(const uint8_t[]){0xD8U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, /* 10 */ + 0xFFU, 0xFFU, 0xFFU}, + 13U}, + + {(const uint8_t[]){0xBDU, 0x00U}, 2U}, + {(const uint8_t[]){0xBDU, 0x01U}, 2U}, + {(const uint8_t[]){0xB1U, 0x00U}, 2U}, + {(const uint8_t[]){0xBDU, 0x00U}, 2U}, + + {(const uint8_t[]){0xBFU, 0x40U, 0x81U, 0x50U, 0x00U, 0x1AU, 0xFCU, 0x01}, 8U}, + + {(const uint8_t[]){0xC6U, 0xEDU}, 2U}, + + {(const uint8_t[]){0x35U, 0x00U}, 2U}, +}; + +/******************************************************************************* + * Code + ******************************************************************************/ + +status_t HX8394_Init(display_handle_t *handle, const display_config_t *config) +{ + uint8_t i; + status_t status = kStatus_Success; + const hx8394_resource_t *resource = (const hx8394_resource_t *)(handle->resource); + mipi_dsi_device_t *dsiDevice = resource->dsiDevice; + uint8_t setmipi[7] = {0xBAU, 0x60U, 0x03U, 0x68U, 0x6BU, 0xB2U, 0xC0U}; + + /* Only support 720 * 1280 */ + if (config->resolution != FSL_VIDEO_RESOLUTION(720, 1280)) + { + return kStatus_InvalidArgument; + } + + /* Power on. */ + resource->pullPowerPin(true); + HX8394_DelayMs(1); + + /* Perform reset. */ + resource->pullResetPin(false); + HX8394_DelayMs(1); + resource->pullResetPin(true); + HX8394_DelayMs(50U); + + status = MIPI_DSI_GenericWrite(dsiDevice, (const uint8_t[]){0xB9U, 0xFFU, 0x83U, 0x94U}, 4); + + setmipi[1] |= (config->dsiLanes - 1U); + + if (kStatus_Success == status) + { + status = MIPI_DSI_GenericWrite(dsiDevice, setmipi, 7); + } + + if (kStatus_Success == status) + { + for (i = 0; i < ARRAY_SIZE(s_hx8394Cmds); i++) + { + status = MIPI_DSI_GenericWrite(dsiDevice, s_hx8394Cmds[i].cmd, (int32_t)s_hx8394Cmds[i].cmdLen); + + if (kStatus_Success != status) + { + break; + } + } + } + + if (kStatus_Success == status) + { + status = MIPI_DSI_DCS_EnterSleepMode(dsiDevice, false); + } + + if (kStatus_Success == status) + { + HX8394_DelayMs(120U); + + status = MIPI_DSI_DCS_SetDisplayOn(dsiDevice, true); + } + + return status; +} + +status_t HX8394_Deinit(display_handle_t *handle) +{ + const hx8394_resource_t *resource = (const hx8394_resource_t *)(handle->resource); + mipi_dsi_device_t *dsiDevice = resource->dsiDevice; + + (void)MIPI_DSI_DCS_EnterSleepMode(dsiDevice, true); + + resource->pullResetPin(false); + resource->pullPowerPin(false); + + return kStatus_Success; +} + +status_t HX8394_Start(display_handle_t *handle) +{ + const hx8394_resource_t *resource = (const hx8394_resource_t *)(handle->resource); + mipi_dsi_device_t *dsiDevice = resource->dsiDevice; + + return MIPI_DSI_DCS_SetDisplayOn(dsiDevice, true); +} + +status_t HX8394_Stop(display_handle_t *handle) +{ + const hx8394_resource_t *resource = (const hx8394_resource_t *)(handle->resource); + mipi_dsi_device_t *dsiDevice = resource->dsiDevice; + + return MIPI_DSI_DCS_SetDisplayOn(dsiDevice, false); +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_hx8394.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_hx8394.h new file mode 100644 index 0000000000..b33aea98ac --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_hx8394.h @@ -0,0 +1,57 @@ +/* + * Copyright 2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_HX8394_H_ +#define _FSL_HX8394_H_ + +#include "fsl_display.h" +#include "fsl_mipi_dsi_cmd.h" + +/* + * Change log: + * + * 1.0.0 + * - Initial version + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! + * @brief HX8394 resource. + */ +typedef struct _hx8394_resource +{ + mipi_dsi_device_t *dsiDevice; /*!< MIPI DSI device. */ + void (*pullResetPin)(bool pullUp); /*!< Function to pull reset pin high or low. */ + void (*pullPowerPin)(bool pullUp); /*!< Function to pull power pin high or low. */ +} hx8394_resource_t; + +extern const display_operations_t hx8394_ops; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +status_t HX8394_Init(display_handle_t *handle, const display_config_t *config); + +status_t HX8394_Deinit(display_handle_t *handle); + +status_t HX8394_Start(display_handle_t *handle); + +status_t HX8394_Stop(display_handle_t *handle); + +#if defined(__cplusplus) +} +#endif + +#endif /* _FSL_HX8394_H_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_mipi_dsi_cmd.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_mipi_dsi_cmd.c new file mode 100644 index 0000000000..e9ff8f6561 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_mipi_dsi_cmd.c @@ -0,0 +1,351 @@ +/* + * Copyright 2017-2020 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_mipi_dsi_cmd.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +status_t MIPI_DSI_DCS_SoftReset(mipi_dsi_device_t *device) +{ + dsi_transfer_t dsiXfer = {0}; + uint8_t txData = (uint8_t)kMIPI_DCS_SoftReset; + + dsiXfer.virtualChannel = device->virtualChannel; + dsiXfer.txDataType = kDSI_TxDataDcsShortWrNoParam; + dsiXfer.txDataSize = 1; + dsiXfer.txData = &txData; + + return device->xferFunc(&dsiXfer); +} + +status_t MIPI_DSI_DCS_SetDisplayOn(mipi_dsi_device_t *device, bool on) +{ + dsi_transfer_t dsiXfer = {0}; + uint8_t txData; + + dsiXfer.virtualChannel = device->virtualChannel; + dsiXfer.txDataType = kDSI_TxDataDcsShortWrNoParam; + dsiXfer.txDataSize = 1; + dsiXfer.txData = &txData; + + if (on) + { + txData = (uint8_t)kMIPI_DCS_SetDisplayOn; + } + else + { + txData = (uint8_t)kMIPI_DCS_SetDisplayOff; + } + + return device->xferFunc(&dsiXfer); +} + +status_t MIPI_DSI_DCS_SetPixelFormat(mipi_dsi_device_t *device, + mipi_dsc_pixel_format_t dbiFormat, + mipi_dsc_pixel_format_t dpiFormat) +{ + dsi_transfer_t dsiXfer = {0}; + uint8_t txData[2]; + + dsiXfer.virtualChannel = device->virtualChannel; + dsiXfer.txDataType = kDSI_TxDataDcsShortWrOneParam; + dsiXfer.txDataSize = 2; + dsiXfer.txData = txData; + + txData[0] = (uint8_t)kMIPI_DCS_SetPixelFormat; + txData[1] = ((uint8_t)dbiFormat << 0U) | ((uint8_t)dpiFormat << 4U); + + return device->xferFunc(&dsiXfer); +} + +status_t MIPI_DSI_DCS_EnterSleepMode(mipi_dsi_device_t *device, bool enter) +{ + dsi_transfer_t dsiXfer = {0}; + uint8_t txData; + + dsiXfer.virtualChannel = device->virtualChannel; + dsiXfer.txDataType = kDSI_TxDataDcsShortWrNoParam; + dsiXfer.txDataSize = 1; + dsiXfer.txData = &txData; + + if (enter) + { + txData = (uint8_t)kMIPI_DCS_EnterSleepMode; + } + else + { + txData = (uint8_t)kMIPI_DCS_ExitSleepMode; + } + + return device->xferFunc(&dsiXfer); +} + +status_t MIPI_DSI_DCS_EnterPartialMode(mipi_dsi_device_t *device, bool enter) +{ + dsi_transfer_t dsiXfer = {0}; + uint8_t txData; + + dsiXfer.virtualChannel = device->virtualChannel; + dsiXfer.txDataType = kDSI_TxDataDcsShortWrNoParam; + dsiXfer.txDataSize = 1; + dsiXfer.txData = &txData; + + if (enter) + { + txData = (uint8_t)kMIPI_DCS_EnterPartialMode; + } + else + { + txData = (uint8_t)kMIPI_DCS_EnterNormalMode; + } + + return device->xferFunc(&dsiXfer); +} + +status_t MIPI_DSI_DCS_EnterInvertMode(mipi_dsi_device_t *device, bool enter) +{ + dsi_transfer_t dsiXfer = {0}; + uint8_t txData; + + dsiXfer.virtualChannel = device->virtualChannel; + dsiXfer.txDataType = kDSI_TxDataDcsShortWrNoParam; + dsiXfer.txDataSize = 1; + dsiXfer.txData = &txData; + + if (enter) + { + txData = (uint8_t)kMIPI_DCS_EnterInvertMode; + } + else + { + txData = (uint8_t)kMIPI_DCS_ExitInvertMode; + } + + return device->xferFunc(&dsiXfer); +} + +status_t MIPI_DSI_DCS_EnterIdleMode(mipi_dsi_device_t *device, bool enter) +{ + dsi_transfer_t dsiXfer = {0}; + uint8_t txData; + + dsiXfer.virtualChannel = device->virtualChannel; + dsiXfer.txDataType = kDSI_TxDataDcsShortWrNoParam; + dsiXfer.txDataSize = 1; + dsiXfer.txData = &txData; + + if (enter) + { + txData = (uint8_t)kMIPI_DCS_EnterIdleMode; + } + else + { + txData = (uint8_t)kMIPI_DCS_ExitIdleMode; + } + + return device->xferFunc(&dsiXfer); +} + +status_t MIPI_DSI_DCS_Write(mipi_dsi_device_t *device, const uint8_t *txData, int32_t txDataSize) +{ + dsi_transfer_t dsiXfer = {0}; + + dsiXfer.virtualChannel = device->virtualChannel; + dsiXfer.txDataSize = (uint16_t)txDataSize; + dsiXfer.txData = txData; + + if (0 == txDataSize) + { + /* For DSC command, the data size should not be 0. */ + return kStatus_InvalidArgument; + } + else if (1 == txDataSize) + { + dsiXfer.txDataType = kDSI_TxDataDcsShortWrNoParam; + } + else if (2 == txDataSize) + { + dsiXfer.txDataType = kDSI_TxDataDcsShortWrOneParam; + } + else + { + dsiXfer.txDataType = kDSI_TxDataDcsLongWr; + } + + return device->xferFunc(&dsiXfer); +} + +status_t MIPI_DSI_GenericWrite(mipi_dsi_device_t *device, const uint8_t *txData, int32_t txDataSize) +{ + dsi_transfer_t dsiXfer = {0}; + + dsiXfer.virtualChannel = device->virtualChannel; + dsiXfer.txDataSize = (uint16_t)txDataSize; + dsiXfer.txData = txData; + + if (0 == txDataSize) + { + dsiXfer.txDataType = kDSI_TxDataGenShortWrNoParam; + } + else if (1 == txDataSize) + { + dsiXfer.txDataType = kDSI_TxDataGenShortWrOneParam; + } + else if (2 == txDataSize) + { + dsiXfer.txDataType = kDSI_TxDataGenShortWrTwoParam; + } + else + { + dsiXfer.txDataType = kDSI_TxDataGenLongWr; + } + + return device->xferFunc(&dsiXfer); +} + +status_t MIPI_DSI_DCS_SetMaxReturnPktSize(mipi_dsi_device_t *device, uint16_t sizeBytes) +{ + dsi_transfer_t dsiXfer = {0}; + + dsiXfer.virtualChannel = device->virtualChannel; + dsiXfer.txDataType = kDSI_TxDataSetMaxReturnPktSize; + dsiXfer.txDataSize = 2; + dsiXfer.txData = (uint8_t *)&sizeBytes; + + return device->xferFunc(&dsiXfer); +} + +status_t MIPI_DSI_GenericRead( + mipi_dsi_device_t *device, const uint8_t *txData, int32_t txDataSize, uint8_t *rxData, int32_t *rxDataSize) +{ + status_t status; + dsi_transfer_t dsiXfer = {0}; + + dsiXfer.virtualChannel = device->virtualChannel; + dsiXfer.txDataSize = (uint16_t)txDataSize; + dsiXfer.txData = txData; + dsiXfer.rxDataSize = (uint16_t)*rxDataSize; + dsiXfer.rxData = rxData; + + *rxDataSize = 0; + + if (0 == txDataSize) + { + dsiXfer.txDataType = kDSI_TxDataGenShortRdNoParam; + } + else if (1 == txDataSize) + { + dsiXfer.txDataType = kDSI_TxDataGenShortRdOneParam; + } + else if (2 == txDataSize) + { + dsiXfer.txDataType = kDSI_TxDataGenShortRdTwoParam; + } + else + { + return kStatus_InvalidArgument; + } + + status = device->xferFunc(&dsiXfer); + + /* Return actual received size. */ + *rxDataSize = (int32_t)dsiXfer.rxDataSize; + + return status; +} + +status_t MIPI_DSI_ReadCMD(mipi_dsi_device_t *device, enum _mipi_dcs dcsCmd, uint8_t *rxData, int32_t *rxDataSize) +{ + uint8_t txData[2]; + status_t status = kStatus_Fail; + + txData[0] = (uint8_t)dcsCmd; + if (kStatus_Success == MIPI_DSI_DCS_SetMaxReturnPktSize(device, (uint16_t)*rxDataSize)) + { + status = MIPI_DSI_GenericRead(device, txData, 1, rxData, rxDataSize); + } + + return status; +} + +status_t MIPI_DSI_SelectArea(mipi_dsi_device_t *device, uint16_t startX, uint16_t startY, uint16_t endX, uint16_t endY) +{ + status_t status; + dsi_transfer_t dsiXfer = {0}; + uint8_t txData[4]; + + dsiXfer.virtualChannel = device->virtualChannel; + dsiXfer.txDataType = kDSI_TxDataDcsLongWr; + dsiXfer.txDataSize = 4; + dsiXfer.txData = txData; + dsiXfer.sendDscCmd = true; + dsiXfer.dscCmd = (uint8_t)kMIPI_DCS_SetColumnAddress; + + txData[0] = (uint8_t)((startX >> 8U) & 0xFFU); + txData[1] = (uint8_t)(startX & 0xFFU); + txData[2] = (uint8_t)((endX >> 8U) & 0xFFU); + txData[3] = (uint8_t)(endX & 0xFFU); + + status = device->xferFunc(&dsiXfer); + + if (kStatus_Success != status) + { + return status; + } + + dsiXfer.dscCmd = (uint8_t)kMIPI_DCS_SetPageAddress; + txData[0] = (uint8_t)((startY >> 8U) & 0xFFU); + txData[1] = (uint8_t)(startY & 0xFFU); + txData[2] = (uint8_t)((endY >> 8U) & 0xFFU); + txData[3] = (uint8_t)(endY & 0xFFU); + + return device->xferFunc(&dsiXfer); +} + +status_t MIPI_DSI_WriteMemory(mipi_dsi_device_t *device, const uint8_t *data, uint32_t length) +{ + return device->memWriteFunc(device->virtualChannel, data, length); +} + +status_t MIPI_DSI_WriteMemory2D( + mipi_dsi_device_t *device, const uint8_t *data, uint32_t minorLoop, uint32_t minorLoopOffset, uint32_t majorLoop) +{ + if (device->memWriteFunc2D != NULL) + { + return device->memWriteFunc2D(device->virtualChannel, data, minorLoop, minorLoopOffset, majorLoop); + } + else + { + return kStatus_Fail; + } +} + +void MIPI_DSI_SetMemoryDoneCallback(mipi_dsi_device_t *device, mipi_dsi_mem_done_callback_t callback, void *userData) +{ + device->callback = callback; + device->userData = userData; +} + +void MIPI_DSI_MemoryDoneDriverCallback(status_t status, void *userData) +{ + mipi_dsi_device_t *device = (mipi_dsi_device_t *)userData; + + if (NULL != device->callback) + { + device->callback(status, device->userData); + } +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_mipi_dsi_cmd.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_mipi_dsi_cmd.h new file mode 100644 index 0000000000..2843d8c55d --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_mipi_dsi_cmd.h @@ -0,0 +1,354 @@ +/* + * Copyright 2017-2020 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_MIPI_DSI_CMD_H_ +#define _FSL_MIPI_DSI_CMD_H_ + +#include "fsl_common.h" +#include "fsl_mipi_dsi.h" + +/* + * Change log: + * + * 1.0.2 + * - Fix MISRA-C 2012 issues. + * + * 1.0.1 + * - Add more functions for panel works in command mode. + * + * 1.0.0 + * - Initial version + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +enum _mipi_dcs +{ + kMIPI_DCS_Nop = 0x00, + kMIPI_DCS_SoftReset = 0x01, + kMIPI_DCS_GetRedChannel = 0x06, + kMIPI_DCS_GetGreenChannel = 0x07, + kMIPI_DCS_GetBlueChannel = 0x08, + kMIPI_DCS_GetPowerMode = 0x0A, + kMIPI_DCS_GetAddressMode = 0x0B, + kMIPI_DCS_GetPixelFormat = 0x0C, + kMIPI_DCS_GetDisplayMode = 0x0D, + kMIPI_DCS_GetSignalMode = 0x0E, + kMIPI_DCS_GetDiagnosticResult = 0x0F, + kMIPI_DCS_EnterSleepMode = 0x10, + kMIPI_DCS_ExitSleepMode = 0x11, + kMIPI_DCS_EnterPartialMode = 0x12, + kMIPI_DCS_EnterNormalMode = 0x13, + kMIPI_DCS_ExitInvertMode = 0x20, + kMIPI_DCS_EnterInvertMode = 0x21, + kMIPI_DCS_SetGammaCurve = 0x26, + kMIPI_DCS_SetDisplayOff = 0x28, + kMIPI_DCS_SetDisplayOn = 0x29, + kMIPI_DCS_SetColumnAddress = 0x2a, + kMIPI_DCS_SetPageAddress = 0x2b, + kMIPI_DCS_WriteMemoryStart = 0x2C, + kMIPI_DCS_WriteLUT = 0x2D, + kMIPI_DCS_ReadMemoryStart = 0x2E, + kMIPI_DCS_SetPartialRows = 0x30, + kMIPI_DCS_SetPartialColumns = 0x31, + kMIPI_DCS_SetScrollArea = 0x33, + kMIPI_DCS_SetTearOff = 0x34, + kMIPI_DCS_SetTearOn = 0x35, + kMIPI_DCS_SetAddressMode = 0x36, + kMIPI_DCS_SetScrollStart = 0x37, + kMIPI_DCS_ExitIdleMode = 0x38, + kMIPI_DCS_EnterIdleMode = 0x39, + kMIPI_DCS_SetPixelFormat = 0x3A, + kMIPI_DCS_WriteMemoryContinue = 0x3C, + kMIPI_DCS_Set3DControl = 0x3D, + kMIPI_DCS_ReadMemoryContinue = 0x3E, + kMIPI_DCS_Get3DControl = 0x3F, + kMIPI_DCS_SetVsyncTiming = 0x40, + kMIPI_DCS_SetTearScanline = 0x44, + kMIPI_DCS_GetScanline = 0x45, + kMIPI_DCS_SetDisplayBrightness = 0x51, + kMIPI_DCS_GetDisplayBrightness = 0x52, + kMIPI_DCS_WriteControlDisplay = 0x53, + kMIPI_DCS_GetControlDisplay = 0x54, + kMIPI_DCS_WritePowerSave = 0x55, + kMIPI_DCS_GetPowerSave = 0x56, + kMIPI_DCS_SetCABCMinBrightness = 0x5E, + kMIPI_DCS_GetCABCMinBrightness = 0x5F, + kMIPI_DCS_ReadDDBStart = 0xA1, + kMIPI_DCS_ReadDDBContinue = 0xA8, +}; + +/*! + * @brief Pixel format used by DSC command. + */ +typedef enum _mipi_dsc_pixel_format +{ + kMIPI_DCS_Pixel3Bits = 1U, /*!< 3-bit per pixel. */ + kMIPI_DCS_Pixel8Bits = 2U, /*!< 8-bit per pixel. */ + kMIPI_DCS_Pixel12Bits = 3U, /*!< 12-bit per pixel. */ + kMIPI_DCS_Pixel16Bits = 5U, /*!< 16-bit per pixel. */ + kMIPI_DCS_Pixel18Bits = 6U, /*!< 18-bit per pixel. */ + kMIPI_DCS_Pixel24Bits = 7U, /*!< 24-bit per pixel. */ +} mipi_dsc_pixel_format_t; + +/*! + * @brief Callback function when the write memory finished. + * + * If transfer done successfully, the @p status is kStatus_Success. + */ +typedef void (*mipi_dsi_mem_done_callback_t)(status_t status, void *userData); + +/*! @brief MIPI DSI transfer function. */ +typedef status_t (*mipi_dsi_transfer_func_t)(dsi_transfer_t *xfer); + +/*! @brief MIPI DSI memory write function. */ +typedef status_t (*mipi_dsi_mem_write_func_t)(uint8_t virtualChannel, const uint8_t *data, uint32_t length); + +/*! @brief MIPI DSI memory write function using 2-dimensional way. */ +typedef status_t (*mipi_dsi_mem_write_func_2D_t)( + uint8_t virtualChannel, const uint8_t *data, uint32_t minorLoop, uint32_t minorLoopOffset, uint32_t majorLoop); + +/*! @brief MIPI DSI device. */ +typedef struct _mipi_dsi_device +{ + uint8_t virtualChannel; + mipi_dsi_transfer_func_t xferFunc; + mipi_dsi_mem_write_func_t memWriteFunc; /*!< Function to write display memory, + it should be non-blocking function and + notify upper layer using callback when finished. + Not used when panel works in video mode. */ + mipi_dsi_mem_write_func_2D_t memWriteFunc2D; /*!< Function to write display memory using 2-dimensional way, + it should be non-blocking function and + notify upper layer using callback when finished. + Not used when panel works in video mode. */ + mipi_dsi_mem_done_callback_t callback; /*!< The callback function to notify upper layer + that memory write done. Not used when panel + works in video mode. */ + void *userData; /*!< Parameter for the memory write done callback. + not used when panel works in video mode. */ +} mipi_dsi_device_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @brief Send software reset to MIPI DSI device. + * + * @param device The MIPI DSI device. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +status_t MIPI_DSI_DCS_SoftReset(mipi_dsi_device_t *device); + +/*! + * @brief Set display on or off. + * + * @param device The MIPI DSI device. + * @param on Set true to turn on, false to turn off. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +status_t MIPI_DSI_DCS_SetDisplayOn(mipi_dsi_device_t *device, bool on); + +/*! + * @brief Enter or exit sleep mode. + * + * @param device The MIPI DSI device. + * @param enter Set true to enter sleep mode, false to exit. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +status_t MIPI_DSI_DCS_EnterSleepMode(mipi_dsi_device_t *device, bool enter); + +/*! + * @brief Enter or exit partial mode. + * + * @param device The MIPI DSI device. + * @param enter Set true to enter partial mode, false to exit. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +status_t MIPI_DSI_DCS_EnterPartialMode(mipi_dsi_device_t *device, bool enter); + +/*! + * @brief Enter or exit invert mode. + * + * @param device The MIPI DSI device. + * @param enter Set true to enter invert mode, false to exit. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +status_t MIPI_DSI_DCS_EnterInvertMode(mipi_dsi_device_t *device, bool enter); + +/*! + * @brief Enter or exit idle mode. + * + * @param device The MIPI DSI device. + * @param enter Set true to enter idle mode, false to exit. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +status_t MIPI_DSI_DCS_EnterIdleMode(mipi_dsi_device_t *device, bool enter); + +/*! + * @brief Send DCS command. + * + * @param device The MIPI DSI device. + * @param txData The data to send. + * @param txDataSize Size of the data to send (in bytes). + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +status_t MIPI_DSI_DCS_Write(mipi_dsi_device_t *device, const uint8_t *txData, int32_t txDataSize); + +/*! + * @brief Send generic data. + * + * @param device The MIPI DSI device. + * @param txData The data to send. + * @param txDataSize Size of the data to send (in bytes). + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +status_t MIPI_DSI_GenericWrite(mipi_dsi_device_t *device, const uint8_t *txData, int32_t txDataSize); + +/*! + * @brief Set the maximum return data length. + * + * @param device The MIPI DSI device. + * @param sizeBytes Maximum return data length. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +status_t MIPI_DSI_DCS_SetMaxReturnPktSize(mipi_dsi_device_t *device, uint16_t sizeBytes); + +/*! + * @brief Generic read. + * + * @param device The MIPI DSI device. + * @param txData The data to send before read. + * @param txDataSize Size of the data to send (in bytes). + * @param rxData The data to read. + * @param rxDataSize Size of the data to read (in bytes), after this function returns, + * it is the actual read length. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +status_t MIPI_DSI_GenericRead( + mipi_dsi_device_t *device, const uint8_t *txData, int32_t txDataSize, uint8_t *rxData, int32_t *rxDataSize); + +/*! + * @brief Read DCS command(read type command, such as: Get Display ID). + * + * @param device The MIPI DSI device. + * @param dcsCmd The command to send before read. + * @param rxData The data to read. + * @param rxDataSize Size of the data to read (in bytes), after this function returns, + * it is the actual read length. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +status_t MIPI_DSI_ReadCMD(mipi_dsi_device_t *device, enum _mipi_dcs dcsCmd, uint8_t *rxData, int32_t *rxDataSize); + +/*! + * @brief Set the panel pixel format. + * + * @param device The MIPI DSI device. + * @param dbiFormat The DBI interface pixel format. + * @param dpiFormat The DPI interface pixel format. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +status_t MIPI_DSI_DCS_SetPixelFormat(mipi_dsi_device_t *device, + mipi_dsc_pixel_format_t dbiFormat, + mipi_dsc_pixel_format_t dpiFormat); + +/*! + * @brief Select area to write or read pixels. + * + * @param device The MIPI DSI device. + * @param startX Start point X coordination. + * @param startY Start point Y coordination. + * @param endX End point X coordination. + * @param endY End point Y coordination. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +status_t MIPI_DSI_SelectArea(mipi_dsi_device_t *device, uint16_t startX, uint16_t startY, uint16_t endX, uint16_t endY); + +/*! + * @brief Send pixel data to the display controller's frame memory. + * + * The pixels will be shown in the region selected by @ref MIPI_DSI_SelectArea. + * This function is non-blocking function, user should install callback function + * using @ref MIPI_DSI_SetMemoryDoneCallback to get informed when write finished. + * + * @param device The MIPI DSI device. + * @param data The pixel data to send. + * @param length Length of the data in byte. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +status_t MIPI_DSI_WriteMemory(mipi_dsi_device_t *device, const uint8_t *data, uint32_t length); + +/*! + * @brief Send pixel data to the display controller's frame memory in 2-dinmensional way. + * + * The pixels will be shown in the region selected by @ref MIPI_DSI_SelectArea. + * This function is non-blocking function, user should install callback function + * using @ref MIPI_DSI_SetMemoryDoneCallback to get informed when write finished. + * + * @verbatim + * +---------------------------------------------------+ + * | | + * | data | + * | +-------------------+ | + * | | minorLoop | | + * | | | | + * | | | majorLoop | + * | | | | + * | | | | + * | +-------------------+ | + * | | + * | minorLoop + minorLoopOffset | + * +---------------------------------------------------+ + * @endverbatim + * + * @param device The MIPI DSI device. + * @param data The pixel data to send. + * @param minorLoop Count of the data in one line in byte. + * @param minorLoopOffset The offset between line stride and the count of one line in byte. + * @param majorLoop Count of the lines in byte. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +status_t MIPI_DSI_WriteMemory2D( + mipi_dsi_device_t *device, const uint8_t *data, uint32_t minorLoop, uint32_t minorLoopOffset, uint32_t majorLoop); + +/*! + * @brief Install the callback called when write memory finished. + * + * Upper layer should install callback function using this function to + * get memory write done notification. + * + * @param device The MIPI DSI device. + * @param callback The callback function to inform upper layer that memory write done. + * @param userData Parameter used by the callback. + * @return Returns @ref kStatus_Success if success, otherwise returns error code. + */ +void MIPI_DSI_SetMemoryDoneCallback(mipi_dsi_device_t *device, mipi_dsi_mem_done_callback_t callback, void *userData); + +/*! + * @brief The callback function lower layer should call when write memory finished. + * + * When implement the @ref mipi_dsi_device_t, this function should be called when + * the memory writing finished. The parameter @p userData should be pointer to the + * @ref mipi_dsi_device_t. + * + * @param status The memory writing result. @ref kStatus_Success if success. + * @param userData Must be pointer to the @ref mipi_dsi_device_t instance. + */ +void MIPI_DSI_MemoryDoneDriverCallback(status_t status, void *userData); + +#if defined(__cplusplus) +} +#endif + +#endif /* _FSL_MIPI_DSI_CMD_H_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68191.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68191.c new file mode 100644 index 0000000000..3ca01fb28e --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68191.c @@ -0,0 +1,251 @@ +/* + * Copyright 2019-2020 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_display.h" +#include "fsl_rm68191.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define RM68191_DelayMs VIDEO_DelayMs + +typedef struct _rm68191_setting +{ + const uint8_t *value; + uint8_t len; +} rm68191_setting_t; + +#define RM68191_MAKE_SETTING_ITEM(setting) \ + { \ + (setting), (uint8_t)sizeof(setting) \ + } + +/******************************************************************************* + * Variables + ******************************************************************************/ +static const uint8_t s_rm68191Cmd0[] = {0xF0, 0x55, 0xAA, 0x52, 0x08, 0x03}; +static const uint8_t s_rm68191Cmd1[] = {0x90, 0x05, 0x16, 0x09, 0x03, 0xCD, 0x00, 0x00, 0x00, 0x00}; +static const uint8_t s_rm68191Cmd2[] = {0x91, 0x05, 0x16, 0x0B, 0x03, 0xCF, 0x00, 0x00, 0x00, 0x00}; +static const uint8_t s_rm68191Cmd3[] = {0x92, 0x40, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x8F, 0x00, 0x00, 0x04, 0x08}; +static const uint8_t s_rm68191Cmd4[] = {0x94, 0x00, 0x08, 0x0C, 0x03, 0xD1, 0x03, 0xD2, 0x0C}; +static const uint8_t s_rm68191Cmd5[] = {0x95, 0x40, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, + 0x00, 0x8F, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08}; +static const uint8_t s_rm68191Cmd6[] = {0x99, 0x00, 0x00}; +static const uint8_t s_rm68191Cmd7[] = {0x9A, 0x80, 0x10, 0x03, 0xD5, 0x03, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x50}; +static const uint8_t s_rm68191Cmd8[] = {0x9B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const uint8_t s_rm68191Cmd9[] = {0x9C, 0x00, 0x00}; +static const uint8_t s_rm68191Cmd10[] = {0x9D, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00}; +static const uint8_t s_rm68191Cmd11[] = {0x9E, 0x00, 0x00}; +static const uint8_t s_rm68191Cmd12[] = {0xA0, 0x84, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x08, 0x1F, 0x0A, 0x1F}; +static const uint8_t s_rm68191Cmd13[] = {0xA1, 0x1F, 0x1F, 0x1F, 0x1F, 0x0C, 0x1F, 0x0E, 0x1F, 0x1F, 0x1F}; +static const uint8_t s_rm68191Cmd14[] = {0xA2, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x02, 0x1F, 0x06, 0x1F}; +static const uint8_t s_rm68191Cmd15[] = {0xA3, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F}; +static const uint8_t s_rm68191Cmd16[] = {0xA4, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x07, 0x1F, 0x03, 0x1F, 0x0F}; +static const uint8_t s_rm68191Cmd17[] = {0xA5, 0x1F, 0x0D, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x0B, 0x1F, 0x09}; +static const uint8_t s_rm68191Cmd18[] = {0xA6, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x01, 0x05}; +static const uint8_t s_rm68191Cmd19[] = {0xA7, 0x03, 0x07, 0x1F, 0x1F, 0x1F, 0x1F, 0x0B, 0x1F, 0x09, 0x1F}; +static const uint8_t s_rm68191Cmd20[] = {0xA8, 0x1F, 0x1F, 0x1F, 0x1F, 0x0F, 0x1F, 0x0D, 0x1F, 0x1F, 0x1F}; +static const uint8_t s_rm68191Cmd21[] = {0xA9, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x05, 0x1F, 0x01, 0x1F}; +static const uint8_t s_rm68191Cmd22[] = {0xAA, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F}; +static const uint8_t s_rm68191Cmd23[] = {0xAB, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x1F, 0x04, 0x1F, 0x0C}; +static const uint8_t s_rm68191Cmd24[] = {0xAC, 0x1F, 0x0E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x08, 0x1F, 0x0A}; +static const uint8_t s_rm68191Cmd25[] = {0xAD, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x06, 0x02}; +static const uint8_t s_rm68191Cmd26[] = {0xF0, 0x55, 0xAA, 0x52, 0x08, 0x02}; +static const uint8_t s_rm68191Cmd27[] = {0xEA, 0x7D}; +static const uint8_t s_rm68191Cmd28[] = {0xF0, 0x55, 0xAA, 0x52, 0x08, 0x00}; +static const uint8_t s_rm68191Cmd29[] = {0xBC, 0x00, 0x00, 0x00}; +static const uint8_t s_rm68191Cmd30[] = {0xB8, 0x01, 0xAF, 0x8F, 0x8F}; +static const uint8_t s_rm68191Cmd31[] = {0xF0, 0x55, 0xAA, 0x52, 0x08, 0x01}; +static const uint8_t s_rm68191Cmd32[] = {0xD1, 0x00, 0x00, 0x00, 0x26, 0x00, 0x5E, 0x00, 0x88, + 0x00, 0xA8, 0x00, 0xDB, 0x01, 0x02, 0x01, 0x3D}; +static const uint8_t s_rm68191Cmd33[] = {0xD2, 0x01, 0x67, 0x01, 0xA6, 0x01, 0xD3, 0x02, 0x16, + 0x02, 0x49, 0x02, 0x4B, 0x02, 0x7B, 0x02, 0xB3}; +static const uint8_t s_rm68191Cmd34[] = {0xD3, 0x02, 0xD9, 0x03, 0x0E, 0x03, 0x31, 0x03, 0x61, + 0x03, 0x80, 0x03, 0xA5, 0x03, 0xBD, 0x03, 0xD2}; +static const uint8_t s_rm68191Cmd35[] = {0xD4, 0x03, 0xE5, 0x03, 0xFF}; +static const uint8_t s_rm68191Cmd36[] = {0xD5, 0x00, 0x00, 0x00, 0x26, 0x00, 0x5E, 0x00, 0x88, + 0x00, 0xA8, 0x00, 0xDB, 0x01, 0x02, 0x01, 0x3D}; +static const uint8_t s_rm68191Cmd37[] = {0xD6, 0x01, 0x67, 0x01, 0xA6, 0x01, 0xD3, 0x02, 0x16, + 0x02, 0x49, 0x02, 0x4B, 0x02, 0x7B, 0x02, 0xB3}; +static const uint8_t s_rm68191Cmd38[] = {0xD7, 0x02, 0xD9, 0x03, 0x0E, 0x03, 0x31, 0x03, 0x61, + 0x03, 0x80, 0x03, 0xA5, 0x03, 0xBD, 0x03, 0xD2}; +static const uint8_t s_rm68191Cmd39[] = {0xD8, 0x03, 0xE5, 0x03, 0xFF}; +static const uint8_t s_rm68191Cmd40[] = {0xD9, 0x00, 0x00, 0x00, 0x26, 0x00, 0x5E, 0x00, 0x88, + 0x00, 0xA8, 0x00, 0xDB, 0x01, 0x02, 0x01, 0x3D}; +static const uint8_t s_rm68191Cmd41[] = {0xDD, 0x01, 0x67, 0x01, 0xA6, 0x01, 0xD3, 0x02, 0x16, + 0x02, 0x49, 0x02, 0x4B, 0x02, 0x7B, 0x02, 0xB3}; +static const uint8_t s_rm68191Cmd42[] = {0xDE, 0x02, 0xD9, 0x03, 0x0E, 0x03, 0x31, 0x03, 0x61, + 0x03, 0x80, 0x03, 0xA5, 0x03, 0xBD, 0x03, 0xD2}; +static const uint8_t s_rm68191Cmd43[] = {0xDF, 0x03, 0xE5, 0x03, 0xFF}; +static const uint8_t s_rm68191Cmd44[] = {0xE0, 0x00, 0x00, 0x00, 0x26, 0x00, 0x5E, 0x00, 0x88, + 0x00, 0xA8, 0x00, 0xDB, 0x01, 0x02, 0x01, 0x3D}; +static const uint8_t s_rm68191Cmd45[] = {0xE1, 0x01, 0x67, 0x01, 0xA6, 0x01, 0xD3, 0x02, 0x16, + 0x02, 0x49, 0x02, 0x4B, 0x02, 0x7B, 0x02, 0xB3}; +static const uint8_t s_rm68191Cmd46[] = {0xE2, 0x02, 0xD9, 0x03, 0x0E, 0x03, 0x31, 0x03, 0x61, + 0x03, 0x80, 0x03, 0xA5, 0x03, 0xBD, 0x03, 0xD2}; +static const uint8_t s_rm68191Cmd47[] = {0xE3, 0x03, 0xE5, 0x03, 0xFF}; +static const uint8_t s_rm68191Cmd48[] = {0xE4, 0x00, 0x00, 0x00, 0x26, 0x00, 0x5E, 0x00, 0x88, + 0x00, 0xA8, 0x00, 0xDB, 0x01, 0x02, 0x01, 0x3D}; +static const uint8_t s_rm68191Cmd49[] = {0xE5, 0x01, 0x67, 0x01, 0xA6, 0x01, 0xD3, 0x02, 0x16, + 0x02, 0x49, 0x02, 0x4B, 0x02, 0x7B, 0x02, 0xB3}; +static const uint8_t s_rm68191Cmd50[] = {0xE6, 0x02, 0xD9, 0x03, 0x0E, 0x03, 0x31, 0x03, 0x61, + 0x03, 0x80, 0x03, 0xA5, 0x03, 0xBD, 0x03, 0xD2}; +static const uint8_t s_rm68191Cmd51[] = {0xE7, 0x03, 0xE5, 0x03, 0xFF}; +static const uint8_t s_rm68191Cmd52[] = {0xE8, 0x00, 0x00, 0x00, 0x26, 0x00, 0x5E, 0x00, 0x88, + 0x00, 0xA8, 0x00, 0xDB, 0x01, 0x02, 0x01, 0x3D}; +static const uint8_t s_rm68191Cmd53[] = {0xE9, 0x01, 0x67, 0x01, 0xA6, 0x01, 0xD3, 0x02, 0x16, + 0x02, 0x49, 0x02, 0x4B, 0x02, 0x7B, 0x02, 0xB3}; +static const uint8_t s_rm68191Cmd54[] = {0xEA, 0x02, 0xD9, 0x03, 0x0E, 0x03, 0x31, 0x03, 0x61, + 0x03, 0x80, 0x03, 0xA5, 0x03, 0xBD, 0x03, 0xD2}; +static const uint8_t s_rm68191Cmd55[] = {0xEB, 0x03, 0xE5, 0x03, 0xFF}; +static const uint8_t s_rm68191Cmd56[] = {0xB0, 0x07, 0x07, 0x07}; +static const uint8_t s_rm68191Cmd57[] = {0xB1, 0x07, 0x07, 0x07}; +static const uint8_t s_rm68191Cmd58[] = {0xB3, 0x11, 0x11, 0x11}; +static const uint8_t s_rm68191Cmd59[] = {0xB4, 0x09, 0x09, 0x09}; +static const uint8_t s_rm68191Cmd60[] = {0xB6, 0x44, 0x44, 0x44}; +static const uint8_t s_rm68191Cmd61[] = {0xB7, 0x34, 0x34, 0x34}; +static const uint8_t s_rm68191Cmd62[] = {0xB9, 0x34, 0x34, 0x34}; +static const uint8_t s_rm68191Cmd63[] = {0xBA, 0x14, 0x14, 0x14}; +static const uint8_t s_rm68191Cmd64[] = {0xBC, 0x00, 0x98, 0x00}; +static const uint8_t s_rm68191Cmd65[] = {0xBD, 0x00, 0x98, 0x00}; +static const uint8_t s_rm68191Cmd66[] = {0xBE, 0x1D}; +static const uint8_t s_rm68191Cmd67[] = {0x35, 0x00}; + +static const rm68191_setting_t s_rm68191InitSetting[] = { + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd0), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd1), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd2), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd3), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd4), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd5), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd6), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd7), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd8), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd9), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd10), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd11), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd12), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd13), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd14), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd15), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd16), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd17), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd18), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd19), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd20), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd21), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd22), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd23), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd24), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd25), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd26), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd27), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd28), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd29), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd30), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd31), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd32), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd33), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd34), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd35), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd36), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd37), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd38), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd39), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd40), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd41), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd42), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd43), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd44), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd45), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd46), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd47), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd48), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd49), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd50), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd51), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd52), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd53), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd54), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd55), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd56), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd57), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd58), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd59), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd60), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd61), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd62), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd63), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd64), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd65), + RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd66), RM68191_MAKE_SETTING_ITEM(s_rm68191Cmd67), +}; + +const display_operations_t rm68191_ops = { + .init = RM68191_Init, + .deinit = RM68191_Deinit, + .start = RM68191_Start, + .stop = RM68191_Stop, +}; + +/******************************************************************************* + * Code + ******************************************************************************/ + +status_t RM68191_Init(display_handle_t *handle, const display_config_t *config) +{ + uint32_t i; + status_t status = kStatus_Success; + const rm68191_resource_t *resource = (const rm68191_resource_t *)(handle->resource); + mipi_dsi_device_t *dsiDevice = resource->dsiDevice; + + /* Only support 540 * 960 */ + if (config->resolution != FSL_VIDEO_RESOLUTION(540, 960)) + { + return kStatus_InvalidArgument; + } + + /* Power on. */ + resource->pullPowerPin(true); + RM68191_DelayMs(1); + + /* Perform reset. */ + resource->pullResetPin(false); + RM68191_DelayMs(1); + resource->pullResetPin(true); + RM68191_DelayMs(5); + + /* Set the LCM init settings. */ + for (i = 0; i < ARRAY_SIZE(s_rm68191InitSetting); i++) + { + status = MIPI_DSI_DCS_Write(dsiDevice, s_rm68191InitSetting[i].value, (int32_t)s_rm68191InitSetting[i].len); + + if (kStatus_Success != status) + { + return status; + } + } + + /* Exit sleep mode */ + status = MIPI_DSI_DCS_EnterSleepMode(dsiDevice, false); + + if (kStatus_Success != status) + { + return status; + } + + RM68191_DelayMs(200); + + /* Set display on. */ + status = MIPI_DSI_DCS_SetDisplayOn(dsiDevice, true); + + if (kStatus_Success != status) + { + return status; + } + + RM68191_DelayMs(200); + + return kStatus_Success; +} + +status_t RM68191_Deinit(display_handle_t *handle) +{ + const rm68191_resource_t *resource = (const rm68191_resource_t *)(handle->resource); + mipi_dsi_device_t *dsiDevice = resource->dsiDevice; + + (void)MIPI_DSI_DCS_EnterSleepMode(dsiDevice, true); + + resource->pullResetPin(false); + resource->pullPowerPin(false); + + return kStatus_Success; +} + +status_t RM68191_Start(display_handle_t *handle) +{ + const rm68191_resource_t *resource = (const rm68191_resource_t *)(handle->resource); + mipi_dsi_device_t *dsiDevice = resource->dsiDevice; + + return MIPI_DSI_DCS_SetDisplayOn(dsiDevice, true); +} + +status_t RM68191_Stop(display_handle_t *handle) +{ + const rm68191_resource_t *resource = (const rm68191_resource_t *)(handle->resource); + mipi_dsi_device_t *dsiDevice = resource->dsiDevice; + + return MIPI_DSI_DCS_SetDisplayOn(dsiDevice, false); +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68191.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68191.h new file mode 100644 index 0000000000..2f372da002 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68191.h @@ -0,0 +1,62 @@ +/* + * Copyright 2019-2020 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_RM68191_H_ +#define _FSL_RM68191_H_ + +#include "fsl_display.h" +#include "fsl_mipi_dsi_cmd.h" + +/* + * Change log: + * + * 1.1.0 + * - Fix MISRA-C 2012 issues. + * - Change rm68191_resource_t structure. + * + * 1.0.0 + * - Initial version + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! + * @brief RM68191 resource. + */ +typedef struct _rm68191_resource +{ + mipi_dsi_device_t *dsiDevice; /*!< MIPI DSI device. */ + void (*pullResetPin)(bool pullUp); /*!< Function to pull reset pin high or low. */ + void (*pullPowerPin)(bool pullUp); /*!< Function to pull power pin high or low. */ +} rm68191_resource_t; + +extern const display_operations_t rm68191_ops; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +status_t RM68191_Init(display_handle_t *handle, const display_config_t *config); + +status_t RM68191_Deinit(display_handle_t *handle); + +status_t RM68191_Start(display_handle_t *handle); + +status_t RM68191_Stop(display_handle_t *handle); + +#if defined(__cplusplus) +} +#endif + +#endif /* _FSL_RM68191_H_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68200.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68200.c new file mode 100644 index 0000000000..1d8c2831f5 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68200.c @@ -0,0 +1,409 @@ +/* + * Copyright 2019-2021 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_display.h" +#include "fsl_rm68200.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define RM68200_DelayMs VIDEO_DelayMs + +/******************************************************************************* + * Variables + ******************************************************************************/ + +uint8_t RM68200_DDB_START[5] = {0x00, 0x00, 0x00, 0x00, 0xff}; + +static const uint8_t lcmInitPage0Setting[][2] = { + {0xFE, 0x01}, {0x24, 0xC0}, {0x25, 0x53}, {0x26, 0x00}, {0x2B, 0xE5}, {0x27, 0x0A}, + {0x29, 0x0A}, {0x16, 0x52}, {0x2F, 0x53}, {0x34, 0x5A}, {0x1B, 0x00}, {0x12, 0x0A}, + {0x1A, 0x06}, {0x46, 0x56}, {0x52, 0xA0}, {0x53, 0x00}, {0x54, 0xA0}, {0x55, 0x00}, +}; + +static const uint8_t lcmInitSetting[][2] = { + {0xFE, 0x03}, + {0x00, 0x05}, + {0x02, 0x0B}, + {0x03, 0x0F}, + {0x04, 0x7D}, + {0x05, 0x00}, + {0x06, 0x50}, + {0x07, 0x05}, + {0x08, 0x16}, + {0x09, 0x0D}, + {0x0A, 0x11}, + {0x0B, 0x7D}, + {0x0C, 0x00}, + {0x0D, 0x50}, + {0x0E, 0x07}, + {0x0F, 0x08}, + {0x10, 0x01}, + {0x11, 0x02}, + {0x12, 0x00}, + {0x13, 0x7D}, + {0x14, 0x00}, + {0x15, 0x85}, + {0x16, 0x08}, + {0x17, 0x03}, + {0x18, 0x04}, + {0x19, 0x05}, + {0x1A, 0x06}, + {0x1B, 0x00}, + {0x1C, 0x7D}, + {0x1D, 0x00}, + {0x1E, 0x85}, + {0x1F, 0x08}, + {0x20, 0x00}, + {0x21, 0x00}, + {0x22, 0x00}, + {0x23, 0x00}, + {0x24, 0x00}, + {0x25, 0x00}, + {0x26, 0x00}, + {0x27, 0x00}, + {0x28, 0x00}, + {0x29, 0x00}, + {0x2A, 0x07}, + {0x2B, 0x08}, + {0x2D, 0x01}, + {0x2F, 0x02}, + {0x30, 0x00}, + {0x31, 0x40}, + {0x32, 0x05}, + {0x33, 0x08}, + {0x34, 0x54}, + {0x35, 0x7D}, + {0x36, 0x00}, + {0x37, 0x03}, + {0x38, 0x04}, + {0x39, 0x05}, + {0x3A, 0x06}, + {0x3B, 0x00}, + {0x3D, 0x40}, + {0x3F, 0x05}, + {0x40, 0x08}, + {0x41, 0x54}, + {0x42, 0x7D}, + {0x43, 0x00}, + {0x44, 0x00}, + {0x45, 0x00}, + {0x46, 0x00}, + {0x47, 0x00}, + {0x48, 0x00}, + {0x49, 0x00}, + {0x4A, 0x00}, + {0x4B, 0x00}, + {0x4C, 0x00}, + {0x4D, 0x00}, + {0x4E, 0x00}, + {0x4F, 0x00}, + {0x50, 0x00}, + {0x51, 0x00}, + {0x52, 0x00}, + {0x53, 0x00}, + {0x54, 0x00}, + {0x55, 0x00}, + {0x56, 0x00}, + {0x58, 0x00}, + {0x59, 0x00}, + {0x5A, 0x00}, + {0x5B, 0x00}, + {0x5C, 0x00}, + {0x5D, 0x00}, + {0x5E, 0x00}, + {0x5F, 0x00}, + {0x60, 0x00}, + {0x61, 0x00}, + {0x62, 0x00}, + {0x63, 0x00}, + {0x64, 0x00}, + {0x65, 0x00}, + {0x66, 0x00}, + {0x67, 0x00}, + {0x68, 0x00}, + {0x69, 0x00}, + {0x6A, 0x00}, + {0x6B, 0x00}, + {0x6C, 0x00}, + {0x6D, 0x00}, + {0x6E, 0x00}, + {0x6F, 0x00}, + {0x70, 0x00}, + {0x71, 0x00}, + {0x72, 0x20}, + {0x73, 0x00}, + {0x74, 0x08}, + {0x75, 0x08}, + {0x76, 0x08}, + {0x77, 0x08}, + {0x78, 0x08}, + {0x79, 0x08}, + {0x7A, 0x00}, + {0x7B, 0x00}, + {0x7C, 0x00}, + {0x7D, 0x00}, + {0x7E, 0xBF}, + {0x7F, 0x02}, + {0x80, 0x06}, + {0x81, 0x14}, + {0x82, 0x10}, + {0x83, 0x16}, + {0x84, 0x12}, + {0x85, 0x08}, + {0x86, 0x3F}, + {0x87, 0x3F}, + {0x88, 0x3F}, + {0x89, 0x3F}, + {0x8A, 0x3F}, + {0x8B, 0x0C}, + {0x8C, 0x0A}, + {0x8D, 0x0E}, + {0x8E, 0x3F}, + {0x8F, 0x3F}, + {0x90, 0x00}, + {0x91, 0x04}, + {0x92, 0x3F}, + {0x93, 0x3F}, + {0x94, 0x3F}, + {0x95, 0x3F}, + {0x96, 0x05}, + {0x97, 0x01}, + {0x98, 0x3F}, + {0x99, 0x3F}, + {0x9A, 0x0F}, + {0x9B, 0x0B}, + {0x9C, 0x0D}, + {0x9D, 0x3F}, + {0x9E, 0x3F}, + {0x9F, 0x3F}, + {0xA0, 0x3F}, + {0xA2, 0x3F}, + {0xA3, 0x09}, + {0xA4, 0x13}, + {0xA5, 0x17}, + {0xA6, 0x11}, + {0xA7, 0x15}, + {0xA9, 0x07}, + {0xAA, 0x03}, + {0xAB, 0x3F}, + {0xAC, 0x3F}, + {0xAD, 0x05}, + {0xAE, 0x01}, + {0xAF, 0x17}, + {0xB0, 0x13}, + {0xB1, 0x15}, + {0xB2, 0x11}, + {0xB3, 0x0F}, + {0xB4, 0x3F}, + {0xB5, 0x3F}, + {0xB6, 0x3F}, + {0xB7, 0x3F}, + {0xB8, 0x3F}, + {0xB9, 0x0B}, + {0xBA, 0x0D}, + {0xBB, 0x09}, + {0xBC, 0x3F}, + {0xBD, 0x3F}, + {0xBE, 0x07}, + {0xBF, 0x03}, + {0xC0, 0x3F}, + {0xC1, 0x3F}, + {0xC2, 0x3F}, + {0xC3, 0x3F}, + {0xC4, 0x02}, + {0xC5, 0x06}, + {0xC6, 0x3F}, + {0xC7, 0x3F}, + {0xC8, 0x08}, + {0xC9, 0x0C}, + {0xCA, 0x0A}, + {0xCB, 0x3F}, + {0xCC, 0x3F}, + {0xCD, 0x3F}, + {0xCE, 0x3F}, + {0xCF, 0x3F}, + {0xD0, 0x0E}, + {0xD1, 0x10}, + {0xD2, 0x14}, + {0xD3, 0x12}, + {0xD4, 0x16}, + {0xD5, 0x00}, + {0xD6, 0x04}, + {0xD7, 0x3F}, + {0xDC, 0x02}, + {0xDE, 0x12}, + {0xFE, 0x0E}, + {0x01, 0x75}, + + /* Gamma Settings */ + {0xFE, 0x04}, + {0x60, 0x00}, + {0x61, 0x0C}, + {0x62, 0x12}, + {0x63, 0x0E}, + {0x64, 0x06}, + {0x65, 0x12}, + {0x66, 0x0E}, + {0x67, 0x0B}, + {0x68, 0x15}, + {0x69, 0x0B}, + {0x6A, 0x10}, + {0x6B, 0x07}, + {0x6C, 0x0F}, + {0x6D, 0x12}, + {0x6E, 0x0C}, + {0x6F, 0x00}, + {0x70, 0x00}, + {0x71, 0x0C}, + {0x72, 0x12}, + {0x73, 0x0E}, + {0x74, 0x06}, + {0x75, 0x12}, + {0x76, 0x0E}, + {0x77, 0x0B}, + {0x78, 0x15}, + {0x79, 0x0B}, + {0x7A, 0x10}, + {0x7B, 0x07}, + {0x7C, 0x0F}, + {0x7D, 0x12}, + {0x7E, 0x0C}, + {0x7F, 0x00}, + + /* Page 0. */ + {0xFE, 0x00}, + {0x11, 0x00}, +}; + +const display_operations_t rm68200_ops = { + .init = RM68200_Init, + .deinit = RM68200_Deinit, + .start = RM68200_Start, + .stop = RM68200_Stop, +}; + +/******************************************************************************* + * Code + ******************************************************************************/ + +status_t RM68200_Init(display_handle_t *handle, const display_config_t *config) +{ + uint32_t i; + uint8_t param[2]; + status_t status = kStatus_Success; + const rm68200_resource_t *resource = (const rm68200_resource_t *)(handle->resource); + mipi_dsi_device_t *dsiDevice = resource->dsiDevice; + + /* Only support 720 * 1280 */ + if (config->resolution != FSL_VIDEO_RESOLUTION(720, 1280)) + { + return kStatus_InvalidArgument; + } + + /* Power on. */ + resource->pullPowerPin(true); + RM68200_DelayMs(1); + + /* Perform reset. */ + resource->pullResetPin(false); + RM68200_DelayMs(1); + resource->pullResetPin(true); + RM68200_DelayMs(5); + + /* Set the LCM page0 init settings. */ + for (i = 0; i < ARRAY_SIZE(lcmInitPage0Setting); i++) + { + status = MIPI_DSI_GenericWrite(dsiDevice, lcmInitPage0Setting[i], 2); + + if (kStatus_Success != status) + { + return status; + } + } + + /* Data lane number selection. */ + param[0] = 0x5FU; + param[1] = 0x10U | (config->dsiLanes - 1U); + status = MIPI_DSI_GenericWrite(dsiDevice, param, 2); + if (kStatus_Success != status) + { + return status; + } + + /* Set the LCM init settings. */ + for (i = 0; i < ARRAY_SIZE(lcmInitSetting); i++) + { + status = MIPI_DSI_GenericWrite(dsiDevice, lcmInitSetting[i], 2); + + if (kStatus_Success != status) + { + return status; + } + } + + RM68200_DelayMs(200); + + param[0] = 0x29; + param[1] = 0x00; + status = MIPI_DSI_GenericWrite(dsiDevice, param, 2); + if (kStatus_Success != status) + { + return status; + } + + RM68200_DelayMs(100); + + param[0] = 0x2c; + status = MIPI_DSI_GenericWrite(dsiDevice, param, 1); + if (kStatus_Success != status) + { + return status; + } + + param[0] = 0x35; + param[1] = 0x00; + status = MIPI_DSI_GenericWrite(dsiDevice, param, 2); + if (kStatus_Success != status) + { + return status; + } + + RM68200_DelayMs(200); + + return kStatus_Success; +} + +status_t RM68200_Deinit(display_handle_t *handle) +{ + const rm68200_resource_t *resource = (const rm68200_resource_t *)(handle->resource); + mipi_dsi_device_t *dsiDevice = resource->dsiDevice; + + (void)MIPI_DSI_DCS_EnterSleepMode(dsiDevice, true); + + resource->pullResetPin(false); + resource->pullPowerPin(false); + + return kStatus_Success; +} + +status_t RM68200_Start(display_handle_t *handle) +{ + const rm68200_resource_t *resource = (const rm68200_resource_t *)(handle->resource); + mipi_dsi_device_t *dsiDevice = resource->dsiDevice; + + return MIPI_DSI_DCS_SetDisplayOn(dsiDevice, true); +} + +status_t RM68200_Stop(display_handle_t *handle) +{ + const rm68200_resource_t *resource = (const rm68200_resource_t *)(handle->resource); + mipi_dsi_device_t *dsiDevice = resource->dsiDevice; + + return MIPI_DSI_DCS_SetDisplayOn(dsiDevice, false); +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68200.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68200.h new file mode 100644 index 0000000000..f039e89e99 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68200.h @@ -0,0 +1,67 @@ +/* + * Copyright 2019-2021 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_RM68200_H_ +#define _FSL_RM68200_H_ + +#include "fsl_display.h" +#include "fsl_mipi_dsi_cmd.h" + +/* + * Change log: + * + * 1.1.1 + * - Support 1 lane to 4 lanes, previously only support 2 lanes. + * + * 1.1.0 + * - Fix MISRA-C 2012 issues. + * - Change rm68200_resource_t structure. + * + * 1.0.0 + * - Initial version + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! + * @brief RM68200 resource. + */ +typedef struct _rm68200_resource +{ + mipi_dsi_device_t *dsiDevice; /*!< MIPI DSI device. */ + void (*pullResetPin)(bool pullUp); /*!< Function to pull reset pin high or low. */ + void (*pullPowerPin)(bool pullUp); /*!< Function to pull power pin high or low. */ +} rm68200_resource_t; + +extern const display_operations_t rm68200_ops; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +extern uint8_t RM68200_DDB_START[5]; + +status_t RM68200_Init(display_handle_t *handle, const display_config_t *config); + +status_t RM68200_Deinit(display_handle_t *handle); + +status_t RM68200_Start(display_handle_t *handle); + +status_t RM68200_Stop(display_handle_t *handle); + +#if defined(__cplusplus) +} +#endif + +#endif /* _FSL_RM68200_H_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_video_common.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_video_common.c new file mode 100644 index 0000000000..aa123ffe76 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_video_common.c @@ -0,0 +1,301 @@ +/* + * Copyright 2017, 2020-2021, 2023 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_video_common.h" +#if defined(SDK_OS_RTOS) +#include "rtthread.h" +#endif + +/******************************************************************************* + * Code + ******************************************************************************/ + +bool VIDEO_IsYUV(video_pixel_format_t format) +{ + if ((kVIDEO_PixelFormatYUYV == format) || (kVIDEO_PixelFormatYVYU == format) || + (kVIDEO_PixelFormatUYVY == format) || (kVIDEO_PixelFormatVYUY == format) || + (kVIDEO_PixelFormatXYVU == format) || (kVIDEO_PixelFormatXYUV == format)) + { + return true; + } + else + { + return false; + } +} + +void VIDEO_DelayMs(uint32_t ms) +{ +#if defined(SDK_OS_RTOS) + rt_thread_mdelay(ms); +#else + while (0U != (ms--)) + { + SDK_DelayAtLeastUs(1000U, SystemCoreClock); + } +#endif +} + +uint8_t VIDEO_GetPixelSizeBits(video_pixel_format_t pixelFormat) +{ + uint8_t ret; + + switch (pixelFormat) + { + case kVIDEO_PixelFormatXRGB8888: + case kVIDEO_PixelFormatRGBX8888: + case kVIDEO_PixelFormatXBGR8888: + case kVIDEO_PixelFormatBGRX8888: + case kVIDEO_PixelFormatXYUV: + case kVIDEO_PixelFormatXYVU: + ret = 32; + break; + + case kVIDEO_PixelFormatRGB888: + case kVIDEO_PixelFormatBGR888: + ret = 24; + break; + + case kVIDEO_PixelFormatRGB565: + case kVIDEO_PixelFormatBGR565: + case kVIDEO_PixelFormatXRGB1555: + case kVIDEO_PixelFormatRGBX5551: + case kVIDEO_PixelFormatXBGR1555: + case kVIDEO_PixelFormatBGRX5551: + case kVIDEO_PixelFormatXRGB4444: + case kVIDEO_PixelFormatRGBX4444: + case kVIDEO_PixelFormatXBGR4444: + case kVIDEO_PixelFormatBGRX4444: + case kVIDEO_PixelFormatYUYV: + case kVIDEO_PixelFormatYVYU: + case kVIDEO_PixelFormatUYVY: + case kVIDEO_PixelFormatVYUY: + ret = 16; + break; + + case kVIDEO_PixelFormatRAW8: + case kVIDEO_PixelFormatLUT8: + ret = 8; + break; + + default: + ret = 0; + break; + } + + return ret; +} + +status_t VIDEO_RINGBUF_Init(video_ringbuf_t *ringbuf, void **buf, uint32_t size) +{ + assert(ringbuf != NULL); + + ringbuf->rear = 0; + ringbuf->front = 0; + ringbuf->size = size; + ringbuf->buf = buf; + + return kStatus_Success; +} + +status_t VIDEO_RINGBUF_Get(video_ringbuf_t *ringbuf, void **item) +{ + uint32_t front_next; + + /* To fix IAR Pa082 warning. */ + uint32_t rear = ringbuf->rear; + uint32_t front = ringbuf->front; + + if (rear != front) + { + *item = ringbuf->buf[ringbuf->front]; + + /* + * Here don't use ringbuf->front = (ringbuf->front + 1) % ringbuf->size, + * because mod operation might be slow. + */ + front_next = (ringbuf->front + 1U); + + /* Use two steps to make sure ringbuf->front is always a valid value. */ + ringbuf->front = (front_next == ringbuf->size) ? 0UL : front_next; + + return kStatus_Success; + } + else + { + return kStatus_Fail; + } +} + +status_t VIDEO_RINGBUF_Put(video_ringbuf_t *ringbuf, void *item) +{ + /* + * Here don't use ringbuf->rear = (ringbuf->rear + 1) % ringbuf->size, + * because mod operation might be slow. + */ + uint32_t rear_next = ringbuf->rear + 1U; + + rear_next = (rear_next == ringbuf->size) ? 0U : rear_next; + + if (rear_next != ringbuf->front) + { + ringbuf->buf[ringbuf->rear] = item; + ringbuf->rear = rear_next; + + return kStatus_Success; + } + /* No room. */ + else + { + return kStatus_Fail; + } +} + +uint32_t VIDEO_RINGBUF_GetLength(video_ringbuf_t *ringbuf) +{ + uint32_t ret; + + /* To fix IAR Pa082 warning. */ + uint32_t rear = ringbuf->rear; + uint32_t front = ringbuf->front; + + ret = (rear + ringbuf->size) - front; + + if (ret >= ringbuf->size) + { + ret -= ringbuf->size; + } + + return ret; +} + +bool VIDEO_RINGBUF_IsEmpty(video_ringbuf_t *ringbuf) +{ + /* To fix IAR Pa082 warning. */ + uint32_t rear = ringbuf->rear; + uint32_t front = ringbuf->front; + + if (rear == front) + { + return true; + } + else + { + return false; + } +} + +bool VIDEO_RINGBUF_IsFull(video_ringbuf_t *ringbuf) +{ + uint32_t rear = ringbuf->rear; + uint32_t front = ringbuf->front; + + rear++; + + if (rear >= ringbuf->size) + { + rear = 0; + } + + if (rear == front) + { + return true; + } + else + { + return false; + } +} + +status_t VIDEO_MEMPOOL_Init(video_mempool_t *mempool, void *initMem, uint32_t size, uint32_t count) +{ + (void)memset(mempool, 0, sizeof(video_mempool_t)); + + while (0U != (count--)) + { + VIDEO_MEMPOOL_Put(mempool, initMem); + initMem = &((uint8_t *)initMem)[size]; + } + + return kStatus_Success; +} + +void VIDEO_MEMPOOL_InitEmpty(video_mempool_t *mempool) +{ + mempool->pool = NULL; + mempool->cnt = 0; +} + +void VIDEO_MEMPOOL_Put(video_mempool_t *mempool, void *mem) +{ + *(void **)mem = mempool->pool; + mempool->pool = mem; + mempool->cnt++; +} + +void *VIDEO_MEMPOOL_Get(video_mempool_t *mempool) +{ + void *mem = mempool->pool; + + if (NULL != mem) + { + mempool->cnt--; + mempool->pool = *(void **)mem; + } + + return mem; +} + +uint32_t VIDEO_MEMPOOL_GetCount(video_mempool_t *mempool) +{ + return mempool->cnt; +} + +status_t VIDEO_STACK_Init(video_stack_t *stack, void **buf, uint32_t size) +{ + stack->buf = buf; + stack->maxCount = size; + stack->top = 0U; + + return kStatus_Success; +} + +status_t VIDEO_STACK_Pop(video_stack_t *stack, void **item) +{ + status_t status; + + if (stack->top > 0U) + { + *item = stack->buf[--stack->top]; + status = kStatus_Success; + } + else + { + *item = NULL; + status = kStatus_Fail; + } + + return status; +} + +status_t VIDEO_STACK_Push(video_stack_t *stack, void *item) +{ + status_t status; + + if (stack->top < (stack->maxCount)) + { + stack->buf[stack->top++] = item; + status = kStatus_Success; + } + else + { + status = kStatus_Fail; + } + + return status; +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_video_common.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_video_common.h new file mode 100644 index 0000000000..e4097607f7 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_video_common.h @@ -0,0 +1,364 @@ +/* + * Copyright 2017, 2020-2021, 2023 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_VIDEO_COMMON_H_ +#define _FSL_VIDEO_COMMON_H_ + +#include "fsl_common.h" + +/* + * Change log: + * + * 1.1.0 + * - Add stack function which supports LIFO item management. + * + * 1.0.5 + * - Fix IAR Pa082 warning. + * + * 1.0.4 + * - Add LUT8 definition. + * + * 1.0.3 + * - Add RAW8 definition. + * + * 1.0.2 + * - Fixed MISRA-C 2012 issues. + * + * 1.0.1 + * - Update the VIDEO_DelayMs for bare metal. + * + * 1.0.0 + * - Initial version + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Pixel format FOURCC. */ +#define FSL_VIDEO_FOURCC(a, b, c, d) \ + ((uint32_t)(a) | ((uint32_t)(b) << 8U) | ((uint32_t)(c) << 16U) | ((uint32_t)(d) << 24U)) + +/*! @brief Macro to define resolution. */ +#define FSL_VIDEO_RESOLUTION(width, height) ((uint32_t)(width) | ((uint32_t)(height) << 16U)) + +#define FSL_VIDEO_EXTRACT_WIDTH(resolution) ((uint16_t)((resolution)&0xFFFFU)) +#define FSL_VIDEO_EXTRACT_HEIGHT(resolution) ((uint16_t)((resolution) >> 16U)) + +/*! @brief Pixel format definition. */ +typedef enum _video_pixel_format +{ + /* RAW */ + kVIDEO_PixelFormatRAW8 = FSL_VIDEO_FOURCC('G', 'R', 'B', 'G'), /*!< RAW8, GRBG. */ + + /* LUT/palette */ + kVIDEO_PixelFormatLUT8 = FSL_VIDEO_FOURCC('L', 'U', 'T', '8'), /*!< 8-bit Indexed Color. */ + + /* RGB */ + kVIDEO_PixelFormatXRGB8888 = FSL_VIDEO_FOURCC('X', 'R', '2', '4'), /*!< 32-bit XRGB8888. */ + kVIDEO_PixelFormatRGBX8888 = FSL_VIDEO_FOURCC('R', 'X', '2', '4'), /*!< 32-bit RGBX8888. */ + kVIDEO_PixelFormatXBGR8888 = FSL_VIDEO_FOURCC('X', 'B', '2', '4'), /*!< 32-bit XBGR8888. */ + kVIDEO_PixelFormatBGRX8888 = FSL_VIDEO_FOURCC('B', 'X', '2', '4'), /*!< 32-bit BGRX8888. */ + + kVIDEO_PixelFormatRGB888 = FSL_VIDEO_FOURCC('R', 'G', '2', '4'), /*!< 24-bit RGB888. */ + kVIDEO_PixelFormatBGR888 = FSL_VIDEO_FOURCC('B', 'G', '2', '4'), /*!< 24-bit BGR888. */ + + kVIDEO_PixelFormatRGB565 = FSL_VIDEO_FOURCC('R', 'G', '1', '6'), /*!< 16-bit RGB565. */ + kVIDEO_PixelFormatBGR565 = FSL_VIDEO_FOURCC('B', 'G', '1', '6'), /*!< 16-bit BGR565. */ + + kVIDEO_PixelFormatXRGB1555 = FSL_VIDEO_FOURCC('X', 'R', '1', '5'), /*!< 16-bit XRGB1555. */ + kVIDEO_PixelFormatRGBX5551 = FSL_VIDEO_FOURCC('R', 'X', '1', '5'), /*!< 16-bit RGBX5551. */ + kVIDEO_PixelFormatXBGR1555 = FSL_VIDEO_FOURCC('X', 'B', '1', '5'), /*!< 16-bit XBGR1555. */ + kVIDEO_PixelFormatBGRX5551 = FSL_VIDEO_FOURCC('B', 'X', '1', '5'), /*!< 16-bit BGRX5551. */ + + kVIDEO_PixelFormatXRGB4444 = FSL_VIDEO_FOURCC('X', 'R', '1', '2'), /*!< 16-bit XRGB4444. */ + kVIDEO_PixelFormatRGBX4444 = FSL_VIDEO_FOURCC('R', 'X', '1', '2'), /*!< 16-bit RGBX4444. */ + kVIDEO_PixelFormatXBGR4444 = FSL_VIDEO_FOURCC('X', 'B', '1', '2'), /*!< 16-bit XBGR4444. */ + kVIDEO_PixelFormatBGRX4444 = FSL_VIDEO_FOURCC('B', 'X', '1', '2'), /*!< 16-bit BGRX4444. */ + + /* YUV. */ + kVIDEO_PixelFormatYUYV = FSL_VIDEO_FOURCC('Y', 'U', 'Y', 'V'), /*!< YUV422, Y-U-Y-V. */ + kVIDEO_PixelFormatYVYU = FSL_VIDEO_FOURCC('Y', 'V', 'Y', 'U'), /*!< YUV422, Y-V-Y-U. */ + kVIDEO_PixelFormatUYVY = FSL_VIDEO_FOURCC('U', 'Y', 'V', 'Y'), /*!< YUV422, U-Y-V-Y. */ + kVIDEO_PixelFormatVYUY = FSL_VIDEO_FOURCC('V', 'Y', 'U', 'Y'), /*!< YUV422, V-Y-U-Y. */ + + kVIDEO_PixelFormatXYUV = FSL_VIDEO_FOURCC('X', 'Y', 'U', 'V'), /*!< YUV444, X-Y-U-V. */ + kVIDEO_PixelFormatXYVU = FSL_VIDEO_FOURCC('X', 'Y', 'V', 'U'), /*!< YUV444, X-Y-V-U. */ +} video_pixel_format_t; + +/*! @brief Resolution definition. */ +typedef enum _video_resolution +{ + kVIDEO_ResolutionVGA = FSL_VIDEO_RESOLUTION(640, 480), /*!< VGA, 640 * 480 */ + kVIDEO_ResolutionQVGA = FSL_VIDEO_RESOLUTION(320, 240), /*!< QVGA, 320 * 240 */ + kVIDEO_ResolutionQQVGA = FSL_VIDEO_RESOLUTION(160, 120), /*!< QQVGA, 160 * 120 */ + kVIDEO_ResolutionCIF = FSL_VIDEO_RESOLUTION(352, 288), /*!< CIF, 352 * 288 */ + kVIDEO_ResolutionQCIF = FSL_VIDEO_RESOLUTION(176, 144), /*!< QCIF, 176 * 144 */ + kVIDEO_ResolutionQQCIF = FSL_VIDEO_RESOLUTION(88, 72), /*!< QQCIF, 88 * 72 */ + kVIDEO_Resolution720P = FSL_VIDEO_RESOLUTION(1280, 720), /*!< 720P, 1280 * 720 */ + kVIDEO_Resolution1080P = FSL_VIDEO_RESOLUTION(1920, 1080), /*!< 1080P, 1920 * 1280*/ + kVIDEO_ResolutionWXGA = FSL_VIDEO_RESOLUTION(1280, 800), /*!< WXGA, 1280 * 800 */ +} video_resolution_t; + +/*! + * @brief Ring buffer structure. + * + * There is one empty room reserved in the ring buffer, used to distinguish + * whether the ring buffer is full or empty. When rear equals front, it is empty; + * when rear+1 equals front, it is full. + */ +typedef struct +{ + volatile uint32_t rear; /*!< Pointer to save the incoming item. */ + volatile uint32_t front; /*!< Pointer to read out the item. */ + void *volatile *buf; /*!< Memory to the ring buffer. */ + uint32_t size; /*!< Ring buffer total size. */ +} video_ringbuf_t; + +/*! + * @brief Memory pool structure. + */ +typedef struct +{ + void *volatile pool; /*!< Pointer to the pool. */ + volatile uint32_t cnt; /*!< Count of memory blocks in the pool. */ +} video_mempool_t; + +/*! + * @brief Stack structure. + */ +typedef struct +{ + void **buf; /*!< Pointer to the memory to store the items. */ + volatile uint32_t top; /*!< Current top stack top. */ + uint32_t maxCount; /*!< Maximal count of items can be stored in the stack. */ +} video_stack_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name Common + * @{ + */ + +/*! + * @brief Check the pixel format is YUV or not. + * + * @param format Pixel format. + */ +bool VIDEO_IsYUV(video_pixel_format_t format); + +/*! + * @brief Delay the specific time. + * + * @param ms How many milli-second to delay. + */ +void VIDEO_DelayMs(uint32_t ms); + +/*! + * @brief Get the pixel size in bits. + * + * @param pixelFormat The pixel format. + * @return Bits per pixel. + */ +uint8_t VIDEO_GetPixelSizeBits(video_pixel_format_t pixelFormat); + +/* @} */ + +/*! + * @name Ring buffer. + * @{ + */ + +/*! + * @brief Initializes ring buffer. + * + * @param ringbuf Pointer to the ring buffer handle. + * @param buf Memory to save the items. + * @param size Size of the @p buf. + * @return Returns @ref kStatus_Success if initialize success, otherwise returns + * error code. + */ +status_t VIDEO_RINGBUF_Init(video_ringbuf_t *ringbuf, void **buf, uint32_t size); + +/*! + * @brief Get one item from the ring buffer. + * + * @param ringbuf Pointer to the ring buffer handle. + * @param item Memory to save the item. + * @return Returns @ref kStatus_Success if get success, otherwise returns + * error code. + */ +status_t VIDEO_RINGBUF_Get(video_ringbuf_t *ringbuf, void **item); + +/*! + * @brief Put one item to the ring buffer. + * + * @param ringbuf Pointer to the ring buffer handle. + * @param item The new item to save. + * @return Returns @ref kStatus_Success if put success, otherwise returns + * error code. + */ +status_t VIDEO_RINGBUF_Put(video_ringbuf_t *ringbuf, void *item); + +/*! + * @brief Get current count of items in the ring buffer. + * + * @param ringbuf Pointer to the ring buffer handle. + * @return Returns the item count. + */ +uint32_t VIDEO_RINGBUF_GetLength(video_ringbuf_t *ringbuf); + +/*! + * @brief Check whether the ring buffer is empty. + * + * @param ringbuf Pointer to the ring buffer handle. + * @return Returns true if the ring buffer is empty, otherwise returns false. + */ +bool VIDEO_RINGBUF_IsEmpty(video_ringbuf_t *ringbuf); + +/*! + * @brief Check whether the ring buffer is full. + * + * @param ringbuf Pointer to the ring buffer handle. + * @return Returns true if the ring buffer is full, otherwise returns false. + */ +bool VIDEO_RINGBUF_IsFull(video_ringbuf_t *ringbuf); +/* @} */ + +/*! + * @name Memory Pool + * + * User can put memory block to the pool, or get memory block from the pool. + * There is no count limitation to put memory block in to the pool. The memory + * content in the pool might be modified. + * + * The memory block should be 4-byte aligned, and the dividable by 4-byte. + * + * @{ + */ + +/*! + * @brief Initializes memory pool. + * + * Initializes memory pool. Initial memory blocks in the memory pool is optional. + * If initial blocks are used, user should specify the initial block size and count. + * + * @param mempool Pointer to the memory pool handle. + * @param initMem Initial memory blocks to saved in the pool. + * @param size Every memory block's size (bytes) in the @p initMem. + * @param count Number of memory blocks @p initMem. + * @return Returns @ref kStatus_Success if initialize success, otherwise returns + * error code. + */ +status_t VIDEO_MEMPOOL_Init(video_mempool_t *mempool, void *initMem, uint32_t size, uint32_t count); + +/*! + * @brief Create an empty memory pool. + * + * @param mempool Pointer to the memory pool handle. + */ +void VIDEO_MEMPOOL_InitEmpty(video_mempool_t *mempool); + +/*! + * @brief Put memory block in the pool. + * + * @param mempool Pointer to the memory pool handle. + * @param mem Pointer to the memory block. + */ +void VIDEO_MEMPOOL_Put(video_mempool_t *mempool, void *mem); + +/*! + * @brief Get memory block in the pool. + * + * @param mempool Pointer to the memory pool handle. + * @return The memory block get from pool. If the pool is empty, returns NULL. + */ +void *VIDEO_MEMPOOL_Get(video_mempool_t *mempool); + +/*! + * @brief How many memory blocks in the pool. + * + * @param mempool Pointer to the memory pool handle. + * @return The memory block count in the pool + */ +uint32_t VIDEO_MEMPOOL_GetCount(video_mempool_t *mempool); + +/* @} */ + +/*! + * @name Stack which supports LIFO item management. + * @{ + */ + +/*! + * @brief Initializes stack. + * + * @param stack Pointer to the stack handle. + * @param buf Memory to save the items. + * @param size Size of the @p buf. + * @return Returns @ref kStatus_Success if initialize success, otherwise returns + * error code. + */ +status_t VIDEO_STACK_Init(video_stack_t *stack, void **buf, uint32_t size); + +/*! + * @brief Pop one item from the stack. + * + * @param stack Pointer to the stack handle. + * @param item Memory to save the item. + * @return Returns @ref kStatus_Success if get success, returns + * kStatus_Fail if the stack is empty. + */ +status_t VIDEO_STACK_Pop(video_stack_t *stack, void **item); + +/*! + * @brief Put one item to the stack. + * + * @param stack Pointer to the stack handle. + * @param item The new item to save. + * @return Returns @ref kStatus_Success if put success, returns + * kStatus_Fail if the stack is full. + */ +status_t VIDEO_STACK_Push(video_stack_t *stack, void *item); + +/*! + * @brief Get current count of items in the stack. + * + * @param stack Pointer to the stack handle. + * @return Returns the item count. + */ +static inline uint32_t VIDEO_STACK_GetCount(video_stack_t *stack) +{ + return stack->top; +} + +/*! + * @brief Get maxiumal count of items in the stack. + * + * @param stack Pointer to the stack handle. + * @return Returns the maxiumal count of items in the stack. + */ +static inline uint32_t VIDEO_STACK_GetMaxCount(video_stack_t *stack) +{ + return stack->maxCount; +} + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +#endif /* _FSL_VIDEO_COMMON_H_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mcufont.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mcufont.h new file mode 100644 index 0000000000..8a81ff42e7 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mcufont.h @@ -0,0 +1,14 @@ +/* Tiny library for rendering compressed bitmap fonts on microcontrollers. */ + +#ifndef _MCUFONT_H_ +#define _MCUFONT_H_ + +#include "mf_config.h" +#include "mf_encoding.h" +#include "mf_justify.h" +#include "mf_kerning.h" +#include "mf_rlefont.h" +#include "mf_scaledfont.h" +#include "mf_wordwrap.h" + +#endif diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_bwfont.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_bwfont.c new file mode 100644 index 0000000000..95e9b86e87 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_bwfont.c @@ -0,0 +1,134 @@ +#include "mf_bwfont.h" +#include + +/* Find the character range and index that contains a given glyph.. */ +static const struct mf_bwfont_char_range_s *find_char_range( + const struct mf_bwfont_s *font, uint16_t character, uint16_t *index_ret) +{ + unsigned i, index; + const struct mf_bwfont_char_range_s *range; + for (i = 0; i < font->char_range_count; i++) + { + range = &font->char_ranges[i]; + index = character - range->first_char; + if (character >= range->first_char && index < range->char_count) + { + *index_ret = index; + return range; + } + } + + return 0; +} + +static uint8_t get_width(const struct mf_bwfont_char_range_s *r, uint16_t index) +{ + if (r->width) + { + return r->width + r->offset_x; + } + else + { + return r->glyph_widths[index]; + } +} + +static uint8_t render_char(const struct mf_bwfont_char_range_s *r, + int16_t x0, int16_t y0, uint16_t index, + mf_pixel_callback_t callback, + void *state) +{ + const uint8_t *data, *p; + uint8_t stride, runlen; + uint8_t x, y, height, num_cols; + uint8_t bit, byte, mask; + bool oldstate, newstate; + + if (r->width) + { + data = r->glyph_data + r->width * index * r->height_bytes; + num_cols = r->width; + } + else + { + data = r->glyph_data + r->glyph_offsets[index] * r->height_bytes; + num_cols = r->glyph_offsets[index + 1] - r->glyph_offsets[index]; + } + + stride = r->height_bytes; + height = r->height_pixels; + y0 += r->offset_y; + x0 += r->offset_x; + bit = 0; + byte = 0; + + for (y = 0; y < height; y++) + { + mask = (1 << bit); + + oldstate = false; + runlen = 0; + p = data + byte; + for (x = 0; x < num_cols; x++, p += stride) + { + newstate = pgm_read_byte(p) & mask; + if (newstate != oldstate) + { + if (oldstate && runlen) + { + callback(x0 + x - runlen, y0 + y, runlen, 255, state); + } + + oldstate = newstate; + runlen = 0; + } + + runlen++; + } + + if (oldstate && runlen) + { + callback(x0 + x - runlen, y0 + y, runlen, 255, state); + } + + bit++; + if (bit > 7) + { + bit = 0; + byte++; + } + } + + return get_width(r, index); +} + +uint8_t mf_bwfont_render_character(const struct mf_font_s *font, + int16_t x0, int16_t y0, + uint16_t character, + mf_pixel_callback_t callback, + void *state) +{ + const struct mf_bwfont_s *bwfont = (const struct mf_bwfont_s*)font; + const struct mf_bwfont_char_range_s *range; + uint16_t index; + + range = find_char_range(bwfont, character, &index); + if (!range) + return 0; + + return render_char(range, x0, y0, index, callback, state); +} + +uint8_t mf_bwfont_character_width(const struct mf_font_s *font, + uint16_t character) +{ + const struct mf_bwfont_s *bwfont = (const struct mf_bwfont_s*)font; + const struct mf_bwfont_char_range_s *range; + uint16_t index; + + range = find_char_range(bwfont, character, &index); + if (!range) + return 0; + + return get_width(range, index); +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_bwfont.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_bwfont.h new file mode 100644 index 0000000000..94be3452a5 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_bwfont.h @@ -0,0 +1,77 @@ +/* Uncompressed font format for storing black & white fonts. Very efficient + * to decode and works well for small font sizes. + */ + +#ifndef _MF_BWFONT_H_ +#define _MF_BWFONT_H_ + +#include "mf_font.h" + +/* Versions of the BW font format that are supported. */ +#define MF_BWFONT_VERSION_4_SUPPORTED 1 + +/* Structure for a range of characters. */ +struct mf_bwfont_char_range_s +{ + /* The number of the first character in this range. */ + uint16_t first_char; + + /* The total count of characters in this range. */ + uint16_t char_count; + + /* The left and top skips of the characters in this range. + * This is the number of empty rows at left and at top. */ + uint8_t offset_x; + uint8_t offset_y; + + /* Column height for glyphs in this range, in bytes and pixels. */ + uint8_t height_bytes; + uint8_t height_pixels; + + /* Positive value if the width of all glyphs in this range is the + * same, or zero if it is not. */ + uint8_t width; + + /* Lookup table for the character widths. NULL if width is specified. */ + uint8_t *glyph_widths; + + /* Lookup table for the character offsets. Multiply by height_bytes + * to get the byte offset. Also allows lookup of the number of columns. + * NULL if width is specified. */ + uint16_t *glyph_offsets; + + /* Table for the glyph data. + * The data for each glyph is column-by-column, with N bytes per each + * column. The LSB of the first byte is the top left pixel. + */ + uint8_t *glyph_data; +}; + +/* Structure for the font */ +struct mf_bwfont_s +{ + struct mf_font_s font; + + /* Version of the font format. */ + uint8_t version; + + /* Number of character ranges. */ + uint8_t char_range_count; + + /* Array of the character ranges */ + struct mf_bwfont_char_range_s *char_ranges; +}; + +#ifdef MF_BWFONT_INTERNALS +/* Internal functions, don't use these directly. */ +MF_EXTERN uint8_t mf_bwfont_render_character(const struct mf_font_s *font, + int16_t x0, int16_t y0, + mf_char character, + mf_pixel_callback_t callback, + void *state); + +MF_EXTERN uint8_t mf_bwfont_character_width(const struct mf_font_s *font, + mf_char character); +#endif + +#endif diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_config.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_config.h new file mode 100644 index 0000000000..681ff8ba87 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_config.h @@ -0,0 +1,144 @@ +/* Configuration constants for mcufont. */ + +#ifndef _MF_CONFIG_H_ +#define _MF_CONFIG_H_ + +#ifdef __AVR__ + #include +#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) + #include +#else + #include + #define PROGMEM + #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) + #define pgm_read_word(addr) (*(const uint16_t *)(addr)) +#endif /* __AVR__ */ + + +/******************************************************* + * Configuration settings related to build environment * + *******************************************************/ + +/* Name of the file that contains all the included fonts. */ +#ifndef MF_FONT_FILE_NAME +#define MF_FONT_FILE_NAME "fonts.h" +#endif + + +/***************************************** + * Configuration settings related to API * + *****************************************/ + +/* Encoding for the input data. + * With the unicode encodings, the library supports the range of unicode + * characters 0x0000-0xFFFF (the Basic Multilingual Plane). + * + * ASCII: Plain ascii (somewhat works with ISO8859-1 also) + * UTF8: UTF8 encoding (variable number of bytes) + * UTF16: UTF16 encoding (2 bytes per character, compatible with UCS-2) + * WCHAR: Use compiler's wchar_t (usually same as UTF16) + */ +#define MF_ENCODING_ASCII 0 +#define MF_ENCODING_UTF8 1 +#define MF_ENCODING_UTF16 2 +#define MF_ENCODING_WCHAR 3 +#ifndef MF_ENCODING +#define MF_ENCODING MF_ENCODING_UTF8 +#endif + + +/************************************************************************ + * Configuration settings related to visual appearance of rendered text * + ************************************************************************/ + +/* Minimum space between characters, in percents of the glyph width. + * Increasing this causes the kerning module to leave more space between + * characters. + */ +#ifndef MF_KERNING_SPACE_PERCENT +#define MF_KERNING_SPACE_PERCENT 15 +#endif + +/* Minimum space between characters, in pixels. Added to the percentual + * spacing. This pixel-based value guarantees enough space even with small + * fonts. + */ +#ifndef MF_KERNING_SPACE_PIXELS +#define MF_KERNING_SPACE_PIXELS 3 +#endif + +/* Maximum adjustment done by the kerning algorithm, as percent of the + * glyph width. + */ +#ifndef MF_KERNING_LIMIT +#define MF_KERNING_LIMIT 20 +#endif + +/* Spacing of tabulator stops. The value is multiplied by the width of the + * 'm' character in the current font. + */ +#ifndef MF_TABSIZE +#define MF_TABSIZE 8 +#endif + + +/************************************************************************* + * Configuration settings to strip down library to reduce resource usage * + *************************************************************************/ + +/* Enable or disable the kerning module. + * Disabling it saves some code size and run time, but causes the spacing + * between characters to be less consistent. + */ +#ifndef MF_USE_KERNING +#define MF_USE_KERNING 1 +#endif + +/* Enable or disable the advanced word wrap algorithm. + * If disabled, uses a simpler algorithm. + */ +#ifndef MF_USE_ADVANCED_WORDWRAP +#define MF_USE_ADVANCED_WORDWRAP 1 +#endif + +/* Enable of disable the justification algorithm. + * If disabled, mf_render_justified renders just left-aligned. + */ +#ifndef MF_USE_JUSTIFY +#define MF_USE_JUSTIFY 1 +#endif + +/* Enable or disable the center and right alignment code. + * If disabled, any alignment results in MF_ALIGN_LEFT. + */ +#ifndef MF_USE_ALIGN +#define MF_USE_ALIGN 1 +#endif + +/* Enable or disable the support for tab alignment. + * If disabled, tabs will be rendered as regular space character. + */ +#ifndef MF_USE_TABS +#define MF_USE_TABS 1 +#endif + +/* Number of vertical zones to use when computing kerning. + * Larger values give more accurate kerning, but are slower and use somewhat + * more memory. There is no point to increase this beyond the height of the + * font. + */ +#ifndef MF_KERNING_ZONES +#define MF_KERNING_ZONES 16 +#endif + + + +/* Add extern "C" when used from C++. */ +#ifdef __cplusplus +#define MF_EXTERN extern "C" +#else +#define MF_EXTERN extern +#endif + +#endif + diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_encoding.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_encoding.c new file mode 100644 index 0000000000..c96a8d3a17 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_encoding.c @@ -0,0 +1,84 @@ +#include "mf_encoding.h" + +#if MF_ENCODING == MF_ENCODING_UTF8 + +mf_char mf_getchar(mf_str *str) +{ + uint8_t c; + uint8_t tmp, seqlen; + uint16_t result; + + c = **str; + if (!c) + return 0; + + (*str)++; + + if ((c & 0x80) == 0) + { + /* Just normal ASCII character. */ + return c; + } + else if ((c & 0xC0) == 0x80) + { + /* Dangling piece of corrupted multibyte sequence. + * Did you cut the string in the wrong place? + */ + return c; + } + else if ((**str & 0xC0) == 0xC0) + { + /* Start of multibyte sequence without any following bytes. + * Silly. Maybe you are using the wrong encoding. + */ + return c; + } + else + { + /* Beginning of a multi-byte sequence. + * Find out how many characters and combine them. + */ + seqlen = 2; + tmp = 0x20; + result = 0; + while ((c & tmp) && (seqlen < 5)) + { + seqlen++; + tmp >>= 1; + + result = (result << 6) | (**str & 0x3F); + (*str)++; + } + + result = (result << 6) | (**str & 0x3F); + (*str)++; + + result |= (c & (tmp - 1)) << ((seqlen - 1) * 6); + return result; + } +} + +void mf_rewind(mf_str *str) +{ + (*str)--; + + while ((**str & 0x80) != 0x00 && (**str & 0xC0) != 0xC0) + (*str)--; +} + +#else + +mf_char mf_getchar(mf_str *str) +{ + if (!(**str)) + return 0; + else + return *(*str)++; +} + +void mf_rewind(mf_str *str) +{ + (*str)--; +} + +#endif diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_encoding.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_encoding.h new file mode 100644 index 0000000000..f43538113a --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_encoding.h @@ -0,0 +1,45 @@ +/* Simple UTF-8 decoder. Also implements the much simpler ASCII and UTF16 + * input encodings. + */ + +#ifndef _MF_ENCODING_H_ +#define _MF_ENCODING_H_ + +#include "mf_config.h" +#include + +/* Type used to represent characters internally. */ +#if MF_ENCODING == MF_ENCODING_ASCII +typedef char mf_char; +#else +typedef uint16_t mf_char; +#endif + +/* Type used to represent input strings. */ +#if MF_ENCODING == MF_ENCODING_ASCII +typedef const char * mf_str; +#elif MF_ENCODING == MF_ENCODING_UTF8 +typedef const char * mf_str; +#elif MF_ENCODING == MF_ENCODING_UTF16 +typedef const uint16_t * mf_str; +#elif MF_ENCODING == MF_ENCODING_WCHAR +#include +typedef const wchar_t * mf_str; +#endif + +/* Returns the next character in the string and advances the pointer. + * When the string ends, returns 0 and leaves the pointer at the 0 byte. + * + * str: Pointer to variable holding current location in string. + * Initialize it to the start of the string. + * + * Returns: The next character, as unicode codepoint. + */ +MF_EXTERN mf_char mf_getchar(mf_str *str); + +/* Moves back the pointer to the beginning of the previous character. + * Be careful not to go beyond the start of the string. + */ +MF_EXTERN void mf_rewind(mf_str *str); + +#endif diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_font.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_font.c new file mode 100644 index 0000000000..9453939a4b --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_font.c @@ -0,0 +1,122 @@ +#include "mf_font.h" +#include + +/* This will be made into a list of included fonts using macro magic. */ +#define MF_INCLUDED_FONTS 0 + +/* Included fonts begin here */ +#include MF_FONT_FILE_NAME +/* Include fonts end here */ + +uint8_t mf_render_character(const struct mf_font_s *font, + int16_t x0, int16_t y0, + mf_char character, + mf_pixel_callback_t callback, + void *state) +{ + uint8_t width; + width = font->render_character(font, x0, y0, character, callback, state); + + if (!width) + { + width = font->render_character(font, x0, y0, font->fallback_character, + callback, state); + } + + return width; +} + +uint8_t mf_character_width(const struct mf_font_s *font, + mf_char character) +{ + uint8_t width; + width = font->character_width(font, character); + + if (!width) + { + width = font->character_width(font, font->fallback_character); + } + + return width; +} + +struct whitespace_state +{ + uint8_t min_x, min_y; + uint8_t max_x, max_y; +}; + +static void whitespace_callback(int16_t x, int16_t y, uint8_t count, + uint8_t alpha, void *state) +{ + struct whitespace_state *s = state; + if (alpha > 7) + { + if (s->min_x > x) s->min_x = x; + if (s->min_y > y) s->min_y = y; + x += count - 1; + if (s->max_x < x) s->max_x = x; + if (s->max_y < y) s->max_y = y; + } +} + +MF_EXTERN void mf_character_whitespace(const struct mf_font_s *font, + mf_char character, + uint8_t *left, uint8_t *top, + uint8_t *right, uint8_t *bottom) +{ + struct whitespace_state state = {255, 255, 0, 0}; + mf_render_character(font, 0, 0, character, whitespace_callback, &state); + + if (state.min_x == 255 && state.min_y == 255) + { + /* Character is whitespace */ + if (left) *left = font->width; + if (top) *top = font->height; + if (right) *right = 0; + if (bottom) *bottom = 0; + } + else + { + if (left) *left = state.min_x; + if (top) *top = state.min_y; + if (right) *right = font->width - state.max_x - 1; + if (bottom) *bottom = font->height - state.max_y - 1; + } +} + +/* Avoids a dependency on libc */ +static bool strequals(const char *a, const char *b) +{ + while (*a) + { + if (*a++ != *b++) + return false; + } + return (!*b); +} + +const struct mf_font_s *mf_find_font(const char *name) +{ + const struct mf_font_list_s *f; + f = MF_INCLUDED_FONTS; + + while (f) + { + if (strequals(f->font->full_name, name) || + strequals(f->font->short_name, name)) + { + return f->font; + } + + f = f->next; + } + + return 0; +} + +const struct mf_font_list_s *mf_get_font_list() +{ + return MF_INCLUDED_FONTS; +} + diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_font.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_font.h new file mode 100644 index 0000000000..f0190005f9 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_font.h @@ -0,0 +1,137 @@ +/* Generic font type that supports fonts with multiple kinds of compression. + * Provides an interface for decoding and rendering single characters. + */ + +#ifndef _MF_FONT_H_ +#define _MF_FONT_H_ + +#include "mf_encoding.h" + +/* Callback function that writes pixels to screen / buffer / whatever. + * + * x: X coordinate of the first pixel to write. + * y: Y coordinate of the first pixel to write. + * count: Number of pixels to fill (horizontally). + * alpha: The "opaqueness" of the pixels, 0 for background, 255 for text. + * state: Free variable that was passed to render_character(). + */ +typedef void (*mf_pixel_callback_t) (int16_t x, int16_t y, uint8_t count, + uint8_t alpha, void *state); + +/* General information about a font. */ +struct mf_font_s +{ + /* Full name of the font, comes from the original font file. */ + char *full_name; + + /* Short name of the font, comes from file name. */ + char *short_name; + + /* Width and height of the character bounding box. */ + uint8_t width; + uint8_t height; + + /* Minimum and maximum tracking width of characters. */ + uint8_t min_x_advance; + uint8_t max_x_advance; + + /* Location of the text baseline relative to character. */ + int8_t baseline_x; + uint8_t baseline_y; + + /* Line height of the font (vertical advance). */ + uint8_t line_height; + + /* Flags identifying various aspects of the font. */ + uint8_t flags; + + /* Fallback character to use for missing glyphs. */ + mf_char fallback_character; + + /* Function to get character width. Should return 0 if character is + * not found. */ + uint8_t (*character_width)(const struct mf_font_s *font, mf_char character); + + /* Function to render a character. Returns the character width or 0 if + * character is not found. */ + uint8_t (*render_character)(const struct mf_font_s *font, + int16_t x0, int16_t y0, + mf_char character, + mf_pixel_callback_t callback, + void *state); +}; + +/* The flag definitions for the font.flags field. */ +#define MF_FONT_FLAG_MONOSPACE 0x01 +#define MF_FONT_FLAG_BW 0x02 + +/* Lookup structure for searching fonts by name. */ +struct mf_font_list_s +{ + const struct mf_font_list_s *next; + const struct mf_font_s *font; +}; + + +/* Function to decode and render a single character. + * + * font: Pointer to the font definition. + * x0, y0: Upper left corner of the target area. + * character: The character code (unicode) to render. + * callback: Callback function to write out the pixels. + * state: Free variable for caller to use (can be NULL). + * + * Returns width of the character. + */ +MF_EXTERN uint8_t mf_render_character(const struct mf_font_s *font, + int16_t x0, int16_t y0, + mf_char character, + mf_pixel_callback_t callback, + void *state); + +/* Function to get the width of a single character. + * This is not necessarily the bounding box of the character + * data, but rather the tracking width. + * + * font: Pointer to the font definition. + * character: The character code (unicode) to check width of. + * + * Returns width of the character in pixels. + */ +MF_EXTERN uint8_t mf_character_width(const struct mf_font_s *font, + mf_char character); + +/* Count the amount of white space at the borders of a character. + * + * E.g. if the font->width and font->height are 10x20, but the character + * is only a thin line at the very left edge, this function will return + * (0, 0, 9, 0). If the character is fully whitespace, the function will + * return (10, 20, 0, 0). + * + * font: Pointer to the font definition. + * character: The character code (unicode) to check white space of. + * left: Number of empty rows at left edge. Can be NULL. + * top: Number of empty rows at top edge. Can be NULL. + * right: Number of empty rows at right edge. Can be NULL. + * bottom: Number of empty rows at bottom edge. Can be NULL. + */ +MF_EXTERN void mf_character_whitespace(const struct mf_font_s *font, + mf_char character, + uint8_t *left, uint8_t *top, + uint8_t *right, uint8_t *bottom); + +/* Find a font based on name. The name can be either short name or full name. + * Note: You can pass MF_INCLUDED_FONTS to search among all the included .h + * files. + * + * name: Font name to search for. + * fonts: Pointer to the first font search entry. + * + * Returns a pointer to the font or NULL if not found. + */ +MF_EXTERN const struct mf_font_s *mf_find_font(const char *name); + +/* Get the list of included fonts */ +MF_EXTERN const struct mf_font_list_s *mf_get_font_list(); + +#endif diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_justify.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_justify.c new file mode 100644 index 0000000000..def9be05c4 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_justify.c @@ -0,0 +1,332 @@ +#include "mf_justify.h" +#include "mf_kerning.h" + +#if MF_USE_TABS +/* Round the X coordinate up to the nearest tab stop. */ +static int16_t mf_round_to_tab(const struct mf_font_s *font, + int16_t x0, int16_t x) +{ + int16_t tabw, dx; + + tabw = mf_character_width(font, 'm') * MF_TABSIZE; + + /* Always atleast 1 space */ + x += mf_character_width(font, ' '); + + /* Round to next tab stop */ + dx = x - x0 + font->baseline_x; + x += tabw - (dx % tabw); + + return x; +} + +/* Round the X coordinate down to the nearest tab stop. */ +static int16_t mf_round_to_prev_tab(const struct mf_font_s *font, + int16_t x0, int16_t x) +{ + int16_t tabw, dx; + + tabw = mf_character_width(font, 'm') * MF_TABSIZE; + + /* Always atleast 1 space */ + x -= mf_character_width(font, ' '); + + /* Round to previous tab stop */ + dx = x0 - x + font->baseline_x; + x -= tabw - (dx % tabw); + + return x; +} +#endif + +int16_t mf_get_string_width(const struct mf_font_s *font, mf_str text, + uint16_t count, bool kern) +{ + int16_t result = 0; + uint16_t c1 = 0, c2; + + if (!count) + count = 0xFFFF; + + while (count-- && *text) + { + c2 = mf_getchar(&text); + + if (c2 == '\t') + { +#if MF_USE_TABS + result = mf_round_to_tab(font, 0, result); + c1 = ' '; + continue; +#else + c2 = ' '; +#endif + } + + if (kern && c1 != 0) + result += mf_compute_kerning(font, c1, c2); + + result += mf_character_width(font, c2); + c1 = c2; + } + + return result; +} + +/* Return the length of the string without trailing spaces. */ +static uint16_t strip_spaces(mf_str text, uint16_t count, mf_char *last_char) +{ + uint16_t i = 0, result = 0; + mf_char tmp = 0; + + if (!count) + count = 0xFFFF; + + while (count-- && *text) + { + i++; + tmp = mf_getchar(&text); + if (tmp != ' ' && tmp != 0xA0 && tmp != '\n' && + tmp != '\r' && tmp != '\t') + { + result = i; + } + } + + if (last_char) + { + if (!*text) + *last_char = 0; + else + *last_char = tmp; + } + + return result; +} + +/* Render left-aligned string, left edge at x0. */ +static void render_left(const struct mf_font_s *font, + int16_t x0, int16_t y0, + mf_str text, uint16_t count, + mf_character_callback_t callback, + void *state) +{ + int16_t x; + mf_char c1 = 0, c2; + + x = x0 - font->baseline_x; + while (count--) + { + c2 = mf_getchar(&text); + + if (c2 == '\t') + { +#if MF_USE_TABS + x = mf_round_to_tab(font, x0, x); + c1 = ' '; + continue; +#else + c2 = ' '; +#endif + } + + if (c1 != 0) + x += mf_compute_kerning(font, c1, c2); + + x += callback(x, y0, c2, state); + c1 = c2; + } +} + +#if !MF_USE_ALIGN + +void mf_render_aligned(const struct mf_font_s *font, + int16_t x0, int16_t y0, + enum mf_align_t align, + mf_str text, uint16_t count, + mf_character_callback_t callback, + void *state) +{ + int16_t string_width; + count = strip_spaces(text, count, 0); + render_left(font, x0, y0, text, count, callback, state); +} + +#else + +/* Render right-aligned string, right edge at x0. */ +static void render_right(const struct mf_font_s *font, + int16_t x0, int16_t y0, + mf_str text, uint16_t count, + mf_character_callback_t callback, + void *state) +{ + int16_t x; + uint16_t i; + mf_char c1, c2 = 0; + mf_str tmp; + + /* Go to the end of the line. */ + for (i = 0; i < count; i++) + mf_getchar(&text); + + x = x0 - font->baseline_x; + for (i = 0; i < count; i++) + { + mf_rewind(&text); + tmp = text; + c1 = mf_getchar(&tmp); + + /* Perform tab alignment */ + if (c1 == '\t') + { +#if MF_USE_TABS + x = mf_round_to_prev_tab(font, x0, x); + c2 = ' '; + continue; +#else + c1 = ' '; +#endif + } + + /* Apply the nominal character width */ + x -= mf_character_width(font, c1); + + /* Apply kerning */ + if (c2 != 0) + x -= mf_compute_kerning(font, c1, c2); + + callback(x, y0, c1, state); + c2 = c1; + } +} + +void mf_render_aligned(const struct mf_font_s *font, + int16_t x0, int16_t y0, + enum mf_align_t align, + mf_str text, uint16_t count, + mf_character_callback_t callback, + void *state) +{ + int16_t string_width; + count = strip_spaces(text, count, 0); + + if (align == MF_ALIGN_LEFT) + { + render_left(font, x0, y0, text, count, callback, state); + } + if (align == MF_ALIGN_CENTER) + { + string_width = mf_get_string_width(font, text, count, false); + x0 -= string_width / 2; + render_left(font, x0, y0, text, count, callback, state); + } + else if (align == MF_ALIGN_RIGHT) + { + render_right(font, x0, y0, text, count, callback, state); + } +} + +#endif + + +#if !MF_USE_JUSTIFY + +void mf_render_justified(const struct mf_font_s *font, + int16_t x0, int16_t y0, int16_t width, + mf_str text, uint16_t count, + mf_character_callback_t callback, + void *state) +{ + mf_render_aligned(font, x0, y0, MF_ALIGN_LEFT, text, count, callback, state); +} + +#else + +/* Returns true if the character is a justification point, i.e. expands + * when the text is being justified. */ +static bool is_justify_space(uint16_t c) +{ + return c == ' ' || c == 0xA0; +} + +/* Count the number of space characters in string */ +static uint16_t count_spaces(mf_str text, uint16_t count) +{ + uint16_t spaces = 0; + while (count-- && *text) + { + if (is_justify_space(mf_getchar(&text))) + spaces++; + } + return spaces; +} + +void mf_render_justified(const struct mf_font_s *font, + int16_t x0, int16_t y0, int16_t width, + mf_str text, uint16_t count, + mf_character_callback_t callback, + void *state) +{ + int16_t string_width, adjustment; + uint16_t num_spaces; + mf_char last_char; + + count = strip_spaces(text, count, &last_char); + + if (last_char == '\n' || last_char == 0) + { + /* Line ends in linefeed, do not justify. */ + render_left(font, x0, y0, text, count, callback, state); + return; + } + + string_width = mf_get_string_width(font, text, count, false); + adjustment = width - string_width; + num_spaces = count_spaces(text, count); + + { + int16_t x, tmp; + uint16_t c1 = 0, c2; + + x = x0 - font->baseline_x; + while (count--) + { + c2 = mf_getchar(&text); + + if (c2 == '\t') + { +#if MF_USE_TABS + tmp = x; + x = mf_round_to_tab(font, x0, x); + adjustment -= x - tmp - mf_character_width(font, '\t'); + c1 = c2; + continue; +#else + c2 = ' '; +#endif + } + + if (is_justify_space(c2)) + { + tmp = (adjustment + num_spaces / 2) / num_spaces; + adjustment -= tmp; + num_spaces--; + x += tmp; + } + + if (c1 != 0) + { + tmp = mf_compute_kerning(font, c1, c2); + x += tmp; + adjustment -= tmp; + } + + x += callback(x, y0, c2, state); + c1 = c2; + } + } +} + +#endif + diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_justify.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_justify.h new file mode 100644 index 0000000000..c3e8ba75ef --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_justify.h @@ -0,0 +1,74 @@ +/* Text alignment and justification algorithm. Supports left, right, center + * alignment and justify. Supports tab stops and kerning. + */ + +#ifndef _MF_JUSTIFY_H_ +#define _MF_JUSTIFY_H_ + +#include "mf_rlefont.h" +#include + +enum mf_align_t +{ + MF_ALIGN_LEFT = 0, + MF_ALIGN_CENTER, + MF_ALIGN_RIGHT +}; + +/* Callback for rendering a single character. + * x0: Left edge of the target position of character. + * y0: Upper edge of the target position of character. + * character: Character to render. + * state: Free state variable for use by the callback. + * Returns the width of the character. + */ +typedef uint8_t (*mf_character_callback_t) (int16_t x0, int16_t y0, + mf_char character, void *state); + +/* Get width of a string in pixels. + * + * font: Pointer to the font definition. + * text: Pointer to start of the text to measure. + * count: Number of characters on the line or 0 to read until end of string. + * kern: True to consider kerning (slower). + */ +MF_EXTERN int16_t mf_get_string_width(const struct mf_font_s *font, + mf_str text, uint16_t count, bool kern); + +/* Render a single line of aligned text. + * + * font: Pointer to the font definition. + * x0: Depending on aligned, either left, center or right edge of target. + * y0: Upper edge of the target area. + * align: Type of alignment. + * text: Pointer to start of the text to render. + * count: Number of characters on the line or 0 to read until end of string. + * callback: Callback to call for each character. + * state: Free variable for use in the callback. + */ +MF_EXTERN void mf_render_aligned(const struct mf_font_s *font, + int16_t x0, int16_t y0, + enum mf_align_t align, + mf_str text, uint16_t count, + mf_character_callback_t callback, + void *state); + +/* Render a single line of justified text. + * + * font: Pointer to the font definition. + * x0: Left edge of the target area. + * y0: Upper edge of the target area. + * width: Width of the target area. + * text: Pointer to start of the text to render. + * count: Number of characters on the line or 0 to read until end of string. + * callback: Callback to call for each character. + * state: Free variable for use in the callback. + */ +MF_EXTERN void mf_render_justified(const struct mf_font_s *font, + int16_t x0, int16_t y0, int16_t width, + mf_str text, uint16_t count, + mf_character_callback_t callback, + void *state); + + +#endif diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_kerning.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_kerning.c new file mode 100644 index 0000000000..cc6e392c24 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_kerning.c @@ -0,0 +1,118 @@ +#include "mf_kerning.h" +#include + +#if MF_USE_KERNING + +/* Structure for keeping track of the edge of the glyph as it is rendered. */ +struct kerning_state_s +{ + uint8_t edgepos[MF_KERNING_ZONES]; + uint8_t zoneheight; +}; + +/* Pixel callback for analyzing the left edge of a glyph. */ +static void fit_leftedge(int16_t x, int16_t y, uint8_t count, uint8_t alpha, + void *state) +{ + struct kerning_state_s *s = state; + + if (alpha > 7) + { + uint8_t zone = y / s->zoneheight; + if (x < s->edgepos[zone]) + s->edgepos[zone] = x; + } +} + +/* Pixel callback for analyzing the right edge of a glyph. */ +static void fit_rightedge(int16_t x, int16_t y, uint8_t count, uint8_t alpha, + void *state) +{ + struct kerning_state_s *s = state; + + if (alpha > 7) + { + uint8_t zone = y / s->zoneheight; + x += count - 1; + if (x > s->edgepos[zone]) + s->edgepos[zone] = x; + } +} + +/* Should kerning be done against this character? */ +static bool do_kerning(mf_char c) +{ + /* Just a speed optimization, spaces would be ignored anyway. */ + if (c == ' ' || c == '\n' || c == '\r' || c == '\t') + return false; + + /* Do not kern against digits, in order to keep values in tables nicely + * aligned. Most fonts have constant width for digits. */ + if (c >= '0' && c <= '9') + return false; + + return true; +} + +/*static int16_t min16(int16_t a, int16_t b) { return (a < b) ? a : b; }*/ +static int16_t max16(int16_t a, int16_t b) { return (a > b) ? a : b; } +static int16_t avg16(int16_t a, int16_t b) { return (a + b) / 2; } + +int8_t mf_compute_kerning(const struct mf_font_s *font, + mf_char c1, mf_char c2) +{ + struct kerning_state_s leftedge, rightedge; + uint8_t w1, w2, i, min_space; + int16_t normal_space, adjust, max_adjust; + + if (font->flags & MF_FONT_FLAG_MONOSPACE) + return 0; /* No kerning for monospace fonts */ + + if (!do_kerning(c1) || !do_kerning(c2)) + return 0; + + /* Compute the height of one kerning zone in pixels */ + i = (font->height + MF_KERNING_ZONES - 1) / MF_KERNING_ZONES; + if (i < 1) i = 1; + + /* Initialize structures */ + leftedge.zoneheight = rightedge.zoneheight = i; + for (i = 0; i < MF_KERNING_ZONES; i++) + { + leftedge.edgepos[i] = 255; + rightedge.edgepos[i] = 0; + } + + /* Analyze the edges of both glyphs. */ + w1 = mf_render_character(font, 0, 0, c1, fit_rightedge, &rightedge); + w2 = mf_render_character(font, 0, 0, c2, fit_leftedge, &leftedge); + + /* Find the minimum horizontal space between the glyphs. */ + min_space = 255; + for (i = 0; i < MF_KERNING_ZONES; i++) + { + uint8_t space; + if (leftedge.edgepos[i] == 255 || rightedge.edgepos[i] == 0) + continue; /* Outside glyph area. */ + + space = w1 - rightedge.edgepos[i] + leftedge.edgepos[i]; + if (space < min_space) + min_space = space; + } + + if (min_space == 255) + return 0; /* One of the characters is space, or both are punctuation. */ + + /* Compute the adjustment of the glyph position. */ + normal_space = avg16(w1, w2) * MF_KERNING_SPACE_PERCENT / 100; + normal_space += MF_KERNING_SPACE_PIXELS; + adjust = normal_space - min_space; + max_adjust = -max16(w1, w2) * MF_KERNING_LIMIT / 100; + + if (adjust > 0) adjust = 0; + if (adjust < max_adjust) adjust = max_adjust; + + return adjust; +} + +#endif diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_kerning.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_kerning.h new file mode 100644 index 0000000000..3cbf5f82cc --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_kerning.h @@ -0,0 +1,27 @@ +/* Automatic kerning for font rendering. This solves the issue where some + * fonts (especially serif fonts) have too much space between specific + * character pairs, like WA or L'. + */ + +#ifndef _MF_KERNING_H_ +#define _MF_KERNING_H_ + +#include "mf_config.h" +#include "mf_rlefont.h" + +/* Compute the kerning adjustment when c1 is followed by c2. + * + * font: Pointer to the font definition. + * c1: The previous character. + * c2: The next character to render. + * + * Returns the offset to add to the x position for c2. + */ +#if MF_USE_KERNING +MF_EXTERN int8_t mf_compute_kerning(const struct mf_font_s *font, + mf_char c1, mf_char c2); +#else +#define mf_compute_kerning(f,c1,c2) (0) +#endif + +#endif diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_rlefont.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_rlefont.c new file mode 100644 index 0000000000..d45d720962 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_rlefont.c @@ -0,0 +1,286 @@ +#include "mf_rlefont.h" + +/* Number of reserved codes before the dictionary entries. */ +#define DICT_START 24 + +/* Special reference to mean "fill with zeros to the end of the glyph" */ +#define REF_FILLZEROS 16 + +/* RLE codes */ +#define RLE_CODEMASK 0xC0 +#define RLE_VALMASK 0x3F +#define RLE_ZEROS 0x00 +#define RLE_64ZEROS 0x40 +#define RLE_ONES 0x80 +#define RLE_SHADE 0xC0 + +/* Dictionary "fill entries" for encoding bits directly. */ +#define DICT_START7BIT 4 +#define DICT_START6BIT 132 +#define DICT_START5BIT 196 +#define DICT_START4BIT 228 +#define DICT_START3BIT 244 +#define DICT_START2BIT 252 + +/* Find a pointer to the glyph matching a given character by searching + * through the character ranges. If the character is not found, return + * pointer to the default glyph. + */ +static const uint8_t *find_glyph(const struct mf_rlefont_s *font, + uint16_t character) +{ + unsigned i, index; + const struct mf_rlefont_char_range_s *range; + for (i = 0; i < font->char_range_count; i++) + { + range = &font->char_ranges[i]; + index = character - range->first_char; + if (character >= range->first_char && index < range->char_count) + { + uint16_t offset = pgm_read_word(range->glyph_offsets + index); + return &range->glyph_data[offset]; + } + } + + return 0; +} + +/* Structure to keep track of coordinates of the next pixel to be written, + * and also the bounds of the character. */ +struct renderstate_r +{ + int16_t x_begin; + int16_t x_end; + int16_t x; + int16_t y; + int16_t y_end; + mf_pixel_callback_t callback; + void *state; +}; + +/* Call the callback to write one pixel to screen, and advance to next + * pixel position. */ +static void write_pixels(struct renderstate_r *rstate, uint16_t count, + uint8_t alpha) +{ + uint8_t rowlen; + + /* Write row-by-row if the run spans multiple rows. */ + while (rstate->x + count >= rstate->x_end) + { + rowlen = rstate->x_end - rstate->x; + rstate->callback(rstate->x, rstate->y, rowlen, alpha, rstate->state); + count -= rowlen; + rstate->x = rstate->x_begin; + rstate->y++; + } + + /* Write the remaining part */ + if (count) + { + rstate->callback(rstate->x, rstate->y, count, alpha, rstate->state); + rstate->x += count; + } +} + +/* Skip the given number of pixels (0 alpha) */ +static void skip_pixels(struct renderstate_r *rstate, uint16_t count) +{ + rstate->x += count; + while (rstate->x >= rstate->x_end) + { + rstate->x -= rstate->x_end - rstate->x_begin; + rstate->y++; + } +} + +/* Decode and write out a RLE-encoded dictionary entry. */ +static void write_rle_dictentry(const struct mf_rlefont_s *font, + struct renderstate_r *rstate, + uint8_t index) +{ + uint16_t offset = pgm_read_word(font->dictionary_offsets + index); + uint16_t length = pgm_read_word(font->dictionary_offsets + index + 1) - offset; + uint16_t i; + + for (i = 0; i < length; i++) + { + uint8_t code = pgm_read_byte(font->dictionary_data + offset + i); + if ((code & RLE_CODEMASK) == RLE_ZEROS) + { + skip_pixels(rstate, code & RLE_VALMASK); + } + else if ((code & RLE_CODEMASK) == RLE_64ZEROS) + { + skip_pixels(rstate, ((code & RLE_VALMASK) + 1) * 64); + } + else if ((code & RLE_CODEMASK) == RLE_ONES) + { + write_pixels(rstate, (code & RLE_VALMASK) + 1, 255); + } + else if ((code & RLE_CODEMASK) == RLE_SHADE) + { + uint8_t count, alpha; + count = ((code & RLE_VALMASK) >> 4) + 1; + alpha = ((code & RLE_VALMASK) & 0xF) * 0x11; + write_pixels(rstate, count, alpha); + } + } +} + +/* Get bit count for the "fill entries" */ +static uint8_t fillentry_bitcount(uint8_t index) +{ + if (index >= DICT_START2BIT) + return 2; + else if (index >= DICT_START3BIT) + return 3; + else if (index >= DICT_START4BIT) + return 4; + else if (index >= DICT_START5BIT) + return 5; + else if (index >= DICT_START6BIT) + return 6; + else + return 7; +} + +/* Decode and write out a direct binary codeword */ +static void write_bin_codeword(const struct mf_rlefont_s *font, + struct renderstate_r *rstate, + uint8_t code) +{ + uint8_t bitcount = fillentry_bitcount(code); + uint8_t byte = code - DICT_START7BIT; + uint8_t runlen = 0; + + while (bitcount--) + { + if (byte & 1) + { + runlen++; + } + else + { + if (runlen) + { + write_pixels(rstate, runlen, 255); + runlen = 0; + } + + skip_pixels(rstate, 1); + } + + byte >>= 1; + } + + if (runlen) + write_pixels(rstate, runlen, 255); +} + +/* Decode and write out a reference codeword */ +static void write_ref_codeword(const struct mf_rlefont_s *font, + struct renderstate_r *rstate, + uint8_t code) +{ + if (code == 0) + { + skip_pixels(rstate, 1); + } + else if (code <= 15) + { + write_pixels(rstate, 1, 0x11 * code); + } + else if (code == REF_FILLZEROS) + { + /* Fill with zeroes to end */ + rstate->y = rstate->y_end; + } + else if (code < DICT_START) + { + /* Reserved */ + } + else if (code < DICT_START + font->rle_entry_count) + { + write_rle_dictentry(font, rstate, code - DICT_START); + } + else + { + write_bin_codeword(font, rstate, code); + } +} + +/* Decode and write out a reference encoded dictionary entry. */ +static void write_ref_dictentry(const struct mf_rlefont_s *font, + struct renderstate_r *rstate, + uint8_t index) +{ + uint16_t offset = pgm_read_word(font->dictionary_offsets + index); + uint16_t length = pgm_read_word(font->dictionary_offsets + index + 1) - offset; + uint16_t i; + + for (i = 0; i < length; i++) + { + uint8_t code = pgm_read_byte(font->dictionary_data + offset + i); + write_ref_codeword(font, rstate, code); + } +} + +/* Decode and write out an arbitrary glyph codeword */ +static void write_glyph_codeword(const struct mf_rlefont_s *font, + struct renderstate_r *rstate, + uint8_t code) +{ + if (code >= DICT_START + font->rle_entry_count && + code < DICT_START + font->dict_entry_count) + { + write_ref_dictentry(font, rstate, code - DICT_START); + } + else + { + write_ref_codeword(font, rstate, code); + } +} + + +uint8_t mf_rlefont_render_character(const struct mf_font_s *font, + int16_t x0, int16_t y0, + uint16_t character, + mf_pixel_callback_t callback, + void *state) +{ + const uint8_t *p; + uint8_t width; + + struct renderstate_r rstate; + rstate.x_begin = x0; + rstate.x_end = x0 + font->width; + rstate.x = x0; + rstate.y = y0; + rstate.y_end = y0 + font->height; + rstate.callback = callback; + rstate.state = state; + + p = find_glyph((struct mf_rlefont_s*)font, character); + if (!p) + return 0; + + width = pgm_read_byte(p++); + while (rstate.y < rstate.y_end) + { + write_glyph_codeword((struct mf_rlefont_s*)font, &rstate, pgm_read_byte(p++)); + } + + return width; +} + +uint8_t mf_rlefont_character_width(const struct mf_font_s *font, + uint16_t character) +{ + const uint8_t *p; + p = find_glyph((struct mf_rlefont_s*)font, character); + if (!p) + return 0; + + return pgm_read_byte(p); +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_rlefont.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_rlefont.h new file mode 100644 index 0000000000..d26691b18e --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_rlefont.h @@ -0,0 +1,82 @@ +/* A compressed font format based on run length encoding and dictionary + * compression. + */ + +#ifndef _MF_RLEFONT_H_ +#define _MF_RLEFONT_H_ + +#include "mf_font.h" + +/* Versions of the RLE font format that are supported. */ +#define MF_RLEFONT_VERSION_4_SUPPORTED 1 + +/* Structure for a range of characters. This implements a sparse storage of + * character indices, so that you can e.g. pick a 100 characters in the middle + * of the UTF16 range and just store them. */ +struct mf_rlefont_char_range_s +{ + /* The number of the first character in this range. */ + uint16_t first_char; + + /* The total count of characters in this range. */ + uint16_t char_count; + + /* Lookup table with the start indices into glyph_data. */ + uint16_t *glyph_offsets; + uint32_t glyph_offsets_size; + uint32_t glyph_offsets_fp_offset; + + /* The encoded glyph data for glyphs in this range. */ + uint8_t *glyph_data; + uint32_t glyph_data_size; + uint32_t glyph_data_fp_offset; +}; + +/* Structure for a single encoded font. */ +struct mf_rlefont_s +{ + struct mf_font_s font; + + /* Version of the font definition used. */ + uint8_t version; + + /* Big array of the data for all the dictionary entries. */ + uint8_t *dictionary_data; + uint32_t dictionary_data_size; + uint32_t dictionary_data_fp_offset; + + /* Lookup table with the start indices into dictionary_data. + * Contains N+1 entries, so that the length of the entry can + * be determined by subtracting from the next offset. */ + uint16_t *dictionary_offsets; + uint32_t dictionary_offsets_size; + uint32_t dictionary_offsets_fp_offset; + + /* Number of dictionary entries using the RLE encoding. + * Entries starting at this index use the dictionary encoding. */ + uint8_t rle_entry_count; + + /* Total number of dictionary entries. + * Entries after this are nonexistent. */ + uint8_t dict_entry_count; + + /* Number of discontinuous character ranges */ + uint8_t char_range_count; + + /* Array of the character ranges */ + struct mf_rlefont_char_range_s *char_ranges; +}; + +#ifdef MF_RLEFONT_INTERNALS +/* Internal functions, don't use these directly. */ +MF_EXTERN uint8_t mf_rlefont_render_character(const struct mf_font_s *font, + int16_t x0, int16_t y0, + mf_char character, + mf_pixel_callback_t callback, + void *state); + +MF_EXTERN uint8_t mf_rlefont_character_width(const struct mf_font_s *font, + mf_char character); +#endif + +#endif diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_scaledfont.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_scaledfont.c new file mode 100644 index 0000000000..132016a9d8 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_scaledfont.c @@ -0,0 +1,83 @@ +#include "mf_scaledfont.h" + +struct scaled_renderstate +{ + mf_pixel_callback_t orig_callback; + void *orig_state; + uint8_t x_scale; + uint8_t y_scale; + int16_t x0; + int16_t y0; +}; + +static void scaled_pixel_callback(int16_t x, int16_t y, uint8_t count, + uint8_t alpha, void *state) +{ + struct scaled_renderstate *rstate = state; + uint8_t dy; + + count *= rstate->x_scale; + x = rstate->x0 + x * rstate->x_scale; + y = rstate->y0 + y * rstate->y_scale; + + for (dy = 0; dy < rstate->y_scale; dy++) + { + rstate->orig_callback(x, y + dy, count, alpha, rstate->orig_state); + } +} + +static uint8_t scaled_character_width(const struct mf_font_s *font, + mf_char character) +{ + struct mf_scaledfont_s *sfont = (struct mf_scaledfont_s*)font; + uint8_t basewidth; + + basewidth = sfont->basefont->character_width(sfont->basefont, character); + + return sfont->x_scale * basewidth; +} + +static uint8_t scaled_render_character(const struct mf_font_s *font, + int16_t x0, int16_t y0, + mf_char character, + mf_pixel_callback_t callback, + void *state) +{ + struct mf_scaledfont_s *sfont = (struct mf_scaledfont_s*)font; + struct scaled_renderstate rstate; + uint8_t basewidth; + + rstate.orig_callback = callback; + rstate.orig_state = state; + rstate.x_scale = sfont->x_scale; + rstate.y_scale = sfont->y_scale; + rstate.x0 = x0; + rstate.y0 = y0; + + basewidth = sfont->basefont->render_character(sfont->basefont, 0, 0, + character, scaled_pixel_callback, &rstate); + + return sfont->x_scale * basewidth; +} + +void mf_scale_font(struct mf_scaledfont_s *newfont, + const struct mf_font_s *basefont, + uint8_t x_scale, uint8_t y_scale) +{ + newfont->font = *basefont; + newfont->basefont = basefont; + + newfont->font.width *= x_scale; + newfont->font.height *= y_scale; + newfont->font.baseline_x *= x_scale; + newfont->font.baseline_y *= y_scale; + newfont->font.min_x_advance *= x_scale; + newfont->font.max_x_advance *= x_scale; + newfont->font.line_height *= y_scale; + newfont->font.character_width = &scaled_character_width; + newfont->font.render_character = &scaled_render_character; + + newfont->x_scale = x_scale; + newfont->y_scale = y_scale; +} + diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_scaledfont.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_scaledfont.h new file mode 100644 index 0000000000..7756591d6c --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_scaledfont.h @@ -0,0 +1,23 @@ +/* Generate scaled (nearest-neighbor) fonts. This can be used for displaying + * larger text without spending the memory required for including larger fonts. + */ + +#ifndef _MF_SCALEDFONT_H_ +#define _MF_SCALEDFONT_H_ + +#include "mf_font.h" + +struct mf_scaledfont_s +{ + struct mf_font_s font; + + const struct mf_font_s *basefont; + uint8_t x_scale; + uint8_t y_scale; +}; + +MF_EXTERN void mf_scale_font(struct mf_scaledfont_s *newfont, + const struct mf_font_s *basefont, + uint8_t x_scale, uint8_t y_scale); + +#endif diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_wordwrap.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_wordwrap.c new file mode 100644 index 0000000000..1d7bfe1317 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_wordwrap.c @@ -0,0 +1,357 @@ +#include "mf_wordwrap.h" + +/* Returns true if the line can be broken at this character. */ +static bool is_wrap_space(uint16_t c) +{ + return c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '-'; +} + +#if MF_USE_ADVANCED_WORDWRAP + +/* Represents a single word and the whitespace after it. */ +struct wordlen_s +{ + int16_t word; /* Length of the word in pixels. */ + int16_t space; /* Length of the whitespace in pixels. */ + uint16_t chars; /* Number of characters in word + space, combined. */ +}; + +/* Take the next word from the string and compute its width. + * Returns true if the word ends in a linebreak. */ +static bool get_wordlen(const struct mf_font_s *font, mf_str *text, + struct wordlen_s *result) +{ + mf_char c; + mf_str prev = *text; + + result->word = 0; + result->space = 0; + result->chars = 0; + + c = mf_getchar(text); + while (c && !is_wrap_space(c)) + { + result->chars++; + result->word += mf_character_width(font, c); + + prev = *text; + c = mf_getchar(text); + } + + while (c && is_wrap_space(c)) + { + result->chars++; + + if (c == ' ' || c == '-') + result->space += mf_character_width(font, c); + else if (c == '\t') + result->space += mf_character_width(font, 'm') * MF_TABSIZE; + else if (c == '\n') { + /* Special case for newlines, skip the character then break. */ + prev = *text; + break; + } + + prev = *text; + c = mf_getchar(text); + } + + /* The last loop reads the first character of next word, put it back. */ + if (c) + *text = prev; + + return (c == '\0' || c == '\n'); +} + +/* Represents the rendered length for a single line. */ +struct linelen_s +{ + mf_str start; /* Start of the text for line. */ + uint16_t chars; /* Total number of characters on the line. */ + int16_t width; /* Total length of all words + whitespace on the line in pixels. */ + bool linebreak; /* True if line ends in a linebreak */ + struct wordlen_s last_word; /* Last word on the line. */ + struct wordlen_s last_word_2; /* Second to last word on the line. */ +}; + +/* Append word onto the line if it fits. If it would overflow, don't add and + * return false. */ +static bool append_word(const struct mf_font_s *font, int16_t width, + struct linelen_s *current, mf_str *text) +{ + mf_str tmp = *text; + struct wordlen_s wordlen; + bool linebreak; + + linebreak = get_wordlen(font, &tmp, &wordlen); + + if (current->width + wordlen.word <= width) + { + *text = tmp; + current->last_word_2 = current->last_word; + current->last_word = wordlen; + current->linebreak = linebreak; + current->chars += wordlen.chars; + current->width += wordlen.word + wordlen.space; + return true; + } + else + { + return false; + } +} + +/* Append a character to the line if it fits. */ +static bool append_char(const struct mf_font_s *font, int16_t width, + struct linelen_s *current, mf_str *text) +{ + mf_str tmp = *text; + mf_char c; + uint16_t w; + + c = mf_getchar(&tmp); + w = mf_character_width(font, c); + + if (current->width + w <= width) + { + *text = tmp; + current->chars++; + current->width += w; + return true; + } + else + { + return false; + } +} + +/*static int16_t abs16(int16_t x) { return (x > 0) ? x : -x; }*/ +static int32_t sq16(int16_t x) { return (int32_t)x * x; } + +/* Try to balance the lines by potentially moving one word from the previous + * line to the the current one. */ +static void tune_lines(struct linelen_s *current, struct linelen_s *previous, + int16_t max_width) +{ + int16_t curw1, prevw1; + int16_t curw2, prevw2; + int32_t delta1, delta2; + + /* If the lines are rendered as is */ + curw1 = current->width - current->last_word.space; + prevw1 = previous->width - previous->last_word.space; + delta1 = sq16(max_width - prevw1) + sq16(max_width - curw1); + + /* If the last word is moved */ + curw2 = current->width + previous->last_word.word; + prevw2 = previous->width - previous->last_word.word + - previous->last_word.space + - previous->last_word_2.space; + delta2 = sq16(max_width - prevw2) + sq16(max_width - curw2); + + if (delta1 > delta2 && curw2 <= max_width) + { + /* Do the change. */ + uint16_t chars; + + chars = previous->last_word.chars; + previous->chars -= chars; + current->chars += chars; + previous->width -= previous->last_word.word + previous->last_word.space; + current->width += previous->last_word.word + previous->last_word.space; + previous->last_word = previous->last_word_2; + + while (chars--) mf_rewind(¤t->start); + } +} + +void mf_wordwrap(const struct mf_font_s *font, int16_t width, + mf_str text, mf_line_callback_t callback, void *state) +{ + struct linelen_s current = { 0 }; + struct linelen_s previous = { 0 }; + bool full; + + current.start = text; + + while (*text) + { + full = !append_word(font, width, ¤t, &text); + + if (full || current.linebreak) + { + if (!current.chars) + { + /* We have a very long word. We must just cut it off at some + * point. */ + while (append_char(font, width, ¤t, &text)); + } + + if (previous.chars) + { + /* Tune the length and dispatch the previous line. */ + if (!previous.linebreak && !current.linebreak) + tune_lines(¤t, &previous, width); + + if (!callback(previous.start, previous.chars, state)) + return; + } + + previous = current; + current.start = text; + current.chars = 0; + current.width = 0; + current.linebreak = false; + current.last_word.word = 0; + current.last_word.space = 0; + current.last_word.chars = 0; + } + } + + /* Dispatch the last lines. */ + if (previous.chars) + { + if (!callback(previous.start, previous.chars, state)) + return; + } + + if (current.chars) + callback(current.start, current.chars, state); +} + +void mf_text_draw_area(const struct mf_font_s *font, int16_t width, + mf_str text, + int *total_height_in_rows, + int *max_pixels_per_row) +{ + struct linelen_s current = { 0 }; + struct linelen_s previous = { 0 }; + bool full; + + current.start = text; + *total_height_in_rows = 0; + *max_pixels_per_row = 0; + + while (*text) + { + full = !append_word(font, width, ¤t, &text); + + if (full || current.linebreak) + { + if (!current.chars) + { + /* We have a very long word. We must just cut it off at some + * point. */ + while (append_char(font, width, ¤t, &text)); + } + + if (previous.chars) + { + /* Tune the length and dispatch the previous line. */ + if (!previous.linebreak && !current.linebreak) + tune_lines(¤t, &previous, width); + *total_height_in_rows += 1; + } + + if ( *max_pixels_per_row < current.width ) + *max_pixels_per_row = current.width; + previous = current; + current.start = text; + current.chars = 0; + current.width = 0; + current.linebreak = false; + current.last_word.word = 0; + current.last_word.space = 0; + current.last_word.chars = 0; + } + } + + /* Dispatch the last lines. */ + if (previous.chars) + { + if ( *max_pixels_per_row < previous.width ) + *max_pixels_per_row = previous.width; + *total_height_in_rows += 1; + } + + if (current.chars) { + if ( *max_pixels_per_row < current.width ) + *max_pixels_per_row = current.width; + *total_height_in_rows += 1; + } + +} + +#else + +void mf_wordwrap(const struct mf_font_s *font, int16_t width, + mf_str text, mf_line_callback_t callback, void *state) +{ + mf_str orig = text; + mf_str linestart; + + /* Current line width and character count */ + int16_t lw_cur = 0, cc_cur = 0; + + /* Previous wrap point */ + int16_t cc_prev; + mf_str ls_prev; + + linestart = text; + + while (*text) + { + cc_prev = 0; + ls_prev = text; + + while (*text) + { + mf_char c; + int16_t new_width; + mf_str tmp; + + tmp = text; + c = mf_getchar(&text); + new_width = lw_cur + mf_character_width(font, c); + + if (c == '\n') + { + cc_prev = cc_cur + 1; + ls_prev = text; + break; + } + + if (new_width > width) + { + text = tmp; + break; + } + + cc_cur++; + lw_cur = new_width; + + if (is_wrap_space(c)) + { + cc_prev = cc_cur; + ls_prev = text; + } + } + + /* Handle unbreakable words */ + if (cc_prev == 0) + { + cc_prev = cc_cur; + ls_prev = text; + } + + if (!callback(linestart, cc_prev, state)) + return; + + linestart = ls_prev; + text = linestart; + lw_cur = 0; + cc_cur = 0; + } +} + +#endif diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_wordwrap.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_wordwrap.h new file mode 100644 index 0000000000..521f4cf636 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_wordwrap.h @@ -0,0 +1,35 @@ +/* Word wrapping algorithm with UTF-8 support. More than just a basic greedy + * word-wrapper: it attempts to balance consecutive lines as pairs. + */ + +#ifndef _MF_WORDWRAP_H_ +#define _MF_WORDWRAP_H_ + +#include "mf_rlefont.h" +#include + +/* Callback function for handling each line. + * + * line: Pointer to the beginning of the string for this line. + * count: Number of characters on the line. + * state: Free variable that was passed to wordwrap(). + * + * Returns: true to continue, false to stop after this line. + */ +typedef bool (*mf_line_callback_t) (mf_str line, uint16_t count, + void *state); + +/* Word wrap a piece of text. Calls the callback function for each line. + * + * font: Font to use for metrics. + * width: Maximum line width in pixels. + * text: Pointer to the start of the text to process. + * state: Free variable for caller to use (can be NULL). + */ +MF_EXTERN void mf_wordwrap(const struct mf_font_s *font, int16_t width, + mf_str text, mf_line_callback_t callback, void *state); + +void mf_text_draw_area(const struct mf_font_s *font, int16_t width, + mf_str text, int *total_height_in_rows, + int *max_pixels_per_row); +#endif diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/rle_font_read.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/rle_font_read.c new file mode 100644 index 0000000000..05f27c8f6e --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/rle_font_read.c @@ -0,0 +1,716 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright 2020 NXP +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +/** Include Files */ +#include +#include +#include +#include + +#include "vg_lite.h" +#include "buf_reader.h" +#include "vg_lite_text.h" +#include "vft_draw.h" +#include "vft_debug.h" + +/** Macros */ +#define __COUNTOF(x) (sizeof(x)/sizeof(x[0])) +#define MAX_SYSTEM_FONTS (8) + +#define RCD_ALLOC(x) _mem_allocate(x) +#define RCD_FREE(x) _mem_free(x) + +#ifdef ENABLE_DEBUG_TRACE +static int g_id; + +#define DBG_ID() (g_id) +#define DBG_INC_ID() (g_id++) +#define DBG_SET_ID(x) g_id = x +#else + +#define DBG_ID() (0) +#define DBG_INC_ID() (0) +#define DBG_SET_ID(x) +#endif + +#if APP_ENABLE_SDCARD +#define sprintf_s snprintf +#endif + +/** Data structures */ +typedef struct font_height_list { + const char font_height; + const char ref_font_height; + const char ref_font_scale; +} font_height_list_t; + +typedef struct font_info_internal { + /* Variable shared between user and driver */ + vg_lite_font_params_t font_params; + /* any additional variables internal to driver */ + int valid; + /* Internal loaded raster font */ + struct mf_font_s *_raster_font; + /* Internal loaded vector font */ + font_face_desc_t *_vector_font; +}font_info_internal_t; + +/** Internal or external API prototypes */ + +/** Globals */ +static font_info_internal_t s_device_fonts[MAX_SYSTEM_FONTS]; + +/** Local function prototypes */ +int read_rle_font_header(bufferred_reader_t *f, struct mf_font_s* font); +int read_rle_font_from_buffer(char *buf, int size, struct mf_font_s* font); +int load_raster_font(char *data, int data_len, struct mf_font_s** font); + +int read_8b(bufferred_reader_t *f, uint8_t* pdata); +int read_16b(bufferred_reader_t *f, uint16_t* pword); +int read_32b(bufferred_reader_t *f, uint32_t* pword); +int read_16b_blob(bufferred_reader_t *f, uint16_t** ary, uint32_t* ary_len); +int read_8b_blob(bufferred_reader_t *f, uint8_t** ary, uint32_t* ary_len); +int free_rle_font_memory(struct mf_font_s** font); +vg_lite_error_t vg_lite_free_font_memory(vg_lite_font_t font); +vg_lite_error_t vg_lite_load_font_data(vg_lite_font_t font, int font_height); + +/** Externs if any */ + +/** Code section */ +vg_lite_font_t vg_lite_find_font( + char *font_name, + eFontWeight_t font_weight, + eFontStretch_t font_stretch, + eFontStyle_t font_style, + int font_height); + +vg_lite_error_t vg_lite_register_font(vg_lite_font_t *font, + vg_lite_font_params_t *params) +{ + int i; + int free_entry = VG_LITE_INVALID_FONT; + + if (font != NULL) + *font = VG_LITE_INVALID_FONT; + + /* Check if font is already registered */ + for (i=0; iname, + strlen(s_device_fonts[i].font_params.name)) == 0) + { + return VG_LITE_ALREADY_EXISTS; + } + } else { + printf("Corrupt font table\n"); + return VG_LITE_INVALID_ARGUMENT; + } + } + + /* Check if list is completely full or not */ + if ( i == MAX_SYSTEM_FONTS && free_entry == VG_LITE_INVALID_FONT) { + /* Font List descriptor exhausted */ + return VG_LITE_OUT_OF_RESOURCES; + } else { + /* Add new font in global table */ + memcpy(&s_device_fonts[free_entry].font_params, params, sizeof(vg_lite_font_params_t)); + s_device_fonts[free_entry].valid = 1; +/* + Loading font here leads to low run-time memory, we may need to characterize memory usage + e.g. pure path test don't require font, eventhrough application registers them +*/ +#if 0 + error = vg_lite_load_font_data(free_entry, params->font_height); + if ( error != 0 ) { + s_device_fonts[free_entry].valid = 0; + return error; + } +#endif + } + + if (font != NULL) + *font = free_entry; + + return VG_LITE_SUCCESS; +} + +int vg_lite_is_font_valid(vg_lite_font_t font) +{ + if (font < MAX_SYSTEM_FONTS) { + if (s_device_fonts[font].valid == 1) + return 0; + } + return VG_LITE_INVALID_ARGUMENT; +} + +int vg_lite_is_vector_font(vg_lite_font_t font) +{ + if (font < MAX_SYSTEM_FONTS) { + if (s_device_fonts[font].valid == 1) + return (s_device_fonts[font].font_params.font_type == + eFontTypeVector); + else + return 0; + } + return VG_LITE_INVALID_ARGUMENT;; +} + +vg_lite_error_t vg_lite_unregister_font(vg_lite_font_t font) +{ + if (vg_lite_is_font_valid(font) != 0 ) { + /* Font not found */ + return VG_LITE_INVALID_ARGUMENT;; + } + + vg_lite_free_font_memory(font); + s_device_fonts[font].valid = 0; + return VG_LITE_SUCCESS; +} + +char *vg_lite_get_font_name(vg_lite_font_t font) +{ + if ( vg_lite_is_font_valid(font) != 0 ) { + return NULL; + } + + return (char *)s_device_fonts[font].font_params.name; +} + +vg_lite_error_t vg_lite_free_font_memory(vg_lite_font_t font) +{ + if ( vg_lite_is_font_valid(font) != 0 ) { + /* Font not found */ + return VG_LITE_INVALID_ARGUMENT; + } + switch (s_device_fonts[font].font_params.font_type) { + case eFontTypeVector: + if ( s_device_fonts[font]._vector_font != NULL ) { + vft_unload(s_device_fonts[font]._vector_font); + s_device_fonts[font]._vector_font = NULL; + } + break; + case eFontTypeRaster: + if ( s_device_fonts[font]._raster_font != NULL ) { + free_rle_font_memory(&s_device_fonts[font]._raster_font); + s_device_fonts[font]._raster_font = NULL; + } + break; + } + + return VG_LITE_SUCCESS; +} + +font_face_desc_t *_vg_lite_get_vector_font(vg_lite_font_t font) +{ + if ( vg_lite_is_font_valid(font) != 0 ) { + return NULL; + } + + return s_device_fonts[font]._vector_font; +} + +struct mf_font_s *_vg_lite_get_raster_font(vg_lite_font_t font) +{ + if ( vg_lite_is_font_valid(font) != 0 ) { + return NULL; + } + + return s_device_fonts[font]._raster_font; +} + +vg_lite_error_t vg_lite_load_font_data(vg_lite_font_t font, int font_height) +{ + if ( vg_lite_is_font_valid(font) != 0 ) { + /* Font not found */ + return VG_LITE_INVALID_ARGUMENT; + } + + switch (s_device_fonts[font].font_params.font_type) { + case eFontTypeVector: + if (s_device_fonts[font]._vector_font == NULL ) { + //printf("Loading vector font : [%s]\n", + // s_device_fonts[font].font_params.name); + s_device_fonts[font]._vector_font = + vft_load_from_buffer( + s_device_fonts[font].font_params.data, + s_device_fonts[font].font_params.data_len); + if ( s_device_fonts[font]._vector_font == NULL ) { + return VG_LITE_INVALID_ARGUMENT; + } + } + return VG_LITE_SUCCESS; + case eFontTypeRaster: + if (s_device_fonts[font]._raster_font == NULL ) { + //printf("Loading raster font : [%s]\n", + // s_device_fonts[font].font_params.name); + /* Raster fonts height should match */ + if ( font_height == s_device_fonts[font].font_params.font_height && + load_raster_font( + s_device_fonts[font].font_params.data, + s_device_fonts[font].font_params.data_len, + &s_device_fonts[font]._raster_font) != 0) + { + return VG_LITE_INVALID_ARGUMENT; + } + } + return VG_LITE_SUCCESS; + } + return VG_LITE_INVALID_ARGUMENT; +} + + +vg_lite_font_t vg_lite_find_font( + char *font_name_list, + eFontWeight_t font_weight, + eFontStretch_t font_stretch, + eFontStyle_t font_style, + int font_height) +{ + int i; + char tmp_data; + int font_found = 0; + int end_pos = 0; /* End position of font name */ + char *font_name; + /* + printf("Font params: [%s],%d, %d, %d, %d\n", + font_name_list, + font_weight, + font_stretch, + font_style, + font_height); + */ + + /* While probing font, if required font is found, then + only keep that name in supplied font list */ + + /* Split and extract font name one-by-one */ + font_name = font_name_list; + while (font_found == 0 && + font_name[end_pos] != '\0') + { + tmp_data = '\0'; + /* Scan for seperator */ + while (font_name[end_pos] != '\0') { + if (font_name[end_pos] == ',' || font_name[end_pos] == ' ' || + font_name[end_pos] == '\t') + { + tmp_data = font_name[end_pos]; + font_name[end_pos] = '\0'; + break; + } + end_pos++; + } + + /* Search for exact font-name match */ + for (i=0; i<__COUNTOF(s_device_fonts); i++) { + if (s_device_fonts[i].valid == 0) + continue; + + /* For vector font only compare name */ + if (s_device_fonts[i].font_params.font_type == eFontTypeVector ) { + if ( strlen(font_name) > 0 && + strcmp(font_name, + s_device_fonts[i].font_params.name) == 0) + { + font_name[end_pos] = tmp_data; /* Restor delimeter */ + return i; + } + } else { + /* For raster font compare all properties */ + if (s_device_fonts[i].font_params.font_weight == font_weight && + s_device_fonts[i].font_params.font_stretch == font_stretch && + s_device_fonts[i].font_params.font_style == font_style ) + { + if ( strlen(font_name) > 0 && + strcmp(font_name, + s_device_fonts[i].font_params.name) == 0) + { + font_name[end_pos] = tmp_data; /* Restor delimeter */ + + if (s_device_fonts[i].font_params.font_height == font_height) + { + return i; + } + /* Update font_name_list to improve future searches */ + strncpy(font_name_list, font_name, strlen(font_name)+1); + } + } + } + } + /* Continue searching for other font entries */ + font_name[end_pos] = tmp_data; + font_name += (end_pos + 1); + end_pos = 0; + } + printf("WARNING: [%s] Font not found\r\n",font_name_list); + + return VG_LITE_INVALID_FONT; +} + +void vg_lite_text_init(void) +{ + static int font_table_ready = 0; + + if (font_table_ready) + return; + + /* Initialize font table */ + memset(s_device_fonts, 0, MAX_SYSTEM_FONTS * sizeof(font_info_internal_t)); + font_table_ready = 1; +} + +/* Read-Write 8-bit unsigned int data */ +int read_8b(bufferred_reader_t * f, uint8_t* pdata) +{ + bufferred_fread(pdata, 1, 1, f); + TRACE_DBG(("%d) 8b: fp=%08x %d %d\r\n", DBG_INC_ID(), + bufferred_ftell(f) - 1, 1, *pdata)); + return 1; +} + +/* Read-Write 16-bit unsigned int data */ +int read_16b(bufferred_reader_t * f, uint16_t* pword) +{ + uint8_t buf[4]; + uint16_t word; + + bufferred_fread(buf, 2, 1, f); + word = 0; word += buf[1]; + word <<= 8; word += buf[0]; + + TRACE_DBG(("%d) 16b: fp=%08x %d %d\r\n", DBG_INC_ID(), + bufferred_ftell(f)-2, 2, word)); + *pword = word; + return 2; +} + +/* Read-write 32-bit unsigned int data */ +int read_32b(bufferred_reader_t * f, uint32_t* pword) +{ + uint8_t buf[4]; + uint32_t word; + + bufferred_fread(buf, 4, 1, f); + word = 0; word += buf[3]; + word <<= 8; word += buf[2]; + word <<= 8; word += buf[1]; + word <<= 8; word += buf[0]; + + *pword = word; + TRACE_DBG(("%d) 32b: fp=%08x %d %d\r\n", DBG_INC_ID(), + bufferred_ftell(f) - 4, 4, + word)); + return 4; +} + +int read_16b_blob(bufferred_reader_t * f, uint16_t** ary, uint32_t* ary_len) +{ + uint16_t blob_len = 0; + + *ary_len = 0; + bufferred_fread(&blob_len, 1, sizeof(uint16_t), f); + *ary = (uint16_t *)RCD_ALLOC(blob_len * sizeof(uint16_t)); /* Malloc must be aligned on 2 byte boundary */ + if (*ary == NULL) { + TRACE_ERR(("ERROR: malloc failed\n"));; + return VG_LITE_OUT_OF_MEMORY; + } + if ((((unsigned long)*ary) & 0x1) != 0) { + TRACE_ERR(("ERROR: malloc pointer not 2 byte aligned\n"));; + return VG_LITE_NOT_ALIGNED; + } + TRACE_DBG(("%d ) 16b_blob: fp=%08x %d\r\n", DBG_INC_ID(), bufferred_ftell(f)-2, + (int)blob_len)); + bufferred_fread(*ary, 2, blob_len, f); + *ary_len = blob_len * 2; + + return blob_len + 2; /* Actual bytes read from file */ +} + +int read_8b_blob(bufferred_reader_t * f, uint8_t** ary, uint32_t *ary_len) +{ + uint16_t blob_len = 0; + uint8_t* p_tmp = (uint8_t *)NULL; + bufferred_fread(&blob_len, 1, sizeof(uint16_t), f); + //TRACE_DBG(("%d) 8b_blob: %d\r\n", DBG_INC_ID(), blob_len)); + p_tmp = (uint8_t *)RCD_ALLOC(blob_len+1); + if (p_tmp == NULL) { + TRACE_ERR(("ERROR: malloc failed\n"));; + return VG_LITE_OUT_OF_MEMORY; + } + TRACE_DBG(("%d ) 8b_blob: fp=%08x %d\r\n", DBG_INC_ID(), bufferred_ftell(f)-2, + (int)blob_len)); + bufferred_fread(p_tmp, 1, blob_len, f); + p_tmp[blob_len] = 0; + *ary = p_tmp; + + return blob_len + 2; /* Actual bytes read from file */ +} + +#define EXIT_IF_NEGATIVE(param) if ((ret = param) < 0) return ret; + +int read_rle_font_header(bufferred_reader_t * f, struct mf_font_s* font) +{ + int raw_header_offset = 0; + struct mf_rlefont_s* mfont = (struct mf_rlefont_s*)font; + uint32_t size = 0; + int ret = 0; + + TRACE_DBG(("** %s\r\n", __FUNCTION__)); + DBG_SET_ID(0); + + EXIT_IF_NEGATIVE(read_8b_blob(f, (uint8_t **)&font->full_name, &size)); + raw_header_offset += ret; /* font.full_name */ + + EXIT_IF_NEGATIVE(read_8b_blob(f, (uint8_t **)&font->short_name, &size)); + raw_header_offset += ret; /* font.short_name */ + + EXIT_IF_NEGATIVE(read_8b(f, &font->width)); + raw_header_offset += 1; /* font.width */ + + EXIT_IF_NEGATIVE(read_8b(f, &font->height)); + raw_header_offset += 1; /* font.height */ + + EXIT_IF_NEGATIVE(read_8b(f, &font->min_x_advance)); + raw_header_offset += 1; /* font.min_x_advance */ + + EXIT_IF_NEGATIVE(read_8b(f, &font->max_x_advance)); + raw_header_offset += 1; /* font.max_x_advance */ + + EXIT_IF_NEGATIVE(read_8b(f, (uint8_t *)&font->baseline_x)); + raw_header_offset += 1; /* font.baseline_x */ + + EXIT_IF_NEGATIVE(read_8b(f, &font->baseline_y)); + raw_header_offset += 1; /* font.baseline_y */ + + EXIT_IF_NEGATIVE(read_8b(f, &font->line_height)); + raw_header_offset += 1; /* font.line_height */ + + EXIT_IF_NEGATIVE(read_8b(f, &font->flags)); + raw_header_offset += 1; /* font.flags */ + + EXIT_IF_NEGATIVE(read_16b(f, &font->fallback_character)); + raw_header_offset += 2; /* font.fallback_character */ + + EXIT_IF_NEGATIVE(read_8b(f, &(mfont->version))); + raw_header_offset += 1; /* mf_rlefont_s.version */ + + /* Other mf_rlefont_s variables */ + uint16_t value = 0; + EXIT_IF_NEGATIVE(read_16b(f, &value)); //&mfont->dictionary_data_size)); + mfont->dictionary_data_size = value; + raw_header_offset += 2; /* mf_rlefont_s.dictionary_data_size */ + + EXIT_IF_NEGATIVE(read_32b(f, &mfont->dictionary_data_fp_offset)); + raw_header_offset += 4; /* mf_rlefont_s.dictionary_data_fp_offset */ + + value = 0; + EXIT_IF_NEGATIVE(read_16b(f, &value)); //mfont->dictionary_offsets_size)); + mfont->dictionary_offsets_size = value; + raw_header_offset += 2; /* mf_rlefont_s.dictionary_data_size */ + + EXIT_IF_NEGATIVE(read_32b(f, &mfont->dictionary_offsets_fp_offset)); + raw_header_offset += 4; /* mf_rlefont_s.dictionary_data_fp_offset */ + + EXIT_IF_NEGATIVE(read_8b(f, &mfont->rle_entry_count)); + raw_header_offset += 1; /* mf_rlefont_s.rle_entry_count */ + + EXIT_IF_NEGATIVE(read_8b(f, &mfont->dict_entry_count)); + raw_header_offset += 1; /* mf_rlefont_s.dict_entry_count */ + + EXIT_IF_NEGATIVE(read_8b(f, &mfont->char_range_count)); + raw_header_offset += 1; /* mf_rlefont_s.char_range_count */ + + mfont->char_ranges = (struct mf_rlefont_char_range_s *)RCD_ALLOC(sizeof(struct mf_rlefont_char_range_s)* mfont->char_range_count); + memset(mfont->char_ranges, 0, sizeof(struct mf_rlefont_char_range_s) * mfont->char_range_count); + + /* Skip size of ranges */ + for (int r = 0; r < mfont->char_range_count; r++) { + EXIT_IF_NEGATIVE(read_16b(f, &mfont->char_ranges[r].first_char)); + raw_header_offset += 2; /* mf_rlefont_s.char_ranges[r].first_char */ + + EXIT_IF_NEGATIVE(read_16b(f, &mfont->char_ranges[r].char_count)); + raw_header_offset += 2; /* mf_rlefont_s.char_ranges[r].char_count */ + + EXIT_IF_NEGATIVE(read_32b(f, &mfont->char_ranges[r].glyph_offsets_fp_offset)); + raw_header_offset += 4; /* mf_rlefont_s.char_ranges[r].glyph_offsets_fp_offset */ + + EXIT_IF_NEGATIVE(read_32b(f, &mfont->char_ranges[r].glyph_offsets_size)); + raw_header_offset += 4; /* mf_rlefont_s.char_ranges[r].glyph_offsets_size */ + + EXIT_IF_NEGATIVE(read_32b(f, &mfont->char_ranges[r].glyph_data_fp_offset)); + raw_header_offset += 4; /* mf_rlefont_s.char_ranges[r].glyph_offsets_fp_offset */ + + EXIT_IF_NEGATIVE(read_32b(f, &mfont->char_ranges[r].glyph_data_size)); + raw_header_offset += 4; /* mf_rlefont_s.char_ranges[r].glyph_offsets_size */ + } + return raw_header_offset; +} + +/* Writes a BMP file. The data is assumed to be 8-bit grayscale. */ +int read_rle_font_from_buffer(char *buff, int size, struct mf_font_s* font) +{ + struct mf_rlefont_s* mfont = (struct mf_rlefont_s*)font; + bufferred_reader_t f_obj; + bufferred_reader_t * f = &f_obj; + int raw_header_offset = 0; + int fp_offset; + int ret; + + DBG_SET_ID(0); + + /* No need to dynamically allocate small descriptor */ + if ( bufferred_fopen(f, buff, size) < 0 ) { + /* Font file open failed */ + return VG_LITE_INVALID_ARGUMENT; + } + + raw_header_offset = read_rle_font_header(f, font); + if (mfont->dictionary_data_fp_offset != raw_header_offset) { + TRACE_ERR(("ERROR: dictonary offset is different")); + } + TRACE_DBG(("** %s\r\n", __FUNCTION__)); + DBG_SET_ID(0); + + /* Skip header portion */ + bufferred_fseek(f, raw_header_offset, SEEK_SET); + /* Write dictionary entries */ + fp_offset = raw_header_offset; + TRACE_DBG(("dictionary_data_fp_offset=%08x %08x\r\n", + mfont->dictionary_data_fp_offset, bufferred_ftell(f))); + //mfont->dictionary_data_fp_offset = fp_offset; + EXIT_IF_NEGATIVE(read_8b_blob(f, &mfont->dictionary_data, + &mfont->dictionary_data_size)); + fp_offset += mfont->dictionary_data_size + 2; + + //mfont->dictionary_offsets_fp_offset = fp_offset; + TRACE_DBG(("dictionary_offsets_fp_offset=%08x %08x\r\n", + mfont->dictionary_offsets_fp_offset, bufferred_ftell(f))); + EXIT_IF_NEGATIVE(read_16b_blob(f, &mfont->dictionary_offsets, + &mfont->dictionary_offsets_size)); + fp_offset += mfont->dictionary_offsets_size + 2; + + /* Write range entries */ + for (int r = 0; r < mfont->char_range_count; r++) { + //mfont->char_ranges[r].glyph_offsets_fp_offset = fp_offset; + TRACE_DBG(("mfont->char_ranges[%d].glyph_offsets=%08x %08x\r\n", r, + mfont->char_ranges[r].glyph_offsets_fp_offset, bufferred_ftell(f))); + EXIT_IF_NEGATIVE(read_16b_blob(f, &mfont->char_ranges[r].glyph_offsets, + &mfont->char_ranges[r].glyph_offsets_size)); + fp_offset += mfont->char_ranges[r].glyph_offsets_size + 2; + + //mfont->char_ranges[r].glyph_data_fp_offset = fp_offset; + TRACE_DBG(("mfont->char_ranges[%d].glyph_data_fp_offset=%08x %08x\r\n", + r, + mfont->char_ranges[r].glyph_data_fp_offset, bufferred_ftell(f))); + EXIT_IF_NEGATIVE(read_8b_blob(f, &mfont->char_ranges[r].glyph_data,\ + &mfont->char_ranges[r].glyph_data_size)); + fp_offset += mfont->char_ranges[r].glyph_data_size + 2; + } + + bufferred_fclose(f); + return 0; +} + +int load_raster_font(char *data, int data_len, struct mf_font_s** font) +{ + int ret; + + /* Allocate font memory */ + *font = (struct mf_font_s*)RCD_ALLOC(sizeof(struct mf_rlefont_s)); + if (*font == NULL) { + return VG_LITE_OUT_OF_MEMORY; + } + memset(*font, 0, sizeof(struct mf_rlefont_s)); + + /* Load font from file */ + ret = read_rle_font_from_buffer(data, + data_len, *font); + if (ret < 0) { + return ret; + } + + /* Update generic char width pointers of mculib */ + uint8_t mf_rlefont_character_width(const struct mf_font_s* font, + uint16_t character); + uint8_t mf_rlefont_render_character(const struct mf_font_s* font, + int16_t x0, int16_t y0, + uint16_t character, + mf_pixel_callback_t callback, + void* state); + + (*font)->character_width = &mf_rlefont_character_width; + (*font)->render_character = &mf_rlefont_render_character; + + + return 0; +} + +int free_rle_font_memory(struct mf_font_s** font) +{ + struct mf_rlefont_s* mfont = (struct mf_rlefont_s*)(*font); + + RCD_FREE(mfont->font.full_name); + RCD_FREE(mfont->font.short_name); + RCD_FREE(mfont->dictionary_data); + RCD_FREE(mfont->dictionary_offsets); + for (int r = 0; r < mfont->char_range_count; r++) { + RCD_FREE(mfont->char_ranges[r].glyph_offsets); + RCD_FREE(mfont->char_ranges[r].glyph_data); + } + #ifdef DEBUG_RESET_DATASTRUCTURE_ON_FREE + memset(mfont->char_ranges); + #endif + RCD_FREE(mfont->char_ranges); + + #ifdef DEBUG_RESET_DATASTRUCTURE_ON_FREE + memset(mfont); + #endif + RCD_FREE(mfont); + + *font = NULL; + return 0; +} + +void vg_lite_unload_font_data(void) +{ + for(int i=0; igContext.object_slots[id % SLOT_COUNT] + + /* + VGLite releated configurations. + */ +#define TS_WIDTH 64 +#define TS_HEIGHT 64 +#define RTOS 1 +#define APP_BUFFER_COUNT 2 +#if (RTOS && DDRLESS) || BAREMETAL +#define OBJCOUNT_GRAD 16 +#define OBJCOUNT_EVO 128 +#define OBJCOUNT_EBO 64 +#define OBJCOUNT_GROUP 16 +#endif + +#if RTOS + +#include "rtthread.h" + +#define elm_alloc(num_objects, object_size) rt_malloc(num_objects * object_size) +#define elm_free rt_free +#else +#define elm_alloc calloc +#define elm_free free +#endif + +typedef enum { + ELEMENT_LINEARGRADIENT = 0, /*! linear gradient element */ + ELEMENT_PATH = 1, /*! path element */ + ELEMENT_GROUP = 2, /*! group element */ + ELEMENT_TEXT = 3, /*! text element */ + ELEMENT_TSPAN = 4, /*! tspan element */ + ELEMENT_FONT = 5, /*! font element */ + ELEMENT_TTF_FONT = 6, /*! ttf-type font */ + ELEMENT_VECTOR_FONT = 7, /*! vector fonts */ + ELEMENT_TEXT_FONT = 8, /*! text fonts */ +} ELM_ELEMENT_TYPE; + +#define COUNT_OF(array) (sizeof(array) / sizeof(array[0])) + /* + System definitions. + */ +#define DEBUG_ASSERT(a, message) \ + if (!a) \ + printf("%s: ASSERT failed @ %s, %d.\n", message, __FILE__, __LINE__) + + /*! + @typedef el_Object + common object type definition shared by all EVO object to identify its handle, + object type, and ELM version info. + for reference purpose, handle = 0 is reserved. + */ + typedef struct { + ElmHandle handle; + ELM_OBJECT_TYPE type; + unsigned int reference; // Reference count by other objects. +#if (RTOS && DDRLESS) || BAREMETAL + int index; /* The index of the object in pool. */ +#endif + } el_Object; + + /*! + @typedef el_Transform + The transformation attribute for an EVO/EBO/Group object. + */ + typedef struct { + float rotate; + float translate[2]; + float scale[2]; + BOOL dirty; + BOOL identity; + vg_lite_matrix_t matrix; + } el_Transform; + + /*! + @typedef el_GradData + Linear gradient definition. + !grad the native vg_lite gradient data; + !gransform the grad's transformation. matrix is synced to grad's. + */ + typedef struct { + vg_lite_linear_gradient_t grad; + el_Transform transform; + } el_GradData; + + /*! + @typedef el_RadgradData + Radial gradient definition. + !rad_grad the native vg_lite_radial_gradient data; + !gransform the grad's transformation. matrix is synced to grad's. + */ + typedef struct { + vg_lite_radial_gradient_t rad_grad; + el_Transform transform; + } el_RadgradData; + + /*! + @typedef el_Obj_Grad + The linear gradient object definition. + */ + typedef struct { + el_Object object; + el_GradData data; + } el_Obj_Grad; + + /*! + @typedef el_Obj_Radgrad + The radial gradient object definition. + */ + typedef struct { + el_Object object; + el_RadgradData data; + } el_Obj_Radgrad; + + /*! + @typedef el_Obj_Pattern + The pattern paint object definition. + pattern: it should be an pointer to an el_Obj_EVO; + mode: the pattern fill mode. + color: the color value if pattern mode is COLOR + */ + typedef struct { + void *pattern; + ELM_PATTERN_MODE mode; + uint32_t color; + } el_Obj_Pattern; + + /*! + @typedef el_Paint + The paint object definition. + color: for solid fill; + grad: for linear gradient fill; + pattern: for image fill. + */ + typedef struct { + ELM_PAINT_TYPE type; + uint32_t color; + el_Obj_Grad * grad; + el_Obj_Radgrad * radgrad; + el_Obj_Pattern pattern; + } el_Paint; + + /*! + @typedef el_Attribute + The rendering attribute definition. + */ + typedef struct { + ELM_QUALITY quality; + ELM_BLEND blend; + ELM_EVO_FILL fill_rule; + el_Paint paint; + el_Transform transform; + } el_Attribute; + + /*! + @typedef el_EVOData + The data definition for EVO (vector object). + */ + typedef struct { + vg_lite_path_t path; + } el_EVOData; + + /*! + @typedef el_Obj_EVO + EVO (Elementry Vector Object) type definition. + */ + typedef struct { + el_Object object; + el_Attribute attribute; + el_Attribute defaultAttrib; + el_EVOData data; + uint32_t has_pattern; + uint32_t is_pattern; + uint32_t is_image; + char eboname[20]; + uint32_t img_width; + uint32_t img_height; + } el_Obj_EVO; + + /*! + @typedef el_EBOData + The data definition for EBO (bitmap object). + */ + typedef struct { + vg_lite_buffer_t buffer; + } el_EBOData; + + /*! + @typedef el_Obj_EBO + EBO (Elementry Buffer Object) type definition. + */ + typedef struct { + el_Object object; + el_Attribute attribute; + el_Attribute defaultAttrib; + el_EBOData data; + uint32_t clut_count; + uint32_t clut[256]; + } el_Obj_EBO; + + /*! + @typedef el_GroupData + The group object data definition. + */ + typedef struct { + unsigned int count; + el_Obj_EVO * objects; + } el_GroupData; + + /*! + @typedef el_Obj_Group + Group object type definition. + */ + typedef struct { + el_Object object; + el_Transform transform; + el_Transform defaultTrans; + el_GroupData group; + } el_Obj_Group; + + /*! + @typedef el_Obj_Buffer + The render buffer object definition. + */ + typedef struct { + el_Object object; + vg_lite_buffer_t buffer; + } el_Obj_Buffer; + + /*! + @typedef el_ObjList + List to organize objects. + */ + typedef struct _object_list{ + el_Object *object; + struct _object_list *next; + } el_ObjList; + + /*! + @typedef ElmRenderBuffer + The ElmRenderBuffer definition. + */ + typedef struct elm_render_buffer { + ElmBuffer handle; + vg_lite_buffer_t *buffer; + } ElmRenderBuffer; + + /*! + @typedef el_Context + The context object for global data management. + !version UXDK version + !currentHandle The current handle for new object + !objectCount Count of all objects + !object_slots List array to manage objects + */ + typedef struct { + uint32_t version; + int reference; + ElmHandle currentHandle; + unsigned int objectCount; + el_ObjList *object_slots[SLOT_COUNT]; + ElmRenderBuffer elmFB[APP_BUFFER_COUNT]; + /* VGLite related states. */ + uint32_t tessellation_width; + uint32_t tessellation_height; + + /* The current vector index (within a group). */ + int32_t vector_id; + +#if (RTOS && DDRLESS) || BAREMETAL + /* Static object pools. */ + el_Obj_Grad objpool_grad[OBJCOUNT_GRAD]; + el_Obj_EVO objpool_evo[OBJCOUNT_EVO]; + el_Obj_EBO objpool_ebo[OBJCOUNT_EBO]; + el_Obj_Group objpool_group[OBJCOUNT_GROUP]; + + /* The allocation map table. + * Each bit in the element maps to the usage of the object. + * 0 means free, 1 means allocated. + * The mapping order is 01234567...31 (hi -> low) in big endian systems. + * */ + int32_t objmap_grad[(OBJCOUNT_GRAD + 31) / 32]; + int32_t objmap_evo[(OBJCOUNT_EVO + 31) / 32]; + int32_t objmap_ebo[(OBJCOUNT_EBO + 31) / 32]; + int32_t objmap_group[(OBJCOUNT_GROUP + 31) / 32]; + + int objcounter_grad; + int objcounter_evo; + int objcounter_ebo; + int objcounter_group; +#endif + } el_Context; + + /*! + @typedef elm_tls_t + The elm_tls_t definition. + */ + typedef struct vglite_elm_tls { + el_Context gContext; + } elm_tls_t; + + /* + API function prototypes. + */ + int add_object (el_Object *object); + int remove_object (el_Object *object); + el_Object *get_object (ElmHandle handle); + +#ifdef __cplusplus +} +#endif +#endif /* VELM_H_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_debug.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_debug.c new file mode 100644 index 0000000000..458dc51f75 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_debug.c @@ -0,0 +1,317 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright 2020 NXP +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +/** Include Files */ +#include +#include +#include "vg_lite_text.h" +#include "vft_draw.h" +#include "vft_debug.h" + +#ifdef ENABLE_DEBUG_TRACE + +/** Macros */ + +/** Data structures */ +typedef enum path_type { + PATH_DONE, + PATH_CLOSE, + MOVE_TO, + MOVE_TO_REL, + LINE_TO, + LINE_TO_REL, + QUAD_TO, + QUAD_TO_REL, + CUBI_TO, + CUBI_TO_REL, + NUM_PATH_CMD +} path_type_t; + +/** Internal or external API prototypes */ + +/** Globals */ +static const int data_count[] = +{ + 0, + 0, + 2, + 2, + 2, + 2, + 4, + 4, + 6, + 6 +}; + +static char s_cmd_name[][16] = +{ + {"PATH_DONE" }, + {"PATH_CLOSE" }, + {"MOVE_TO" }, + {"MOVE_TO_REL" }, + {"LINE_TO" }, + {"LINE_TO_REL" }, + {"QUAD_TO" }, + {"QUAD_TO_REL" }, + {"CUBI_TO" }, + {"CUBI_TO_REL" }, + {"NUM_PATH_CMD"}, +}; + + +/** Externs if any */ + +/** Code section */ +void vfg_dbg_path_data(path_desc_t* path_data_desc, int offset) +{ + float* draw_cmds; + + draw_cmds = &path_data_desc->draw_cmds[0]; + + for (int i = 0; i < path_data_desc->num_draw_cmds; i++) { + uint32_t cmd, j; + + cmd = *((uint32_t*)(&draw_cmds[i])); + if (cmd < NUM_PATH_CMD) { + TRACE_BIN(("BIN: %08x: %s(%d) [", + offset + i * 4, + s_cmd_name[cmd], cmd)); + for (j = 0; j < data_count[cmd]; j++) { + TRACE_BIN((" %.2f", draw_cmds[i + j + 1])); + } + i += j; + TRACE_BIN(("]\n")); + } + } +} + +void vft_dbg_path(char *prefix, void *draw_cmds_args, int num_draw_cmds) +{ + float* draw_cmds; + + draw_cmds = draw_cmds_args; + int offset = 0; + for (int i = 0; i < num_draw_cmds; i++) { + uint32_t cmd, j; + + cmd = *((uint32_t*)(&draw_cmds[i])); + if (cmd < NUM_PATH_CMD) { + printf("BIN: %08x: %s(%d) [", + offset + i * 4, + s_cmd_name[cmd], cmd); + for (j = 0; j < data_count[cmd]; j++) { + printf(" %.2f", draw_cmds[i + j + 1]); + } + i += j; + printf("]\n"); + } + } +} + +void vft_dbg_path_bounds(char *name, float *ary, int num_elements) +{ + float* array_data; + + array_data = ary; + printf("%s [",name); + for (int i = 0; i < num_elements; i++) { + printf(" %.2f", array_data[i]); + } + printf("]\n"); +} + +void vft_dbg_kern_desc(kern_desc_t* kern_desc, int num_kern_entries, int offset) +{ + for (int i = 0; i < num_kern_entries; i++) { + TRACE_BIN(("BIN: %08x: [%d] (u,k)=(%hu, %hu)\n", + (int)(offset + i * sizeof(kern_desc_t)), + i, + kern_desc[i].unicode, + kern_desc[i].kern)); + } +} +void vft_dbg_glyph_desc(glyph_desc_t* g, int offset) +{ + glyph_desc_t _desc = *g; /* Temporary copy descriptor*/ + + TRACE_BIN_FIELD_UINT16(unicode); + TRACE_BIN_FIELD_UINT16(horiz_adv_x); + TRACE_BIN_FIELD_UINT32(kern_num_entries); + TRACE_BIN_FIELD_UINT32(kern_table_offset); + TRACE_BIN_FIELD_FLOAT(path.bounds[0]); + TRACE_BIN_FIELD_FLOAT(path.bounds[1]); + TRACE_BIN_FIELD_FLOAT(path.bounds[2]); + TRACE_BIN_FIELD_FLOAT(path.bounds[3]); + TRACE_BIN_FIELD_UINT32(path.num_draw_cmds); + TRACE_BIN_FIELD_UINT32(path.draw_cmds_offset); + +} + +/* TRACE values for debugging purpose */ +void vft_dbg_font_face_desc(font_face_desc_t* font_face, int offset) +{ + font_face_desc_t _desc = *font_face; /* Temporary copy descriptor*/ + + TRACE_INFO(("font-face-block\n")); + + TRACE_BIN_FIELD_STR(font_family_name); offset += sizeof(_desc.font_family_name); + TRACE_BIN_FIELD_UINT16(units_per_em); + TRACE_BIN_FIELD_UINT16(ascent); + TRACE_BIN_FIELD_UINT16(descent); + TRACE_BIN_FIELD_UINT16(vg_font); + TRACE_BIN_FIELD_UINT32(num_glyphs); +} + +void vft_dbg_matrix(char *name, vg_lite_matrix_t *mat) +{ + printf("%s\n",name); + printf(" %0.3f %0.3f %0.3f\n", + mat->m[0][0],mat->m[0][1],mat->m[0][2]); + printf(" %0.3f %0.3f %0.3f\n", + mat->m[1][0],mat->m[1][1],mat->m[1][2]); + printf(" %0.3f %0.3f %0.3f\n", + mat->m[2][0],mat->m[1][1],mat->m[2][2]); +} + +void vft_dbg_path_table(font_face_desc_t* font_face, int offset) +{ + TRACE_INFO(("path-block\n")); + for (uint32_t i = 0; i < font_face->num_glyphs; i++) { + glyph_desc_t* g = &font_face->glyphs[i]; + TRACE_BIN(("Glyph - path: '%c' unicode = %d\n", g->unicode, g->unicode)); + offset = g->path.draw_cmds_offset; + vfg_dbg_path_data(&g->path, offset); + } +} + +void vft_dbg_kern_table(font_face_desc_t* font_face, int offset) +{ + TRACE_INFO(("kern-block\n")); + for (uint32_t i = 0; i < font_face->num_glyphs; i++) { + glyph_desc_t* g = &font_face->glyphs[i]; + + TRACE_INFO(("Kern: '%c' unicode=%hu\n", g->unicode, g->unicode)); + + vft_dbg_kern_desc(&g->kern_table[0], + g->kern_num_entries, + offset); + offset += (g->kern_num_entries * sizeof(kern_desc_t)); + } +} + +void vft_dbg_glyph_table(font_face_desc_t* font_face, int offset) +{ + TRACE_INFO(("glyph-block\n")); + for (uint32_t i = 0; i < font_face->num_glyphs; i++) { + glyph_desc_t* g = &font_face->glyphs[i]; + TRACE_INFO(("Glyph: '%c'\n", g->unicode)); + vft_dbg_glyph_desc(g, offset); + offset += sizeof(glyph_desc_t); + } +} + +int g_offset = 0; + +void dbg_float_ary(char *name, float *ary, int count, int *disk_offset) +{ + int i; + int offset = *disk_offset; + for (i=0; iparam[0], count, &g_offset); + +#define DBG_INT_ARY(obj, param, count) \ + dbg_int_ary(#param, obj->param, count, &g_offset); + +#define DBG_FIELD(obj, param) \ + dbg_int_param(#param, obj->param, &g_offset) + +#define DBG_READ_32B(name, value, offset) \ + dbg_int_param_no_offset_update(name, value, offset) +extern int g_offset; + +#define VFT_DBG_FONT_FACE_DESC(a,b) vft_dbg_font_face_desc(a,b) +#define VFT_DBG_GLYPH_TABLE(a,b) vft_dbg_glyph_table(a,b) +#define VFT_DBG_KERN_TABLE(a,b) vft_dbg_kern_table(a,b) +#define VFT_DBG_PATH_TABLE(a,b) vft_dbg_path_table(a,b) + +static int g_offset = 0; /* Dummy just to solve build errors */ +#define DBG_TRACE(x) +#define DBG_INC_OFFSET(x) g_offset += (x); +#define DBG_OFFSET() (g_offset) + +/* Prorotypes */ +void vft_dbg_font_face_desc(font_face_desc_t* font_face, int offset); +void vft_dbg_glyph_desc(glyph_desc_t* g, int offset); +void vft_dbg_kern_desc(kern_desc_t* kern_desc, int num_kern_entries, int offset); +void vfg_dbg_path_data(path_desc_t* path_data_desc, int offset); +void vft_dbg_matrix(char *name, vg_lite_matrix_t *mat); +void vft_dbg_path_table(font_face_desc_t* font_face, int offset); +void vft_dbg_kern_table(font_face_desc_t* font_face, int offset); +void vft_dbg_glyph_table(font_face_desc_t* font_face, int offset); + +void dbg_float_ary_no_offset_update(char *name, float *ary, + int count, int disk_offset); +void dbg_int_ary_no_offset_update(char *name, uint32_t *ary, + int count, int disk_offset); +void dbg_int_param_no_offset_update(char *name, uint32_t value, int disk_offset); + +#else +/** Without -debug configuration */ +/* Macros */ +#define TRACE_DBG(x) +#define TRACE_BIN(x) +#define TRACE_WRN(x) printf x +#define TRACE_INFO(x) +#define TRACE_ERR(x) printf x + +#define DBG_READ_32B(a,b,c) +#define DBG_TRACE(x) +#define vft_dbg_glyph_desc(g,offset) +#define dbg_float_ary_no_offset_update(a, b, c,d) +#define dbg_int_ary_no_offset_update(a, b, c,d) +#define vft_dbg_path_bounds(a,b,c) +#define vft_dbg_path(a,b,c) + +#define VFT_DBG_FONT_FACE_DESC(a,b) +#define VFT_DBG_GLYPH_TABLE(a,b) +#define VFT_DBG_KERN_TABLE(a,b) +#define VFT_DBG_PATH_TABLE(a,b) + +#define DBG_INC_OFFSET(x) +#define DBG_OFFSET() (0) + +#endif + +#define TRACE_BIN_FIELD_STR(x) TRACE_BIN(("BIN: %08x: "#x"=%s\n",offset,_desc.x)); +#define TRACE_BIN_FIELD_UINT16(x) TRACE_BIN(("BIN: %08x: "#x"=%hu\n",offset,_desc.x)); offset += 2; +#define TRACE_BIN_FIELD_UINT32(x) TRACE_BIN(("BIN: %08x: "#x"=%u\n",offset,_desc.x)); offset += 4; +#define TRACE_BIN_FIELD_FLOAT(x) TRACE_BIN(("BIN: %08x: "#x"=%f\n",offset,_desc.x)); offset += 4; + diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_draw.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_draw.c new file mode 100644 index 0000000000..6c17192083 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_draw.c @@ -0,0 +1,463 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright 2020 NXP +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +/** Include Files */ +#include +#include +#include +#include "vg_lite.h" +#include "vg_lite_text.h" +#include "vft_draw.h" +#include "vft_debug.h" + +#include "rtthread.h" + +/** Macros */ +#define VFT_ALLOC(x) _mem_allocate(x) +#define VFT_FREE(x) _mem_free(x) +#define READ_BIN_FIELD(x) memcpy(&g->x, (buf + offset), sizeof(g->x)); offset += sizeof(g->x) +#define READ_BIN_FIELD_STR(x) READ_BIN_FIELD(x) +#define READ_BIN_FIELD_UINT16(x) READ_BIN_FIELD(x) +#define READ_BIN_FIELD_UINT32(x) READ_BIN_FIELD(x) +#define READ_BIN_FIELD_FLOAT(x) READ_BIN_FIELD(x) +#define READ_BIN_FIELD_DUMMY_POINTER(x) offset += 4; +#define GLYPH_CACHE_SIZE 16 +#define ENABLE_TEXT_WRAP 0 +#define HALT_ALLOCATOR_ERROR 1 + +/** Data structures */ +typedef struct glyph_cache_desc { + vg_lite_path_t *h_path; + glyph_desc_t *g; + uint32_t use_count; +}glyph_cache_desc_t; + +/** Internal or external API prototypes */ + +/** Globals */ +static int g_glyph_cache_init_done = 0; +static glyph_cache_desc_t g_glyph_cache[GLYPH_CACHE_SIZE]; +int g_total_bytes = 0; + +/** Externs if any */ + +/* Internal API, not published to user */ +font_face_desc_t *_vg_lite_get_vector_font(vg_lite_font_t font_idx); +void matrix_multiply(vg_lite_matrix_t * matrix, vg_lite_matrix_t *mult); + +void *_mem_allocate(int size) +{ + char *buf = NULL; + + if ( size == 0 ) { + printf("ERROR: HALT: Why allocating %d bytes\n", size); +#if HALT_ALLOCATOR_ERROR + while(1); +#else + return NULL; +#endif + } + + buf = rt_malloc(size); + if (buf == NULL) { + printf("ERROR: HALT: allocating %d bytes \"system out of memory\"\n", size); +#if HALT_ALLOCATOR_ERROR + while(1); +#else + return NULL; +#endif + } + g_total_bytes += size; + return buf; +} + +void _mem_free(void *buf) +{ + rt_free(buf); +} + +/** GLYPH CACHING Code */ +void glyph_cache_init(void) +{ + if ( g_glyph_cache_init_done == 0 ) { + memset(g_glyph_cache,0,sizeof(g_glyph_cache)); + g_glyph_cache_init_done = 1; + } +} + +void glyph_cache_free(void) +{ + int i; + for (i=0; iunicode == + g_glyph_cache[i].g->unicode ) + { + g_glyph_cache[i].use_count++; + return g_glyph_cache[i].h_path; + } + } + + /* Find least used descriptor */ + unused_idx = 0; + for (i=1; ipath.num_draw_cmds*4, + g->path.draw_cmds, + g->path.bounds[0], + g->path.bounds[1], + g->path.bounds[2], + g->path.bounds[3]); + g_glyph_cache[unused_idx].g = g; + g_glyph_cache[unused_idx].use_count = 1; + return g_glyph_cache[unused_idx].h_path; +} + +/** Render text using vector fonts */ +int vg_lite_vtf_draw_text(vg_lite_buffer_t *rt, int x, int y, + vg_lite_blend_t blend, + vg_lite_font_t font, + vg_lite_matrix_t *matrix, + vg_lite_font_attributes_t * attributes, + char *text) +{ + font_face_desc_t *font_face; + glyph_desc_t* g1 = NULL; + glyph_desc_t* g2; + int error = 0; + float font_scale = 1.0; + int text_wrap = 0; + + font_face = (font_face_desc_t *)_vg_lite_get_vector_font(font); + + attributes->last_dx = 0; + font_scale = ((1.0*attributes->font_height)/font_face->units_per_em); + + vg_lite_matrix_t mat; + + vg_lite_fill_t fill_rule = VG_LITE_FILL_NON_ZERO; + vg_lite_color_t color = attributes->text_color; + + /* Compute size of tex in pixels + * For center alignment adjust x position + * Present parser has bug in encoding alignment value, + * Once it is fixed following code will align text in center + */ + if ( attributes->alignment == eTextAlignCenter || + attributes->alignment == eTextAlignRight ) { + char *t2 = text; + int dx = 0; + uint16_t ug2; /* Unicode glyph */ + int kx; + + /* Case of center alignement */ + while (*t2 != '\0') { + ug2 = *t2; + kx = 0; + g2 = vft_find_glyph(font_face, ug2); + if (g1 != NULL && g2 != NULL) { + kx = vft_glyph_distance(g1, g2); + } + + dx += ((g2->horiz_adv_x + kx )* font_scale); + t2++; + } + + if ( attributes->alignment == eTextAlignCenter) { + x -= (dx/2); + } else if ( attributes->alignment == eTextAlignRight) { + x -= (dx); + } + } + + /* Compute pixels that will cover this vector path */ + while (*text != '\0') { + uint16_t ug2; /* Unicode glyph */ + int kx; + + if (text_wrap == 0) { + vg_lite_identity(&mat); + matrix_multiply(&mat, matrix); + vg_lite_translate(x,y, &mat); + vg_lite_scale(font_scale,font_scale, &mat); // 0.35 = height/units_per_em + vg_lite_scale(-1.0,1.0, &mat); + vg_lite_scale(-1.0,-1.0, &mat); + text_wrap = 1; + } + + /* Read unicode character */ + kx = 0; + ug2 = *text; + g2 = vft_find_glyph(font_face, ug2); + if (g1 != NULL && g2 != NULL) { + kx = vft_glyph_distance(g1, g2); + } + +#if (ENABLE_TEXT_WRAP==1) + /* Wrap text */ + if ( (x + attributes->last_dx + ((g2->horiz_adv_x + kx )* font_scale)) + >= (720 - 5) ) + { + text_wrap = 0; + attributes->last_dx = 0; + y += (attributes->font_height + 1); + continue; + } +#endif /* ENABLE_TEXT_WRAP */ + + /* Compute glyph size in horizontal dimension */ + g1 = g2; + text++; + + error = vg_lite_draw(rt, vft_cache_lookup(g2), + fill_rule, + &mat, + blend, + color); + if ( error != VG_LITE_SUCCESS ) { + break; + } + + vg_lite_translate(g2->horiz_adv_x + kx, 0, &mat); + attributes->last_dx += ((g2->horiz_adv_x + kx )* font_scale); + } + + attributes->last_dx += 2; /* Space between 2 text strings */ + + return 0; +} + +void load_font_face(font_face_desc_t* font_face, uint8_t* buf, int font_face_offset) +{ + font_face_desc_t* g = font_face; + int offset = font_face_offset; + + READ_BIN_FIELD_STR(font_family_name); + READ_BIN_FIELD_UINT16(units_per_em); + READ_BIN_FIELD_UINT16(ascent); + READ_BIN_FIELD_UINT16(descent); + READ_BIN_FIELD_UINT16(vg_font); + READ_BIN_FIELD_UINT32(num_glyphs); +} + +void load_glyph_table(font_face_desc_t* font_face, uint8_t* buf, int glyph_table_offset) +{ + int offset = glyph_table_offset; + + for (uint32_t i = 0; i < font_face->num_glyphs; i++) { + glyph_desc_t* g = &font_face->glyphs[i]; + + memset(g, 0, sizeof(glyph_desc_t)); + READ_BIN_FIELD_UINT16(unicode); + READ_BIN_FIELD_UINT16(horiz_adv_x); + READ_BIN_FIELD_UINT32(kern_num_entries); + READ_BIN_FIELD_UINT32(kern_table_offset); + READ_BIN_FIELD_DUMMY_POINTER(); + READ_BIN_FIELD_FLOAT(path.bounds[0]); + READ_BIN_FIELD_FLOAT(path.bounds[1]); + READ_BIN_FIELD_FLOAT(path.bounds[2]); + READ_BIN_FIELD_FLOAT(path.bounds[3]); + READ_BIN_FIELD_UINT32(path.num_draw_cmds); + READ_BIN_FIELD_UINT32(path.draw_cmds_offset); + READ_BIN_FIELD_DUMMY_POINTER(); + + font_face->glyphs[i].kern_table = (kern_desc_t *)(buf + font_face->glyphs[i].kern_table_offset); + font_face->glyphs[i].path.draw_cmds = (float *)(buf + font_face->glyphs[i].path.draw_cmds_offset); + + TRACE_INFO(("Glyph: '%c'\n", g->unicode)); + vft_dbg_glyph_desc(g, d_offset); + } +} + +/* Load vector font ROM table from file */ +font_face_desc_t* vft_load_from_buffer(char* buf_base, int file_size) +{ + font_face_desc_t* font_face = NULL; + uint32_t* blk_hdr; + //int error = 0; + + /* Setup internal memory pointers of font_face_desc_t */ + int font_face_offset = 0; + int glyph_table_offset = 0; + //int kern_table_offset = 0; + //int path_data_offset = 0; + int offset = 0; + + /* May be we can avoid this lookup */ + while (offset < file_size) { + blk_hdr = (uint32_t*)(buf_base + offset); + eFontBlock_t eType = (eFontBlock_t)((*blk_hdr) >> 24); + int size = ((*blk_hdr) & ((1<<24)-1)); + TRACE_BIN(("BIN: %08x: block(%hu, %hu)\n", + offset, eType, size)); + offset += BLK_HDR_SIZE; + + /* Check integrity of block and then only proceed */ + switch (eType) { + case eFontFaceDesc: + font_face_offset = offset; + break; + case eGlyphTableDesc: + glyph_table_offset = offset; + break; + case eKernTableDesc: + //kern_table_offset = offset; + break; + case eGlyphData: + //path_data_offset = offset; + break; + default: + case eUnkBlock: + case eMaxBlock: + return NULL;; + } + offset += size; + } + + if (offset < 0 || offset > file_size) { + printf("ERROR: Vector font file integrity error aborting..\n"); + return NULL; + } + + /* Make structure binary compliant to reduce loading time */ + font_face = (font_face_desc_t*)(buf_base + font_face_offset); + font_face->glyphs = (glyph_desc_t*)(buf_base + glyph_table_offset); + + VFT_DBG_FONT_FACE_DESC(font_face, font_face_offset); + for (uint32_t i = 0; i < font_face->num_glyphs; i++) { + /* Update internal pointer from memory mapped file */ + font_face->glyphs[i].kern_table = + (kern_desc_t*)(buf_base + font_face->glyphs[i].kern_table_offset); + font_face->glyphs[i].path.draw_cmds = + (float*)(buf_base + + font_face->glyphs[i].path.draw_cmds_offset); + /* Try to get these paramters from Binary object or attributes */ + //vg_lite_format_t data_format = VG_LITE_FP32; //VG_LITE_S16; + //vg_lite_quality_t quality = VG_LITE_HIGH; + } + VFT_DBG_GLYPH_TABLE(font_face, glyph_table_offset); + + VFT_DBG_KERN_TABLE(font_face, kern_table_offset); + VFT_DBG_PATH_TABLE(font_face, path_data_offset); + + return font_face; +} + +/* Find glyph of given character from glyph table */ +glyph_desc_t* vft_find_glyph(font_face_desc_t* font_face, uint16_t ug2) +{ + const int num_glyphs = font_face->num_glyphs; + glyph_desc_t* glyphs = font_face->glyphs; + + /* + * Present approach is slow linear search, this is ok in 1st prototype + * Since glyph table is already sorted, we can have binary search + */ + for (int i = 0; i < num_glyphs; i++) { + if (glyphs[i].unicode == ug2) { + return (glyph_desc_t*)&glyphs[i]; + } + } + return (glyph_desc_t*)&glyphs[0];; +} + +/* Find distance between 2 glyph symbols */ +int vft_glyph_distance(glyph_desc_t* g1, glyph_desc_t* g2) +{ + signed short kx = 0; + uint16_t ug2 = g2->unicode; + kern_desc_t* kern_table = &g1->kern_table[0]; + + for (int i = 0; i < g1->kern_num_entries; i++) { + if (kern_table[i].unicode == ug2) { + signed short *pkx = (signed short *)&kern_table[i].kern; + kx = *pkx; + break; + } + } + + return kx; +} + +/* +* Get internal vector path of given glyph +* This is internal function +*/ +path_desc_t* vft_get_glyph_path(glyph_desc_t* g2) +{ + return &g2->path; +} + +/* Unload font face descriptor and all glyphs */ +void vft_unload(font_face_desc_t* font_face) +{ + glyph_cache_free(); + //VFT_FREE(font_face); +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_draw.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_draw.h new file mode 100644 index 0000000000..716b777a1c --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_draw.h @@ -0,0 +1,119 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright 2020 NXP +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#ifndef _VFT_DRAW_H +#define _VFT_DRAW_H + +#include + +typedef enum eFontBlkType { + eUnkBlock, + eFontFaceDesc, + eGlyphTableDesc, + eKernTableDesc, + eGlyphData, + eMaxBlock +}eFontBlock_t; + +static const int32_t BLK_HDR_SIZE = 4; + +typedef struct path_descriptor { + float bounds[4]; + uint32_t num_draw_cmds; + uint32_t draw_cmds_offset; + float* draw_cmds; /* NOTE: this will be used while loading table, DONT REMOVE */ +}path_desc_t; + +typedef struct kern_desc { + uint16_t unicode; + uint16_t kern; +}kern_desc_t; + +typedef struct glyph_descriptor { + uint16_t unicode; /* unicode name */ + uint16_t horiz_adv_x; /* Short to align to 32-bit boundry */ + uint32_t kern_num_entries; + uint32_t kern_table_offset; + kern_desc_t* kern_table; /* NOTE: this will be used while loading table, DONT REMOVE */ + path_desc_t path; +}glyph_desc_t; + +typedef struct font_face_info { + int8_t font_family_name[64]; + uint16_t units_per_em; + uint16_t ascent; + uint16_t descent; + uint16_t vg_font; + uint32_t num_glyphs; + glyph_desc_t* glyphs; /* NOTE: this will be used while loading table, DONT REMOVE */ +}font_face_desc_t; + +//NOTE: No glyph caching at this time + +/* Load vector font ROM table from file */ +font_face_desc_t* vft_load(char* vcft_file_path); + +/* Find glyph of given character from glyph table */ +glyph_desc_t* vft_find_glyph(font_face_desc_t* font_face, uint16_t ug2); + +/* Find distance between 2 glyph symbols */ +int vft_glyph_distance(glyph_desc_t* g1, glyph_desc_t* g2); + +/* +* Get internal vector path of given glyph +* This is internal function +*/ +path_desc_t* vft_get_glyph_path(glyph_desc_t* g2); + +/* Draw vector font based glyph on given x,y co-ordinate */ +void vft_draw_glyph(int x, int y, glyph_desc_t* g2); + +/* Compute horizotal pixels coverted by this path */ +int vft_compute_dx(glyph_desc_t* g2); + +/* Unload font face descriptor and all glyphs */ +void vft_unload(font_face_desc_t*); + +/* Draw string with vector font s*/ +int vg_lite_vtf_draw_text(vg_lite_buffer_t *rt, int x, int y, + vg_lite_blend_t blend, + vg_lite_font_t font, + vg_lite_matrix_t *matrix, + vg_lite_font_attributes_t * attributes, + char *text); + +/* Internal memory allocator API */ +void *_mem_allocate(int size); +void _mem_free(void *buf); + +vg_lite_error_t vg_lite_load_font_data(vg_lite_font_t font, int font_height); +font_face_desc_t* vft_load_from_buffer(char* buf_base, int file_size); +void vg_lite_unload_font_data(void); + +#endif //!_VFT_DRAW_H diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite.c new file mode 100644 index 0000000000..e51b0edb3d --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite.c @@ -0,0 +1,10894 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright 2012 - 2020 Vivante Corporation, Santa Clara, California. +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "vg_lite.h" +#include "vg_lite_kernel.h" +#if !defined(VG_DRIVER_SINGLE_THREAD) +#include "vg_lite_os.h" +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ +#if (VG_RENDER_TEXT==1) +#include "vg_lite_text.h" +#endif /* VG_RENDER_TEXT */ +#include "vg_lite_flat.h" + +/* + * Stop IAR compiler from warning about implicit conversions from float to + * double + */ +#if (defined(__ICCARM__)) +#pragma diag_suppress = Pa205 +#endif + +/* This is the function to call from the VGLite driver to interface with the GPU. */ +vg_lite_error_t vg_lite_kernel(vg_lite_kernel_command_t command, void * data); + + +/*** Command buffer dump ***/ +#ifndef DUMP_COMMAND +#define DUMP_COMMAND 0 +#endif + +#ifndef DUMP_IMAGE +#define DUMP_IMAGE 0 + +#else +#ifndef DUMP_COMMAND +#define DUMP_COMMAND 0 +#endif + +#ifndef DUMP_IMAGE +#define DUMP_IMAGE 0 +#endif +#endif + +#define VG_TARGET_FC_DUMP 0 + +/* Fast clear is not used by default,if SOC should use this ,set this macro to 1. */ +#ifndef VG_TARGET_FAST_CLEAR + #define VG_TARGET_FAST_CLEAR 0 +#endif /* VG_TARGET_FAST_CLEAR */ + +#if DUMP_COMMAND || DUMP_IMAGE +#ifdef __linux__ +#include +#endif +#endif + +#if defined(VG_DRIVER_SINGLE_THREAD) +/*** Global Context Access ***/ +#define GET_CONTEXT() &s_context +#endif /* VG_DRIVER_SINGLE_THREAD */ + +/*** Command buffer configurations, double buffer support ***/ +#define VG_LITE_COMMAND_BUFFER_SIZE (64 << 10) +#define CMDBUF_BUFFER(context) (context).command_buffer[(context).command_buffer_current] +#define CMDBUF_INDEX(context) (context).command_buffer_current +#define CMDBUF_SIZE(context) (context).command_buffer_size +#define CMDBUF_OFFSET(context) (context).command_offset[(context).command_buffer_current] +#define CMDBUF_SWAP(context) (context).command_buffer_current = \ + ((context).command_buffer_current + 1) % CMDBUF_COUNT + +#if !defined(VG_DRIVER_SINGLE_THREAD) +#ifndef CMDBUF_IN_QUEUE +#define CMDBUF_IN_QUEUE(context, id) \ + (vg_lite_os_event_state(&(context)->async_event[(id)]) == VG_LITE_IN_QUEUE) +#endif + +#define RESERVE_BYTES_IN_CMDBUF(context) \ + {\ + ((uint32_t *) (CMDBUF_BUFFER((context)) + CMDBUF_OFFSET((context))))[0] = VG_LITE_STATE(0x0a00);\ + ((uint32_t *) (CMDBUF_BUFFER((context)) + CMDBUF_OFFSET((context))))[1] = 0;\ + CMDBUF_OFFSET((context)) += 8;\ + } +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +#define VG_LITE_RETURN_ERROR(func) \ +if ((error = func) != VG_LITE_SUCCESS) \ +return error + +#define VG_LITE_BREAK_ERROR(func) \ +if ((error = func) != VG_LITE_SUCCESS) \ +break + +#define VG_LITE_ERROR_HANDLER(func) \ +if ((error = func) != VG_LITE_SUCCESS) \ +goto ErrorHandler + +/*** Command macros ***/ + +#define VG_LITE_END(interrupt) (0x00000000 | interrupt) +#define VG_LITE_SEMAPHORE(id) (0x10000000 | id) +#define VG_LITE_STALL(id) (0x20000000 | id) +#define VG_LITE_STATE(address) (0x30010000 | address) +#define VG_LITE_STATES(count, address) (0x30000000 | ((count) << 16) | address) +#define VG_LITE_DATA(count) (0x40000000 | count) +#define VG_LITE_CALL(count) (0x60000000 | count) +#define VG_LITE_RETURN() (0x70000000) +#define VG_LITE_NOP() (0x80000000) + +/*** Shortcuts. ***/ +#define A(color) (color) >> 24 +#define R(color) ((color) & 0x00ff0000) >> 16 +#define G(color) ((color) & 0x0000ff00) >> 8 +#define B(color) ((color) & 0xff) +#define ARGB(a, r, g, b) ((a) << 24) | ((r) << 16) | ((g) << 8 ) | (b) +#define ARGB4(a, r, g, b) (((a) & 0xf0) << 8) | (((r) & 0xf0) << 4) | (((g) & 0xf0)) | ((b) >> 4) + +#define FC_BURST_BYTES 64 +#define FC_BIT_TO_BYTES 64 + +#define MIN(a, b) ((a) > (b) ? (b) : (a)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +static uint32_t command_buffer_size = VG_LITE_COMMAND_BUFFER_SIZE; + +#define FORMAT_ALIGNMENT(stride,align) \ + { \ + if((stride) % (align) != 0) \ + return VG_LITE_INVALID_ARGUMENT; \ + return VG_LITE_SUCCESS; \ + } + +#define DEST_ALIGNMENT_LIMITATION 64 /* To match hardware alignment requirement */ +#if !defined(VG_DRIVER_SINGLE_THREAD) +#define TS_STATE_COUNT 20 /* Initial state count for tessellation buffer. */ +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +#define MATRIX_ROWS 3 +#define GET_MATRIX_VALUES(Pointer) ((float *) (Pointer)) +#define MAT(Matrix, Row, Column) (GET_MATRIX_VALUES(Matrix)[Row * MATRIX_ROWS + Column]) + +#define COLOR_FROM_RAMP(ColorRamp) (((vg_lite_float_t *) ColorRamp) + 1) +#define CLAMP(x, min, max) (((x) < (min)) ? (min) : \ + ((x) > (max)) ? (max) : (x)) +#define LERP(v1, v2, w) ((v1) * (w) + (v2) * (1.0f - (w))) + +#define PI 3.141592653589793238462643383279502f +#define SINF(x) ((vg_lite_float_t) sin(x)) +#define COSF(x) ((vg_lite_float_t) cos(x)) +#define FABSF(x) ((vg_lite_float_t) fabs(x)) +#define SQRTF(x) ((vg_lite_float_t) sqrt(x)) +#define CLAMP(x, min, max) (((x) < (min)) ? (min) : \ + ((x) > (max)) ? (max) : (x)) +#define ACOSF(x) ((vg_lite_float_t) acos(x)) +#define FMODF(x, y) ((vg_lite_float_t) fmod((x), (y))) +#define CEILF(x) ((vg_lite_float_t) ceil(x)) +#define FALSE 0 +#define TURE 1 +#define SIZEOF(a) \ +( \ + (size_t) (sizeof(a)) \ +) + +typedef uintptr_t UINTPTR_T; + +#define PTR2SIZE(p) \ +( \ + (UINTPTR_T) (p) \ +) + +#define GETINCREMENT(pointer, datatype_size) \ + (datatype_size - (PTR2SIZE(pointer) & (datatype_size - 1))) + +#define SKIPTODATA(pointer, datatype_size, SIZE) \ + /* Determine the increment value. */ \ + increment = GETINCREMENT(pointer, datatype_size); \ + /* Skip to the data. */ \ + pointer += increment; \ + SIZE -= increment + +#define VGSL_GETVALUE(X) \ + X = get_value(data_pointer); \ + data_pointer += data_type_size; \ + size -= data_type_size + +#define VGSL_GETCOORDXY(X, Y) \ + VGSL_GETVALUE(X); \ + VGSL_GETVALUE(Y); \ + if (is_relative) { X += ox; Y += oy; } + +#define FLOAT_EPSILON 0.001f + +#define SWING_NO 0 +#define SWING_OUT 1 +#define SWING_IN 2 + +/* Point curve type for generated stroke path. */ +#define CURVE_LINE 0 +#define CURVE_QUAD_CONTROL 1 +#define CURVE_QUAD_ANCHOR 2 +#define CURVE_ARC_SCCW 3 +#define CURVE_ARC_SCCW_HALF 4 + +#define FLOAT_PI 3.141592654f +#define FLOAT_PI_TWO 6.283185307f +#define FLOAT_PI_THREE_QUARTER 2.356194490f +#define FLOAT_PI_HALF 1.570796327f +#define FLOAT_PI_QUARTER 0.7853981634f +#define FLOAT_PI_EIGHTH 0.3926990817f +/* cos(PI/8) */ +#define FLOAT_COS_PI_EIGHTH 0.9238795325f + +#define centerX tangentX +#define centerY tangentY + +#define FLOAT_DIFF_EPSILON 0.125f +#define FLOAT_SWING_CENTER_RANGE 0.125f +#define FLOAT_ANGLE_EPSILON 0.0045f +#define FLOAT_ANGLE_EPSILON_COS 0.99999f +#define FLOAT_MIN_ARC_ANGLE 0.044f +#define FLOAT_MIN_ARC_ANGLE_COS 0.999f +/* Float constants. */ +#define gcvMAX_POS_FLOAT ((vg_lite_float_t) 3.4028235e+038) +#define gcvMAX_NEG_FLOAT ((vg_lite_float_t) -3.4028235e+038) +#define FLOAT_MIN gcvMAX_NEG_FLOAT +#define FLOAT_MAX gcvMAX_POS_FLOAT + +#define FLOAT_FAT_LINE_WIDTH 2.5f + +/* Point flatten type for flattened line segments. */ +#define vgcFLATTEN_NO 0 +#define vgcFLATTEN_START 1 +#define vgcFLATTEN_MIDDLE 2 +#define vgcFLATTEN_END 3 + +/* Command size calculation shortcuts. */ +#define COMMANDSIZE(CoordinateCount, CoordinateType) \ + ((1+CoordinateCount) * SIZEOF(CoordinateType)) + +#define ABS(x) (((x) < 0) ? -(x) : (x)) +#define EPS 2.2204460492503131e-14 +#if !defined(VG_DRIVER_SINGLE_THREAD) +/* VG:24 + TS:28 + IM:345 + PE:9 + RS:16 +Debug:2 */ +#define STATES_COUNT 424 +/* STATES_COUNT size + return command size */ +#define CONTEXT_BUFFER_SIZE STATES_COUNT * 2 * 4 + 8 +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +#define UPDATE_BOUNDING_BOX(bbx, point) \ + do { \ + if ((point).x < (bbx).x) { \ + (bbx).width += (bbx).x - (point).x; \ + (bbx).x = (point).x; \ + } \ + if ((point).y < (bbx).y) { \ + (bbx).height += (bbx).y - (point).y; \ + (bbx).y = (point).y; \ + } \ + if ((point).x > (bbx).x + (bbx).width) \ + (bbx).width = (point).x - (bbx).x; \ + if ((point).y > (bbx).y + (bbx).height) \ + (bbx).height = (point).y - (bbx).y; \ + } while(0) + +typedef vg_lite_float_t FLOATVECTOR4[4]; + +typedef struct vg_lite_ftable { + uint32_t ftable[gcFEATURE_COUNT]; + uint32_t ftflag; +} vg_lite_ftable_t; + +#if !defined(VG_DRIVER_SINGLE_THREAD) +typedef struct vg_lite_states { + uint32_t state; + uint8_t init; +}vg_lite_states_t; + +typedef struct vg_lite_hardware { + vg_lite_states_t hw_states[STATES_COUNT]; +} vg_lite_hardware_t; + +static vg_lite_hardware_t hw = {0}; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +typedef struct vg_lite_context { + vg_lite_kernel_context_t context; + vg_lite_capabilities_t capabilities; + uint8_t * command_buffer[CMDBUF_COUNT]; + uint32_t command_buffer_size; + uint32_t command_offset[CMDBUF_COUNT]; + uint32_t command_buffer_current; +#if !defined(VG_DRIVER_SINGLE_THREAD) + uint8_t * context_buffer[CMDBUF_COUNT]; + uint32_t context_buffer_size; + uint32_t context_buffer_offset[CMDBUF_COUNT]; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + vg_lite_tsbuffer_info_t tsbuffer; + vg_lite_buffer_t * rtbuffer; /* DDRLess: this is used as composing buffer. */ + +#if VG_TARGET_FAST_CLEAR + vg_lite_buffer_t fcBuffer; /* Buffer used for fast clear cache. */ + uint32_t clearValue; +#endif + + uint32_t scissor_enabled; +#if defined(VG_DRIVER_SINGLE_THREAD) + uint32_t scissor_dirty; /* Indicates whether scissor states are changed or not. e.g., scissors[4] or scissor_enabled. */ +#endif /* VG_DRIVER_SINGLE_THREAD */ + int32_t scissor[4]; /* Scissor area: x, y, width, height. */ + +#if !defined(VG_DRIVER_SINGLE_THREAD) + uint32_t start_offset; + uint32_t end_offset; + uint32_t ts_init; /* Indicates whether tessellation buffer states are initialized or not. */ + uint32_t ts_record[TS_STATE_COUNT]; /* Tessellation buffer initial states record. */ + uint32_t ts_init_used; + uint32_t ts_init_use; + uint32_t ts_dirty; + +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + + uint32_t chip_id; + uint32_t chip_rev; + + uint32_t premultiply_enabled; + +#if defined(VG_DRIVER_SINGLE_THREAD) + uint32_t premultiply_dirty; + uint8_t init; +#else + uint32_t semaphore_id; + + uint32_t * colors[4]; /* index colors. */ + uint32_t clut_dirty[4]; /* clut dirty flag. */ + uint32_t index_format; /* check if use index. */ + uint32_t clut_used[4]; /* check if used index. */ +#endif /* VG_DRIVER_SINGLE_THREAD */ + vg_lite_ftable_t s_ftable; +} vg_lite_context_t; + +#if !defined(VG_DRIVER_SINGLE_THREAD) +typedef struct vg_lite_tls{ + /* currently just contains struct vg_lite_context_t */ + vg_lite_context_t t_context; +}vg_lite_tls_t; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +typedef struct vg_lite_feature_database{ + uint32_t chip_id; + uint32_t chip_version; + uint32_t cid; + uint32_t vg_im_index_format:1; + uint32_t vg_pe_premultiply:1; + uint32_t vg_border_culling:1; + uint32_t vg_rgba2_format:1; + uint32_t vg_quality_8x:1; + uint32_t vg_radial_gradient:1; + uint32_t vg_linear_gradient_ext:1; + uint32_t vg_dither:1; + uint32_t vg_color_key:1; +} vg_lite_feature_database_t; + +static vg_lite_feature_database_t VGFeatureInfos[] = { + /* vg255 */ + { + GPU_CHIP_ID_GCNanoliteV, /* ChipID */ + 0x1311, /* ChipRevision */ + 0x404, /* CID */ + 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */ + 0x0, /* gcFEATURE_BIT_VG_PE_PREMULTIPLY */ + 0x1, /* gcFEATURE_BIT_VG_BORDER_CULLING */ + 0x1, /* gcFEATURE_BIT_VG_RGBA2_FORMAT */ + 0X0, /* gcFEATURE_BIT_VG_QUALITY_8X */ + 0X0, /* gcFEATURE_BIT_VG_RADIAL_GRADIENT */ + 0x0, /* gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT */ + 0x0, /* gcFEATURE_BIT_VG_DITHER */ + 0x0, /* gcFEATURE_BIT_VG_COLOR_KEY */ + }, + /* vg255 */ + { + GPU_CHIP_ID_GCNanoliteV, /* ChipID */ + 0x1311, /* ChipRevision */ + 0x40a, /* CID */ + 0x1, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */ + 0x0, /* gcFEATURE_BIT_VG_PE_PREMULTIPLY */ + 0x1, /* gcFEATURE_BIT_VG_BORDER_CULLING */ + 0x1, /* gcFEATURE_BIT_VG_RGBA2_FORMAT */ + 0X1, /* gcFEATURE_BIT_VG_QUALITY_8X */ + 0X0, /* gcFEATURE_BIT_VG_RADIAL_GRADIENT */ + 0x0, /* gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT */ + 0x0, /* gcFEATURE_BIT_VG_DITHER */ + 0x0, /* gcFEATURE_BIT_VG_COLOR_KEY */ + }, + /* vg255 */ + { + GPU_CHIP_ID_GCNanoliteV, /* ChipID */ + 0x1311, /* ChipRevision */ + 0x40b, /* CID */ + 0x1, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */ + 0x0, /* gcFEATURE_BIT_VG_PE_PREMULTIPLY */ + 0x1, /* gcFEATURE_BIT_VG_BORDER_CULLING */ + 0x1, /* gcFEATURE_BIT_VG_RGBA2_FORMAT */ + 0X1, /* gcFEATURE_BIT_VG_QUALITY_8X */ + 0X0, /* gcFEATURE_BIT_VG_RADIAL_GRADIENT */ + 0x0, /* gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT */ + 0x0, /* gcFEATURE_BIT_VG_DITHER */ + 0x0, /* gcFEATURE_BIT_VG_COLOR_KEY */ + }, + /* vg255 */ + { + GPU_CHIP_ID_GCNanoliteV, /* ChipID */ + 0x1311, /* ChipRevision */ + 0x40d, /* CID */ + 0x1, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */ + 0x0, /* gcFEATURE_BIT_VG_PE_PREMULTIPLY */ + 0x1, /* gcFEATURE_BIT_VG_BORDER_CULLING */ + 0x1, /* gcFEATURE_BIT_VG_RGBA2_FORMAT */ + 0X1, /* gcFEATURE_BIT_VG_QUALITY_8X */ + 0X0, /* gcFEATURE_BIT_VG_RADIAL_GRADIENT */ + 0x0, /* gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT */ + 0x0, /* gcFEATURE_BIT_VG_DITHER */ + 0x0, /* gcFEATURE_BIT_VG_COLOR_KEY */ + }, + /* vg255 */ + { + GPU_CHIP_ID_GCNanoliteV, /* ChipID */ + 0x1322, /* ChipRevision */ + 0x403, /* CID */ + 0x1, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */ + 0x0, /* gcFEATURE_BIT_VG_PE_PREMULTIPLY */ + 0x1, /* gcFEATURE_BIT_VG_BORDER_CULLING */ + 0x1, /* gcFEATURE_BIT_VG_RGBA2_FORMAT */ + 0X1, /* gcFEATURE_BIT_VG_QUALITY_8X */ + 0X0, /* gcFEATURE_BIT_VG_RADIAL_GRADIENT */ + 0x0, /* gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT */ + 0x0, /* gcFEATURE_BIT_VG_DITHER */ + 0x0, /* gcFEATURE_BIT_VG_COLOR_KEY */ + }, + /* vg355 */ + { + GPU_CHIP_ID_GC355, /* ChipID */ + 0x1217, /* ChipRevision */ + 0x408, /* CID */ + 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */ + 0x1, /* gcFEATURE_BIT_VG_PE_PREMULTIPLY */ + 0x0, /* gcFEATURE_BIT_VG_BORDER_CULLING */ + 0x0, /* gcFEATURE_BIT_VG_RGBA2_FORMAT */ + 0X0, /* gcFEATURE_BIT_VG_QUALITY_8X */ + 0X1, /* gcFEATURE_BIT_VG_RADIAL_GRADIENT */ + 0x1, /* gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT */ + 0x1, /* gcFEATURE_BIT_VG_DITHER */ + 0x0, /* gcFEATURE_BIT_VG_COLOR_KEY */ + }, + /* vg355 */ + { + GPU_CHIP_ID_GC355, /* ChipID */ + 0x1216, /* ChipRevision */ + 0x0, /* CID */ + 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */ + 0x1, /* gcFEATURE_BIT_VG_PE_PREMULTIPLY */ + 0x0, /* gcFEATURE_BIT_VG_BORDER_CULLING */ + 0x0, /* gcFEATURE_BIT_VG_RGBA2_FORMAT */ + 0X0, /* gcFEATURE_BIT_VG_QUALITY_8X */ + 0X1, /* gcFEATURE_BIT_VG_RADIAL_GRADIENT */ + 0x1, /* gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT */ + 0x1, /* gcFEATURE_BIT_VG_DITHER */ + 0x0, /* gcFEATURE_BIT_VG_COLOR_KEY */ + }, + /* vg355 */ + { + GPU_CHIP_ID_GC355, /* ChipID */ + 0x1215, /* ChipRevision */ + 0x0, /* CID */ + 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */ + 0x1, /* gcFEATURE_BIT_VG_PE_PREMULTIPLY */ + 0x0, /* gcFEATURE_BIT_VG_BORDER_CULLING */ + 0x0, /* gcFEATURE_BIT_VG_RGBA2_FORMAT */ + 0X0, /* gcFEATURE_BIT_VG_QUALITY_8X */ + 0X1, /* gcFEATURE_BIT_VG_RADIAL_GRADIENT */ + 0x1, /* gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT */ + 0x1, /* gcFEATURE_BIT_VG_DITHER */ + 0x1, /* gcFEATURE_BIT_VG_COLOR_KEY */ + } +}; + +#if defined(VG_DRIVER_SINGLE_THREAD) +vg_lite_context_t s_context = {0}; +#endif /* VG_DRIVER_SINGLE_THREAD */ + +#if DUMP_COMMAND +FILE * fp; +char filename[30]; +#endif + +int submit_flag = 0; + +static vg_lite_float_t _GetS8_NS_NB(int8_t * Data) +{ + int8_t x0 = *((int8_t *) Data); + vg_lite_float_t x = (vg_lite_float_t) x0; + + return x; +} + +static vg_lite_float_t _GetS16_NS_NB(int8_t * Data) +{ + int16_t x0 = *((int16_t *) Data); + vg_lite_float_t x = (vg_lite_float_t) x0; + + return x; +} + +static vg_lite_float_t _GetS32_NS_NB(int8_t * Data) +{ + int32_t x0 = *((int32_t *) Data); + vg_lite_float_t x = (vg_lite_float_t) x0; + + return x; +} + +static vg_lite_float_t _GetF_NS_NB(int8_t * Data) +{ + vg_lite_float_t x = *((vg_lite_float_t *) Data); + + return x; +} + +typedef vg_lite_float_t (* vg_value_getter) (int8_t * Data); + +typedef struct vg_lite_control_coord +{ + vg_lite_float_t startX; + vg_lite_float_t startY; + vg_lite_float_t lastX; + vg_lite_float_t lastY; + vg_lite_float_t controlX; + vg_lite_float_t controlY; +} +vg_lite_control_coord_t; + +static uint32_t _commandSize_float[] = +{ + COMMANDSIZE(0, vg_lite_float_t), /* 0: END */ + COMMANDSIZE(0, vg_lite_float_t), /* 1: CLOSE */ + COMMANDSIZE(2, vg_lite_float_t), /* 2: MOVE */ + COMMANDSIZE(2, vg_lite_float_t), /* 3: MOVE_REL */ + COMMANDSIZE(2, vg_lite_float_t), /* 4: LINE */ + COMMANDSIZE(2, vg_lite_float_t), /* 5: LINE_REL */ + COMMANDSIZE(4, vg_lite_float_t), /* 6: QUAD */ + COMMANDSIZE(4, vg_lite_float_t), /* 7: QUAD_REL */ + COMMANDSIZE(6, vg_lite_float_t), /* 8: CUBIC */ + COMMANDSIZE(6, vg_lite_float_t), /* 9: CUBIC_REL */ + COMMANDSIZE(5, vg_lite_float_t), /* 10: SCCWARC */ + COMMANDSIZE(5, vg_lite_float_t), /* 11: SCCWARC_REL */ + COMMANDSIZE(5, vg_lite_float_t), /* 12: SCWARC */ + COMMANDSIZE(5, vg_lite_float_t), /* 13: SCWARC_REL */ + COMMANDSIZE(5, vg_lite_float_t), /* 14: LCCWARC */ + COMMANDSIZE(5, vg_lite_float_t), /* 15: LCCWARC_REL */ + COMMANDSIZE(5, vg_lite_float_t), /* 16: LCWARC */ + COMMANDSIZE(5, vg_lite_float_t), /* 17: LCWARC_REL */ +}; + +/* Special sqrt(1.0f + x) for quick calculation when 0 <= x <= 1. */ +static vg_lite_float_t _Sqrt( + vg_lite_float_t X + ) +{ + vg_lite_float_t x = X; + vg_lite_float_t s = 1.0f; + + s += x * 0.5f; + x *= X; + s -= x * 0.12445995211601257f; + x *= X; + s += x * 0.058032196015119553f; + x *= X; + s -= x * 0.025314478203654289f; + x *= X; + s += x * 0.0059584137052297592f; + + return s; +} + +static vg_lite_error_t _set_point_tangent( + vg_lite_path_point_ptr Point, + vg_lite_float_t Dx, + vg_lite_float_t Dy + ) +{ + if(!Point) + return VG_LITE_INVALID_ARGUMENT; + + if (Dx == 0.0f) + { + if (Dy == 0.0f) + { + if (Point->prev) + { + Point->length = 0.0f; + Point->tangentX = Point->prev->tangentX; + Point->tangentY = Point->prev->tangentY; + } + else + { + Point->length = 0.0f; + Point->tangentX = 0.0f; + Point->tangentY = 0.0f; + } + } + else + { + Point->tangentX = 0.0f; + if (Dy > 0.0f) + { + Point->length = Dy; + Point->tangentY = 1.0f; + } + else + { + Point->length = -Dy; + Point->tangentY = -1.0f; + } + } + } + else if (Dy == 0.0f) + { + Point->tangentY = 0.0f; + if (Dx > 0.0f) + { + Point->length = Dx; + Point->tangentX = 1.0f; + } + else + { + Point->length = -Dx; + Point->tangentX = -1.0f; + } + } + else + { + vg_lite_float_t l, tx, ty; + + vg_lite_float_t dx, dy; + vg_lite_float_t t, t2; + + dx = (Dx >= 0.0f ? Dx : -Dx); + dy = (Dy >= 0.0f ? Dy : -Dy); + if (dx >= dy) + { + t = dy / dx; + t2 = t * t; + l = _Sqrt(t2); + Point->length = l * dx; + + tx = 1.0f / l; + ty = tx * t; + } + else + { + t = dx / dy; + t2 = t * t; + l = _Sqrt(t2); + Point->length = l * dy; + + ty = 1.0f / l; + tx = ty * t; + } + if (Dx < 0.0f) tx = -tx; + if (Dy < 0.0f) ty = -ty; + + tx = CLAMP(tx, -1.0f, 1.0f); + ty = CLAMP(ty, -1.0f, 1.0f); + Point->tangentX = tx; + Point->tangentY = ty; + } + return VG_LITE_SUCCESS; +} + +vg_lite_error_t _add_point_to_point_list_wdelta( + vg_lite_stroke_conversion_t * stroke_conversion, + vg_lite_float_t X, + vg_lite_float_t Y, + vg_lite_float_t DX, + vg_lite_float_t DY, + uint8_t flatten_flag + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + vg_lite_path_point_ptr last_point; + vg_lite_path_point_ptr point; + + if(!stroke_conversion) + return VG_LITE_INVALID_ARGUMENT; + + last_point = stroke_conversion->path_last_point; + point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*point)); + + if(!point) + return VG_LITE_OUT_OF_RESOURCES; + + memset(point, 0, sizeof(*point)); + + point->x = X; + point->y = Y; + point->flatten_flag = flatten_flag; + + /* Calculate tangent for last_point. */ + VG_LITE_ERROR_HANDLER(_set_point_tangent(last_point, DX, DY)); + + last_point->next = point; + stroke_conversion->path_last_point = point; + point->prev = last_point; + stroke_conversion->point_count++; + + return error; +ErrorHandler: + + vg_lite_os_free(point); + point = NULL; + return error; +} + +vg_lite_error_t _add_point_to_point_list( + vg_lite_stroke_conversion_t * stroke_conversion, + vg_lite_float_t X, + vg_lite_float_t Y, + uint8_t flatten_flag + ) +{ + vg_lite_error_t status = VG_LITE_SUCCESS; + vg_lite_path_point_ptr last_point; + vg_lite_path_point_ptr point; + + if(!stroke_conversion) + return VG_LITE_INVALID_ARGUMENT; + + last_point = stroke_conversion->path_last_point; + if (last_point == NULL) + { + point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*point)); + if(!point) + return VG_LITE_OUT_OF_RESOURCES; + memset(point, 0, sizeof(*point)); + + point->x = X; + point->y = Y; + point->flatten_flag = flatten_flag; + point->prev = NULL; + stroke_conversion->path_last_point = stroke_conversion->path_point_list = point; + stroke_conversion->point_count++; + status = VG_LITE_SUCCESS; + } + else + { + vg_lite_float_t dX = X - last_point->x; + vg_lite_float_t dY = Y - last_point->y; + vg_lite_float_t deltaX = (dX >= 0.0f ? dX : -dX); + vg_lite_float_t deltaY = (dY >= 0.0f ? dY : -dY); + + /* Check for degenerated line. */ + if (deltaX == 0.0f && deltaY == 0.0f) + { + /* Skip degenerated line. */ + status = VG_LITE_SUCCESS; + goto ErrorHandler; + } + if (deltaX < FLOAT_EPSILON && deltaY < FLOAT_EPSILON) + { + vg_lite_float_t ratioX, ratioY; + + if (deltaX == 0.0f) + { + ratioX = 0.0f; + } + else if (X == 0.0f) + { + ratioX = deltaX; + } + else + { + ratioX = deltaX / X; + if (ratioX < 0.0f) ratioX = -ratioX; + } + if (deltaY == 0.0f) + { + ratioY = 0.0f; + } + else if (Y == 0.0f) + { + ratioY = deltaY; + } + else + { + ratioY = deltaY / Y; + if (ratioY < 0.0f) ratioY = -ratioY; + } + if (ratioX < 1.0e-6f && ratioY < 1.0e-6f) + { + /* Skip degenerated line. */ + status = VG_LITE_SUCCESS; + goto ErrorHandler; + } + } + + status = _add_point_to_point_list_wdelta(stroke_conversion, X, Y, dX, dY, flatten_flag); + } + +ErrorHandler: + return status; +} + +static vg_lite_error_t _flatten_path( + vg_lite_stroke_conversion_t * stroke_conversion, + vg_lite_path_t *path + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + uint32_t increment; + uint8_t is_relative; + uint32_t size; + uint32_t path_command; + uint32_t prev_command; + uint8_t data_type_size; + int8_t* data_pointer = NULL; + vg_lite_float_t sx, sy; + vg_lite_float_t ox, oy; + vg_lite_float_t x0, y0, x1, y1, x2, y2; + vg_value_getter get_value = NULL; + + if(!stroke_conversion || !path) + return VG_LITE_INVALID_ARGUMENT; + + sx = sy = ox = oy = 0.0f; + + prev_command = VLC_OP_MOVE; + + /* Determine the data size. */ + size = path->path_length; + + /* Determine the beginning of the path data. */ + data_pointer = (int8_t*)path->path; + + /* Select the data picker. */ + switch (path->format) + { + case VG_LITE_S8: + data_type_size = 1; + get_value = _GetS8_NS_NB; + break; + + case VG_LITE_S16: + data_type_size = 2; + get_value = _GetS16_NS_NB; + break; + + case VG_LITE_S32: + data_type_size = 4; + get_value = _GetS32_NS_NB; + break; + + case VG_LITE_FP32: + data_type_size = 4; + get_value = _GetF_NS_NB; + break; + + default: + error = VG_LITE_INVALID_ARGUMENT; + goto ErrorHandler; + } + /* Add an extra gcvVGCMD_MOVE 0.0 0.0 to handle the case the first command is not gcvVGCMD_MOVE. */ + if (*data_pointer != VLC_OP_MOVE) + { + /* Add first point to subpath. */ + VG_LITE_ERROR_HANDLER(_add_point_to_point_list(stroke_conversion, sx, sy, vgcFLATTEN_NO)); + } + + while (size > 0) + { + /* Get the command. */ + path_command = *data_pointer & 0x1F; + + /* Assume absolute. */ + is_relative = FALSE; + + switch (path_command) + { + case VLC_OP_END: + /* Skip the command. */ + size -= 1; + + if (prev_command == VLC_OP_END) + { + /* Continuous gcvVGCMD_CLOSE - do nothing. */ + break; + } + + /* Check if subPath is already closed. */ + if (ox != sx || oy != sy) + { + /* Add a line from current point to the first point of current subpath. */ + VG_LITE_ERROR_HANDLER(_add_point_to_point_list(stroke_conversion, sx, sy,vgcFLATTEN_NO)); + } + if (stroke_conversion->path_point_list != stroke_conversion->path_last_point) + { + /* Copy tangent data from first point to last_point. */ + vg_lite_path_point_ptr first_point = stroke_conversion->path_point_list; + vg_lite_path_point_ptr last_point = stroke_conversion->path_last_point; + last_point->length = first_point->length; + last_point->tangentX = first_point->tangentX; + last_point->tangentY = first_point->tangentY; + } + else + { + /* Single point path. */ + vg_lite_path_point_ptr point = stroke_conversion->path_point_list; + point->tangentX = 0.0f; + point->tangentY = 0.0f; + point->length = 0.0f; + } + stroke_conversion->closed = 1; + stroke_conversion->path_last_point->next = NULL; + break; + + case VLC_OP_MOVE_REL: + is_relative = 1; + + case VLC_OP_MOVE: /* Indicate the beginning of a new sub-path. */ + /* Skip to the data. */ + SKIPTODATA(data_pointer, data_type_size, size); + VGSL_GETCOORDXY(x0, y0); + + /* First command is gcvVGCMD_MOVE. */ + /* Add first point to subpath. */ + VG_LITE_ERROR_HANDLER(_add_point_to_point_list(stroke_conversion, x0, y0, vgcFLATTEN_NO)); + + sx = ox = x0; + sy = oy = y0; + break; + + case VLC_OP_LINE_REL: + is_relative = 1; + + case VLC_OP_LINE: + /* Skip to the data. */ + SKIPTODATA(data_pointer, data_type_size, size); + VGSL_GETCOORDXY(x0, y0); + + /* Add a point to subpath. */ + VG_LITE_ERROR_HANDLER(_add_point_to_point_list(stroke_conversion, x0, y0, vgcFLATTEN_NO)); + + ox = x0; + oy = y0; + break; + + case VLC_OP_QUAD_REL: + is_relative = 1; + + case VLC_OP_QUAD: + /* Skip to the data. */ + SKIPTODATA(data_pointer, data_type_size, size); + VGSL_GETCOORDXY(x0, y0); + VGSL_GETCOORDXY(x1, y1); + + if ((ox == x0 && oy == y0) && (ox == x1 && oy == y1)) + { + /* Degenerated Bezier curve. Becomes a point. */ + /* Discard zero-length segments. */ + } + else if ((ox == x0 && oy == y0) || (x0 == x1 && y0 == y1)) + { + /* Degenerated Bezier curve. Becomes a line. */ + /* Add a point to subpath. */ + VG_LITE_ERROR_HANDLER(_add_point_to_point_list( stroke_conversion, x1, y1, vgcFLATTEN_NO)); + } + else + { + VG_LITE_ERROR_HANDLER(_flatten_quad_bezier(stroke_conversion, ox, oy, x0, y0, x1, y1)); + } + + ox = x1; + oy = y1; + break; + + case VLC_OP_CUBIC_REL: + is_relative = 1; + + case VLC_OP_CUBIC: + /* Skip to the data. */ + SKIPTODATA(data_pointer, data_type_size, size); + VGSL_GETCOORDXY(x0, y0); + VGSL_GETCOORDXY(x1, y1); + VGSL_GETCOORDXY(x2, y2); + + if ((ox == x0 && oy == y0) && (ox == x1 && oy == y1) && (ox == x2 && oy == y2)) + { + /* Degenerated Bezier curve. Becomes a point. */ + /* Discard zero-length segments. */ + } + else + { + VG_LITE_ERROR_HANDLER(_flatten_cubic_bezier(stroke_conversion, ox, oy, x0, y0, x1, y1, x2, y2)); + } + + ox = x2; + oy = y2; + break; + + default: + error = VG_LITE_INVALID_ARGUMENT; + goto ErrorHandler; + } + prev_command = path_command; + } + + if ((prev_command != VLC_OP_END)) + { + stroke_conversion->path_last_point->next = NULL; + if (stroke_conversion->point_count == 1) + { + /* Single point path. */ + vg_lite_path_point_ptr point = stroke_conversion->path_point_list; + point->tangentX = 0.0f; + point->tangentY = 0.0f; + point->length = 0.0f; + } + } + +ErrorHandler: + return error; +} + +static vg_lite_error_t +_add_point_to_right_stroke_point_list_tail( + vg_lite_stroke_conversion_t * stroke_conversion, + vg_lite_float_t X, + vg_lite_float_t Y + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + vg_lite_path_point_ptr point; + + if(!stroke_conversion) + return VG_LITE_INVALID_ARGUMENT; + + point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*point)); + if(!point) + return VG_LITE_OUT_OF_RESOURCES; + + memset(point, 0, sizeof(*point)); + + point->x = X; + point->y = Y; + point->curve_type = CURVE_LINE; + point->prev = stroke_conversion->last_right_stroke_point; + point->next = NULL; + stroke_conversion->last_right_stroke_point->next = point; + stroke_conversion->last_right_stroke_point = point; + stroke_conversion->stroke_point_count++; + + stroke_conversion->last_stroke_sub_path->point_count++; + + return error; +} + +static vg_lite_error_t +_add_point_to_left_stroke_point_list_head( + vg_lite_stroke_conversion_t * stroke_conversion, + vg_lite_float_t X, + vg_lite_float_t Y + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + vg_lite_path_point_ptr point; + + if(!stroke_conversion) + return VG_LITE_INVALID_ARGUMENT; + + point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*point)); + + if(!point) + return VG_LITE_OUT_OF_RESOURCES; + + memset(point, 0, sizeof(*point)); + + point->x = X; + point->y = Y; + point->curve_type = CURVE_LINE; + point->next = stroke_conversion->left_stroke_point; + point->prev = NULL; + stroke_conversion->left_stroke_point->prev = point; + stroke_conversion->left_stroke_point = point; + stroke_conversion->stroke_point_count++; + + stroke_conversion->last_stroke_sub_path->point_count++; + + return error; +} + +static vg_lite_error_t _add_stroke_sub_path( + vg_lite_stroke_conversion_t * stroke_conversion, + vg_lite_sub_path_ptr *sub_path + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + + if(!stroke_conversion || !sub_path) + return VG_LITE_INVALID_ARGUMENT; + + *sub_path = (vg_lite_sub_path_ptr)vg_lite_os_malloc(sizeof(**sub_path)); + + if(!*sub_path) + return VG_LITE_OUT_OF_RESOURCES; + + memset(*sub_path, 0, sizeof(**sub_path)); + + if (stroke_conversion->last_stroke_sub_path != NULL) + { + stroke_conversion->last_stroke_sub_path->next = *sub_path; + stroke_conversion->last_stroke_sub_path = *sub_path; + } + else + { + stroke_conversion->last_stroke_sub_path = stroke_conversion->stroke_sub_path_list = *sub_path; + } + + return error; +} + +static vg_lite_error_t +_add_zero_length_stroke_sub_path( + vg_lite_stroke_conversion_t * stroke_conversion, + vg_lite_sub_path_ptr *stroke_subpath + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + vg_lite_path_point_ptr new_point,Point; + vg_lite_sub_path_ptr stroke_sub_path; + vg_lite_float_t half_width; + + if(!stroke_conversion) + return VG_LITE_INVALID_ARGUMENT; + + half_width = stroke_conversion->half_line_width; + Point = stroke_conversion->path_point_list; + if (stroke_conversion->stroke_cap_style == VG_LITE_CAP_BUTT) + { + /* No need to draw zero-length subPath for gcvCAP_BUTT. */ + error = VG_LITE_SUCCESS; + goto ErrorHandler; + } + + VG_LITE_ERROR_HANDLER(_add_stroke_sub_path(stroke_conversion, &stroke_sub_path)); + + if (stroke_conversion->stroke_cap_style == VG_LITE_CAP_SQUARE) + { + /* Draw a square along the point's direction. */ + vg_lite_float_t dx, dy; + + if (Point->tangentX == 0.0f || Point->tangentY == 0.0f) + { + dx = half_width; + dy = 0.0f; + } + else + { + dx = Point->tangentY * half_width; + dy = -Point->tangentX * half_width; + } + + new_point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*new_point)); + + if(!new_point) + return VG_LITE_OUT_OF_RESOURCES; + memset(new_point, 0, sizeof(*new_point)); + + new_point->x = Point->x + dx + dy; + new_point->y = Point->y - dx + dy; + new_point->curve_type = CURVE_LINE; + stroke_sub_path->point_list = stroke_conversion->last_right_stroke_point = new_point; + stroke_sub_path->point_count = 1; + + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, + Point->x + dx - dy, Point->y + dx + dy)); + + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, + Point->x - dx - dy, Point->y + dx - dy)); + + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, + Point->x - dx + dy, Point->y - dx - dy)); + } + else + { + /* Draw a circle. */ + new_point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*new_point)); + + if(!new_point) + return VG_LITE_OUT_OF_RESOURCES; + memset(new_point, 0, sizeof(*new_point)); + + new_point->x = Point->x + half_width; + new_point->y = Point->y; + new_point->curve_type = CURVE_LINE; + stroke_sub_path->point_list = stroke_conversion->last_right_stroke_point = new_point; + stroke_sub_path->point_count = 1; + + /* Add upper half circle. */ + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, + Point->x - half_width, Point->y)); + + stroke_conversion->last_right_stroke_point->curve_type = CURVE_ARC_SCCW_HALF; + stroke_conversion->last_right_stroke_point->centerX = Point->x; + stroke_conversion->last_right_stroke_point->centerY = Point->y; + + /* Add lower half circle. */ + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, + Point->x + half_width, Point->y)); + + stroke_conversion->last_right_stroke_point->curve_type = CURVE_ARC_SCCW_HALF; + stroke_conversion->last_right_stroke_point->centerX = Point->x; + stroke_conversion->last_right_stroke_point->centerY = Point->y; + } + + stroke_sub_path->last_point = stroke_conversion->last_right_stroke_point; + stroke_sub_path->last_point->next = NULL; + +ErrorHandler: + return error; +} + +/* Special asin(x) for quick calculation when -sqrt(0.5) <= x <= sqrt(0.5). */ +static vg_lite_float_t _Asin( + vg_lite_float_t X + ) +{ + vg_lite_float_t x = X; + vg_lite_float_t x2 = X * X; + vg_lite_float_t s = X; + + x *= x2; + s += x * 0.1660510562575219f; + x *= x2; + s += x * 0.084044676143618186f; + x *= x2; + s += x * 0.0023776176698039313f; + x *= x2; + s += x * 0.10211922020091345f; + + return s; +} +/* Special cos(x) for quick calculation when -PI <= x <= PI. */ +static vg_lite_float_t _Cos( + vg_lite_float_t X + ) +{ + vg_lite_float_t x2 = X * X; + vg_lite_float_t x = x2; + vg_lite_float_t s = 1.0f; + + s -= x * 0.49985163079668843f; + x *= x2; + s += x * 0.041518066216932693f; + x *= x2; + s -= x * 0.0013422997970712939f; + x *= x2; + s += x * 0.000018930111278021357f; + + return s; +} +/* Special sin(x) for quick calculation when -PI <= x <= PI. */ +static vg_lite_float_t _Sine( + vg_lite_float_t X + ) +{ + vg_lite_float_t x = X; + vg_lite_float_t x2 = X * X; + vg_lite_float_t s = X; + + x *= x2; + s -= x * 0.16664527099620879f; + x *= x2; + s += x * 0.0083154803736487041f; + x *= x2; + s -= x * 0.00019344151251408578f; + x *= x2; + s += x * 0.0000021810214160988925f; + + return s; +} + +static vg_lite_float_t +_Angle( + vg_lite_float_t X, + vg_lite_float_t Y, + vg_lite_float_t Length + ) +{ + vg_lite_float_t angle; + vg_lite_float_t ux = (X >= 0.0f ? X : -X); + vg_lite_float_t uy = (Y >= 0.0f ? Y : -Y); + + if (ux > uy) + { + angle = ((uy > 0.0f && ux < Length) ? _Asin(uy / Length) : 0.0f); + } + else + { + angle = ((ux > 0.0f && uy < Length) ? (FLOAT_PI_HALF - _Asin(ux / Length)) : FLOAT_PI_HALF); + } + + if (X < 0.0f) angle = FLOAT_PI - angle; + if (Y < 0.0f) angle = -angle; + + return angle; +} + +/* The arc is always counter clockwise and less than half circle (small). */ +static vg_lite_error_t +_convert_circle_arc( + vg_lite_stroke_conversion_t *stroke_conversion, + vg_lite_float_t Radius, + vg_lite_float_t CenterX, + vg_lite_float_t CenterY, + vg_lite_float_t StartX, + vg_lite_float_t StartY, + vg_lite_float_t EndX, + vg_lite_float_t EndY, + uint8_t Half_circle, + vg_lite_path_point_ptr *point_list + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + /*gceVGCMD segmentCommand;*/ + vg_lite_float_t theta1, theta_span; + uint32_t segs; + vg_lite_float_t theta, theta_half, theta2; + vg_lite_float_t cos_theta_half; + vg_lite_float_t control_ratio; + vg_lite_float_t controlX, controlY, anchorX, anchorY; + /*gctFLOAT lastX, lastY;*/ + vg_lite_path_point_ptr point, start_point, last_point; + + if(!stroke_conversion || !point_list) + return VG_LITE_INVALID_ARGUMENT; + + /* Converting. */ + theta1 = _Angle(StartX - CenterX, StartY - CenterY, Radius); + if (Half_circle) + { + theta_span = FLOAT_PI; + segs = 4; + theta = FLOAT_PI_QUARTER; + theta_half = FLOAT_PI_EIGHTH; + cos_theta_half = FLOAT_COS_PI_EIGHTH; + } + else + { + theta_span = _Angle(EndX - CenterX, EndY - CenterY, Radius) - theta1; + if (theta_span == 0.0f) + { + /* Handle specail case for huge scaling. */ + *point_list = NULL; + error = VG_LITE_SUCCESS; + return error; + } + + if ((theta_span < 0)) + { + theta_span += FLOAT_PI_TWO; + } + + /* Calculate the number of quadratic Bezier curves. */ + /* Assumption: most of angles are small angles. */ + if (theta_span <= FLOAT_PI_QUARTER) segs = 1; + else if (theta_span <= FLOAT_PI_HALF) segs = 2; + else if (theta_span <= FLOAT_PI_THREE_QUARTER) segs = 3; + else segs = 4; + + theta = theta_span / segs; + theta_half = theta / 2.0f; + cos_theta_half = _Cos(theta_half); + } + + /* Determine the segment command. */ + /*egmentCommand = gcvVGCMD_ARC_QUAD;*/ + + /* Generate quadratic Bezier curves. */ + start_point = last_point = NULL; + control_ratio = Radius / cos_theta_half; + while (segs-- > 0) + { + theta1 += theta; + + theta2 = theta1 - theta_half; + if (theta2 > FLOAT_PI) theta2 -= FLOAT_PI_TWO; + controlX = CenterX + _Cos(theta2) * control_ratio; + controlY = CenterY + _Sine(theta2) * control_ratio; + + theta2 = theta1; + if (theta2 > FLOAT_PI) theta2 -= FLOAT_PI_TWO; + anchorX = CenterX + _Cos(theta2) * Radius; + anchorY = CenterY + _Sine(theta2) * Radius; + + if (segs == 0) + { + /* Use end point directly to avoid accumulated errors. */ + anchorX = EndX; + anchorY = EndY; + } + + /* Add control point. */ + point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*point)); + + if(!point) + return VG_LITE_OUT_OF_RESOURCES; + + memset(point, 0, sizeof(*point)); + + point->x = controlX; + point->y = controlY; + point->curve_type = CURVE_QUAD_CONTROL; + if (last_point) + { + last_point->next = point; + last_point = point; + } + else + { + start_point = last_point = point; + } + + /* Add anchor point. */ + point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*point)); + + if(!point) { + error = VG_LITE_OUT_OF_RESOURCES; + goto ErrorHandler; + } + + memset(point, 0, sizeof(*point)); + + point->x = anchorX; + point->y = anchorY; + point->curve_type = CURVE_QUAD_ANCHOR; + last_point->next = point; + last_point = point; + } + + last_point->next = NULL; + *point_list = start_point; + + return error; +ErrorHandler: + /* Return status. */ + while (start_point) + { + point = start_point; + start_point = start_point->next; + vg_lite_os_free(point); + } + start_point = last_point = point = NULL; + return error; +} + +static vg_lite_error_t +_start_new_stroke_sub_path( + vg_lite_stroke_conversion_t * stroke_conversion, + vg_lite_float_t X, + vg_lite_float_t Y, + vg_lite_float_t Dx, + vg_lite_float_t Dy, + uint8_t add_end_cap, + vg_lite_sub_path_ptr *stroke_subpath + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + + vg_lite_sub_path_ptr stroke_sub_path; + vg_lite_path_point_ptr new_point; + + if(!stroke_conversion || !stroke_subpath) + return VG_LITE_INVALID_ARGUMENT; + + VG_LITE_ERROR_HANDLER(_add_stroke_sub_path(stroke_conversion, &stroke_sub_path)); + + new_point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*new_point)); + if(!new_point) + return VG_LITE_OUT_OF_RESOURCES; + + memset(new_point, 0, sizeof(*new_point)); + new_point->x = X + Dx; + new_point->y = Y + Dy; + new_point->prev = NULL; + new_point->curve_type = CURVE_LINE; + stroke_conversion->stroke_point_list = stroke_conversion->last_right_stroke_point = new_point; + + stroke_sub_path->point_list = stroke_conversion->last_right_stroke_point = new_point; + + new_point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*new_point)); + if(!new_point) + return VG_LITE_OUT_OF_RESOURCES; + + memset(new_point, 0, sizeof(*new_point)); + new_point->x = X - Dx; + new_point->y = Y - Dy; + new_point->curve_type = CURVE_LINE; + new_point->next = NULL; + stroke_conversion->stroke_last_point = stroke_conversion->left_stroke_point = new_point; + + stroke_conversion->stroke_point_count = 2; + + stroke_sub_path->last_point = stroke_conversion->left_stroke_point = new_point; + stroke_sub_path->point_count = 2; + + if (add_end_cap) + { + /* Add end cap if the subPath is not closed. */ + switch (stroke_conversion->stroke_cap_style) + { + case VG_LITE_CAP_BUTT: + /* No adjustment needed. */ + break; + case VG_LITE_CAP_ROUND: + /* Add curve. */ + /* Add the starting point again as arc. */ + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, + stroke_sub_path->point_list->x, stroke_sub_path->point_list->y)); + stroke_conversion->last_right_stroke_point->curve_type = CURVE_ARC_SCCW_HALF; + stroke_conversion->last_right_stroke_point->centerX = X; + stroke_conversion->last_right_stroke_point->centerY = Y; + /* Change the starting point to end point. */ + stroke_sub_path->point_list->x = stroke_sub_path->last_point->x; + stroke_sub_path->point_list->y = stroke_sub_path->last_point->y; + break; + case VG_LITE_CAP_SQUARE: + stroke_conversion->last_right_stroke_point->x += Dy; + stroke_conversion->last_right_stroke_point->y -= Dx; + stroke_conversion->left_stroke_point->x += Dy; + stroke_conversion->left_stroke_point->y -= Dx; + break; + } + } + + *stroke_subpath = stroke_sub_path; + +ErrorHandler: + return error; +} + +static void +_adjust_joint_point( + vg_lite_path_point_ptr Point, + vg_lite_path_point_ptr join_point, + vg_lite_float_t X, + vg_lite_float_t Y, + vg_lite_float_t Ratio + ) +{ + vg_lite_float_t mx = (join_point->x + X) / 2.0f; + vg_lite_float_t my = (join_point->y + Y) / 2.0f; + vg_lite_float_t dx = mx - Point->x; + vg_lite_float_t dy = my - Point->y; + + dx = dx * Ratio; + dy = dy * Ratio; + join_point->x = Point->x + dx; + join_point->y = Point->y + dy; +} + +static uint8_t +_is_angle_span_acute( + vg_lite_float_t Ux, + vg_lite_float_t Uy, + vg_lite_float_t Vx, + vg_lite_float_t Vy + ) +{ + return ((Ux * Vx + Uy * Vy) > 0.0f ? 1 : 0); +} + +static vg_lite_error_t +_draw_swing_pie_area( + vg_lite_stroke_conversion_t *stroke_conversion, + vg_lite_path_point_ptr center_point, + uint8_t end_at_prev_point + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + + if(!stroke_conversion) + return VG_LITE_INVALID_ARGUMENT; + + if (stroke_conversion->swing_counter_clockwise) + { + vg_lite_path_point_ptr start_point = stroke_conversion->swing_start_stroke_point; + vg_lite_path_point_ptr end_point = NULL, real_end_point = NULL; + vg_lite_path_point_ptr point, prev_point; + uint32_t count = 0; + + { + if (end_at_prev_point) + { + /* Detach the end point from leftStrokePoint. */ + /* The end point will be added back later. */ + real_end_point = stroke_conversion->left_stroke_point; + stroke_conversion->left_stroke_point = real_end_point->next; + stroke_conversion->left_stroke_point->prev = NULL; + } + + VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, + center_point->x, center_point->y)); + end_point = stroke_conversion->left_stroke_point; + + /* Reverse the point list from startPoint to endPoint. */ + for (point = start_point; point; point = prev_point) + { + prev_point = point->prev; + point->prev = point->next; + point->next = prev_point; + count++; + } + end_point->next = start_point->prev; + start_point->prev->prev = end_point; + start_point->prev = NULL; + stroke_conversion->left_stroke_point = start_point; + + VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, + center_point->x, center_point->y)); + VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, + stroke_conversion->swing_start_point->x, + stroke_conversion->swing_start_point->y)); + VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, + end_point->prev->x, end_point->prev->y)); + + if (end_at_prev_point) + { + real_end_point->next = stroke_conversion->left_stroke_point; + stroke_conversion->left_stroke_point->prev = real_end_point; + stroke_conversion->left_stroke_point = real_end_point; + } + } + } + else + { + vg_lite_path_point_ptr start_point = stroke_conversion->swing_start_stroke_point; + vg_lite_path_point_ptr end_point = NULL, real_end_point = NULL; + vg_lite_path_point_ptr point, next_point; + uint32_t count = 0; + + { + if (end_at_prev_point) + { + /* Detach the end point from leftStrokePoint. */ + /* The end point will be added back later. */ + real_end_point = stroke_conversion->last_right_stroke_point; + stroke_conversion->last_right_stroke_point = real_end_point->prev; + stroke_conversion->last_right_stroke_point->next = NULL; + } + + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, + center_point->x, center_point->y)); + end_point = stroke_conversion->last_right_stroke_point; + + /* Reverse the point list from startPoint to endPoint. */ + for (point = start_point; point; point = next_point) + { + next_point = point->next; + point->next = point->prev; + point->prev = next_point; + count++; + } + end_point->prev = start_point->next; + start_point->next->next = end_point; + start_point->next = NULL; + stroke_conversion->last_right_stroke_point = start_point; + + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, + center_point->x, center_point->y)); + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, + stroke_conversion->swing_start_point->x, + stroke_conversion->swing_start_point->y)); + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, + end_point->next->x, end_point->next->y)); + + if (end_at_prev_point) + { + real_end_point->prev = stroke_conversion->last_right_stroke_point; + stroke_conversion->last_right_stroke_point->next = real_end_point; + stroke_conversion->last_right_stroke_point = real_end_point; + } + } + } + + stroke_conversion->swing_handling = SWING_NO; + +ErrorHandler: + + return error; +} + +static vg_lite_error_t +_process_line_joint( + vg_lite_stroke_conversion_t * stroke_conversion, + vg_lite_path_point_ptr Point, + vg_lite_float_t Length, + vg_lite_float_t prev_length, + uint32_t Swing_handling, + vg_lite_float_t X1, + vg_lite_float_t Y1, + vg_lite_float_t X2, + vg_lite_float_t Y2 + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + vg_lite_join_style_t stroke_join_style = stroke_conversion->stroke_join_style; + vg_lite_float_t half_width = stroke_conversion->half_line_width; + vg_lite_float_t ratio; + vg_lite_float_t min_length_square; + vg_lite_float_t cos_theta; + uint8_t counter_clockwise; + uint8_t fat_line = stroke_conversion->is_fat; + uint32_t swing_handling = SWING_NO; + uint8_t handle_short_line = 0; + + if(!stroke_conversion) + return VG_LITE_INVALID_ARGUMENT; + + if (stroke_conversion->swing_accu_length < half_width) + { + if (stroke_conversion->swing_need_to_handle) + { + swing_handling = SWING_OUT; + } + else + { + handle_short_line = 1; + } + } + else if (stroke_conversion->stroke_path_length - stroke_conversion->swing_accu_length < half_width) + { + if (stroke_conversion->swing_need_to_handle) + { + swing_handling = SWING_IN; + } + else + { + handle_short_line = 1; + } + } + + if (swing_handling != Swing_handling) + { + error = VG_LITE_INVALID_ARGUMENT; + goto ErrorHandler; + } + + /* For flattened curves/arcs, the join style is always round. */ + if ((Point->flatten_flag != vgcFLATTEN_NO) && fat_line) + { + stroke_join_style = VG_LITE_JOIN_ROUND; + } + + /* First, determine the turn is clockwise or counter-clockwise. */ + cos_theta = Point->prev->tangentX * Point->tangentX + Point->prev->tangentY * Point->tangentY; + + if (cos_theta > FLOAT_ANGLE_EPSILON_COS) + { + /* Straight line or semi-straight line--no need to handle join. */ + if (stroke_conversion->swing_handling !=SWING_NO) + { + /* Begin to swing to the opposite direction. */ + /* Draw the swing area (pie area). */ + VG_LITE_ERROR_HANDLER(_draw_swing_pie_area(stroke_conversion, Point->prev, 1)); + } + + /* Add the new stroke points. */ + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X1, Y1)); + VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, X2, Y2)); + if (stroke_conversion->swing_handling != SWING_NO) + { + stroke_conversion->swing_count++; + } + + goto endCheck; + } + else if (cos_theta < -FLOAT_ANGLE_EPSILON_COS) + { + /* Almost 180 degree turn. */ + counter_clockwise = 1; + ratio = FLOAT_MAX; + min_length_square = FLOAT_MAX; + } + else + { + vg_lite_float_t angleSign = Point->prev->tangentX * Point->tangentY - Point->prev->tangentY * Point->tangentX; + counter_clockwise = (angleSign >= 0.0f ? 1 : 0); + ratio = 2.0f / (1.0f + cos_theta); + min_length_square = half_width * half_width * (1.0f - cos_theta) / (1.0f + cos_theta) + 0.02f; + } + + if (stroke_conversion->swing_handling != SWING_NO) + { + if (counter_clockwise != stroke_conversion->swing_counter_clockwise) + { + /* Swing to the opposite direction. */ + /* Draw the swing area (pie area). */ + VG_LITE_ERROR_HANDLER(_draw_swing_pie_area(stroke_conversion, Point->prev, 1)); + } + } + + if (counter_clockwise) + { + if (stroke_conversion->swing_handling != SWING_NO) + { + vg_lite_path_point_ptr prev_point = stroke_conversion->left_stroke_point->next; /* Skip the line segment movement. */ + vg_lite_float_t deltaX = X2 - prev_point->x; + vg_lite_float_t deltaY = Y2 - prev_point->y; + if (_is_angle_span_acute(stroke_conversion->swing_stroke_deltax, + stroke_conversion->swing_stroke_deltay, + deltaX, deltaY)) + { + /* Continue swinging. */ + stroke_conversion->swing_stroke_deltax = deltaX; + stroke_conversion->swing_stroke_deltay = deltaY; + } + else + { + /* Swing to the max. */ + /* Draw the swing area (pie area). */ + VG_LITE_ERROR_HANDLER(_draw_swing_pie_area(stroke_conversion, Point->prev, 1)); + } + } + + /* Check if the miter length is too long for inner intersection. */ + if (stroke_conversion->swing_handling == SWING_NO + && ! handle_short_line + && min_length_square <= Length * Length + && min_length_square <= prev_length * prev_length) + { + /* Adjust leftStrokePoint to the intersection point. */ + _adjust_joint_point(Point, stroke_conversion->left_stroke_point, X2, Y2, ratio); + } + else if (stroke_conversion->swing_handling == SWING_NO && Point->flatten_flag == vgcFLATTEN_NO) + { + /* Add the point to avoid incorrect sharp angle. */ + VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, Point->x, Point->y)); + /* Add the point to form a loop to avoid out-of-bound problem. */ + VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, X2, Y2)); + } + else if (stroke_conversion->swing_handling == SWING_NO && (! fat_line || Swing_handling == SWING_NO)) + { + /* Flattened line segments should not have sharp angle. */ + /* Add the point to form a loop to avoid out-of-bound problem. */ + VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, X2, Y2)); + } + else + { + if (stroke_conversion->swing_handling == SWING_NO) + { + vg_lite_path_point_ptr prev_point = stroke_conversion->left_stroke_point; + + /* Start swing handling. */ + stroke_conversion->swing_handling = Swing_handling; + stroke_conversion->swing_counter_clockwise = 1; + stroke_conversion->swing_start_point = Point; + stroke_conversion->swing_center_length = 0.0f; + stroke_conversion->swing_count= 0; + + /* Save stroking path delta. */ + stroke_conversion->swing_stroke_deltax = X2 - prev_point->x; + stroke_conversion->swing_stroke_deltay = Y2 - prev_point->y; + + /* Add extra center point for swing out pie area. */ + /* VIV: [todo] Should adjust prev_point, instead of adding new point? */ + VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, Point->x, Point->y)); + + /* Add extra start stroke point for swing out pie area. */ + VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, prev_point->x, prev_point->y)); + + stroke_conversion->swing_start_stroke_point = stroke_conversion->left_stroke_point; + } + +#if USE_MIN_ARC_FILTER + if (cosTheta > FLOAT_MIN_ARC_ANGLE_COS) + { + /* Add a point. */ + gcmERR_GOTO(_add_point_to_left_stroke_point_list_head(Context, stroke_conversion, X2, Y2)); + + VGSL_STAT_COUNTER_INCREASE(vgStrokeFilteredByMinArcAngleCount); + } + else +#endif + { + /* Add curve. */ + /* Note that the curve will be reversed, so the direction is CW. */ + /* Then, left side is in reversed order, so the direction is CCW. */ + VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, X2, Y2)); + stroke_conversion->left_stroke_point->curve_type = CURVE_ARC_SCCW; + stroke_conversion->left_stroke_point->centerX = Point->x; + stroke_conversion->left_stroke_point->centerY = Point->y; + } + stroke_conversion->swing_count++; + } + + switch (stroke_join_style) + { + case VG_LITE_JOIN_ROUND: + if (cos_theta > FLOAT_MIN_ARC_ANGLE_COS) + { + /* Add a point. */ + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X1, Y1)); + } + else + { + /* Add curve. */ + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X1, Y1)); + stroke_conversion->last_right_stroke_point->curve_type = CURVE_ARC_SCCW; + stroke_conversion->last_right_stroke_point->centerX = Point->x; + stroke_conversion->last_right_stroke_point->centerY = Point->y; + } + break; + case VG_LITE_JOIN_MITER: + if (ratio <= stroke_conversion->stroke_miter_limit_square) + { + /* Adjust lastRightStrokePoint to the outer intersection point. */ + _adjust_joint_point(Point, stroke_conversion->last_right_stroke_point, X1, Y1, ratio); + break; + } + /* Else use Bevel join style. */ + case VG_LITE_JOIN_BEVEL: + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X1, Y1)); + break; + } + } + else + { + if (stroke_conversion->swing_handling != SWING_NO) + { + vg_lite_path_point_ptr prev_point = stroke_conversion->last_right_stroke_point->prev; /* Skip the line segment movement. */ + vg_lite_float_t deltaX = X1 - prev_point->x; + vg_lite_float_t deltaY = Y1 - prev_point->y; + if (_is_angle_span_acute(stroke_conversion->swing_stroke_deltax, + stroke_conversion->swing_stroke_deltay, + deltaX, deltaY)) + { + /* Continue swinging. */ + stroke_conversion->swing_stroke_deltax = deltaX; + stroke_conversion->swing_stroke_deltay = deltaY; + } + else + { + /* Swing to the max. */ + /* Draw the swing area (pie area). */ + VG_LITE_ERROR_HANDLER(_draw_swing_pie_area(stroke_conversion, Point->prev, 1)); + } + } + + /* Check if the miter length is too long for inner intersection. */ + if (stroke_conversion->swing_handling == SWING_NO + && ! handle_short_line + && min_length_square <= Length * Length + && min_length_square <= prev_length * prev_length) + { + /* Adjust lastRightStrokePoint to the intersection point. */ + _adjust_joint_point(Point, stroke_conversion->last_right_stroke_point, X1, Y1, ratio); + } + else if (stroke_conversion->swing_handling == SWING_NO && Point->flatten_flag == vgcFLATTEN_NO) + { + /* Add the point to avoid incorrect sharp angle. */ + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, Point->x, Point->y)); + /* Add the point to form a loop to avoid out-of-bound problem. */ + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X1, Y1)); + } + else if (stroke_conversion->swing_handling == SWING_NO && (! fat_line || Swing_handling == SWING_NO)) + { + /* Flattened line segments should not have sharp angle. */ + /* Add the point to form a loop to avoid out-of-bound problem. */ + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X1, Y1)); + } + else + { + if (stroke_conversion->swing_handling == SWING_NO) + { + vg_lite_path_point_ptr prev_point = stroke_conversion->last_right_stroke_point; + + /* Start swing handling. */ + stroke_conversion->swing_handling = Swing_handling; + stroke_conversion->swing_counter_clockwise = 0; + stroke_conversion->swing_start_point = Point; + stroke_conversion->swing_center_length = 0.0f; + stroke_conversion->swing_count= 0; + + /* Save stroking path delta. */ + stroke_conversion->swing_stroke_deltax = X1 - prev_point->x; + stroke_conversion->swing_stroke_deltay = Y1 - prev_point->y; + + /* Add extra center point for swing out pie area. */ + /* VIV: [todo] Should adjust prev_point, instead of adding new point? */ + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, Point->x, Point->y)); + + /* Add extra start stroke point for swing out pie area. */ + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, prev_point->x, prev_point->y)); + + stroke_conversion->swing_start_stroke_point = stroke_conversion->last_right_stroke_point; + } + + if (cos_theta > FLOAT_MIN_ARC_ANGLE_COS) + { + /* Add a point. */ + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X1, Y1)); + } + else + { + /* Add curve. */ + /* Note that the curve will be reversed, so the direction is CCW. */ + stroke_conversion->last_right_stroke_point->curve_type = CURVE_ARC_SCCW; + stroke_conversion->last_right_stroke_point->centerX = Point->x; + stroke_conversion->last_right_stroke_point->centerY = Point->y; + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X1, Y1)); + } + stroke_conversion->swing_count++; + } + + switch (stroke_join_style) + { + case VG_LITE_JOIN_ROUND: + if (cos_theta > FLOAT_MIN_ARC_ANGLE_COS) + { + /* Add a point. */ + VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, X2, Y2)); + } + else + { + /* Add curve. */ + stroke_conversion->left_stroke_point->curve_type = CURVE_ARC_SCCW; + stroke_conversion->left_stroke_point->centerX = Point->x; + stroke_conversion->left_stroke_point->centerY = Point->y; + VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, X2, Y2)); + } + break; + case VG_LITE_JOIN_MITER: + if (ratio <= stroke_conversion->stroke_miter_limit_square) + { + /* Adjust leftStrokePoint to the outer intersection point. */ + _adjust_joint_point(Point, stroke_conversion->left_stroke_point, X2, Y2, ratio); + break; + } + /* Else use Bevel join style. */ + case VG_LITE_JOIN_BEVEL: + VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, X2, Y2)); + break; + } + } + +endCheck: + if (stroke_conversion->swing_need_to_handle) + { + stroke_conversion->swing_accu_length += Point->length; + } + if (stroke_conversion->swing_handling != SWING_NO) + { + if (Point->flatten_flag == vgcFLATTEN_END || + (stroke_conversion->swing_handling == SWING_OUT && + stroke_conversion->swing_accu_length > half_width)) + { + /* Draw the swing area (pie area). */ + VG_LITE_ERROR_HANDLER(_draw_swing_pie_area(stroke_conversion, Point, 0)); + } + else + { + /* Check if center line will move too far. */ + stroke_conversion->swing_center_length += Point->length; + if (stroke_conversion->swing_center_length > FLOAT_SWING_CENTER_RANGE) + { +#if USE_NEW_SWING_HANDLE_FOR_END + if (stroke_conversion->currentSubPath->length < half_width || + Point->next->flatten_flag == vgcFLATTEN_END) +#endif + { + /* Draw the swing area (pie area). */ + VG_LITE_ERROR_HANDLER(_draw_swing_pie_area(stroke_conversion, Point, 0)); + } + } + } + } + +ErrorHandler: + + return error; +} + +static vg_lite_error_t +_close_stroke_sub_path( + vg_lite_stroke_conversion_t * stroke_conversion, + vg_lite_path_point_ptr Point, + vg_lite_float_t Length, + vg_lite_float_t prev_length, + uint8_t Swing_handling, + vg_lite_path_point_ptr first_stroke_point, + vg_lite_path_point_ptr last_stroke_point + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + if(!stroke_conversion) + return VG_LITE_INVALID_ARGUMENT; + + /* Handle line joint style for the first/last point in closed path. */ + VG_LITE_ERROR_HANDLER(_process_line_joint( + stroke_conversion, Point, + Length, prev_length, Swing_handling, + first_stroke_point->x, first_stroke_point->y, + last_stroke_point->x, last_stroke_point->y + )); + + /* Adjust the two end ponts of the first point. */ + first_stroke_point->x = stroke_conversion->last_right_stroke_point->x; + first_stroke_point->y = stroke_conversion->last_right_stroke_point->y; + last_stroke_point->x = stroke_conversion->left_stroke_point->x; + last_stroke_point->y = stroke_conversion->left_stroke_point->y; + + /* Concatnate right and left point lists. */ + stroke_conversion->last_right_stroke_point->next = stroke_conversion->left_stroke_point; + stroke_conversion->left_stroke_point->prev = stroke_conversion->last_right_stroke_point; + + /*gcmERROR_RETURN(_CheckStrokeSubPath(stroke_conversion->lastStrokeSubPath));*/ + +ErrorHandler: + return error; +} + +static vg_lite_error_t _end_stroke_sub_path( + vg_lite_stroke_conversion_t *stroke_conversion, + vg_lite_float_t X, + vg_lite_float_t Y, + vg_lite_float_t Dx, + vg_lite_float_t Dy + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + + if(!stroke_conversion) + return VG_LITE_INVALID_ARGUMENT; + + /* Add points for end of line. */ + VG_LITE_RETURN_ERROR(_add_point_to_right_stroke_point_list_tail(stroke_conversion, X + Dx, Y + Dy)); + VG_LITE_RETURN_ERROR(_add_point_to_left_stroke_point_list_head(stroke_conversion, X - Dx, Y - Dy)); + + /* Add end cap if the subPath is not closed. */ + switch (stroke_conversion->stroke_cap_style) + { + case VG_LITE_CAP_BUTT: + /* No adjustment needed. */ + break; + case VG_LITE_CAP_ROUND: + /* Add curve. */ + stroke_conversion->left_stroke_point->curve_type = CURVE_ARC_SCCW_HALF; + stroke_conversion->left_stroke_point->centerX = X; + stroke_conversion->left_stroke_point->centerY = Y; + break; + case VG_LITE_CAP_SQUARE: + stroke_conversion->last_right_stroke_point->x -= Dy; + stroke_conversion->last_right_stroke_point->y += Dx; + stroke_conversion->left_stroke_point->x -= Dy; + stroke_conversion->left_stroke_point->y += Dx; + break; + } + + /* Concatnate right and left point lists. */ + stroke_conversion->last_right_stroke_point->next = stroke_conversion->left_stroke_point; + stroke_conversion->left_stroke_point->prev = stroke_conversion->last_right_stroke_point; + + /*gcmERROR_RETURN(_CheckStrokeSubPath(stroke_conversion->lastStrokeSubPath));*/ + return error; +} + +static vg_lite_error_t _get_next_dash_length( + vg_lite_stroke_conversion_t * stroke_conversion, + uint32_t * dash_index, + vg_lite_float_t * dash_length + ) +{ + if(!stroke_conversion || !dash_index || !dash_length) + return VG_LITE_INVALID_ARGUMENT; + + (*dash_index)++; + if (*dash_index == stroke_conversion->stroke_dash_pattern_count) + { + *dash_index = 0; + } + *dash_length = stroke_conversion->stroke_dash_pattern[*dash_index]; + + return VG_LITE_SUCCESS; +} + +static vg_lite_error_t +_create_stroke_path( + vg_lite_stroke_conversion_t * stroke_conversion + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + vg_lite_sub_path_ptr stroke_sub_path = NULL,first_stroke_sub_path = NULL; + vg_lite_path_point_ptr point, next_point; + vg_lite_float_t half_width; + vg_lite_float_t x, y; + vg_lite_float_t dx, dy, ux, uy; + vg_lite_float_t length, prev_length, first_length; + vg_lite_float_t dash_length; + uint32_t dash_index; + uint8_t dashing; + uint8_t add_end_cap; + uint8_t need_to_handle_swing = 1 /* (stroke_conversion->strokeCapStyle == gcvCAP_BUTT) */; + + vg_lite_path_point_ptr first_right_point = NULL; + vg_lite_path_point_ptr last_left_point = NULL; + vg_lite_float_t first_dx = 0.0f, first_dy = 0.0f; + uint8_t drawing = 0; + vg_lite_float_t total_length = 0.0f; + vg_lite_float_t accu_length = 0.0f; + uint32_t swing_handling = SWING_NO; + + if(!stroke_conversion) + return VG_LITE_INVALID_ARGUMENT; + + half_width = stroke_conversion->half_line_width; + dashing = stroke_conversion->stroke_dash_pattern_count > 0 ? 1 : 0; + dash_index = stroke_conversion->stroke_dash_initial_index; + dash_length = stroke_conversion->stroke_dash_initial_length; + + /* VIV: [todo] Need to check/debug closed stroke path. */ + need_to_handle_swing = (stroke_conversion->stroke_cap_style == VG_LITE_CAP_BUTT || stroke_conversion->closed); + if (need_to_handle_swing) + { + uint8_t reallyneed_to_handle_swing = 0; + + /* Calculate the total length. */ + for (point = stroke_conversion->path_point_list; point; point = point->next) + { + total_length += point->length; + + if (point->flatten_flag != vgcFLATTEN_NO) + { + reallyneed_to_handle_swing = 1; + } + } + stroke_conversion->stroke_path_length = total_length; + if (reallyneed_to_handle_swing) + { + swing_handling = SWING_OUT; + } + else + { + need_to_handle_swing = 0; + swing_handling = SWING_NO; + } + } + stroke_conversion->swing_need_to_handle = need_to_handle_swing; + + point = stroke_conversion->path_point_list; + next_point = point->next; + if (next_point == NULL) + { + if (!dashing || ((dash_index & 0x1) == 0)) + { + /* Single point (zero-length) subpath. */ + /* Note that one-MOVE_TO subpaths are removed during parsing. */ + VG_LITE_ERROR_HANDLER(_add_zero_length_stroke_sub_path(stroke_conversion, &stroke_sub_path)); + } + goto ErrorHandler; + } + + /* Adjust closed status for dashing. */ + if (dashing && stroke_conversion->closed && ((dash_index & 0x1) == 1)) + { + stroke_conversion->closed = FALSE; + } + + /* Set add_end_cap. */ + add_end_cap = dashing ? 1: (stroke_conversion->closed ? 0 : 1); + + /* Process first line. */ + first_length = point->length; + ux = point->tangentX; + uy = point->tangentY; + dx = uy * half_width; + dy = -ux * half_width; + if (need_to_handle_swing) + { + stroke_conversion->swing_accu_length = first_length; + } + + if (dashing) + { + vg_lite_float_t delta_length; + + /* Draw dashes. */ + x = point->x; + y = point->y; + do + { + if ((dash_index & 0x1) == 0) + { + VG_LITE_ERROR_HANDLER(_start_new_stroke_sub_path( + stroke_conversion, + x, y, + dx, dy, add_end_cap, + &stroke_sub_path + )); + + drawing = 1; + add_end_cap = 1; + if (stroke_conversion->closed && (first_stroke_sub_path == NULL)) + { + first_stroke_sub_path = stroke_conversion->last_stroke_sub_path; + first_right_point = stroke_conversion->last_right_stroke_point; + last_left_point = stroke_conversion->left_stroke_point; + first_dx = dx; + first_dy = dy; + } + } + + delta_length = first_length - dash_length; + if (delta_length >= FLOAT_EPSILON) + { + /* Move (x, y) forward along the line by dash_length. */ + x += ux * dash_length; + y += uy * dash_length; + + if ((dash_index & 0x1) == 0) + { + VG_LITE_ERROR_HANDLER(_end_stroke_sub_path( + stroke_conversion, + x, y, + dx, dy + )); + + drawing = 0; + } + + VG_LITE_ERROR_HANDLER(_get_next_dash_length(stroke_conversion, &dash_index, &dash_length)); + first_length = delta_length; + } + else if (delta_length <= -FLOAT_EPSILON) + { + dash_length = -delta_length; + break; + } + else + { + if ((dash_index & 0x1) == 0) + { + VG_LITE_ERROR_HANDLER(_end_stroke_sub_path( + stroke_conversion, + next_point->x, next_point->y, + dx, dy + )); + + drawing = 0; + } + + VG_LITE_ERROR_HANDLER(_get_next_dash_length(stroke_conversion, &dash_index, &dash_length)); + first_length = 0; + break; + } + } + while (1); + } + else + { + VG_LITE_ERROR_HANDLER(_start_new_stroke_sub_path( + stroke_conversion, + point->x, point->y, + dx, dy, add_end_cap, + &stroke_sub_path + )); + + drawing = 1; + add_end_cap = 1; + } + + /* Process the rest of lines. */ + prev_length = first_length; + for (point = next_point, next_point = point->next; next_point; + point = next_point, next_point = point->next) + { + if (!dashing || ((dash_index & 0x1) == 0 && drawing)) + { + /* Add points for end of line for line join process with next line. */ + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, + point->x + dx, point->y + dy)); + VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, + point->x - dx, point->y - dy)); + } + + length = point->length; + ux = point->tangentX; + uy = point->tangentY; + dx = uy * half_width; + dy = -ux * half_width; + if (need_to_handle_swing) + { + accu_length += point->prev->length; + stroke_conversion->swing_accu_length = accu_length; + if (accu_length < half_width) + { + swing_handling = SWING_OUT; + } + else if (total_length - accu_length < half_width) + { + swing_handling = SWING_IN; + } + else + { + swing_handling = SWING_NO; + } + } + + if (!dashing) + { + /* Handle line joint style. */ + VG_LITE_ERROR_HANDLER(_process_line_joint( + stroke_conversion, point, + length, prev_length, swing_handling, + point->x + dx, point->y + dy, + point->x - dx, point->y - dy + )); + } + else + { + vg_lite_float_t delta_length; + + /* Draw dashes. */ + x = point->x; + y = point->y; + if ((dash_index & 0x1) == 0) + { + if (drawing) + { + /* Handle line joint style. */ + VG_LITE_ERROR_HANDLER(_process_line_joint( + stroke_conversion, point, + dash_length, prev_length, swing_handling, + x + dx, y + dy, + x - dx, y - dy + )); + } + else + { + /* Start a new sub path. */ + VG_LITE_ERROR_HANDLER(_start_new_stroke_sub_path( + stroke_conversion, + x, y, + dx, dy, add_end_cap, + &stroke_sub_path + )); + + drawing = 1; + add_end_cap = 1; + } + } + do + { + delta_length = length - dash_length; + if (delta_length >= FLOAT_EPSILON) + { + /* Move (x, y) forward along the line by dash_length. */ + x += ux * dash_length; + y += uy * dash_length; + + if ((dash_index & 0x1) == 0) + { + VG_LITE_ERROR_HANDLER(_end_stroke_sub_path( + stroke_conversion, + x, y, dx, dy + )); + + drawing = 0; + } + + VG_LITE_ERROR_HANDLER(_get_next_dash_length(stroke_conversion, &dash_index, &dash_length)); + length = delta_length; + } + else if (delta_length <= -FLOAT_EPSILON) + { + dash_length = -delta_length; + break; + } + else + { + if ((dash_index & 0x1) == 0) + { + VG_LITE_ERROR_HANDLER(_end_stroke_sub_path( + stroke_conversion, + next_point->x, next_point->y, + dx, dy + )); + + drawing = 0; + } + + VG_LITE_ERROR_HANDLER(_get_next_dash_length(stroke_conversion, &dash_index, &dash_length)); + length = 0; + break; + } + + if ((dash_index & 0x1) == 0) + { + VG_LITE_ERROR_HANDLER(_start_new_stroke_sub_path( + stroke_conversion, + x, y, + dx, dy, add_end_cap, + &stroke_sub_path + )); + + drawing = 1; + add_end_cap = 1; + } + } + while (1); + } + + prev_length = length; + } + + if (need_to_handle_swing) + { + accu_length += point->prev->length; + stroke_conversion->swing_accu_length = accu_length; + if (accu_length < half_width) + { + swing_handling = SWING_OUT; + } + else if (total_length - accu_length < half_width) + { + swing_handling = SWING_IN; + } + else + { + swing_handling = SWING_NO; + } + } + + if (stroke_conversion->swing_handling != SWING_NO) + { + /* Draw the swing area (pie area). */ + VG_LITE_ERROR_HANDLER(_draw_swing_pie_area(stroke_conversion, stroke_conversion->path_last_point, FALSE)); + } + + if (stroke_conversion->closed) + { + if (! dashing || drawing) + { + /* Add points for end of line. */ + VG_LITE_ERROR_HANDLER(_add_point_to_right_stroke_point_list_tail(stroke_conversion, + point->x + dx, point->y + dy)); + VG_LITE_ERROR_HANDLER(_add_point_to_left_stroke_point_list_head(stroke_conversion, + point->x - dx, point->y - dy)); + + if (! dashing) + { + /* Handle line joint style for the first/last point in closed path. */ + VG_LITE_ERROR_HANDLER(_close_stroke_sub_path( + stroke_conversion, point, + first_length, prev_length, swing_handling, + stroke_sub_path->point_list, stroke_sub_path->last_point + )); + } + else + { + /* Handle line joint style for the first/last point in closed path. */ + VG_LITE_ERROR_HANDLER(_close_stroke_sub_path( + stroke_conversion, point, + first_length, prev_length, swing_handling, + first_right_point, last_left_point + )); + } + } + else if (stroke_conversion->stroke_cap_style != VG_LITE_CAP_BUTT) + { + /* No closing join need. Add end cap for the starting point. */ + + if (stroke_conversion->stroke_cap_style == VG_LITE_CAP_SQUARE) + { + first_right_point->x += first_dy; + first_right_point->y -= first_dx; + last_left_point->x += first_dy; + last_left_point->y -= first_dx; + } + else + { + vg_lite_sub_path_ptr last_stroke_sub_path = stroke_conversion->last_stroke_sub_path; + vg_lite_path_point_ptr start_point = last_stroke_sub_path->point_list; + vg_lite_path_point_ptr point; + + /* Add curve. */ + /* Add extra point to the beginning with end point's coordinates. */ + point = (vg_lite_path_point_ptr)vg_lite_os_malloc(sizeof(*point)); + if(!point) + return VG_LITE_INVALID_ARGUMENT; + memset(point, 0, sizeof(*point)); + + point->x = last_stroke_sub_path->last_point->x; + point->y = last_stroke_sub_path->last_point->y; + point->next = start_point; + start_point->prev = point; + start_point->curve_type = CURVE_ARC_SCCW; + start_point->centerX = stroke_conversion->path_point_list->x; + start_point->centerY = stroke_conversion->path_point_list->y; + last_stroke_sub_path->point_list = point; + } + } + } + else if (! dashing || + (((dash_index & 0x1) == 0) && (dash_length < stroke_conversion->stroke_dash_pattern[dash_index]))) + { + /* Add end cap if the subPath is not closed. */ + VG_LITE_ERROR_HANDLER(_end_stroke_sub_path( + stroke_conversion, + point->x, point->y, + dx, dy + )); + + drawing = 0; + } + + +ErrorHandler: + return error; +} + +static vg_lite_error_t _copy_stroke_path( + vg_lite_stroke_conversion_t * stroke_conversion, + vg_lite_path_t *path + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + vg_lite_path_point_ptr point,prev_point,tmp_point; + uint32_t totalsize = 0,real_size = 0; + float *pfloat; + char *cpath = NULL; + char last_opcode = 0; + void *temp_stroke_path_data = NULL; + uint32_t temp_stroke_path_size; + vg_lite_sub_path_ptr sub_path; + vg_lite_float_t half_width; + + if(!stroke_conversion || !path) + return VG_LITE_INVALID_ARGUMENT; + + half_width = stroke_conversion->half_line_width; + sub_path = stroke_conversion->stroke_sub_path_list; + + if(!stroke_conversion || !path || !sub_path) + return VG_LITE_INVALID_ARGUMENT; + + while (sub_path) + { + tmp_point = prev_point = point = sub_path->point_list; + totalsize += _commandSize_float[VLC_OP_LINE] * sub_path->point_count + _commandSize_float[VLC_OP_CLOSE]; + for(;tmp_point;tmp_point = tmp_point->next) + { + if(tmp_point->curve_type == CURVE_ARC_SCCW || tmp_point->curve_type == CURVE_ARC_SCCW_HALF) { + totalsize += 4 * _commandSize_float[VLC_OP_QUAD]; + } + } + + temp_stroke_path_data = path->stroke_path_data; + temp_stroke_path_size = path->stroke_path_size; + + path->stroke_path_size += totalsize; + if(path->stroke_path_size == 0) { + error = VG_LITE_INVALID_ARGUMENT; + goto ErrorHandler; + } + path->stroke_path_data = (void *)vg_lite_os_malloc(path->stroke_path_size); + if(!path->stroke_path_data) { + error = VG_LITE_OUT_OF_RESOURCES; + goto ErrorHandler; + } + + memset(path->stroke_path_data, 0, path->stroke_path_size); + + if(temp_stroke_path_data) { + memcpy(path->stroke_path_data,temp_stroke_path_data,temp_stroke_path_size); + vg_lite_os_free(temp_stroke_path_data); + temp_stroke_path_data = NULL; + } + + pfloat = (vg_lite_float_t *)((char *)path->stroke_path_data + temp_stroke_path_size); + if(last_opcode == VLC_OP_CLOSE) { + cpath = (char *)(pfloat - 1) + 1; + *cpath++ = VLC_OP_MOVE; + cpath = (char *)pfloat; + } + else { + cpath = (char *)pfloat; + *cpath = VLC_OP_MOVE; + pfloat++; + } + + *pfloat++ = point->x; + *pfloat++ = point->y; + real_size += _commandSize_float[VLC_OP_MOVE]; + if(last_opcode == VLC_OP_CLOSE) + real_size -= 4; + + for (point = point->next; point; prev_point = point, point = point->next) + { + if (point->curve_type == CURVE_LINE) + { + if (point->x == prev_point->x && point->y == prev_point->y) + { + path->stroke_path_size -= _commandSize_float[VLC_OP_LINE]; + /* Skip zero-length lines. */ + continue; + } + + /* Add new command. */ + cpath = (char *)pfloat; + *cpath = VLC_OP_LINE; + pfloat++; + + /* Set the coordinates. */ + *pfloat++ = point->x; + *pfloat++ = point->y; + real_size += _commandSize_float[VLC_OP_LINE]; + } + else if (point->curve_type == CURVE_QUAD_CONTROL) + { + /* Add new command. */ + cpath = (char *)pfloat; + *cpath = VLC_OP_QUAD; + pfloat++; + + /* Set the coordinates. */ + prev_point = point, point = point->next; + *pfloat++ = prev_point->x; + *pfloat++ = prev_point->y; + *pfloat++ = point->x; + *pfloat++ = point->y; + + real_size += _commandSize_float[VLC_OP_QUAD]; + } + else + { + vg_lite_path_point_ptr point_list, p, nextP; + vg_lite_path_point_ptr p2; + + if (point->curve_type == CURVE_ARC_SCCW) + { + /* Convert an arc to Bezier curves. */ + VG_LITE_ERROR_HANDLER(_convert_circle_arc(stroke_conversion, half_width, + point->centerX, point->centerY, + prev_point->x, prev_point->y, + point->x, point->y, + 0, &point_list)); + } + else + { + /* Convert a half circle to Bezier curves. */ + VG_LITE_ERROR_HANDLER(_convert_circle_arc(stroke_conversion, half_width, + point->centerX, point->centerY, + prev_point->x, prev_point->y, + point->x, point->y, + 1, &point_list)); + + } + + if (point_list) + { + for (p = point_list; p; p = nextP) + { + /* Add new command. */ + cpath = (char *)pfloat; + *cpath = VLC_OP_QUAD; + pfloat++; + + /* Set the coordinates. */ + p2 = p->next; + nextP = p2->next; + + *pfloat++ = p->x; + *pfloat++ = p->y; + *pfloat++ = p2->x; + *pfloat++ = p2->y; + real_size += _commandSize_float[VLC_OP_QUAD]; + vg_lite_os_free(p); + vg_lite_os_free(p2); + } + } + else + { + /* Handle special case of huge scaling. */ + /* Add new command. */ + cpath = (char *)pfloat; + *cpath = VLC_OP_LINE; + pfloat++; + + /* Set the coordinates. */ + *pfloat++ = point->x; + *pfloat++ = point->y; + real_size += _commandSize_float[VLC_OP_LINE]; + } + } + } + + /* Create a CLOSE_PATH command at the end. */ + cpath = (char *)pfloat; + if(sub_path->next) + *cpath = VLC_OP_CLOSE; + else + *cpath = VLC_OP_END; + real_size += _commandSize_float[VLC_OP_CLOSE]; + path->stroke_path_size = temp_stroke_path_size + real_size; + totalsize = 0; + real_size = 0; + sub_path = sub_path->next; + last_opcode = *cpath; + } + +ErrorHandler: + + if(temp_stroke_path_data) { + vg_lite_os_free(temp_stroke_path_data); + temp_stroke_path_data = NULL; + } + + return error; +} + +static vg_lite_error_t _initialize_stroke_dash_parameters( + vg_lite_stroke_conversion_t * stroke_conversion + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + uint32_t count; + uint32_t i; + vg_lite_float_t *pattern_src; + vg_lite_float_t *pattern,*temp_pattern; + vg_lite_float_t length; + + if(!stroke_conversion) + return VG_LITE_INVALID_ARGUMENT; + + count = stroke_conversion->stroke_dash_pattern_count; + if (count == 0 || !stroke_conversion->stroke_dash_pattern) + return error; + + length = stroke_conversion->stroke_dash_phase; + + /* The last pattern is ignored if the number is odd. */ + if (count & 0x1) count--; + + pattern = (vg_lite_float_t *)vg_lite_os_malloc(count * sizeof(vg_lite_float_t)); + if(!pattern) + return VG_LITE_OUT_OF_RESOURCES; + + temp_pattern = pattern; + stroke_conversion->stroke_dash_pattern_length = 0.0f; + pattern_src = stroke_conversion->stroke_dash_pattern; + + for (i = 0; i < count; i++, pattern++, pattern_src++) + { + if (*pattern_src < 0.0f) + { + *pattern = 0.0f; + } + else + { + *pattern = *pattern_src; + } + stroke_conversion->stroke_dash_pattern_length += *pattern; + } + + if (stroke_conversion->stroke_dash_pattern_length < FLOAT_EPSILON) + { + stroke_conversion->stroke_dash_pattern_count = 0; + vg_lite_os_free(temp_pattern); + temp_pattern = NULL; + return error; + } + + while (length < 0.0f) + { + length += stroke_conversion->stroke_dash_pattern_length; + } + + while (length >= stroke_conversion->stroke_dash_pattern_length) + { + length -= stroke_conversion->stroke_dash_pattern_length; + } + + pattern = stroke_conversion->stroke_dash_pattern; + for (i = 0; i < stroke_conversion->stroke_dash_pattern_count; i++, pattern++) + { + if (length <= *pattern) break; + + length -= *pattern; + } + + stroke_conversion->stroke_dash_initial_index = i; + stroke_conversion->stroke_dash_initial_length = *pattern - length; + + vg_lite_os_free(temp_pattern); + temp_pattern = NULL; + + return error; +} + +vg_lite_error_t vg_lite_update_stroke( + vg_lite_path_t *path + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + vg_lite_stroke_conversion_t * stroke_conversion; + + if(!path) + return VG_LITE_INVALID_ARGUMENT; + + if(!path->path_length) + return VG_LITE_SUCCESS; + + if(!path->path) + return VG_LITE_INVALID_ARGUMENT; + + if (!path->stroke_conversion) + return VG_LITE_INVALID_ARGUMENT; + + stroke_conversion = path->stroke_conversion; + + /* Free the stroke. */ + if (path->stroke_path_data) + { + vg_lite_os_free(path->stroke_path_data); + /* Reset the stroke. */ + path->stroke_path_data = NULL; + } + + if (stroke_conversion->stroke_line_width >= FLOAT_FAT_LINE_WIDTH + && stroke_conversion->stroke_line_width >= 1.0f) + { + stroke_conversion->is_fat = 1; + } + VG_LITE_RETURN_ERROR(_initialize_stroke_dash_parameters(stroke_conversion)); + VG_LITE_RETURN_ERROR(_flatten_path(stroke_conversion, path)); + VG_LITE_RETURN_ERROR(_create_stroke_path(stroke_conversion)); + VG_LITE_RETURN_ERROR(_copy_stroke_path(stroke_conversion, path)); + + return error; +} + +vg_lite_error_t vg_lite_set_stroke( + vg_lite_path_t *path, + vg_lite_cap_style_t stroke_cap_style, + vg_lite_join_style_t stroke_join_style, + vg_lite_float_t stroke_line_width, + vg_lite_float_t stroke_miter_limit, + vg_lite_float_t *stroke_dash_pattern, + uint32_t stroke_dash_pattern_count, + vg_lite_float_t stroke_dash_phase, + vg_lite_color_t stroke_color + ) +{ + if(!path || stroke_line_width <= 0) + return VG_LITE_INVALID_ARGUMENT; + + if(stroke_miter_limit < 1.0f) + stroke_miter_limit = 1.0f; + + if (!path->stroke_conversion) { + path->stroke_conversion = (vg_lite_stroke_conversion_t *)vg_lite_os_malloc(sizeof(vg_lite_stroke_conversion_t)); + if (!path->stroke_conversion) + return VG_LITE_OUT_OF_RESOURCES; + memset(path->stroke_conversion, 0, sizeof(vg_lite_stroke_conversion_t)); + } + + path->stroke_conversion->stroke_cap_style = stroke_cap_style; + path->stroke_conversion->stroke_join_style = stroke_join_style; + path->stroke_conversion->stroke_line_width = stroke_line_width; + path->stroke_conversion->stroke_miter_limit = stroke_miter_limit; + path->stroke_conversion->half_line_width = stroke_line_width / 2.0f; + path->stroke_conversion->stroke_miter_limit_square = path->stroke_conversion->stroke_miter_limit * path->stroke_conversion->stroke_miter_limit; + path->stroke_conversion->stroke_dash_pattern = stroke_dash_pattern; + path->stroke_conversion->stroke_dash_pattern_count = stroke_dash_pattern_count; + path->stroke_conversion->stroke_dash_phase = stroke_dash_phase; + path->stroke_color = stroke_color; + + return VG_LITE_SUCCESS; +} + +static inline vg_lite_error_t transform_bounding_box(vg_lite_rectangle_t *in_bbx, + vg_lite_matrix_t *matrix, + vg_lite_rectangle_t *clip, + vg_lite_rectangle_t *out_bbx, + vg_lite_point_t *origin); + +#if (VG_BLIT_WORKAROUND == 1) +/* + * Calculates the minimal possible target buffer starting from a given target + * buffer and considering a source texture (to blit), graphic transformations + * and clipping window. + */ +static vg_lite_error_t config_new_target(vg_lite_buffer_t *target, + vg_lite_buffer_t *source, + vg_lite_matrix_t *matrix, + vg_lite_rectangle_t *clip, + vg_lite_buffer_t *new_target); +#endif /* VG_BLIT_WORKAROUND */ + +static vg_lite_error_t swap(float *a,float *b) +{ + float temp; + if(a == NULL || b == NULL) + return VG_LITE_INVALID_ARGUMENT; + temp = *a; + *a = *b; + *b = temp; + return VG_LITE_SUCCESS; +} + +static vg_lite_float_t _angle( + vg_lite_float_t Ux, + vg_lite_float_t Uy, + vg_lite_float_t Vx, + vg_lite_float_t Vy + ) +{ + + vg_lite_float_t dot, length, angle, cosVal; + int32_t sign; + + dot = Ux * Vx + Uy * Vy; + length = SQRTF(Ux * Ux + Uy * Uy) * SQRTF(Vx * Vx + Vy * Vy); + sign = (Ux * Vy - Uy * Vx < 0) ? -1 : 1; + cosVal = dot / length; + cosVal = CLAMP(cosVal, -1.0f, 1.0f); + angle = sign * ACOSF(cosVal); + return angle; +} + +/*! + @discussion + Convert arc to multi-segment bezier curve. + @param HorRadius + Major axis radius. + @param VerRadius + minor axis radius. + @param RotAngle + Rotation angle. + @param EndX + End coordinate x. + @param EndX + End coordinate y. + @param CounterClockwise + If this is 0,anticlockwise rotation,if this is 1,clockwise rotation. + @param Large + 1 means big arc,0 means little arc. + @param Relative + 1 means absolute coordinates,0 means relative coordinates. + @param coords + Including the start point coordinates of the path,the control point of the last segment of the path, + and the end point of the last segment of the path. + @param path_data + Path data usr for internal conversion. + @param offset + The offset of path_data. + @param last_size + The remain unconverted size of the original path data. + @result + Error code. VG_LITE_INVALID_ARGUMENTS to indicate the parameters are wrong. +*/ +vg_lite_error_t _convert_arc( + vg_lite_float_t HorRadius, + vg_lite_float_t VerRadius, + vg_lite_float_t RotAngle, + vg_lite_float_t EndX, + vg_lite_float_t EndY, + uint8_t CounterClockwise, + uint8_t Large, + uint8_t Relative, + vg_lite_control_coord_t* coords, + void ** path_data, + uint32_t *offset, + uint32_t last_size + ) +{ + vg_lite_float_t endX, endY; + uint8_t segmentCommand; + vg_lite_float_t phi, cosPhi, sinPhi; + vg_lite_float_t dxHalf, dyHalf; + vg_lite_float_t x1Prime, y1Prime; + vg_lite_float_t rx, ry; + vg_lite_float_t x1PrimeSquare, y1PrimeSquare; + vg_lite_float_t lambda; + vg_lite_float_t rxSquare, rySquare; + int32_t sign; + vg_lite_float_t sq, signedSq; + vg_lite_float_t cxPrime, cyPrime; + vg_lite_float_t theta1, thetaSpan; + int32_t segs; + vg_lite_float_t theta, ax, ay, x, y; + vg_lite_float_t controlX, controlY, anchorX, anchorY; + vg_lite_float_t lastX, lastY; + uint32_t bufferSize; + char *pchar, *arcPath; + vg_lite_float_t *pfloat; + /******************************************************************* + ** Converting. + */ + if(path_data == NULL || *path_data == NULL || offset == NULL || coords == NULL) + return VG_LITE_INVALID_ARGUMENT; + + if (Relative) + { + endX = EndX + coords->lastX; + endY = EndY + coords->lastY; + } + else + { + endX = EndX; + endY = EndY; + } + + phi = RotAngle / 180.0f * PI; + cosPhi = COSF(phi); + sinPhi = SINF(phi); + + if (Relative) + { + dxHalf = - EndX / 2.0f; + dyHalf = - EndY / 2.0f; + } + else + { + dxHalf = (coords->lastX - endX) / 2.0f; + dyHalf = (coords->lastY - endY) / 2.0f; + } + + x1Prime = cosPhi * dxHalf + sinPhi * dyHalf; + y1Prime = -sinPhi * dxHalf + cosPhi * dyHalf; + + rx = FABSF(HorRadius); + ry = FABSF(VerRadius); + + x1PrimeSquare = x1Prime * x1Prime; + y1PrimeSquare = y1Prime * y1Prime; + + lambda = x1PrimeSquare / (rx * rx) + y1PrimeSquare / (ry * ry); + if (lambda > 1.0f) + { + rx *= SQRTF(lambda); + ry *= SQRTF(lambda); + } + + rxSquare = rx * rx; + rySquare = ry * ry; + + sign = (Large == CounterClockwise) ? -1 : 1; + sq = ( rxSquare * rySquare + - rxSquare * y1PrimeSquare + - rySquare * x1PrimeSquare + ) + / + ( rxSquare * y1PrimeSquare + + rySquare * x1PrimeSquare + ); + signedSq = sign * ((sq < 0) ? 0 : SQRTF(sq)); + cxPrime = signedSq * (rx * y1Prime / ry); + cyPrime = signedSq * -(ry * x1Prime / rx); + + theta1 = _angle(1, 0, (x1Prime - cxPrime) / rx, (y1Prime - cyPrime) / ry); + theta1 = FMODF(theta1, 2 * PI); + + thetaSpan = _angle(( x1Prime - cxPrime) / rx, ( y1Prime - cyPrime) / ry, + (-x1Prime - cxPrime) / rx, (-y1Prime - cyPrime) / ry); + + if (!CounterClockwise && (thetaSpan > 0)) + { + thetaSpan -= 2 * PI; + } + else if (CounterClockwise && (thetaSpan < 0)) + { + thetaSpan += 2 * PI; + } + + thetaSpan = FMODF(thetaSpan, 2 * PI); + + + /******************************************************************* + ** Drawing. + */ + + segs = (int32_t) (CEILF(FABSF(thetaSpan) / (45.0f / 180.0f * PI))); + + theta = thetaSpan / segs; + + ax = coords->lastX - COSF(theta1) * rx; + ay = coords->lastY - SINF(theta1) * ry; + + /* Determine the segment command. */ + segmentCommand = Relative + ? VLC_OP_QUAD_REL + : VLC_OP_QUAD; + + /* Determine the size of the buffer required. */ + bufferSize = (1 + 2 * 2) * SIZEOF(vg_lite_float_t) * segs; + + arcPath = (char *)vg_lite_os_malloc(*offset + bufferSize + last_size); + if (arcPath == NULL) + return VG_LITE_OUT_OF_MEMORY; + memset(arcPath, 0, *offset + bufferSize + last_size); + memcpy(arcPath,(char *)*path_data,*offset); + vg_lite_os_free(*path_data); + + *path_data = arcPath; + + pchar = arcPath + *offset; + pfloat = (vg_lite_float_t *)pchar; + + /* Set initial last point. */ + lastX = coords->lastX; + lastY = coords->lastY; + + while (segs-- > 0) + { + theta1 += theta; + + controlX = ax + COSF(theta1 - (theta / 2.0f)) * rx / COSF(theta / 2.0f); + controlY = ay + SINF(theta1 - (theta / 2.0f)) * ry / COSF(theta / 2.0f); + + anchorX = ax + COSF(theta1) * rx; + anchorY = ay + SINF(theta1) * ry; + + if (RotAngle != 0) + { + x = coords->lastX + cosPhi * (controlX - coords->lastX) - sinPhi * (controlY - coords->lastY); + y = coords->lastY + sinPhi * (controlX - coords->lastX) + cosPhi * (controlY - coords->lastY); + controlX = x; + controlY = y; + + x = coords->lastX + cosPhi * (anchorX - coords->lastX) - sinPhi * (anchorY - coords->lastY); + y = coords->lastY + sinPhi * (anchorX - coords->lastX) + cosPhi * (anchorY - coords->lastY); + anchorX = x; + anchorY = y; + } + + if (segs == 0) + { + /* Use end point directly to avoid accumulated errors. */ + anchorX = endX; + anchorY = endY; + } + + /* Adjust relative coordinates. */ + if (Relative) + { + vg_lite_float_t nextLastX = anchorX; + vg_lite_float_t nextLastY = anchorY; + + controlX -= lastX; + controlY -= lastY; + + anchorX -= lastX; + anchorY -= lastY; + + lastX = nextLastX; + lastY = nextLastY; + } + pchar = (char*)pfloat; + *pchar = segmentCommand ; + pfloat++; + *pfloat++ = controlX; + *pfloat++ = controlY; + *pfloat++ = anchorX; + *pfloat++ = anchorY; + *offset += (1 + 2 * 2) * SIZEOF(vg_lite_float_t); + } + + /* Update the control coordinates. */ + coords->lastX = endX; + coords->lastY = endY; + coords->controlX = endX; + coords->controlY = endY; + + return VG_LITE_SUCCESS; +} + +vg_lite_error_t _allocate_command_buffer(uint32_t size) +{ + vg_lite_kernel_allocate_t allocate; + vg_lite_error_t error = VG_LITE_SUCCESS; +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t *tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif + + if(size == 0) + return VG_LITE_SUCCESS; + + allocate.bytes = size; + allocate.contiguous = 1; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &allocate)); + + ctx->context.command_buffer[0] = allocate.memory_handle; + ctx->context.command_buffer_logical[0] = allocate.memory; + ctx->context.command_buffer_physical[0] = allocate.memory_gpu; + + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &allocate)); + + ctx->context.command_buffer[1] = allocate.memory_handle; + ctx->context.command_buffer_logical[1] = allocate.memory; + ctx->context.command_buffer_physical[1] = allocate.memory_gpu; + + ctx->command_buffer[0] = ctx->context.command_buffer_logical[0]; + ctx->command_buffer[1] = ctx->context.command_buffer_logical[1]; + + ctx->command_buffer_size = size; + ctx->command_offset[0] = 0; + ctx->command_offset[1] = 0; + ctx->command_buffer_current = 0; + +#if !defined(VG_DRIVER_SINGLE_THREAD) + ctx->start_offset = 0; + ctx->end_offset = 0; + ctx->ts_init = 0; + memset(ctx->ts_record, 0, sizeof(ctx->ts_record)); +#endif + + return error; +} + +vg_lite_error_t _free_command_buffer() +{ + vg_lite_kernel_free_t free; + vg_lite_error_t error = VG_LITE_SUCCESS; + +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t* tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif + + if(ctx->context.command_buffer[0]){ + free.memory_handle = ctx->context.command_buffer[0]; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &free)); + ctx->context.command_buffer[0] = 0; + ctx->context.command_buffer_logical[0] = 0; + } + + if(ctx->context.command_buffer[1]){ + free.memory_handle = ctx->context.command_buffer[1]; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &free)); + ctx->context.command_buffer[1] = 0; + ctx->context.command_buffer_logical[1] = 0; + } + + return error; +} + +static void ClampColor(FLOATVECTOR4 Source,FLOATVECTOR4 Target,uint8_t Premultiplied) +{ + vg_lite_float_t colorMax; + /* Clamp the alpha channel. */ + Target[3] = CLAMP(Source[3], 0.0f, 1.0f); + + /* Determine the maximum value for the color channels. */ + colorMax = Premultiplied ? Target[3] : 1.0f; + + /* Clamp the color channels. */ + Target[0] = CLAMP(Source[0], 0.0f, colorMax); + Target[1] = CLAMP(Source[1], 0.0f, colorMax); + Target[2] = CLAMP(Source[2], 0.0f, colorMax); +} + +static uint8_t PackColorComponent(vg_lite_float_t value) +{ + /* Compute the rounded normalized value. */ + vg_lite_float_t rounded = value * 255.0f + 0.5f; + + /* Get the integer part. */ + int32_t roundedInt = (int32_t) rounded; + + /* Clamp to 0..1 range. */ + uint8_t clamped = (uint8_t) CLAMP(roundedInt, 0, 255); + + /* Return result. */ + return clamped; +} + +#if !defined(VG_DRIVER_SINGLE_THREAD) +static void command_buffer_copy(void *new_cmd, void *old_cmd, uint32_t start, uint32_t end, uint32_t *cmd_count) +{ + uint32_t i = start,j; + uint32_t *p_new_cmd32,*p_cmd32,*temp; + uint32_t data_count = 0; + + memset(&hw,0,sizeof(vg_lite_hardware_t)); + temp = NULL; + p_new_cmd32 = (uint32_t *)new_cmd; + p_cmd32 = (uint32_t *)old_cmd; + while(i < end) + { + /* data command is 0x40000000 | count, and count = databytes / 8 ,and data command and databytes should align to 8 */ + if((*p_cmd32 & 0xF0000000) == 0x40000000) { + data_count = *p_cmd32 & 0x0FFFFFFF; + data_count++; + p_cmd32 += 2 * data_count; + i += data_count * 8; + /* SEMAPHORE command is 0x10000000 | id,stall command is 0x20000000 | id , call command is is 0x20000000 | count, + and this three command should occupy 8bytes*/ + }else if((*p_cmd32 & 0xF0000000) == 0x20000000 || (*p_cmd32 & 0xF0000000) == 0x10000000 + || (*p_cmd32 & 0xF0000000) == 0x60000000 || (*p_cmd32 & 0xF0000000) == 0x80000000){ + p_cmd32 += 2; + i += 8; + /* register command is 0x30000000 | ((count) << 16) | address, + and the bytes of this command add register count should align to 8 */ + }else if((*p_cmd32 & 0xF0000000) == 0x30000000) { + /* get register data count */ + data_count = (*p_cmd32 & 0x0FFFFFFF) >> 16; + if(data_count == 1) + { + temp = p_cmd32 + 1; + if(hw.hw_states[*p_cmd32 & 0xff].state != *temp || !hw.hw_states[*p_cmd32 & 0xff].init){ + hw.hw_states[*p_cmd32 & 0xff].state = *temp; + hw.hw_states[*p_cmd32 & 0xff].init = 1; + for(j = 0; j < 2; j++) { + *p_new_cmd32 = *p_cmd32; + p_new_cmd32++; + p_cmd32++; + *cmd_count += 4; + i += 4; + } + } + else + { + p_cmd32 += 2; + i += 8; + } + }else{ + /* the bytes of register count add register command */ + data_count++; + if(data_count % 2 != 0) + data_count++; + for(j = 0; j < data_count; j++) { + *p_new_cmd32 = *p_cmd32; + p_new_cmd32++; + p_cmd32++; + *cmd_count += 4; + i += 4; + } + } + } + } +} +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +static void _memset(void *p, unsigned char value, int size) +{ + int i; + for (i = 0; i < size; i++) { + ((unsigned char*) p)[i] = value; + } +} + +static int has_valid_command_buffer(vg_lite_context_t *context) +{ + if(context == NULL) + return 0; + if(context->command_buffer_current >= CMDBUF_COUNT) + return 0; + if(context->command_buffer[context->command_buffer_current] == NULL) + return 0; + + return 1; +} + +#if !defined(VG_DRIVER_SINGLE_THREAD) +static int has_valid_context_buffer(vg_lite_context_t *context) +{ + if(context == NULL) + return 0; + if(context->context_buffer == NULL) + return 0; + + return 1; +} +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +#if DUMP_IMAGE +static void dump_img(void * memory, int width, int height, vg_lite_buffer_format_t format) +{ + FILE * fp; + char imgname[255] = {'\0'}; + int i; + static int num = 1; + unsigned int* pt = (unsigned int*) memory; + + sprintf(imgname, "img_pid%d_%d.txt", getpid(), num++); + + fp = fopen(imgname, "w"); + + if (fp == NULL) + printf("error!\n"); + + + switch (format) { + case VG_LITE_INDEX_1: + for(i = 0; i < width * height / 32; ++i) + { + fprintf(fp, "0x%08x\n",pt[i]); + } + break; + + case VG_LITE_INDEX_2: + for(i = 0; i < width * height / 16; ++i) + { + fprintf(fp, "0x%08x\n",pt[i]); + } + break; + + case VG_LITE_INDEX_4: + for(i = 0; i < width * height / 8; ++i) + { + fprintf(fp, "0x%08x\n",pt[i]); + } + break; + + case VG_LITE_INDEX_8: + for(i = 0; i < width * height / 4; ++i) + { + fprintf(fp, "0x%08x\n",pt[i]); + } + break; + + case VG_LITE_RGBA2222: + for(i = 0; i < width * height / 4; ++i) + { + fprintf(fp, "0x%08x\n",pt[i]); + } + break; + + case VG_LITE_RGBA4444: + case VG_LITE_BGRA4444: + case VG_LITE_RGB565: + case VG_LITE_BGR565: + for(i = 0; i < width * height / 2; ++i) + { + fprintf(fp, "0x%08x\n",pt[i]); + } + break; + + case VG_LITE_RGBA8888: + case VG_LITE_BGRA8888: + case VG_LITE_RGBX8888: + case VG_LITE_BGRX8888: + for(i = 0; i < width * height; ++i) + { + fprintf(fp, "0x%08x\n",pt[i]); + } + break; + + default: + break; + } + fclose(fp); + fp = NULL; +} +#endif + +/* Convert VGLite data format to HW value. */ +static uint32_t convert_path_format(vg_lite_format_t format) +{ + switch (format) { + case VG_LITE_S8: + return 0; + + case VG_LITE_S16: + return 0x100000; + + case VG_LITE_S32: + return 0x200000; + + case VG_LITE_FP32: + return 0x300000; + + default: + return 0; + } +} + +/* Convert VGLite quality enums to HW values. */ +static uint32_t convert_path_quality(vg_lite_quality_t quality) +{ + switch (quality) { + case VG_LITE_HIGH: + return 0x3; + + case VG_LITE_UPPER: + return 0x2; + + case VG_LITE_MEDIUM: + return 0x1; + + default: + return 0x0; + } +} + +static uint32_t rgb_to_l(uint32_t color) +{ + uint32_t l = (uint32_t)((0.2126f * (vg_lite_float_t)(color & 0xFF)) + + (0.7152f * (vg_lite_float_t)((color >> 8) & 0xFF)) + + (0.0722f * (vg_lite_float_t)((color >> 16) & 0xFF))); + return l | (l << 24); +} + +/* Get the bpp information of a color format. */ +static void get_format_bytes(vg_lite_buffer_format_t format, + uint32_t *mul, + uint32_t *div, + uint32_t *bytes_align) +{ + *mul = *div = 1; + *bytes_align = 4; + switch (format) { + case VG_LITE_L8: + case VG_LITE_A8: + *bytes_align = 16; + break; + + case VG_LITE_A4: + *div = 2; + *bytes_align = 8; + break; + + case VG_LITE_ABGR1555: + case VG_LITE_ARGB1555: + case VG_LITE_BGRA5551: + case VG_LITE_RGBA5551: + case VG_LITE_RGBA4444: + case VG_LITE_BGRA4444: + case VG_LITE_ABGR4444: + case VG_LITE_ARGB4444: + case VG_LITE_RGB565: + case VG_LITE_BGR565: + case VG_LITE_YUYV: + case VG_LITE_YUY2: + case VG_LITE_YUY2_TILED: + /* AYUY2 buffer memory = YUY2 + alpha. */ + case VG_LITE_AYUY2: + case VG_LITE_AYUY2_TILED: + *mul = 2; + *bytes_align = 32; + break; + + case VG_LITE_RGBA8888: + case VG_LITE_BGRA8888: + case VG_LITE_ABGR8888: + case VG_LITE_ARGB8888: + case VG_LITE_RGBX8888: + case VG_LITE_BGRX8888: + case VG_LITE_XBGR8888: + case VG_LITE_XRGB8888: + *mul = 4; + *bytes_align = 64; + break; + + case VG_LITE_NV12: + case VG_LITE_NV12_TILED: + *mul = 3; + *bytes_align = 32; + break; + + case VG_LITE_ANV12: + case VG_LITE_ANV12_TILED: + *mul = 4; + *bytes_align = 64; + break; + + case VG_LITE_INDEX_1: + *div = 8; + *bytes_align = 8; + break; + + case VG_LITE_INDEX_2: + *div = 4; + *bytes_align = 8; + break; + + case VG_LITE_INDEX_4: + *div = 2; + *bytes_align = 8; + break; + + case VG_LITE_INDEX_8: + *bytes_align = 16; + break; + + case VG_LITE_RGBA2222: + case VG_LITE_BGRA2222: + case VG_LITE_ABGR2222: + case VG_LITE_ARGB2222: + *mul = 1; + *bytes_align = 8; + break; + + default: + break; + } +} + +/* Convert VGLite target color format to HW value. */ +static uint32_t convert_target_format(vg_lite_buffer_format_t format, vg_lite_capabilities_t caps) +{ + switch (format) { + case VG_LITE_A8: + return 0x0; + + case VG_LITE_L8: + return 0x6; + + case VG_LITE_ABGR4444: + return 0x14; + + case VG_LITE_ARGB4444: + return 0x34; + + case VG_LITE_RGBA4444: + return 0x24; + + case VG_LITE_BGRA4444: + return 0x4; + + case VG_LITE_RGB565: + return 0x21; + + case VG_LITE_BGR565: + return 0x1; + + case VG_LITE_ABGR8888: + return 0x13; + + case VG_LITE_ARGB8888: + return 0x33; + + case VG_LITE_RGBA8888: + return 0x23; + + case VG_LITE_BGRA8888: + return 0x3; + + case VG_LITE_RGBX8888: + return 0x22; + + case VG_LITE_BGRX8888: + return 0x2; + + case VG_LITE_XBGR8888: + return 0x12; + + case VG_LITE_XRGB8888: + return 0x32; + + case VG_LITE_ABGR1555: + return 0x15; + + case VG_LITE_RGBA5551: + return 0x25; + + case VG_LITE_ARGB1555: + return 0x35; + + case VG_LITE_BGRA5551: + return 0x5; + + case VG_LITE_YUYV: + case VG_LITE_YUY2: + case VG_LITE_YUY2_TILED: + return 0x8; + + case VG_LITE_NV12: + case VG_LITE_NV12_TILED: + return 0xB; + + case VG_LITE_ANV12: + case VG_LITE_ANV12_TILED: + return 0xE; + + case VG_LITE_BGRA2222: + return 0x7; + + case VG_LITE_RGBA2222: + return 0x27; + + case VG_LITE_ABGR2222: + return 0x17; + + case VG_LITE_ARGB2222: + return 0x37; + + case VG_LITE_AYUY2: + case VG_LITE_AYUY2_TILED: + default: + return 0xF; + } +} + +/* determine source IM is aligned by specified bytes */ +static vg_lite_error_t _check_source_aligned(vg_lite_buffer_format_t format,uint32_t stride) +{ + switch (format) { + case VG_LITE_A4: + case VG_LITE_INDEX_1: + case VG_LITE_INDEX_2: + case VG_LITE_INDEX_4: + FORMAT_ALIGNMENT(stride,8); + break; + + case VG_LITE_L8: + case VG_LITE_A8: + case VG_LITE_INDEX_8: + case VG_LITE_RGBA2222: + case VG_LITE_BGRA2222: + case VG_LITE_ABGR2222: + case VG_LITE_ARGB2222: + FORMAT_ALIGNMENT(stride,16); + break; + + case VG_LITE_RGBA4444: + case VG_LITE_BGRA4444: + case VG_LITE_ABGR4444: + case VG_LITE_ARGB4444: + case VG_LITE_RGB565: + case VG_LITE_BGR565: + case VG_LITE_BGRA5551: + case VG_LITE_RGBA5551: + case VG_LITE_ABGR1555: + case VG_LITE_ARGB1555: + case VG_LITE_YUYV: + case VG_LITE_YUY2: + case VG_LITE_NV12: + case VG_LITE_YV12: + case VG_LITE_YV24: + case VG_LITE_YV16: + case VG_LITE_NV16: + FORMAT_ALIGNMENT(stride,32); + break; + + case VG_LITE_RGBA8888: + case VG_LITE_BGRA8888: + case VG_LITE_ABGR8888: + case VG_LITE_ARGB8888: + case VG_LITE_RGBX8888: + case VG_LITE_BGRX8888: + case VG_LITE_XBGR8888: + case VG_LITE_XRGB8888: + FORMAT_ALIGNMENT(stride,64); + break; + + default: + return VG_LITE_SUCCESS; + } +} + +/* Convert VGLite source color format to HW values. */ +static uint32_t convert_source_format(vg_lite_buffer_format_t format) +{ + switch (format) { + case VG_LITE_L8: + return 0x0; + + case VG_LITE_A4: + return 0x1; + + case VG_LITE_A8: + return 0x2; + + case VG_LITE_RGBA4444: + return 0x23; + + case VG_LITE_BGRA4444: + return 0x3; + + case VG_LITE_ABGR4444: + return 0x13; + + case VG_LITE_ARGB4444: + return 0x33; + + case VG_LITE_RGB565: + return 0x25; + + case VG_LITE_BGR565: + return 0x5; + + case VG_LITE_RGBA8888: + return 0x27; + + case VG_LITE_BGRA8888: + return 0x7; + + case VG_LITE_ABGR8888: + return 0x17; + + case VG_LITE_ARGB8888: + return 0x37; + + case VG_LITE_RGBX8888: + return 0x26; + + case VG_LITE_BGRX8888: + return 0x6; + + case VG_LITE_XBGR8888: + return 0x16; + + case VG_LITE_XRGB8888: + return 0x36; + + case VG_LITE_BGRA5551: + return 0x4; + + case VG_LITE_RGBA5551: + return 0x24; + + case VG_LITE_ABGR1555: + return 0x14; + + case VG_LITE_ARGB1555: + return 0x34; + + case VG_LITE_YUYV: + return 0x8; + + case VG_LITE_YUY2: + case VG_LITE_YUY2_TILED: + return 0x8; + + case VG_LITE_NV12: + case VG_LITE_NV12_TILED: + return 0xB; + + case VG_LITE_ANV12: + case VG_LITE_ANV12_TILED: + return 0xE; + + case VG_LITE_YV12: + return 0x9; + + case VG_LITE_YV24: + return 0xD; + + case VG_LITE_YV16: + return 0xC; + + case VG_LITE_NV16: + return 0xA; + + case VG_LITE_AYUY2: + case VG_LITE_AYUY2_TILED: + default: + return 0xF; + + case VG_LITE_INDEX_1: + return 0x200; + + case VG_LITE_INDEX_2: + return 0x400; + + case VG_LITE_INDEX_4: + return 0x600; + + case VG_LITE_INDEX_8: + return 0x800; + + case VG_LITE_RGBA2222: + return 0xA20; + + case VG_LITE_BGRA2222: + return 0xA00; + + case VG_LITE_ABGR2222: + return 0xA10; + + case VG_LITE_ARGB2222: + return 0xA30; + } +} + +/* Convert VGLite blend modes to HW values. */ +static uint32_t convert_blend(vg_lite_blend_t blend) +{ + switch (blend) { + case VG_LITE_BLEND_SRC_OVER: + return 0x00000100; + + case VG_LITE_BLEND_DST_OVER: + return 0x00000200; + + case VG_LITE_BLEND_SRC_IN: + return 0x00000300; + + case VG_LITE_BLEND_DST_IN: + return 0x00000400; + + case VG_LITE_BLEND_SCREEN: + return 0x00000600; + + case VG_LITE_BLEND_MULTIPLY: + return 0x00000500; + + case VG_LITE_BLEND_ADDITIVE: + return 0x00000900; + + case VG_LITE_BLEND_SUBTRACT: + return 0x00000A00; + + default: + return 0; + } +} + +/* Convert VGLite uv swizzle enums to HW values. */ +static uint32_t convert_uv_swizzle(vg_lite_swizzle_t swizzle) +{ + switch (swizzle) { + case VG_LITE_SWIZZLE_UV: + return 0x00000040; + break; + + case VG_LITE_SWIZZLE_VU: + return 0x00000050; + + default: + return 0; + break; + } +} + +/* Convert VGLite yuv standard enums to HW values. */ +static uint32_t convert_yuv2rgb(vg_lite_yuv2rgb_t yuv) +{ + switch (yuv) { + case VG_LITE_YUV601: + return 0; + break; + + case VG_LITE_YUV709: + return 0x00008000; + + default: + return 0; + break; + } +} + +/* Initialize the feature table of a chip. */ +static vg_lite_error_t fill_feature_table(uint32_t * feature) +{ + uint16_t size = sizeof(VGFeatureInfos) / sizeof(VGFeatureInfos[0]); + uint16_t i; + uint32_t cid = 0; + +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t* tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif + + /* Clear all bits. */ + _memset(feature, 0, sizeof(uint32_t) * gcFEATURE_COUNT); + vg_lite_get_product_info(NULL,&ctx->chip_id,&ctx->chip_rev); + if(ctx->chip_id == GPU_CHIP_ID_GC355) + ctx->premultiply_enabled = 1; + vg_lite_get_register(0x30, &cid); + + for(i = 0;i < size; i++){ + if ((VGFeatureInfos[i].chip_id == ctx->chip_id) + && (VGFeatureInfos[i].chip_version == ctx->chip_rev) + && (VGFeatureInfos[i].cid == cid) + ) + { + feature[gcFEATURE_BIT_VG_IM_INDEX_FORMAT] = VGFeatureInfos[i].vg_im_index_format; + feature[gcFEATURE_BIT_VG_PE_PREMULTIPLY] = VGFeatureInfos[i].vg_pe_premultiply; + feature[gcFEATURE_BIT_VG_BORDER_CULLING] = VGFeatureInfos[i].vg_border_culling; + feature[gcFEATURE_BIT_VG_RGBA2_FORMAT] = VGFeatureInfos[i].vg_rgba2_format; + feature[gcFEATURE_BIT_VG_QUALITY_8X] = VGFeatureInfos[i].vg_quality_8x; + feature[gcFEATURE_BIT_VG_RADIAL_GRADIENT] = VGFeatureInfos[i].vg_radial_gradient; + feature[gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT] = VGFeatureInfos[i].vg_linear_gradient_ext; + feature[gcFEATURE_BIT_VG_DITHER] = VGFeatureInfos[i].vg_dither; + feature[gcFEATURE_BIT_VG_COLOR_KEY] = VGFeatureInfos[i].vg_color_key; + break; + } + } + + if(i == size) { + return VG_LITE_INVALID_ARGUMENT; + } + ctx->s_ftable.ftflag = 1; + + return VG_LITE_SUCCESS; +} + +#if !defined(VG_DRIVER_SINGLE_THREAD) +static vg_lite_error_t flush(vg_lite_context_t *context); +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ +static vg_lite_error_t submit(vg_lite_context_t * context); +#if defined(VG_DRIVER_SINGLE_THREAD) +static vg_lite_error_t stall(vg_lite_context_t * context, uint32_t time_ms, uint32_t mask); +#else +static vg_lite_error_t stall(vg_lite_context_t * context, uint32_t time_ms); +#endif /* VG_DRIVER_SINGLE_THREAD */ + +#if !defined(VG_DRIVER_SINGLE_THREAD) +/* Push a state array into context buffer. */ +static vg_lite_error_t push_states_to_context(vg_lite_context_t * context, uint32_t address, uint32_t count, uint32_t *data) +{ + uint32_t i, command_id; + vg_lite_error_t error; + if (!has_valid_context_buffer(context)) + return VG_LITE_NO_CONTEXT; + + command_id = CMDBUF_INDEX(*context); + if(CMDBUF_IN_QUEUE(&context->context, command_id)) + VG_LITE_RETURN_ERROR(stall(context, 0)); + + /* Reserve enough space in the context buffer for flush and submit */ + if (context->context_buffer_offset[command_id] + 8 >= context->context_buffer_size) { + return VG_LITE_OUT_OF_RESOURCES; + } + + ((uint32_t *) (context->context_buffer[command_id] + context->context_buffer_offset[command_id]))[0] = VG_LITE_STATES(count, address); + + for (i = 0; i < count; i++) { + ((uint32_t *) (context->context_buffer[command_id] + context->context_buffer_offset[command_id]))[1 + i] = data[i]; + } + if (i%2 == 0) { + ((uint32_t *) (context->context_buffer[command_id] + context->context_buffer_offset[command_id]))[1 + i] = VG_LITE_NOP(); + } + + context->context_buffer_offset[command_id] += VG_LITE_ALIGN(count + 1, 2) * 4; + + return VG_LITE_SUCCESS; +} + +static vg_lite_error_t update_context_buffer() +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + vg_lite_kernel_context_switch_t check; + vg_lite_tls_t* tls; + uint32_t command_id; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + command_id = CMDBUF_INDEX(tls->t_context); + check.context =(uint32_t)&tls->t_context.context; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_QUERY_CONTEXT_SWITCH, &check)); + /* if context have been switched and this task need use index. */ + if(check.isContextSwitched && tls->t_context.index_format) + { + uint32_t clut_addr[4]={0x0A98,0x0A9C,0x0AA0,0x0B00}; + uint32_t clut_count[4]={2,4,16,256}; + + for(int i = 0; i < 4; i++) + { + /* check which index colors would be use in this task. */ + if(tls->t_context.colors[i] && tls->t_context.clut_used[i]){ + VG_LITE_RETURN_ERROR(push_states_to_context(&tls->t_context, clut_addr[i], clut_count[i], tls->t_context.colors[i])); + tls->t_context.clut_used[i] = 0; + } + } + tls->t_context.index_format = 0; + } + + /* Set tessellation buffer states */ + if(check.isContextSwitched && tls->t_context.ts_init && !tls->t_context.ts_init_used && tls->t_context.ts_init_use){ + /* Reserve enough space in the context buffer for flush and submit */ + if (tls->t_context.context_buffer_offset[command_id] + 80 >= tls->t_context.context_buffer_size) { + return VG_LITE_OUT_OF_RESOURCES; + } + memcpy(tls->t_context.context_buffer[command_id] + tls->t_context.context_buffer_offset[command_id], tls->t_context.ts_record, 80); + tls->t_context.ts_init = 0; + tls->t_context.ts_init_used = 0; + tls->t_context.ts_init_use = 0; + tls->t_context.context_buffer_offset[command_id] += 80; + } + + if(tls->t_context.context_buffer_offset[command_id]){ + ((uint32_t *) (tls->t_context.context_buffer[command_id] + tls->t_context.context_buffer_offset[command_id]))[0] = VG_LITE_RETURN(); + ((uint32_t *) (tls->t_context.context_buffer[command_id] + tls->t_context.context_buffer_offset[command_id]))[1] = 0; + tls->t_context.context_buffer_offset[command_id] += 8; + ((uint32_t *) CMDBUF_BUFFER(tls->t_context))[0] = VG_LITE_CALL((tls->t_context.context_buffer_offset[command_id] + 7) / 8); + ((uint32_t *) CMDBUF_BUFFER(tls->t_context))[1] = tls->t_context.context.context_buffer_physical[command_id]; + tls->t_context.context_buffer_offset[command_id] = 0; + } + + return error; +} +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +#if defined(VG_DRIVER_SINGLE_THREAD) +/* Push a state array into current command buffer. */ +static vg_lite_error_t push_states(vg_lite_context_t * context, uint32_t address, uint32_t count, uint32_t *data) +{ + uint32_t i; + vg_lite_error_t error; + if (!has_valid_command_buffer(context)) + return VG_LITE_NO_CONTEXT; + + if (CMDBUF_OFFSET(*context) + 8 + VG_LITE_ALIGN(count + 1, 2) * 4 >= CMDBUF_SIZE(*context)) { + VG_LITE_RETURN_ERROR(submit(context)); + VG_LITE_RETURN_ERROR(stall(context, 0, (uint32_t)~0)); + } + + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_STATES(count, address); + + for (i = 0; i < count; i++) { + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1 + i] = data[i]; + } + if (i%2 == 0) { + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1 + i] = VG_LITE_NOP(); + } + + CMDBUF_OFFSET(*context) += VG_LITE_ALIGN(count + 1, 2) * 4; + + return VG_LITE_SUCCESS; +} + +/* Push a single state command into the current command buffer. */ +static vg_lite_error_t push_state(vg_lite_context_t * context, uint32_t address, uint32_t data) +{ + vg_lite_error_t error; + if (!has_valid_command_buffer(context)) + return VG_LITE_NO_CONTEXT; + + if (CMDBUF_OFFSET(*context) + 16 >= CMDBUF_SIZE(*context)) { + VG_LITE_RETURN_ERROR(submit(context)); + VG_LITE_RETURN_ERROR(stall(context, 0, (uint32_t)~0)); + } + + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_STATE(address); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = data; + + CMDBUF_OFFSET(*context) += 8; + + return VG_LITE_SUCCESS; +} + +/* Push a single state command with given address. */ +static vg_lite_error_t push_state_ptr(vg_lite_context_t * context, uint32_t address, void * data_ptr) +{ + vg_lite_error_t error; + uint32_t data = *(uint32_t *) data_ptr; + if (!has_valid_command_buffer(context)) + return VG_LITE_NO_CONTEXT; + + if (CMDBUF_OFFSET(*context) + 16 >= CMDBUF_SIZE(*context)) { + VG_LITE_RETURN_ERROR(submit(context)); + VG_LITE_RETURN_ERROR(stall(context, 0, (uint32_t)~0)); + } + + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_STATE(address); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = data; + + CMDBUF_OFFSET(*context) += 8; + + return VG_LITE_SUCCESS; +} + +/* Push a "call" command into the current command buffer. */ +static vg_lite_error_t push_call(vg_lite_context_t * context, uint32_t address, uint32_t bytes) +{ + vg_lite_error_t error; + if (!has_valid_command_buffer(context)) + return VG_LITE_NO_CONTEXT; + + if (CMDBUF_OFFSET(*context) + 16 >= CMDBUF_SIZE(*context)) { + VG_LITE_RETURN_ERROR(submit(context)); + VG_LITE_RETURN_ERROR(stall(context, 0, (uint32_t)~0)); + } + + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_CALL((bytes + 7) / 8); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = address; + + CMDBUF_OFFSET(*context) += 8; + + return VG_LITE_SUCCESS; +} + +/* Push a rectangle command into the current command buffer. */ +static vg_lite_error_t push_rectangle(vg_lite_context_t * context, int x, int y, int width, int height) +{ + vg_lite_error_t error; + if (!has_valid_command_buffer(context)) + return VG_LITE_NO_CONTEXT; + + if (CMDBUF_OFFSET(*context) + 16 >= CMDBUF_SIZE(*context)) { + VG_LITE_RETURN_ERROR(submit(context)); + VG_LITE_RETURN_ERROR(stall(context, 0, (uint32_t)~0)); + } + + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_DATA(1); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = 0; + ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[4] = (uint16_t)x; + ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[5] = (uint16_t)y; + ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[6] = (uint16_t)width; + ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[7] = (uint16_t)height; + + CMDBUF_OFFSET(*context) += 16; + + return VG_LITE_SUCCESS; +} + +/* Push a data array into the current command buffer. */ +static vg_lite_error_t push_data(vg_lite_context_t * context, int size, void * data) +{ + vg_lite_error_t error; + int bytes = VG_LITE_ALIGN(size, 8); + + if (!has_valid_command_buffer(context)) + return VG_LITE_NO_CONTEXT; + + if (CMDBUF_OFFSET(*context) + 16 + bytes >= CMDBUF_SIZE(*context)) { + VG_LITE_RETURN_ERROR(submit(context)); + VG_LITE_RETURN_ERROR(stall(context, 0, (uint32_t)~0)); + } + + ((uint64_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[(bytes / 8)] = 0; + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_DATA(bytes / 8); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = 0; + memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context) + 8, data, size); + + CMDBUF_OFFSET(*context) += 8 + bytes; + + return VG_LITE_SUCCESS; +} + +/* Push a "stall" command into the current command buffer. */ +static vg_lite_error_t push_stall(vg_lite_context_t * context, uint32_t module) +{ + vg_lite_error_t error; + if (!has_valid_command_buffer(context)) + return VG_LITE_NO_CONTEXT; + + if (CMDBUF_OFFSET(*context) + 16 >= CMDBUF_SIZE(*context)) { + VG_LITE_RETURN_ERROR(submit(context)); + VG_LITE_RETURN_ERROR(stall(context, 0, (uint32_t)~0)); + } + + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_SEMAPHORE(module); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = 0; + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[2] = VG_LITE_STALL(module); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[3] = 0; + + CMDBUF_OFFSET(*context) += 16; + + return VG_LITE_SUCCESS; +} + +#else + +/* Push a state array into current command buffer. */ +static vg_lite_error_t push_states(vg_lite_context_t * context, uint32_t address, uint32_t count, uint32_t *data) +{ + uint32_t i, command_id, index; + vg_lite_error_t error; + if (!has_valid_command_buffer(context)) + return VG_LITE_NO_CONTEXT; + + command_id = CMDBUF_INDEX(*context); + if(CMDBUF_IN_QUEUE(&context->context, command_id)) + VG_LITE_RETURN_ERROR(stall(context, 0)); + + /* Reserve enough space in the command buffer for flush and submit */ + if (CMDBUF_OFFSET(*context) + 40 + VG_LITE_ALIGN(count + 1, 2) * 4 >= CMDBUF_SIZE(*context)) { + uint32_t cmd_count = 0,start_offset = 0; + context->end_offset = CMDBUF_OFFSET(*context); + start_offset = context->start_offset; + VG_LITE_RETURN_ERROR(flush(context)); + VG_LITE_RETURN_ERROR(submit(context)); + CMDBUF_SWAP(*context); + command_id = CMDBUF_INDEX(*context); + if(CMDBUF_IN_QUEUE(&context->context, command_id)) + VG_LITE_RETURN_ERROR(stall(context, 0)); + + RESERVE_BYTES_IN_CMDBUF(*context); + + if(context->ts_init){ + memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context), context->ts_record, 80); + CMDBUF_OFFSET(*context) += 80; + context->ts_init_used = 1; + } + + /* update start offset */ + context->start_offset = CMDBUF_OFFSET(*context); + + index = (command_id? 0 : 1); + command_buffer_copy((void *)(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)), (void *)(context->command_buffer[index] + start_offset), + start_offset, context->end_offset, &cmd_count); + CMDBUF_OFFSET(*context) += cmd_count; + } + + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_STATES(count, address); + + for (i = 0; i < count; i++) { + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1 + i] = data[i]; + } + if (i%2 == 0) { + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1 + i] = VG_LITE_NOP(); + } + +#if DUMP_COMMAND + { + uint32_t loops; + if (strncmp(filename, "Commandbuffer", 13)) { + sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); + } + + fp = fopen(filename, "a"); + + if (fp == NULL) + printf("error!\n"); + + fprintf(fp, "Command buffer: 0x%08x, ", + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0]); + + for (loops = 0; loops < count / 2; loops++) { + fprintf(fp, "0x%08x,\nCommand buffer: 0x%08x, ", + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[(loops + 1) * 2 - 1], + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[(loops + 1) * 2]); + } + + fprintf(fp, "0x%08x,\n", + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[(loops + 1) * 2 - 1]); + + fclose(fp); + fp = NULL; + } +#endif + + CMDBUF_OFFSET(*context) += VG_LITE_ALIGN(count + 1, 2) * 4; + + return VG_LITE_SUCCESS; +} + +/* Push a single state command into the current command buffer. */ +static vg_lite_error_t push_state(vg_lite_context_t * context, uint32_t address, uint32_t data) +{ + vg_lite_error_t error; + uint32_t command_id, index; + if (!has_valid_command_buffer(context)) + return VG_LITE_NO_CONTEXT; + + command_id = CMDBUF_INDEX(*context); + if(CMDBUF_IN_QUEUE(&context->context, command_id)) + VG_LITE_RETURN_ERROR(stall(context, 0)); + + /* Reserve enough space in the command buffer for flush and submit */ + if (CMDBUF_OFFSET(*context) + 56 >= CMDBUF_SIZE(*context)) { + uint32_t cmd_count = 0,start_offset = 0; + context->end_offset = CMDBUF_OFFSET(*context); + start_offset = context->start_offset; + VG_LITE_RETURN_ERROR(flush(context)); + VG_LITE_RETURN_ERROR(submit(context)); + CMDBUF_SWAP(*context); + command_id = CMDBUF_INDEX(*context); + if(CMDBUF_IN_QUEUE(&context->context, command_id)) + VG_LITE_RETURN_ERROR(stall(context, 0)); + + RESERVE_BYTES_IN_CMDBUF(*context); + + if(context->ts_init){ + memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context), context->ts_record, 80); + CMDBUF_OFFSET(*context) += 80; + context->ts_init_used = 1; + } + + /* update start offset */ + context->start_offset = CMDBUF_OFFSET(*context); + + index = (command_id? 0 : 1); + command_buffer_copy((void *)(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)), (void *)(context->command_buffer[index] + start_offset), + start_offset, context->end_offset, &cmd_count); + CMDBUF_OFFSET(*context) += cmd_count; + } + + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_STATE(address); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = data; + +#if DUMP_COMMAND + if (strncmp(filename, "Commandbuffer", 13)) { + sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); + } + + fp = fopen(filename, "a"); + + if (fp == NULL) + printf("error!\n"); + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0], + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1]); + + fclose(fp); + fp = NULL; +#endif + + CMDBUF_OFFSET(*context) += 8; + + return VG_LITE_SUCCESS; +} + +/* Push a single state command with given address. */ +static vg_lite_error_t push_state_ptr(vg_lite_context_t * context, uint32_t address, void * data_ptr) +{ + vg_lite_error_t error; + uint32_t command_id, index; + uint32_t data = *(uint32_t *) data_ptr; + if (!has_valid_command_buffer(context)) + return VG_LITE_NO_CONTEXT; + + command_id = CMDBUF_INDEX(*context); + if(CMDBUF_IN_QUEUE(&context->context, command_id)) + VG_LITE_RETURN_ERROR(stall(context, 0)); + + /* Reserve enough space in the command buffer for flush and submit */ + if (CMDBUF_OFFSET(*context) + 56 >= CMDBUF_SIZE(*context)) { + uint32_t cmd_count = 0,start_offset = 0; + context->end_offset = CMDBUF_OFFSET(*context); + start_offset = context->start_offset; + VG_LITE_RETURN_ERROR(flush(context)); + VG_LITE_RETURN_ERROR(submit(context)); + CMDBUF_SWAP(*context); + command_id = CMDBUF_INDEX(*context); + if(CMDBUF_IN_QUEUE(&context->context, command_id)) + VG_LITE_RETURN_ERROR(stall(context, 0)); + + RESERVE_BYTES_IN_CMDBUF(*context); + + if(context->ts_init){ + memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context), context->ts_record, 80); + CMDBUF_OFFSET(*context) += 80; + context->ts_init_used = 1; + } + + /* update start offset */ + context->start_offset = CMDBUF_OFFSET(*context); + + index = (command_id? 0 : 1); + command_buffer_copy((void *)(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)), (void *)(context->command_buffer[index] + start_offset), + start_offset, context->end_offset, &cmd_count); + CMDBUF_OFFSET(*context) += cmd_count; + } + + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_STATE(address); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = data; + +#if DUMP_COMMAND + if (strncmp(filename, "Commandbuffer", 13)) { + sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); + } + + fp = fopen(filename, "a"); + + if (fp == NULL) + printf("error!\n"); + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0], + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1]); + + fclose(fp); + fp = NULL; +#endif + + CMDBUF_OFFSET(*context) += 8; + + return VG_LITE_SUCCESS; +} + +/* Push a "call" command into the current command buffer. */ +static vg_lite_error_t push_call(vg_lite_context_t * context, uint32_t address, uint32_t bytes) +{ + vg_lite_error_t error; + uint32_t command_id, index; + if (!has_valid_command_buffer(context)) + return VG_LITE_NO_CONTEXT; + + command_id = CMDBUF_INDEX(*context); + if(CMDBUF_IN_QUEUE(&context->context, command_id)) + VG_LITE_RETURN_ERROR(stall(context, 0)); + + /* Reserve enough space in the command buffer for flush and submit */ + if (CMDBUF_OFFSET(*context) + 56 >= CMDBUF_SIZE(*context)) { + uint32_t cmd_count = 0,start_offset = 0; + context->end_offset = CMDBUF_OFFSET(*context); + start_offset = context->start_offset; + VG_LITE_RETURN_ERROR(flush(context)); + VG_LITE_RETURN_ERROR(submit(context)); + CMDBUF_SWAP(*context); + command_id = CMDBUF_INDEX(*context); + if(CMDBUF_IN_QUEUE(&context->context, command_id)) + VG_LITE_RETURN_ERROR(stall(context, 0)); + + RESERVE_BYTES_IN_CMDBUF(*context); + + if(context->ts_init){ + memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context), context->ts_record, 80); + CMDBUF_OFFSET(*context) += 80; + context->ts_init_used = 1; + } + + /* update start offset */ + context->start_offset = CMDBUF_OFFSET(*context); + + index = (command_id? 0 : 1); + command_buffer_copy((void *)(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)), (void *)(context->command_buffer[index] + start_offset), + start_offset, context->end_offset, &cmd_count); + CMDBUF_OFFSET(*context) += cmd_count; + } + + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_CALL((bytes + 7) / 8); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = address; + +#if DUMP_COMMAND + if (strncmp(filename, "Commandbuffer", 13)) { + sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); + } + + fp = fopen(filename, "a"); + + if (fp == NULL) + printf("error!\n"); + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0], + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1]); + + fclose(fp); + fp = NULL; +#endif + + CMDBUF_OFFSET(*context) += 8; + + return VG_LITE_SUCCESS; +} + +/* Push a rectangle command into the current command buffer. */ +static vg_lite_error_t push_rectangle(vg_lite_context_t * context, int x, int y, int width, int height) +{ + vg_lite_error_t error; + uint32_t command_id, index; + if (!has_valid_command_buffer(context)) + return VG_LITE_NO_CONTEXT; + + command_id = CMDBUF_INDEX(*context); + if(CMDBUF_IN_QUEUE(&context->context, command_id)) + VG_LITE_RETURN_ERROR(stall(context, 0)); + + /* Reserve enough space in the command buffer for flush and submit */ + if (CMDBUF_OFFSET(*context) + 56 >= CMDBUF_SIZE(*context)) { + uint32_t cmd_count = 0,start_offset = 0; + context->end_offset = CMDBUF_OFFSET(*context); + start_offset = context->start_offset; + VG_LITE_RETURN_ERROR(flush(context)); + VG_LITE_RETURN_ERROR(submit(context)); + CMDBUF_SWAP(*context); + command_id = CMDBUF_INDEX(*context); + if(CMDBUF_IN_QUEUE(&context->context, command_id)) + VG_LITE_RETURN_ERROR(stall(context, 0)); + + RESERVE_BYTES_IN_CMDBUF(*context); + + if(context->ts_init){ + memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context), context->ts_record, 80); + CMDBUF_OFFSET(*context) += 80; + context->ts_init_used = 1; + } + + /* update start offset */ + context->start_offset = CMDBUF_OFFSET(*context); + + index = (command_id? 0 : 1); + command_buffer_copy((void *)(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)), (void *)(context->command_buffer[index] + start_offset), + start_offset, context->end_offset, &cmd_count); + CMDBUF_OFFSET(*context) += cmd_count; + } + + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_DATA(1); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = 0; + ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[4] = (uint16_t)x; + ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[5] = (uint16_t)y; + ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[6] = (uint16_t)width; + ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[7] = (uint16_t)height; + +#if DUMP_COMMAND + if (strncmp(filename, "Commandbuffer", 13)) { + sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); + } + + fp = fopen(filename, "a"); + + if (fp == NULL) + printf("error!\n"); + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0], 0); + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[5] << 16 | + ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[4], + ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[7] << 16 | + ((uint16_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[6]); + + fclose(fp); + fp = NULL; +#endif + + CMDBUF_OFFSET(*context) += 16; + + return VG_LITE_SUCCESS; +} + +/* Push a data array into the current command buffer. */ +static vg_lite_error_t push_data(vg_lite_context_t * context, int size, void * data) +{ + vg_lite_error_t error; + uint32_t command_id, index; + int bytes = VG_LITE_ALIGN(size, 8); + + if (!has_valid_command_buffer(context)) + return VG_LITE_NO_CONTEXT; + + command_id = CMDBUF_INDEX(*context); + if(CMDBUF_IN_QUEUE(&context->context, command_id)) + VG_LITE_RETURN_ERROR(stall(context, 0)); + + /* Reserve enough space in the command buffer for flush and submit */ + if (CMDBUF_OFFSET(*context) + 48 + bytes >= CMDBUF_SIZE(*context)) { + uint32_t cmd_count = 0,start_offset = 0; + context->end_offset = CMDBUF_OFFSET(*context); + start_offset = context->start_offset; + VG_LITE_RETURN_ERROR(flush(context)); + VG_LITE_RETURN_ERROR(submit(context)); + CMDBUF_SWAP(*context); + command_id = CMDBUF_INDEX(*context); + if(CMDBUF_IN_QUEUE(&context->context, command_id)) + VG_LITE_RETURN_ERROR(stall(context, 0)); + + RESERVE_BYTES_IN_CMDBUF(*context); + + if(context->ts_init){ + memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context), context->ts_record, 80); + CMDBUF_OFFSET(*context) += 80; + context->ts_init_used = 1; + } + + /* update start offset */ + context->start_offset = CMDBUF_OFFSET(*context); + index = (command_id? 0 : 1); + command_buffer_copy((void *)(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)), (void *)(context->command_buffer[index] + start_offset), + start_offset, context->end_offset, &cmd_count); + CMDBUF_OFFSET(*context) += cmd_count; + } + + ((uint64_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[(bytes / 8)] = 0; + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_DATA(bytes / 8); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = 0; + memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context) + 8, data, size); + +#if DUMP_COMMAND + { + int loops; + + if (strncmp(filename, "Commandbuffer", 13)) { + sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); + } + + fp = fopen(filename, "a"); + + if (fp == NULL) + printf("error!\n"); + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0], 0); + for (loops = 0; loops < bytes / 8; loops++) { + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[(loops + 1) * 2], + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[(loops + 1) * 2 + 1]); + } + + fclose(fp); + fp = NULL; + } +#endif + + CMDBUF_OFFSET(*context) += 8 + bytes; + + return VG_LITE_SUCCESS; +} + +/* Push a "stall" command into the current command buffer. */ +static vg_lite_error_t push_stall(vg_lite_context_t * context, uint32_t module) +{ + vg_lite_error_t error; + uint32_t command_id, index; + if (!has_valid_command_buffer(context)) + return VG_LITE_NO_CONTEXT; + + command_id = CMDBUF_INDEX(*context); + if(CMDBUF_IN_QUEUE(&context->context, command_id)) + VG_LITE_RETURN_ERROR(stall(context, 0)); + + /* Reserve enough space in the command buffer for flush and submit */ + if (CMDBUF_OFFSET(*context) + 56 >= CMDBUF_SIZE(*context)) { + uint32_t cmd_count = 0,start_offset = 0; + context->end_offset = CMDBUF_OFFSET(*context); + start_offset = context->start_offset; + VG_LITE_RETURN_ERROR(flush(context)); + VG_LITE_RETURN_ERROR(submit(context)); + CMDBUF_SWAP(*context); + command_id = CMDBUF_INDEX(*context); + if(CMDBUF_IN_QUEUE(&context->context, command_id)) + VG_LITE_RETURN_ERROR(stall(context, 0)); + + RESERVE_BYTES_IN_CMDBUF(*context); + + if(context->ts_init){ + memcpy(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context), context->ts_record, 80); + CMDBUF_OFFSET(*context) += 80; + context->ts_init_used = 1; + } + + /* update start offset */ + context->start_offset = CMDBUF_OFFSET(*context); + + index = (command_id? 0 : 1); + command_buffer_copy((void *)(CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)), (void *)(context->command_buffer[index] + start_offset), + start_offset, context->end_offset, &cmd_count); + CMDBUF_OFFSET(*context) += cmd_count; + } + + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_SEMAPHORE(module); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = 0; + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[2] = VG_LITE_STALL(module); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[3] = 0; + +#if DUMP_COMMAND + if (strncmp(filename, "Commandbuffer", 13)) { + sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); + } + + fp = fopen(filename, "a"); + + if (fp == NULL) + printf("error!\n"); + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0], 0); + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[2], 0); + + fclose(fp); + fp = NULL; +#endif + + CMDBUF_OFFSET(*context) += 16; + + return VG_LITE_SUCCESS; +} + +static vg_lite_error_t flush(vg_lite_context_t *context) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + uint32_t address0 = 0x0A34; + uint32_t address1 = 0x0A1B; + uint32_t data0 = 0; + uint32_t data1 = 0x00000001; + uint32_t module = 7; + + /* Check if there is a valid context and an allocated command buffer. */ + if (!has_valid_command_buffer(context)) + return VG_LITE_NO_CONTEXT; + + /* Check if there is anything to flush. */ + if (CMDBUF_OFFSET(*context) == 0) + return VG_LITE_INVALID_ARGUMENT; + + /* Check if there is enough space in the command buffer. */ + if (CMDBUF_OFFSET(*context) + 32 > CMDBUF_SIZE(*context)) { + return VG_LITE_OUT_OF_RESOURCES; + } + + /* Finialize command buffer. */ + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_STATE(address0); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = data0; + + /* flush target */ + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[2] = VG_LITE_STATE(address1); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[3] = data1; + + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[4] = VG_LITE_SEMAPHORE(module); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[5] = 0; + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[6] = VG_LITE_STALL(module); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[7] = 0; + + CMDBUF_OFFSET(*context) += 32; + + return error; +} +#endif /* VG_DRIVER_SINGLE_THREAD */ + +/* Submit the current command buffer to HW and reset the current command buffer offset. */ +static vg_lite_error_t submit(vg_lite_context_t *context) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + vg_lite_kernel_submit_t submit; + + /* Check if there is a valid context and an allocated command buffer. */ + if (!has_valid_command_buffer(context)) + return VG_LITE_NO_CONTEXT; + + /* Check if there is anything to submit. */ + if (CMDBUF_OFFSET(*context) == 0) + return VG_LITE_INVALID_ARGUMENT; + + /* Check if there is enough space in the command buffer for the END. */ + if (CMDBUF_OFFSET(*context) + 8 > CMDBUF_SIZE(*context)) { + /* Reset command buffer offset. */ + CMDBUF_OFFSET(*context) = 0; + return VG_LITE_OUT_OF_RESOURCES; + } + + /* Append END command into the command buffer. */ + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0] = VG_LITE_END(0); + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[1] = 0; + +#if DUMP_COMMAND + if (strncmp(filename, "Commandbuffer", 13)) { + sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); + } + + fp = fopen(filename, "a"); + + if (fp == NULL) + printf("error!\n"); + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) (CMDBUF_BUFFER(*context) + CMDBUF_OFFSET(*context)))[0], 0); + + fprintf(fp, "Command buffer addr is : %p,\n", CMDBUF_BUFFER(*context)); + fprintf(fp, "Command buffer offset is : %d,\n", CMDBUF_OFFSET(*context) + 8); + + fclose(fp); + fp = NULL; +#endif + + CMDBUF_OFFSET(*context) += 8; + + /* Submit the command buffer. */ + submit.context = &context->context; + submit.commands = CMDBUF_BUFFER(*context); + submit.command_size = CMDBUF_OFFSET(*context); + submit.command_id = CMDBUF_INDEX(*context); + +#if defined(VG_DRIVER_SINGLE_THREAD) + /* Wait if GPU has not completed previous CMD buffer */ + if (submit_flag) { + VG_LITE_RETURN_ERROR(stall(&s_context, 0, (uint32_t)~0)); + } +#endif /* VG_DRIVER_SINGLE_THREAD */ + + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_SUBMIT, &submit)); +#if defined(VG_DRIVER_SINGLE_THREAD) + submit_flag = 1; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + vglitemDUMP_BUFFER("command", (unsigned int)CMDBUF_BUFFER(*context), + submit.context->command_buffer_logical[CMDBUF_INDEX(*context)], 0, submit.command_size); + vglitemDUMP("@[commit]"); + + /* Reset command buffer. */ + CMDBUF_OFFSET(*context) = 0; + + return error; +} + +/* Wait for the HW to finish the current execution. */ +#if defined(VG_DRIVER_SINGLE_THREAD) +static vg_lite_error_t stall(vg_lite_context_t *context, uint32_t time_ms, uint32_t mask) +#else +static vg_lite_error_t stall(vg_lite_context_t *context, uint32_t time_ms) +#endif /* VG_DRIVER_SINGLE_THREAD */ +{ + vg_lite_error_t error; + vg_lite_kernel_wait_t wait; + + vglitemDUMP("@[stall]"); + /* Wait until GPU is ready. */ + wait.context = &context->context; +#if defined(VG_DRIVER_SINGLE_THREAD) + wait.timeout_ms = time_ms > 0 ? time_ms : VG_LITE_INFINITE; + wait.event_mask = mask; +#else + wait.timeout_ms = time_ms > 0 ? time_ms : VG_LITE_MAX_WAIT_TIME; + wait.command_id = CMDBUF_INDEX(*context); +#endif /* VG_DRIVER_SINGLE_THREAD */ + + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_WAIT, &wait)); +#if defined(VG_DRIVER_SINGLE_THREAD) + submit_flag = 0; +#endif /* VG_DRIVER_SINGLE_THREAD */ + return VG_LITE_SUCCESS; +} + +/* Get the inversion of a matrix. */ +VG_LITE_OPTIMIZE(LOW) static int inverse(vg_lite_matrix_t * result, vg_lite_matrix_t * matrix) +{ + vg_lite_float_t det00, det01, det02; + vg_lite_float_t d; + int isAffine; + + /* Test for identity matrix. */ + if (matrix == NULL) { + result->m[0][0] = 1.0f; + result->m[0][1] = 0.0f; + result->m[0][2] = 0.0f; + result->m[1][0] = 0.0f; + result->m[1][1] = 1.0f; + result->m[1][2] = 0.0f; + result->m[2][0] = 0.0f; + result->m[2][1] = 0.0f; + result->m[2][2] = 1.0f; + + /* Success. */ + return 1; + } + + det00 = (matrix->m[1][1] * matrix->m[2][2]) - (matrix->m[2][1] * matrix->m[1][2]); + det01 = (matrix->m[2][0] * matrix->m[1][2]) - (matrix->m[1][0] * matrix->m[2][2]); + det02 = (matrix->m[1][0] * matrix->m[2][1]) - (matrix->m[2][0] * matrix->m[1][1]); + + /* Compute determinant. */ + d = (matrix->m[0][0] * det00) + (matrix->m[0][1] * det01) + (matrix->m[0][2] * det02); + + /* Return 0 if there is no inverse matrix. */ + if (d == 0.0f) + return 0; + + /* Compute reciprocal. */ + d = 1.0f / d; + + /* Determine if the matrix is affine. */ + isAffine = (matrix->m[2][0] == 0.0f) && (matrix->m[2][1] == 0.0f) && (matrix->m[2][2] == 1.0f); + + result->m[0][0] = d * det00; + result->m[0][1] = d * ((matrix->m[2][1] * matrix->m[0][2]) - (matrix->m[0][1] * matrix->m[2][2])); + result->m[0][2] = d * ((matrix->m[0][1] * matrix->m[1][2]) - (matrix->m[1][1] * matrix->m[0][2])); + result->m[1][0] = d * det01; + result->m[1][1] = d * ((matrix->m[0][0] * matrix->m[2][2]) - (matrix->m[2][0] * matrix->m[0][2])); + result->m[1][2] = d * ((matrix->m[1][0] * matrix->m[0][2]) - (matrix->m[0][0] * matrix->m[1][2])); + result->m[2][0] = isAffine ? 0.0f : d * det02; + result->m[2][1] = isAffine ? 0.0f : d * ((matrix->m[2][0] * matrix->m[0][1]) - (matrix->m[0][0] * matrix->m[2][1])); + result->m[2][2] = isAffine ? 1.0f : d * ((matrix->m[0][0] * matrix->m[1][1]) - (matrix->m[1][0] * matrix->m[0][1])); + + /* Success. */ + return 1; +} + +/* Transform a 2D point by a given matrix. */ +static int transform(vg_lite_point_t * result, vg_lite_float_t x, vg_lite_float_t y, vg_lite_matrix_t * matrix) +{ + vg_lite_float_t pt_x; + vg_lite_float_t pt_y; + vg_lite_float_t pt_w; + + /* Test for identity matrix. */ + if (matrix == NULL) { + result->x = (int)x; + result->y = (int)y; + + /* Success. */ + return 1; + } + + /* Transform x, y, and w. */ + pt_x = (x * matrix->m[0][0]) + (y * matrix->m[0][1]) + matrix->m[0][2]; + pt_y = (x * matrix->m[1][0]) + (y * matrix->m[1][1]) + matrix->m[1][2]; + pt_w = (x * matrix->m[2][0]) + (y * matrix->m[2][1]) + matrix->m[2][2]; + + if (pt_w <= 0.0f) + return 0; + + /* Compute projected x and y. */ + result->x = (int)(pt_x / pt_w); + result->y = (int)(pt_y / pt_w); + + /* Success. */ + return 1; +} + +/*! + Flush specific VG module. + */ +static vg_lite_error_t flush_target() +{ + vg_lite_error_t error = VG_LITE_SUCCESS; +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t* tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + do { + VG_LITE_BREAK_ERROR(push_state(ctx, 0x0A1B, 0x00000001)); + VG_LITE_BREAK_ERROR(push_stall(ctx, 7)); + } while (0); + + return error; +} + +/****************** FAST_CLEAR feature implementation. ***************/ +#if VG_TARGET_FAST_CLEAR +static vg_lite_error_t convert_color(vg_lite_buffer_format_t format, uint32_t value, uint32_t *result, int *bpp) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + uint32_t r, g, b, a; + int Bpp = 0; + + r = B(value); + g = G(value); + b = R(value); + a = A(value); + + do { + switch (format) { + case VG_LITE_RGBA8888: + *result = ARGB(a, b, g, r); + Bpp = 32; + break; + + case VG_LITE_BGRA8888: + *result = ARGB(a, r, g, b); + Bpp = 32; + break; + + case VG_LITE_RGBX8888: + *result = ARGB(0xff, b, g, r); + Bpp = 32; + break; + + case VG_LITE_BGRX8888: + *result = ARGB(0xff, r, g, b); + Bpp = 32; + break; + + case VG_LITE_RGBA4444: + *result = ARGB4(a, b, g, r); + Bpp = 16; + break; + + case VG_LITE_BGRA4444: + *result = ARGB4(a, r, g, b); + Bpp = 16; + break; + + case VG_LITE_RGB565: + *result = ((b & 0xf8) << 8) | + ((g & 0xfc) << 3) | + ((r & 0xf8) >> 3); + Bpp = 16; + break; + + case VG_LITE_BGR565: + *result = ((r & 0xf8) << 8) | + ((g & 0xfc) << 3) | + ((b & 0xf8) >> 3); + Bpp = 16; + break; + + case VG_LITE_BGRA5551: + *result = ((b & 0xf8) << 8) | + ((g & 0xf8) << 3) | + ((r & 0xf8) >> 2) | + ((a & 0x80) >> 7); + Bpp = 16; + break; + + case VG_LITE_A8: + *result = ARGB(a, a, a, a); + Bpp = 8; + break; + + case VG_LITE_L8: + *result = ARGB(r, r, r, r); + Bpp = 8; + break; + + default: + error = VG_LITE_NOT_SUPPORT; + break; + } + } while (0); + + if (bpp != NULL) { + *bpp = Bpp; + } + + if (Bpp == 16) { + *result = ((*result) << 16) | (*result); + } + return error; +} + +/* Fill Target buffer by FC buffer. Only used in cmodel/fpga for verification. */ +#if defined(DEBUG) || defined(_DEBUG) +static vg_lite_error_t fill_fc_target(vg_lite_buffer_t *target, vg_lite_buffer_t *fcb) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + uint8_t *fc = (uint8_t *)fcb->memory; + uint16_t *target16; + uint32_t *target32; + uint8_t *target8; + uint32_t clear32; + int byte_done = 0; + int i, j, k; + int bpp; + + do { + convert_color(target->format, s_context.clearValue, &clear32, &bpp); + + if (bpp == 32) { + target32 = (uint32_t *)target->memory; + for (i = 0; i < fcb->width; i++) { + + for (j = 0; j < 8; j++) { /* Loop the bits*/ + + if (!(((*fc) >> j) & 1)) { + for (k = 0; k < 64 / 4; k++) { + target32[k] = clear32; + byte_done+=4; + if (byte_done >= target->stride * target->height) { + return error; + } + } + } + + target32 += 64/4; + } + + fc++; + } + } + else if (bpp == 16){ + target16 = (uint16_t *)target->memory; + for (i = 0; i < fcb->width; i++) { + + for (j = 0; j < 8; j++) { /* Loop the bits*/ + + if (!(((*fc) >> j) & 1)) { + for (k = 0; k < 64 / 2; k++) { + target16[k] = (uint16_t)clear32; + byte_done+=2; + if (byte_done >= target->stride * target->height) { + return error; + } + } + } + + target16 += 64/2; + } + + fc++; + } + } + else if (bpp == 8) { + target8 = (uint8_t *)target->memory; + for (i = 0; i < fcb->width; i++) { + + for (j = 0; j < 8; j++) { /* Loop the bits*/ + + if (!(((*fc) >> j) & 1)) { + for (k = 0; k < 64; k++) { + target8[k] = (uint8_t)clear32; + byte_done++; + if (byte_done >= target->stride * target->height) { + return error; + } + } + } + + target8 += 64; + } + + fc++; + } + } + } while (0); + + return error; +} +#endif + +/* Update the fast_clear buffer when render target switched. */ +static vg_lite_error_t update_fc_buffer(vg_lite_buffer_t *target) +{ + int rt_bytes; + vg_lite_error_t error = VG_LITE_SUCCESS; + vg_lite_context_t *context = GET_CONTEXT(); + vg_lite_kernel_allocate_t allocate; + + do { + if (target == NULL) { + error = VG_LITE_INVALID_ARGUMENT; + break; + } + + rt_bytes = target->stride * target->height; + rt_bytes = VG_LITE_ALIGN(rt_bytes, (FC_BIT_TO_BYTES * 8)); + rt_bytes = rt_bytes / FC_BIT_TO_BYTES / 8; + /* Only allocate new buffer when the allocated is not big enough. Yes*/ + if (rt_bytes > context->fcBuffer.stride ) { + vg_lite_free(&context->fcBuffer); + + context->fcBuffer.width = rt_bytes; /* The actually used bytes. */ + rt_bytes = VG_LITE_ALIGN(rt_bytes, FC_BURST_BYTES); /* The allocated aligned bytes. */ + context->fcBuffer.stride = rt_bytes; + allocate.bytes = rt_bytes; + allocate.contiguous = 1; + + VG_LITE_BREAK_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &allocate)); + context->fcBuffer.handle = allocate.memory_handle; + context->fcBuffer.memory = allocate.memory; + context->fcBuffer.address = allocate.memory_gpu; + } + else { + /* Just update the fc buffer size. */ + context->fcBuffer.width = rt_bytes; + } + memset(context->fcBuffer.memory, 0xff, context->fcBuffer.stride); + } while (0); + + return error; +} + +/* Update FC registers and clear FC buffer. */ +static vg_lite_error_t clear_fc(uint32_t value) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + vg_lite_context_t *context = GET_CONTEXT(); + uint32_t bytes_to_clear = context->fcBuffer.stride / FC_BURST_BYTES; + + do { + VG_LITE_BREAK_ERROR(push_state(context, 0x0A9A, context->fcBuffer.address)); /* FC buffer address. */ + VG_LITE_BREAK_ERROR(push_state(context, 0x0A9B, value)); /* FC clear value. */ + VG_LITE_BREAK_ERROR(push_state(context, 0x0AB0, 0x80000000 | bytes_to_clear)); /* FC clear command. */ + } while (0); + + return error; +} + +#if VG_TARGET_FC_DUMP +static int fc_buf_dump(vg_lite_buffer_t *target, vg_lite_buffer_t *fcb) +{ + int error = VG_LITE_SUCCESS; + uint8_t *fc = (uint8_t *)fcb->memory; + uint8_t *target8; + int byte_done = 0; + int target_bytes; + int i, j; + + static unsigned s_cnt; + unsigned cnt = s_cnt; + + FILE *fpFCBuf; + FILE *fpTargetBuf; + FILE *fpTargetBufInfo; + char buf[256]; + + s_cnt++; + + sprintf(buf, "vg255v2.fc_buf.f%04d.txt", cnt); + fpFCBuf = fopen(buf, "wt"); + if (NULL == fpFCBuf) { + fprintf(stderr, "[Warning] Open file \'%s\' fail.\n", buf); + return -1; + } + + sprintf(buf, "vg255v2.target_buf_info.f%04d.txt", cnt); + fpTargetBufInfo = fopen(buf, "wt"); + if (NULL == fpTargetBufInfo) { + fprintf(stderr, "[Warning] Open file \'%s\' fail.\n", buf); + fclose(fpFCBuf); + return -1; + } else { + fprintf(fpTargetBufInfo, "%-12s: %d\n", "format", target->format); + fprintf(fpTargetBufInfo, "%-12s: %d\n", "tiled", target->tiled); + fprintf(fpTargetBufInfo, "%-12s: %d\n", "width", target->width); + fprintf(fpTargetBufInfo, "%-12s: %d\n", "height", target->height); + fprintf(fpTargetBufInfo, "%-12s: %d\n", "stride", target->stride); + + fclose(fpTargetBufInfo); + } + + sprintf(buf, "vg255v2.target_buf.f%04d.txt", cnt); + fpTargetBuf = fopen(buf, "wt"); + if (NULL == fpTargetBuf) { + fprintf(stderr, "[Warning] Open file \'%s\' fail.\n", buf); + fclose(fpFCBuf); + return -1; + } + + /* Dump FC buffer & Dump target buffer */ + target8 = (uint8_t *)target->memory; + target_bytes = target->stride * target->height; + + for (i = 0; i < fcb->width; ++i) + { + fprintf(fpFCBuf, "%02x\n", fc[i]); + /* 1 byte of fc related with 512 bytes of target buffer */ + for (j = 0; j < 128; ++j) { + fprintf(fpTargetBuf, "%02x", byte_done < target_bytes ? target8[0] : 0); + byte_done++; + + fprintf(fpTargetBuf, "%02x", byte_done < target_bytes ? target8[1] : 0); + byte_done++; + + fprintf(fpTargetBuf, "%02x", byte_done < target_bytes ? target8[2] : 0); + byte_done++; + + fprintf(fpTargetBuf, "%02x\n", byte_done < target_bytes ? target8[3] : 0); + byte_done++; + + target8 += 4; + } + } + + fclose(fpFCBuf); + fclose(fpTargetBuf); + + return error; +} +#endif /* VG_TARGET_FC_DUMP */ + +#endif + +/* Set the current render target. */ +#if defined(VG_DRIVER_SINGLE_THREAD) +static vg_lite_error_t set_render_target(vg_lite_buffer_t *target) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + uint32_t yuv2rgb = 0; + uint32_t uv_swiz = 0; + int32_t tiled; + int32_t dst_align_width; + uint32_t mul, div, align; + if(target == NULL) { + return VG_LITE_INVALID_ARGUMENT; + } else if(s_context.scissor_enabled && (s_context.scissor[2] <= 0 || s_context.scissor[3] <= 0)) { + /* Check scissoring rectangle dimensions + A scissoring rectangle with width <= 0 or height <= 0 must be + ignored. If scissoring is enabled and no valid scissoring rectangles + are present, no drawing occurs. */ + return VG_LITE_NO_CONTEXT; + } + /* Skip if render target and scissor are not changed. */ + if ((s_context.rtbuffer != NULL) && + !(memcmp(s_context.rtbuffer,target,sizeof(vg_lite_buffer_t))) && + (s_context.scissor_dirty == 0) && (s_context.premultiply_dirty == 0)) + { + return VG_LITE_SUCCESS; + } + + if ((target != NULL) && + (target->format == VG_LITE_YUY2 || + target->format == VG_LITE_AYUY2 || + target->format == VG_LITE_YUY2_TILED || + target->format == VG_LITE_AYUY2_TILED)) + { + return VG_LITE_NOT_SUPPORT; + } + + +#if VG_TARGET_FAST_CLEAR + /* Flush target if necessary when switching. */ + if (s_context.rtbuffer&& s_context.rtbuffer->memory) { /* If it's not the first time to set target. */ + vg_lite_finish(); + } + update_fc_buffer(target); +#else + if (s_context.rtbuffer && s_context.rtbuffer->memory) { + /* Flush the old target. */ + vg_lite_finish(); + } +#endif + + tiled = (target->tiled != VG_LITE_LINEAR) ? 0x10000000 : 0; + + if (((target->format >= VG_LITE_YUY2) && + (target->format <= VG_LITE_AYUY2)) || + ((target->format >= VG_LITE_YUY2_TILED) && + (target->format <= VG_LITE_AYUY2_TILED))) { + yuv2rgb = convert_yuv2rgb(target->yuv.yuv2rgb); + uv_swiz = convert_uv_swizzle(target->yuv.swizzle); + } + + /* Program render target. */ + if (s_context.premultiply_dirty || s_context.rtbuffer != target || memcmp(s_context.rtbuffer,target,sizeof(vg_lite_buffer_t)) ) { + if(target->tiled == VG_LITE_TILED) { + if((target->stride % DEST_ALIGNMENT_LIMITATION) != 0) + return VG_LITE_INVALID_ARGUMENT; + } + if(s_context.premultiply_enabled) { + VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A10, + convert_target_format(target->format, s_context.capabilities) | 0x00010000 | uv_swiz | yuv2rgb)); + }else { + VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A10, + convert_target_format(target->format, s_context.capabilities) | 0x00010000 | uv_swiz | yuv2rgb | 0x100)); + } + if (target->yuv.uv_planar) + { /* Program uv plane address if necessary. */ + VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A5C, target->yuv.uv_planar)); + } + if (target->yuv.alpha_planar) { + VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A5D, target->yuv.alpha_planar)); + } + VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A11, target->address)); + VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A12, target->stride | tiled)); + s_context.premultiply_dirty = 0; + } + + get_format_bytes(target->format, &mul, &div, &align); + dst_align_width = target->stride * div / mul; + + if (s_context.scissor_dirty != 0) { + if (s_context.scissor_enabled) { + VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A13, (s_context.scissor[0] + s_context.scissor[2]) | ((s_context.scissor[1] + s_context.scissor[3]) << 16))); + } + else { + VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A13, dst_align_width | (target->height << 16))); + } + s_context.scissor_dirty = 0; + } + else { + VG_LITE_RETURN_ERROR(push_state(&s_context, 0x0A13, dst_align_width | (target->height << 16))); + } + + memcpy(s_context.rtbuffer, target, sizeof(vg_lite_buffer_t)); + + return error; +} +#else +static vg_lite_error_t set_render_target(vg_lite_buffer_t *target) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + uint32_t yuv2rgb = 0; + uint32_t uv_swiz = 0; + int32_t tiled; + vg_lite_tls_t* tls; + int32_t dst_align_width; + uint32_t mul, div, align; + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + if(target == NULL) { + return VG_LITE_INVALID_ARGUMENT; + } else if(tls->t_context.scissor_enabled && (tls->t_context.scissor[2] <= 0 || tls->t_context.scissor[3] <= 0)) { + /* Check scissoring rectangle dimensions + A scissoring rectangle with width <= 0 or height <= 0 must be + ignored. If scissoring is enabled and no valid scissoring rectangles + are present, no drawing occurs. */ + return VG_LITE_NO_CONTEXT; + } + + tls->t_context.start_offset = CMDBUF_OFFSET(tls->t_context); + + if ((target != NULL) && + (target->format == VG_LITE_YUY2 || + target->format == VG_LITE_AYUY2 || + target->format == VG_LITE_YUY2_TILED || + target->format == VG_LITE_AYUY2_TILED)) + { + return VG_LITE_NOT_SUPPORT; + } + +#if VG_TARGET_FAST_CLEAR + /* Flush target if necessary when switching. */ + if (tls->t_context.rtbuffer != NULL) { /* If it's not the first time to set target. */ + vg_lite_finish(); + } + update_fc_buffer(target); +#endif + + tiled = (target->tiled != VG_LITE_LINEAR) ? 0x10000000 : 0; + + if (((target->format >= VG_LITE_YUY2) && + (target->format <= VG_LITE_AYUY2)) || + ((target->format >= VG_LITE_YUY2_TILED) && + (target->format <= VG_LITE_AYUY2_TILED))) { + yuv2rgb = convert_yuv2rgb(target->yuv.yuv2rgb); + uv_swiz = convert_uv_swizzle(target->yuv.swizzle); + } + + /* Program render target. */ + if(target->tiled == VG_LITE_TILED) { + if((target->stride % DEST_ALIGNMENT_LIMITATION) != 0) + return VG_LITE_INVALID_ARGUMENT; + } + + if(tls->t_context.premultiply_enabled) { + VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A10, + convert_target_format(target->format, tls->t_context.capabilities) | 0x00010000 | uv_swiz | yuv2rgb)); + } else { + VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A10, + convert_target_format(target->format, tls->t_context.capabilities) | 0x00010000 | uv_swiz | yuv2rgb | 0x100)); + } + if (target->yuv.uv_planar) + { /* Program uv plane address if necessary. */ + VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A5C, target->yuv.uv_planar)); + } + if (target->yuv.alpha_planar) { + VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A5D, target->yuv.alpha_planar)); + } + VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A11, target->address)); + VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A12, target->stride | tiled)); + get_format_bytes(target->format, &mul, &div, &align); + dst_align_width = target->stride * div / mul; + + if (tls->t_context.scissor_enabled) { + VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A13, (tls->t_context.scissor[0] + tls->t_context.scissor[2]) | ((tls->t_context.scissor[1] + tls->t_context.scissor[3]) << 16))); + } + else { + VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A13, dst_align_width | (target->height << 16))); + } + + tls->t_context.rtbuffer = target; + + return error; +} +#endif /* VG_DRIVER_SINGLE_THREAD */ + +static inline vg_lite_error_t transform_bounding_box(vg_lite_rectangle_t *in_bbx, + vg_lite_matrix_t *matrix, + vg_lite_rectangle_t *clip, + vg_lite_rectangle_t *out_bbx, + vg_lite_point_t *origin) +{ + vg_lite_point_t temp; + + memset(out_bbx, 0, sizeof(vg_lite_rectangle_t)); + + /* Transform image point (x, y). */ + if (!transform(&temp, in_bbx->x, in_bbx->y, matrix)) + return VG_LITE_INVALID_ARGUMENT; + out_bbx->x = temp.x; + out_bbx->y = temp.y; + + /* Provide position of the new origin to the caller if requested. */ + if (origin != NULL) { + origin->x = temp.x; + origin->y = temp.y; + } + + /* Transform image point (x, y+height). */ + if (!transform(&temp, in_bbx->x, (in_bbx->y + in_bbx->height), matrix)) + return VG_LITE_INVALID_ARGUMENT; + UPDATE_BOUNDING_BOX(*out_bbx, temp); + + /* Transform image point (x+width, y+height). */ + if (!transform(&temp, (in_bbx->x + in_bbx->width), (in_bbx->y + in_bbx->height), + matrix)) + return VG_LITE_INVALID_ARGUMENT; + UPDATE_BOUNDING_BOX(*out_bbx, temp); + + /* Transform image point (x+width, y). */ + if (!transform(&temp, (in_bbx->x + in_bbx->width), in_bbx->y, matrix)) + return VG_LITE_INVALID_ARGUMENT; + UPDATE_BOUNDING_BOX(*out_bbx, temp); + + /* Clip is required */ + if (clip) { + out_bbx->x = MAX(out_bbx->x, clip->x); + out_bbx->y = MAX(out_bbx->y, clip->y); + out_bbx->width = MIN((out_bbx->x + out_bbx->width), (clip->x + clip->width)) - out_bbx->x; + out_bbx->height = MIN((out_bbx->y + out_bbx->height), (clip->y + clip->height)) - out_bbx->y; + } + + return VG_LITE_SUCCESS; +} + +#if (VG_BLIT_WORKAROUND == 1) +/* + * Calculates the minimal possible target buffer starting from a given target + * buffer and considering a source texture (to blit), graphic transformations + * and clipping window. + */ +static vg_lite_error_t config_new_target(vg_lite_buffer_t *target, + vg_lite_buffer_t *source, + vg_lite_matrix_t *matrix, + vg_lite_rectangle_t *bbx, + vg_lite_buffer_t *new_target) +{ + uint8_t *p; + vg_lite_point_t origin; + vg_lite_rectangle_t src_bbx, bounding_box, clip; + int tx, ty; + uint32_t mul, div, required_align, align; + + /* + * Acquire the bounding box of the transformed source image and the location + * of its origin. + */ + memset(&src_bbx, 0, sizeof(vg_lite_rectangle_t)); + src_bbx.width = source->width; + src_bbx.height = source->height; + if (bbx == NULL) { + /* + * If no clipping rectangle provided, just configure the clip bounds to + * be as big as the target + */ + memset(&clip, 0, sizeof(vg_lite_rectangle_t)); + clip.width = target->width; + clip.height = target->height; + } else { + /* Otherwise clip according to the bounding box specified by the caller */ + memcpy(&clip, bbx, sizeof(vg_lite_rectangle_t)); + } + transform_bounding_box(&src_bbx, matrix, &clip, &bounding_box, &origin); + + /* Calculate the data address of the new target */ + get_format_bytes(target->format, &mul, &div, &required_align); + p = target->memory; + p += bounding_box.y * target->stride + bounding_box.x * (mul / div); + align = (uint32_t)p & (required_align - 1); + p -= align; + + /* + * Update pixel coordinate of the base address. The width of the target will + * increase, since the x coordinate of the bounding box decreases to + * accomodate the image data alignment. + */ + tx = align / (mul / div); + bounding_box.x -= tx; + bounding_box.width += tx; + + /* Update bounding box if provided by the caller */ + if (bbx) { + bbx->x = tx; + bbx->y = 0; + } + + /* Calculate translation from the source image origin to the target origin. */ + tx = origin.x - bounding_box.x; + ty = origin.y - bounding_box.y; + + /* Copy content of the target buffer descriptor into the new target. */ + memcpy(new_target, target, sizeof(vg_lite_buffer_t)); + + /* Update the new buffer */ + new_target->memory = p; + new_target->address = (uint32_t) p; + new_target->width = bounding_box.width; + new_target->height = bounding_box.height; + + /* Update matrix */ + matrix->m[0][2] = tx; + matrix->m[1][2] = ty; + + return VG_LITE_SUCCESS; +} +#endif /* VG_BLIT_WORKAROUND */ + +static vg_lite_error_t set_interpolation_steps(vg_lite_buffer_t *target, + vg_lite_float_t s_width, + vg_lite_float_t s_height, + vg_lite_matrix_t *matrix) +{ + vg_lite_matrix_t im; + vg_lite_rectangle_t src_bbx, bounding_box, clip; + vg_lite_float_t xs[3], ys[3], cs[3]; + vg_lite_error_t error = VG_LITE_SUCCESS; + float dx = 0.0f, dy = 0.0f; +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t *tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + #define ERR_LIMIT 0.0000610351562f + + /* Get bounding box. */ + memset(&src_bbx, 0, sizeof(vg_lite_rectangle_t)); + memset(&clip, 0, sizeof(vg_lite_rectangle_t)); + src_bbx.width = (int32_t)s_width; + src_bbx.height = (int32_t)s_height; + + if (ctx->scissor_enabled) { + clip.x = ctx->scissor[0]; + clip.y = ctx->scissor[1]; + clip.width = ctx->scissor[2]; + clip.height = ctx->scissor[3]; + } else { + clip.x = clip.y = 0; + clip.width = ctx->rtbuffer->width; + clip.height = ctx->rtbuffer->height; + } + transform_bounding_box(&src_bbx, matrix, &clip, &bounding_box, NULL); + + /* Compute inverse matrix. */ + if (!inverse(&im, matrix)) + return VG_LITE_INVALID_ARGUMENT; + /* Compute interpolation steps. */ + /* X step */ + xs[0] = im.m[0][0] / s_width; + xs[1] = im.m[1][0] / s_height; + xs[2] = im.m[2][0]; + /* Y step */ + ys[0] = im.m[0][1] / s_width; + ys[1] = im.m[1][1] / s_height; + ys[2] = im.m[2][1]; + /* C step 2 */ + cs[2] = 0.5f * (im.m[2][0] + im.m[2][1]) + im.m[2][2]; + /* Keep track of the rounding errors (underflow) */ + if (ctx->chip_id == GPU_CHIP_ID_GCNanoliteV) { + /* Check if matrix has rotation or perspective transformations */ + if (matrix != NULL && + (matrix->m[0][1] != 0.0f || matrix->m[1][0] != 0.0f || + matrix->m[2][0] != 0.0f || matrix->m[2][1] != 0.0f || + matrix->m[2][2] != 1.0f)) { + if (xs[0] != 0.0f && -ERR_LIMIT < xs[0] && xs[0] < ERR_LIMIT) + dx = 0.5f * (2 * bounding_box.x + bounding_box.width) * im.m[0][0]; + else if (ys[0] != 0.0f && -ERR_LIMIT < ys[0] && ys[0] < ERR_LIMIT) + dx = 0.5f * (2 * bounding_box.y + bounding_box.height) * im.m[0][1]; + if (xs[1] != 0.0f && -ERR_LIMIT < xs[1] && xs[1] < ERR_LIMIT) + dy = 0.5f * (2 * bounding_box.x + bounding_box.width) * im.m[1][0]; + else if (ys[1] != 0.0f && -ERR_LIMIT < ys[1] && ys[1] < ERR_LIMIT) + dy = 0.5f * (2 * bounding_box.y + bounding_box.height) * im.m[1][1]; + } + } + /* C step 0, 1*/ + cs[0] = (0.5f * (im.m[0][0] + im.m[0][1]) + im.m[0][2] + dx) / s_width; + cs[1] = (0.5f * (im.m[1][0] + im.m[1][1]) + im.m[1][2] + dy) / s_height; + /* Set command buffer */ + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A18, (void *)&cs[0])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A19, (void *)&cs[1])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A1A, (void *)&cs[2])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A1C, (void *)&xs[0])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A1D, (void *)&xs[1])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A1E, (void *)&xs[2])); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1F, 0x00000001)); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A20, (void *)&ys[0])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A21, (void *)&ys[1])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A22, (void *)&ys[2])); + + return VG_LITE_SUCCESS; +} + +/*************** API Functions ***********************************************/ +vg_lite_error_t vg_lite_get_transform_matrix(vg_lite_point4_t src, vg_lite_point4_t dst,vg_lite_matrix_t *mat) +{ + float a[8][8],b[9],A[64]; + int i, j, k, m = 8, n = 1; + int astep = 8,bstep = 1; + float d; + + if(src == NULL || dst == NULL || mat == NULL) + return VG_LITE_INVALID_ARGUMENT; + + for(i = 0; i < 4; ++i ) + { + a[i][0] = a[i+4][3] = src[i].x; + a[i][1] = a[i+4][4] = src[i].y; + a[i][2] = a[i+4][5] = 1; + a[i][3] = a[i][4] = a[i][5] = + a[i+4][0] = a[i+4][1] = a[i+4][2] = 0; + a[i][6] = -src[i].x*dst[i].x; + a[i][7] = -src[i].y*dst[i].x; + a[i+4][6] = -src[i].x*dst[i].y; + a[i+4][7] = -src[i].y*dst[i].y; + b[i] = dst[i].x; + b[i+4] = dst[i].y; + } + for(i = 0; i < 8; ++i ) + { + for(j = 0; j < 8; ++j ) + { + A[8 * i + j] = a[i][j]; + } + } + + for (i = 0; i < m; i++) + { + k = i; + for (j = i + 1; j < m; j++) + if (ABS(A[j*astep + i]) > ABS(A[k*astep + i])) + k = j; + if (ABS(A[k*astep + i]) < EPS) + return VG_LITE_INVALID_ARGUMENT; + if (k != i) + { + for (j = i; j < m; j++) + swap(&A[i*astep + j], &A[k*astep + j]); + for (j = 0; j < n; j++) + swap(&b[i*bstep + j], &b[k*bstep + j]); + } + d = -1 / A[i*astep + i]; + for (j = i + 1; j < m; j++) + { + float alpha = A[j*astep + i] * d; + for (k = i + 1; k < m; k++) + A[j*astep + k] += alpha * A[i*astep + k]; + for (k = 0; k < n; k++) + b[j*bstep + k] += alpha * b[i*bstep + k]; + } + } + + for (i = m - 1; i >= 0; i--) + for (j = 0; j < n; j++) + { + float s = b[i*bstep + j]; + for (k = i + 1; k < m; k++) + s -= A[i*astep + k] * b[k*bstep + j]; + b[i*bstep + j] = s / A[i*astep + i]; + } + b[8] = 1; + + for(i = 0; i < 3; ++i ) + { + for(j = 0; j < 3; ++j ) + { + mat->m[i][j] = b[i* 3 + j]; + } + } + + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_clear(vg_lite_buffer_t * target, + vg_lite_rectangle_t * rectangle, + vg_lite_color_t color) +{ + vg_lite_error_t error; + int32_t x, y, width, height; + uint32_t color32; +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t* tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + error = set_render_target(target); + if (error != VG_LITE_SUCCESS) { + return error; + } else if (error == VG_LITE_NO_CONTEXT) { + /* If scissoring is enabled and no valid scissoring rectangles + are present, no drawing occurs */ + return VG_LITE_SUCCESS; + } + + /* Get rectangle. */ + x = (rectangle != NULL) ? rectangle->x : 0; + y = (rectangle != NULL) ? rectangle->y : 0; + width = (rectangle != NULL) ? rectangle->width : ctx->rtbuffer->width; + height = (rectangle != NULL) ? rectangle->height : ctx->rtbuffer->height; + + /* Compute the valid rectangle. */ + if (x < 0) + { + width += x; + x = 0; + } + if (y < 0) + { + height += y; + y = 0; + } + + if (ctx->scissor_enabled) + { + int right, bottom; + right = x + width; + bottom = y + height; + + /* Bounds check. */ + if ((ctx->scissor[0] >= x + width) || + (ctx->scissor[0] + ctx->scissor[2] <= x) || + (ctx->scissor[1] >= y + height) || + (ctx->scissor[1] + ctx->scissor[3] <= y)) + { + /* Do nothing. */ + return VG_LITE_SUCCESS; + } + /* Intersects the scissor and the rectangle. */ + x = (x > ctx->scissor[0] ? x : ctx->scissor[0]); + y = (y > ctx->scissor[1] ? y : ctx->scissor[1]); + right = (right < ctx->scissor[0] + ctx->scissor[2] ? right : ctx->scissor[0] + ctx->scissor[2]); + bottom = (bottom < ctx->scissor[1] + ctx->scissor[3] ? bottom : ctx->scissor[1] + ctx->scissor[3]); + width = right - x; + height = bottom - y; + } + + /* Get converted color when target is in L8 format. */ + color32 = (target->format == VG_LITE_L8) ? rgb_to_l(color) : color; + +#if VG_TARGET_FAST_CLEAR + if ((rectangle == NULL) || + ((x == 0) && (y == 0) && + (width == ctx->rtbuffer->width) && + (height == ctx->rtbuffer->height))) { + ctx->clearValue = color32; + convert_color(ctx->rtbuffer->format, color32, &color32, NULL); + clear_fc((uint32_t)color32); + } + else +#endif + { + /* Setup the command buffer. */ + if(ctx->premultiply_enabled) { + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x00000001)); + } else { + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x10000001)); + } + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A02, color32)); + VG_LITE_RETURN_ERROR(push_rectangle(ctx, x, y, width, height)); + VG_LITE_RETURN_ERROR(flush_target()); + } + + /* Success. */ + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_blit(vg_lite_buffer_t * target, + vg_lite_buffer_t * source, + vg_lite_matrix_t * matrix, + vg_lite_blend_t blend, + vg_lite_color_t color, + vg_lite_filter_t filter) +{ + vg_lite_error_t error; + vg_lite_rectangle_t src_bbx, bounding_box, clip; + uint32_t imageMode; + uint32_t blend_mode; + uint32_t transparency_mode = 0; + vg_lite_blend_t forced_blending = blend; + uint32_t conversion = 0; + uint32_t tiled_source; +#if (VG_BLIT_WORKAROUND == 1) + vg_lite_matrix_t new_matrix; + vg_lite_buffer_t new_target; +#endif /* VG_BLIT_WORKAROUND */ + +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t *tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + /* Calculate bounding box */ + memset(&src_bbx, 0, sizeof(vg_lite_rectangle_t)); + memset(&clip, 0, sizeof(vg_lite_rectangle_t)); + src_bbx.width = source->width; + src_bbx.height = source->height; + if (ctx->scissor_enabled) { + clip.x = ctx->scissor[0]; + clip.y = ctx->scissor[1]; + clip.width = ctx->scissor[2]; + clip.height = ctx->scissor[3]; + } else { + clip.width = target->width; + clip.height = target->height; + } + transform_bounding_box(&src_bbx, matrix, &clip, &bounding_box, NULL); + +#if (VG_BLIT_WORKAROUND==1) + /* + * The blit output quality workaround works only for afine transformations + * because it is based on the process of cumulating translations into the + * matrix. This process is not possible for non-affine transformations, such + * as the perspective projections. + */ + if ((matrix->m[2][0] == 0) && (matrix->m[2][1] == 0)) { + /* + * Make a local copy of the transformation matrix in order not to mess + * up the user's matrix. + */ + memcpy(&new_matrix, matrix, sizeof(vg_lite_matrix_t)); + matrix = &new_matrix; + + config_new_target(target, source, matrix, &bounding_box, &new_target); + target = &new_target; + } +#endif /* VG_BLIT_WORKAROUND */ + error = set_render_target(target); + if (error != VG_LITE_SUCCESS) { + return error; + } else if (error == VG_LITE_NO_CONTEXT) { + /* If scissoring is enabled and no valid scissoring rectangles + are present, no drawing occurs */ + return VG_LITE_SUCCESS; + } + + transparency_mode = (source->transparency_mode == VG_LITE_IMAGE_TRANSPARENT ? 0x8000:0); + /* Check if the specified matrix has rotation or perspective. */ + if ( (matrix != NULL) + && ( (matrix->m[0][1] != 0.0f) + || (matrix->m[1][0] != 0.0f) + || (matrix->m[2][0] != 0.0f) + || (matrix->m[2][1] != 0.0f) + || (matrix->m[2][2] != 1.0f) + ) + && ( blend == VG_LITE_BLEND_NONE + || blend == VG_LITE_BLEND_SRC_IN + || blend == VG_LITE_BLEND_DST_IN + ) + ) { + if(vg_lite_query_feature(gcFEATURE_BIT_VG_BORDER_CULLING)) { + /* Mark that we have rotation. */ + transparency_mode = 0x8000; + }else + { + blend_mode = VG_LITE_BLEND_SRC_OVER; + } + + } + + /* Check whether L8 is supported or not. */ + if ((target->format == VG_LITE_L8) && ((source->format != VG_LITE_L8) && (source->format != VG_LITE_A8))) { + conversion = 0x80000000; + } + + /* determine if source specify bytes are aligned */ + error = _check_source_aligned(source->format,source->stride); + if (error != VG_LITE_SUCCESS) { + return error; + } + + /* Determine image mode (NORMAL, NONE or MULTIPLY) depending on the color. */ + imageMode = (source->image_mode == VG_LITE_NONE_IMAGE_MODE) ? 0 : (source->image_mode == VG_LITE_MULTIPLY_IMAGE_MODE) ? 0x00002000 : 0x00001000; + blend_mode = convert_blend(forced_blending); + tiled_source = (source->tiled != VG_LITE_LINEAR) ? 0x10000000 : 0 ; + +#if !defined(VG_DRIVER_SINGLE_THREAD) + /* Setup the command buffer. */ + if(source->format >= VG_LITE_INDEX_1 && source->format <= VG_LITE_INDEX_8) + { + /* this task will use index format,set index_flag to 1. */ + ctx->index_format = 1; + switch (source->format) { + case VG_LITE_INDEX_8: + if(ctx->clut_dirty[3]){ + VG_LITE_RETURN_ERROR(push_states(ctx, 0x0B00, 256, tls->t_context.colors[3])); + tls->t_context.clut_dirty[3] = 0; + } + else + { + ctx->clut_used[3] = 1; + } + break; + + case VG_LITE_INDEX_4: + if(ctx->clut_dirty[2]){ + VG_LITE_RETURN_ERROR(push_states(ctx, 0x0AA0, 16, ctx->colors[2])); + ctx->clut_dirty[2] = 0; + } + else + { + ctx->clut_used[2] = 1; + } + break; + + case VG_LITE_INDEX_2: + if(ctx->clut_dirty[1]){ + VG_LITE_RETURN_ERROR(push_states(ctx, 0x0A9C, 4, ctx->colors[1])); + ctx->clut_dirty[1] = 0; + } + else + { + ctx->clut_used[1] = 1; + } + break; + + default: + if(ctx->clut_dirty[0]){ + VG_LITE_RETURN_ERROR(push_states(ctx, 0x0A98, 2, ctx->colors[0])); + ctx->clut_dirty[0] = 0; + } + else + { + ctx->clut_used[0] = 1; + } + } + } +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + + if(!ctx->premultiply_enabled && source->format != VG_LITE_A8 && source->format != VG_LITE_A4) { + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x10000001 | imageMode | blend_mode | transparency_mode)); + } else { + /* enable pre-multiplied from VG to VGPE */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x00000001 | imageMode | blend_mode | transparency_mode)); + } + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A02, color)); + VG_LITE_RETURN_ERROR(set_interpolation_steps(target, source->width, source->height, matrix)); + + if(!ctx->premultiply_enabled && source->format != VG_LITE_A8 && source->format != VG_LITE_A4) { + if(source->transparency_mode == VG_LITE_IMAGE_OPAQUE){ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | filter | conversion | 0x01000100)); + } else { + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | filter | conversion | 0x00000100)); + } + } else { + /* enable pre-multiplied in imager unit */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | filter | conversion)); + } + + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A27, 0)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A29, source->address)); + + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2B, source->stride | tiled_source)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2D, 0)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2F, source->width | (source->height << 16))); + VG_LITE_RETURN_ERROR(push_rectangle(ctx, bounding_box.x, bounding_box.y, bounding_box.width, + bounding_box.height)); + error = flush_target(); + vglitemDUMP_BUFFER("image", source->address, source->memory, 0, (source->stride)*(source->height)); + +#if DUMP_IMAGE + dump_img(source->memory, source->width, source->height, source->format); +#endif + + return error; +} + +vg_lite_error_t vg_lite_blit_rect(vg_lite_buffer_t * target, + vg_lite_buffer_t * source, + uint32_t * rect, + vg_lite_matrix_t * matrix, + vg_lite_blend_t blend, + vg_lite_color_t color, + vg_lite_filter_t filter) +{ + vg_lite_error_t error; + vg_lite_rectangle_t src_bbx, bounding_box, clip; + uint32_t imageMode; + uint32_t transparency_mode = 0; + uint32_t blend_mode; + vg_lite_blend_t forced_blending = blend; + uint32_t conversion = 0; + uint32_t tiled_source; + uint32_t rect_x = 0, rect_y = 0, rect_w = 0, rect_h = 0; + int32_t src_align_width; + uint32_t mul, div, align; +#if (VG_BLIT_WORKAROUND == 1) + vg_lite_matrix_t new_matrix; + vg_lite_buffer_t new_target; +#endif /* VG_BLIT_WORKAROUND */ +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t *tls; + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + transparency_mode = (source->transparency_mode == VG_LITE_IMAGE_TRANSPARENT ? 0x8000:0); + /* Check if the specified matrix has rotation or perspective. */ + if ( (matrix != NULL) + && ( (matrix->m[0][1] != 0.0f) + || (matrix->m[1][0] != 0.0f) + || (matrix->m[2][0] != 0.0f) + || (matrix->m[2][1] != 0.0f) + || (matrix->m[2][2] != 1.0f) + ) + && ( blend == VG_LITE_BLEND_NONE + || blend == VG_LITE_BLEND_SRC_IN + || blend == VG_LITE_BLEND_DST_IN + ) + ) { + if(vg_lite_query_feature(gcFEATURE_BIT_VG_BORDER_CULLING)) { + /* Mark that we have rotation. */ + transparency_mode = 0x8000; + }else + { + blend_mode = VG_LITE_BLEND_SRC_OVER; + } + + } + + /* Check whether L8 is supported or not. */ + if ((target->format == VG_LITE_L8) && ((source->format != VG_LITE_L8) && (source->format != VG_LITE_A8))) { + conversion = 0x80000000; + } + + /* determine if source specify bytes are aligned */ + error = _check_source_aligned(source->format,source->stride); + if (error != VG_LITE_SUCCESS) { + return error; + } + get_format_bytes(source->format, &mul, &div, &align); + src_align_width = source->stride * div / mul; + memset(&src_bbx, 0, sizeof(vg_lite_rectangle_t)); + /* Set source region. */ + if (rect != NULL) { + rect_x = rect[0]; + rect_y = rect[1]; + rect_w = rect[2]; + rect_h = rect[3]; + + if ((rect_x > (uint32_t)src_align_width) || (rect_y > (uint32_t)source->height) || + (rect_w == 0) || (rect_h == 0)) + { + /*No intersection*/ + return VG_LITE_INVALID_ARGUMENT; + } + + if (rect_x + rect_w > (uint32_t)src_align_width) + { + rect_w = src_align_width - rect_x; + } + + if (rect_y + rect_h > (uint32_t)source->height) + { + rect_h = source->height - rect_y; + } + + src_bbx.width = rect_w; + src_bbx.height = rect_h; + } + else { + rect_x = rect_y = 0; + rect_w = src_bbx.width = src_align_width; + rect_h = src_bbx.height = source->height; + } + + /* Calculate bounding box. */ + memset(&clip, 0, sizeof(vg_lite_rectangle_t)); + if (ctx->scissor_enabled) { + clip.x = ctx->scissor[0]; + clip.y = ctx->scissor[1]; + clip.width = ctx->scissor[2]; + clip.height = ctx->scissor[3]; + } else { + clip.x = clip.y = 0; + clip.width = target->width; + clip.height = target->height; + } + transform_bounding_box(&src_bbx, matrix, &clip, &bounding_box, NULL); + +#if (VG_BLIT_WORKAROUND==1) + /* + * The blit output quality workaround works only for afine transformations + * because it is based on the process of cumulating translations into the + * matrix. This process is not possible for non-affine transformations, such + * as the perspective projections. + */ + if ((matrix->m[2][0] == 0) && (matrix->m[2][1] == 0)) { + /* + * Make a local copy of the transformation matrix in order not to mess + * up the user's matrix. + */ + memcpy(&new_matrix, matrix, sizeof(vg_lite_matrix_t)); + matrix = &new_matrix; + + config_new_target(target, source, matrix, &bounding_box, &new_target); + target = &new_target; + } +#endif /* VG_BLIT_WORKAROUND */ + + error = set_render_target(target); + if (error != VG_LITE_SUCCESS) { + return error; + } else if (error == VG_LITE_NO_CONTEXT) { + /* If scissoring is enabled and no valid scissoring rectangles + are present, no drawing occurs */ + return VG_LITE_SUCCESS; + } + + /* Determine image mode (NORMAL, NONE or MULTIPLY) depending on the color. */ + imageMode = (source->image_mode == VG_LITE_NONE_IMAGE_MODE) ? 0 : (source->image_mode == VG_LITE_MULTIPLY_IMAGE_MODE) ? 0x00002000 : 0x00001000; + blend_mode = convert_blend(forced_blending); + tiled_source = (source->tiled != VG_LITE_LINEAR) ? 0x10000000 : 0 ; + +#if !defined(VG_DRIVER_SINGLE_THREAD) + /* Setup the command buffer. */ + if(source->format >= VG_LITE_INDEX_1 && source->format <= VG_LITE_INDEX_8) + { + /* this task will use index format,set index_flag to 1. */ + ctx->index_format = 1; + switch (source->format) { + case VG_LITE_INDEX_8: + if(tls->t_context.clut_dirty[3]){ + VG_LITE_RETURN_ERROR(push_states(ctx, 0x0B00, 256, ctx->colors[3])); + ctx->clut_dirty[3] = 0; + } + else + { + tls->t_context.clut_used[3] = 1; + } + break; + + case VG_LITE_INDEX_4: + if(tls->t_context.clut_dirty[2]){ + VG_LITE_RETURN_ERROR(push_states(&tls->t_context, 0x0AA0, 16, tls->t_context.colors[2])); + tls->t_context.clut_dirty[2] = 0; + } + else + { + tls->t_context.clut_used[2] = 1; + } + break; + + case VG_LITE_INDEX_2: + if(tls->t_context.clut_dirty[1]){ + VG_LITE_RETURN_ERROR(push_states(&tls->t_context, 0x0A9C, 4, tls->t_context.colors[1])); + tls->t_context.clut_dirty[1] = 0; + } + else + { + tls->t_context.clut_used[1] = 1; + } + break; + + default: + if(tls->t_context.clut_dirty[0]){ + VG_LITE_RETURN_ERROR(push_states(&tls->t_context, 0x0A98, 2, tls->t_context.colors[0])); + tls->t_context.clut_dirty[0] = 0; + } + else + { + tls->t_context.clut_used[0] = 1; + } + } + } +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + + if(!ctx->premultiply_enabled && source->format != VG_LITE_A8 && source->format != VG_LITE_A4) { + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x10000001 | imageMode | blend_mode | transparency_mode)); + } else { + /* enable pre-multiplied from VG to VGPE */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x00000001 | imageMode | blend_mode | transparency_mode)); + } + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A02, color)); + + VG_LITE_RETURN_ERROR(set_interpolation_steps(target, rect_w, rect_h, matrix)); + + if(!ctx->premultiply_enabled && source->format != VG_LITE_A8 && source->format != VG_LITE_A4) { + if(source->transparency_mode == VG_LITE_IMAGE_OPAQUE){ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | filter | conversion | 0x01000100)); + } else { + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | filter | conversion | 0x00000100)); + } + } else { + /* enable pre-multiplied in imager unit */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | filter | conversion)); + } + + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A27, 0)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A29, source->address)); + + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2B, source->stride | tiled_source)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2D, rect_x | (rect_y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2F, rect_w | (rect_h << 16))); + VG_LITE_RETURN_ERROR(push_rectangle(ctx, bounding_box.x, bounding_box.y, bounding_box.width, + bounding_box.height)); + error = flush_target(); + vglitemDUMP_BUFFER("image", source->address, source->memory, 0, (source->stride)*(source->height)); +#if DUMP_IMAGE + dump_img(source->memory, src_align_width, source->height, source->format); +#endif + + return error; +} + +/* Program initial states for tessellation buffer. */ +static vg_lite_error_t program_tessellation(vg_lite_context_t *context) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + uint32_t tessellation_size; +#if !defined(VG_DRIVER_SINGLE_THREAD) + uint32_t offset; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + + tessellation_size = ( context->tsbuffer.tessellation_buffer_size[2] + ? context->tsbuffer.tessellation_buffer_size[2] + : context->tsbuffer.tessellation_buffer_size[1] + ); +#if !defined(VG_DRIVER_SINGLE_THREAD) + offset = CMDBUF_OFFSET(*context); +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + + /* Since TS buffer won't change during runtime, we program it here in initialization. */ + /* Program tessellation buffer: input for VG module. */ + VG_LITE_RETURN_ERROR(push_state(context, 0x0A30, context->tsbuffer.tessellation_buffer_gpu[0])); /* Tessellation buffer address. */ + VG_LITE_RETURN_ERROR(push_state(context, 0x0A31, context->tsbuffer.tessellation_buffer_gpu[1])); /* L1 address of tessellation buffer. */ + VG_LITE_RETURN_ERROR(push_state(context, 0x0A32, context->tsbuffer.tessellation_buffer_gpu[2])); /* L2 address of tessellation buffer. */ + VG_LITE_RETURN_ERROR(push_state(context, 0x0A33, context->tsbuffer.tessellation_stride)); + /* Program tessellation control: for TS module. */ + VG_LITE_RETURN_ERROR(push_state(context, 0x0A35, context->tsbuffer.tessellation_buffer_gpu[0])); + VG_LITE_RETURN_ERROR(push_state(context, 0x0A36, context->tsbuffer.tessellation_buffer_gpu[1])); + VG_LITE_RETURN_ERROR(push_state(context, 0x0A37, context->tsbuffer.tessellation_buffer_gpu[2])); + VG_LITE_RETURN_ERROR(push_state(context, 0x0A38, context->tsbuffer.tessellation_stride)); + VG_LITE_RETURN_ERROR(push_state(context, 0x0A3A, context->tsbuffer.tessellation_width_height)); + + VG_LITE_RETURN_ERROR(push_state(context, 0x0A3D, tessellation_size / 64)); + +#if !defined(VG_DRIVER_SINGLE_THREAD) + /* Backup tessellation buffer states. */ + context->ts_init_used = 0; + context->ts_init_use = 0; + context->ts_dirty = 1; + memcpy(context->ts_record, (CMDBUF_BUFFER(*context) + offset), 80); + CMDBUF_OFFSET(*context) = 0; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + + return error; +} + +#if defined(VG_DRIVER_SINGLE_THREAD) +vg_lite_error_t vg_lite_init(int32_t tessellation_width, + int32_t tessellation_height) +{ + vg_lite_error_t error; + vg_lite_kernel_initialize_t initialize; + + s_context.rtbuffer = (vg_lite_buffer_t *)malloc(sizeof(vg_lite_buffer_t)); + if(!s_context.rtbuffer) + return VG_LITE_OUT_OF_RESOURCES; + memset(s_context.rtbuffer, 0, sizeof(vg_lite_buffer_t)); + + if (tessellation_width <= 0) { + tessellation_width = 0; + tessellation_height = 0; + } + if (tessellation_height <= 0) { + tessellation_height = 0; + tessellation_width = 0; + } + tessellation_width = VG_LITE_ALIGN(tessellation_width, 16); + +#if VG_TARGET_FAST_CLEAR + vg_lite_get_product_info(NULL,&s_context.chip_id,&s_context.chip_rev); + vg_lite_get_register(0x30, &cid); + if(s_context.chip_id == 0x255 && s_context.chip_rev == 0x1311 && cid == 0x404) + { + tessellation_width = 64; + tessellation_height = 64; + } +#endif + + /* Allocate a command buffer and a tessellation buffer. */ + initialize.command_buffer_size = command_buffer_size; + initialize.tessellation_width = tessellation_width; + initialize.tessellation_height = tessellation_height; + initialize.context = &s_context.context; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_INITIALIZE, &initialize)); + + /* Save draw context. */ + s_context.capabilities = initialize.capabilities; + s_context.command_buffer[0] = (uint8_t *)initialize.command_buffer[0]; + s_context.command_buffer[1] = (uint8_t *)initialize.command_buffer[1]; + s_context.command_buffer_size = initialize.command_buffer_size; + s_context.command_offset[0] = 0; + s_context.command_offset[1] = 0; + + if ((tessellation_width > 0) && + (tessellation_height > 0)) + { + /* Set and Program Tessellation Buffer states. */ + s_context.tsbuffer.tessellation_buffer_gpu[0] = initialize.tessellation_buffer_gpu[0]; + s_context.tsbuffer.tessellation_buffer_gpu[1] = initialize.tessellation_buffer_gpu[1]; + s_context.tsbuffer.tessellation_buffer_gpu[2] = initialize.tessellation_buffer_gpu[2]; + s_context.tsbuffer.tessellation_buffer_logic[0] = initialize.tessellation_buffer_logic[0]; + s_context.tsbuffer.tessellation_buffer_logic[1] = initialize.tessellation_buffer_logic[1]; + s_context.tsbuffer.tessellation_buffer_logic[2] = initialize.tessellation_buffer_logic[2]; + s_context.tsbuffer.tessellation_stride = initialize.tessellation_stride; + s_context.tsbuffer.tessellation_width_height = initialize.tessellation_width_height; + s_context.tsbuffer.tessellation_buffer_size[0] = initialize.tessellation_buffer_size[0]; + s_context.tsbuffer.tessellation_buffer_size[1] = initialize.tessellation_buffer_size[1]; + s_context.tsbuffer.tessellation_buffer_size[2] = initialize.tessellation_buffer_size[2]; + s_context.tsbuffer.tessellation_shift = initialize.tessellation_shift; + + VG_LITE_RETURN_ERROR(program_tessellation(&s_context)); + } + + /* Fill feature table. */ + if (!s_context.s_ftable.ftflag){ + VG_LITE_RETURN_ERROR(fill_feature_table(s_context.s_ftable.ftable)); + } + +#if VG_TARGET_FAST_CLEAR + /* Reset the FAST_CLEAR buffer. */ + memset(&s_context.fcBuffer, 0, sizeof(s_context.fcBuffer)); + s_context.fcBuffer.format = VG_LITE_A8; + s_context.fcBuffer.height = 1; + s_context.clearValue = 0; +#endif + + /* Init scissor rect. */ + s_context.scissor[0] = + s_context.scissor[1] = + s_context.scissor[2] = + s_context.scissor[3] = 0; +#if DUMP_CAPTURE + _SetDumpFileInfo(); +#endif + +#if (VG_RENDER_TEXT==1) + vg_lite_text_init(); +#endif /* VG_RENDER_TEXT */ + + return VG_LITE_SUCCESS; +} +#else +vg_lite_error_t vg_lite_init(int32_t tessellation_width, + int32_t tessellation_height) +{ + vg_lite_error_t error; + vg_lite_kernel_initialize_t initialize; + vg_lite_tls_t* task_tls; + + error = (vg_lite_error_t)vg_lite_os_init_tls_array(); + if(error != VG_LITE_SUCCESS) + return error; + + task_tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(task_tls) + return VG_LITE_SUCCESS; + + task_tls = (vg_lite_tls_t *) vg_lite_os_malloc(sizeof(vg_lite_tls_t)); + if(!task_tls) + return VG_LITE_OUT_OF_RESOURCES; + memset(task_tls,0,sizeof(vg_lite_tls_t)); + error = (vg_lite_error_t)vg_lite_os_set_tls((void *) task_tls); + if(error != VG_LITE_SUCCESS) + return error; + + task_tls->t_context.rtbuffer = NULL; + + if (tessellation_width <= 0) { + tessellation_width = 0; + tessellation_height = 0; + } + if (tessellation_height <= 0) { + tessellation_height = 0; + tessellation_width = 0; + } + tessellation_width = VG_LITE_ALIGN(tessellation_width, 16); + + /* Allocate a command buffer and a tessellation buffer. */ + initialize.command_buffer_size = command_buffer_size; + initialize.context_buffer_size = CONTEXT_BUFFER_SIZE; + initialize.tessellation_width = tessellation_width; + initialize.tessellation_height = tessellation_height; + initialize.context = &task_tls->t_context.context; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_INITIALIZE, &initialize)); + + /* Save draw context. */ + task_tls->t_context.capabilities = initialize.capabilities; + task_tls->t_context.command_buffer[0] = (uint8_t *)initialize.command_buffer[0]; + task_tls->t_context.command_buffer[1] = (uint8_t *)initialize.command_buffer[1]; + task_tls->t_context.command_buffer_size = initialize.command_buffer_size; + task_tls->t_context.command_offset[0] = 0; + task_tls->t_context.command_offset[1] = 0; + task_tls->t_context.command_buffer_current = 0; + task_tls->t_context.context_buffer[0] = (uint8_t *)initialize.context_buffer[0]; + task_tls->t_context.context_buffer[1] = (uint8_t *)initialize.context_buffer[1]; + task_tls->t_context.context_buffer_size = initialize.context_buffer_size; + task_tls->t_context.context_buffer_offset[0] = 0; + task_tls->t_context.context_buffer_offset[1] = 0; + task_tls->t_context.start_offset = 0; + task_tls->t_context.end_offset = 0; + task_tls->t_context.ts_init = 0; + memset(task_tls->t_context.ts_record, 0, sizeof(task_tls->t_context.ts_record)); + + if ((tessellation_width > 0) && + (tessellation_height > 0)) + { + /* Set and Program Tessellation Buffer states. */ + task_tls->t_context.tsbuffer.tessellation_buffer_gpu[0] = initialize.tessellation_buffer_gpu[0]; + task_tls->t_context.tsbuffer.tessellation_buffer_gpu[1] = initialize.tessellation_buffer_gpu[1]; + task_tls->t_context.tsbuffer.tessellation_buffer_gpu[2] = initialize.tessellation_buffer_gpu[2]; + task_tls->t_context.tsbuffer.tessellation_buffer_logic[0] = initialize.tessellation_buffer_logic[0]; + task_tls->t_context.tsbuffer.tessellation_buffer_logic[1] = initialize.tessellation_buffer_logic[1]; + task_tls->t_context.tsbuffer.tessellation_buffer_logic[2] = initialize.tessellation_buffer_logic[2]; + task_tls->t_context.tsbuffer.tessellation_stride = initialize.tessellation_stride; + task_tls->t_context.tsbuffer.tessellation_width_height = initialize.tessellation_width_height; + task_tls->t_context.tsbuffer.tessellation_buffer_size[0] = initialize.tessellation_buffer_size[0]; + task_tls->t_context.tsbuffer.tessellation_buffer_size[1] = initialize.tessellation_buffer_size[1]; + task_tls->t_context.tsbuffer.tessellation_buffer_size[2] = initialize.tessellation_buffer_size[2]; + task_tls->t_context.tsbuffer.tessellation_shift = initialize.tessellation_shift; + + VG_LITE_RETURN_ERROR(program_tessellation(&task_tls->t_context)); + } + + VG_LITE_RETURN_ERROR(push_state(&task_tls->t_context, 0x0A00, 0x0)); + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_LOCK, NULL)); + /* Fill feature table. */ + if (!task_tls->t_context.s_ftable.ftflag){ + VG_LITE_RETURN_ERROR(fill_feature_table(task_tls->t_context.s_ftable.ftable)); + } + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_UNLOCK, NULL)); + +#if VG_TARGET_FAST_CLEAR + /* Reset the FAST_CLEAR buffer. */ + memset(&task_tls->t_context.fcBuffer, 0, sizeof(task_tls->t_context.fcBuffer)); + task_tls->t_context.fcBuffer.format = VG_LITE_A8; + task_tls->t_context.fcBuffer.height = 1; + task_tls->t_context.clearValue = 0; +#endif + + /* Init scissor rect. */ + task_tls->t_context.scissor[0] = + task_tls->t_context.scissor[1] = + task_tls->t_context.scissor[2] = + task_tls->t_context.scissor[3] = 0; +#if DUMP_CAPTURE + _SetDumpFileInfo(); +#endif + +#if (VG_RENDER_TEXT==1) + vg_lite_text_init(); +#endif /* VG_RENDER_TEXT */ + + return VG_LITE_SUCCESS; +} +#endif /* VG_DRIVER_SINGLE_THREAD */ + +vg_lite_error_t vg_lite_set_draw_path_type(vg_lite_path_t * path,vg_lite_draw_path_type_t path_type) +{ + if(!path || (path_type > VG_LITE_DRAW_STROKE_PATH + 1)) + return VG_LITE_INVALID_ARGUMENT; + + path->path_type = path_type; + + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_draw(vg_lite_buffer_t * target, + vg_lite_path_t * path, + vg_lite_fill_t fill_rule, + vg_lite_matrix_t * matrix, + vg_lite_blend_t blend, + vg_lite_color_t color) +{ + uint32_t blend_mode; + uint32_t format, quality, tiling, fill; + uint32_t tessellation_size; + vg_lite_error_t error; + vg_lite_point_t point_min = {0}, point_max = {0}, temp = {0}; + int x, y, width, height; + uint8_t ts_is_fullscreen = 0; +#if DUMP_COMMAND + uint32_t return_offset = 0; + vg_lite_kernel_allocate_t memory; +#endif + int32_t dst_align_width; + uint32_t mul, div, align; +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t *tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + if(!path) + return VG_LITE_INVALID_ARGUMENT; + + if(!path->path_length) + return VG_LITE_SUCCESS; + + if(!path->path) + return VG_LITE_INVALID_ARGUMENT; + + if(!vg_lite_query_feature(gcFEATURE_BIT_VG_QUALITY_8X) && path->quality == VG_LITE_UPPER){ + return VG_LITE_NOT_SUPPORT; + } + + error = set_render_target(target); + if (error != VG_LITE_SUCCESS) { + return error; + } else if (error == VG_LITE_NO_CONTEXT) { + /* If scissoring is enabled and no valid scissoring rectangles + are present, no drawing occurs */ + return VG_LITE_SUCCESS; + } + + width = ctx->tsbuffer.tessellation_width_height & 0xFFFF; + height = ctx->tsbuffer.tessellation_width_height >> 16; + get_format_bytes(target->format, &mul, &div, &align); + dst_align_width = target->stride * div / mul; + if(width == 0 || height == 0) + return VG_LITE_NO_CONTEXT; + if ((dst_align_width <= width) && (target->height <= height)) + { + ts_is_fullscreen = 1; + point_min.x = 0; + point_min.y = 0; + point_max.x = dst_align_width; + point_max.y = target->height; + } + + if (ts_is_fullscreen == 0){ + transform(&temp, (vg_lite_float_t)path->bounding_box[0], (vg_lite_float_t)path->bounding_box[1], matrix); + point_min = point_max = temp; + + transform(&temp, (vg_lite_float_t)path->bounding_box[2], (vg_lite_float_t)path->bounding_box[1], matrix); + if (temp.x < point_min.x) point_min.x = temp.x; + if (temp.y < point_min.y) point_min.y = temp.y; + if (temp.x > point_max.x) point_max.x = temp.x; + if (temp.y > point_max.y) point_max.y = temp.y; + + transform(&temp, (vg_lite_float_t)path->bounding_box[2], (vg_lite_float_t)path->bounding_box[3], matrix); + if (temp.x < point_min.x) point_min.x = temp.x; + if (temp.y < point_min.y) point_min.y = temp.y; + if (temp.x > point_max.x) point_max.x = temp.x; + if (temp.y > point_max.y) point_max.y = temp.y; + + transform(&temp, (vg_lite_float_t)path->bounding_box[0], (vg_lite_float_t)path->bounding_box[3], matrix); + if (temp.x < point_min.x) point_min.x = temp.x; + if (temp.y < point_min.y) point_min.y = temp.y; + if (temp.x > point_max.x) point_max.x = temp.x; + if (temp.y > point_max.y) point_max.y = temp.y; + + if (point_min.x < 0) point_min.x = 0; + if (point_min.y < 0) point_min.y = 0; + if (point_max.x > dst_align_width) point_max.x = dst_align_width; + if (point_max.y > target->height) point_max.y = target->height; + } + + if (ctx->scissor_enabled) { + point_min.x = MAX(point_min.x, ctx->scissor[0]); + point_min.y = MAX(point_min.y, ctx->scissor[1]); + point_max.x = MIN(point_max.x, ctx->scissor[0] + ctx->scissor[2]); + point_max.y = MIN(point_max.y, ctx->scissor[1] + ctx->scissor[3]); + } + + /* Convert states into hardware values. */ + blend_mode = convert_blend(blend); + format = convert_path_format(path->format); + quality = convert_path_quality(path->quality); + tiling = (ctx->capabilities.cap.tiled == 2) ? 0x2000000 : 0; + fill = (fill_rule == VG_LITE_FILL_EVEN_ODD) ? 0x10 : 0; + tessellation_size = ( ctx->tsbuffer.tessellation_buffer_size[2] + ? ctx->tsbuffer.tessellation_buffer_size[2] + : ctx->tsbuffer.tessellation_buffer_size[1] + ); + +#if !defined(VG_DRIVER_SINGLE_THREAD) + if(ctx->ts_dirty){ + memcpy(CMDBUF_BUFFER(*ctx) + CMDBUF_OFFSET(*ctx), ctx->ts_record, 80); + CMDBUF_OFFSET(*ctx) += 80; + ctx->ts_dirty = 0; + ctx->ts_init_used = 1; + } + else + { + ctx->ts_init_use = 1; + } +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + + /* Setup the command buffer. */ + /* Program color register. */ + if(ctx->premultiply_enabled) { + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, ctx->capabilities.cap.tiled | blend_mode)); + } else { + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x10000000 | ctx->capabilities.cap.tiled | blend_mode)); + } + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A02, color)); + /* Program tessellation control: for TS module. */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0x01000200 | format | quality | tiling | fill)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3B, 0x3F800000)); /* Path tessellation SCALE. */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3C, 0x00000000)); /* Path tessellation BIAS. */ + /* Program matrix. */ + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A40, (void *) &matrix->m[0][0])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A41, (void *) &matrix->m[0][1])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A42, (void *) &matrix->m[0][2])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A43, (void *) &matrix->m[1][0])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A44, (void *) &matrix->m[1][1])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A45, (void *) &matrix->m[1][2])); + + if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { + vglitemDUMP_BUFFER("path", path->uploaded.address, (uint8_t *)(path->uploaded.memory), 0, path->uploaded.bytes); + } + vglitemDUMP("@[memory 0x%08X 0x%08X]", ctx->tsbuffer.tessellation_buffer_gpu[0], ctx->tsbuffer.tessellation_buffer_size[0]); + /* Setup tessellation loop. */ + if((path->path_type & 0x1) == VG_LITE_DRAW_FILL_PATH) { + for (y = point_min.y; y < point_max.y; y += height) { + for (x = point_min.x; x < point_max.x; x += width) { + /* Tessellate path. */ + VG_LITE_RETURN_ERROR(push_stall(ctx, 15)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1B, 0x00011000)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A01, x | (y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A39, x | (y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3D, tessellation_size / 64)); + + if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { + VG_LITE_RETURN_ERROR(push_call(ctx, path->uploaded.address, path->uploaded.bytes)); +#if (DUMP_COMMAND) + if (strncmp(filename, "Commandbuffer", 13)) { + sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); + } + + fp = fopen(filename, "a"); + + if (fp == NULL) + printf("error!\n"); + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) memory.memory)[0], 0); + + unsigned char* pt = (unsigned char*) memory.memory; + + for(int i = 8; i <= return_offset * 4 - 1; i = i + 4) + { + if (i % 8 == 0) + fprintf(fp, "Command buffer: "); + + if (i % 4 == 0) + fprintf(fp, "0x"); + + for (int j = 3; j >= 0; --j) + fprintf(fp, "%02x", pt[i + j]); + + if ((i / 4 + 1) % 2 == 0) + fprintf(fp, ",\n"); + else + fprintf(fp, ", "); + } + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) memory.memory)[return_offset], 0); + + fclose(fp); + fp = NULL; +#endif + } else { + push_data(ctx, path->path_length, path->path); + } + } + } + } + /* Setup tessellation loop. */ + if(path->path_type == VG_LITE_DRAW_STROKE_PATH || path->path_type == VG_LITE_DRAW_FILL_STROKE_PATH) { + for (y = point_min.y; y < point_max.y; y += height) { + for (x = point_min.x; x < point_max.x; x += width) { + /* Tessellate path. */ + VG_LITE_RETURN_ERROR(push_stall(ctx, 15)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1B, 0x00011000)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A01, x | (y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A39, x | (y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3D, tessellation_size / 64)); + + if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { + VG_LITE_RETURN_ERROR(push_call(ctx, path->uploaded.address, path->uploaded.bytes)); +#if (DUMP_COMMAND) + if (strncmp(filename, "Commandbuffer", 13)) { + sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); + } + + fp = fopen(filename, "a"); + + if (fp == NULL) + printf("error!\n"); + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) memory.memory)[0], 0); + + unsigned char* pt = (unsigned char*) memory.memory; + + for(int i = 8; i <= return_offset * 4 - 1; i = i + 4) + { + if (i % 8 == 0) + fprintf(fp, "Command buffer: "); + + if (i % 4 == 0) + fprintf(fp, "0x"); + + for (int j = 3; j >= 0; --j) + fprintf(fp, "%02x", pt[i + j]); + + if ((i / 4 + 1) % 2 == 0) + fprintf(fp, ",\n"); + else + fprintf(fp, ", "); + } + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) memory.memory)[return_offset], 0); + + fclose(fp); + fp = NULL; +#endif + } else { + format = convert_path_format(VG_LITE_FP32); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0x01000200 | format | quality | tiling | 0x0)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A02, path->stroke_color)); + push_data(ctx, path->stroke_path_size, path->stroke_path_data); + } + } + } + } + + /* Finialize command buffer. */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0)); + VG_LITE_RETURN_ERROR(flush_target()); +#if !defined(VG_DRIVER_SINGLE_THREAD) + ctx->ts_init = 1; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + return error; +} + +vg_lite_error_t vg_lite_close(void) +{ + vg_lite_error_t error; + vg_lite_kernel_terminate_t terminate; +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t* tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + +#if VG_TARGET_FAST_CLEAR + if (ctx->fcBuffer.handle != NULL) { + vg_lite_free(&ctx->fcBuffer); + } +#endif + + /* Termnate the draw context. */ + terminate.context = &ctx->context; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_TERMINATE, &terminate)); + +#if defined(VG_DRIVER_SINGLE_THREAD) + if(ctx->rtbuffer) + free(ctx->rtbuffer); + + submit_flag = 0; + + /* Reset the draw context. */ + _memset(ctx, 0, sizeof(s_context)); + + /* Reset the s_ftable. */ + _memset(&ctx->s_ftable, 0, sizeof(ctx->s_ftable)); + + ctx->init = 0; +#else + /* Reset the draw context. */ + if(tls->t_context.colors){ + free(ctx->colors[0]); + free(ctx->colors[1]); + free(ctx->colors[2]); + free(ctx->colors[3]); + } + + _memset(ctx, 0, sizeof(*ctx)); + + vg_lite_os_reset_tls(); + vg_lite_os_free((void *) tls); + + vg_lite_os_deinit_tls_array(); +#endif /* VG_DRIVER_SINGLE_THREAD */ + +#if DUMP_CAPTURE + _SetDumpFileInfo(); +#endif + + return VG_LITE_SUCCESS; +} + +/* Handle tiled & yuv allocation. Currently including NV12, ANV12, YV12, YV16, NV16, YV24. */ +static vg_lite_error_t _allocate_tiled_yuv_planar(vg_lite_buffer_t *buffer) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + uint32_t yplane_size = 0; + vg_lite_kernel_allocate_t allocate, uv_allocate, v_allocate; + + if ((buffer->format < VG_LITE_NV12) || (buffer->format > VG_LITE_ANV12_TILED) + || (buffer->format == VG_LITE_AYUY2) || (buffer->format == VG_LITE_YUY2_TILED)) + { + return error; + } + + /* For NV12, there are 2 planes (Y, UV); + For ANV12, there are 3 planes (Y, UV, Alpha). + Each plane must be aligned by (4, 8). + Then Y plane must be aligned by (8, 8). + For YVxx, there are 3 planes (Y, U, V). + YV12 is similar to NV12, both YUV420 format. + YV16 and NV16 are YUV422 format. + YV24 is YUV444 format. + */ + buffer->width = VG_LITE_ALIGN(buffer->width, 8); + buffer->height = VG_LITE_ALIGN(buffer->height, 8); + buffer->stride = VG_LITE_ALIGN(buffer->width, 128); + + switch (buffer->format) { + case VG_LITE_NV12: + case VG_LITE_ANV12: + case VG_LITE_NV12_TILED: + case VG_LITE_ANV12_TILED: + buffer->yuv.uv_stride = buffer->stride; + buffer->yuv.alpha_stride = buffer->stride; + buffer->yuv.uv_height = buffer->height / 2; + break; + + case VG_LITE_NV16: + buffer->yuv.uv_stride = buffer->stride; + buffer->yuv.uv_height = buffer->height; + break; + + case VG_LITE_YV12: + buffer->yuv.uv_stride = + buffer->yuv.v_stride = buffer->stride / 2; + buffer->yuv.uv_height = + buffer->yuv.v_height = buffer->height / 2; + break; + + case VG_LITE_YV16: + buffer->yuv.uv_stride = + buffer->yuv.v_stride = buffer->stride; + buffer->yuv.uv_height = + buffer->yuv.v_height = buffer->height / 2; + break; + + case VG_LITE_YV24: + buffer->yuv.uv_stride = + buffer->yuv.v_stride = buffer->stride; + buffer->yuv.uv_height = + buffer->yuv.v_height = buffer->height; + break; + + default: + return error; + } + + yplane_size = buffer->stride * buffer->height; + + /* Allocate buffer memory: Y. */ + allocate.bytes = yplane_size; + allocate.contiguous = 1; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &allocate)); + + /* Save the allocation. */ + buffer->handle = allocate.memory_handle; + buffer->memory = allocate.memory; + buffer->address = allocate.memory_gpu; + + if ((buffer->format == VG_LITE_NV12) || (buffer->format == VG_LITE_ANV12) + || (buffer->format == VG_LITE_NV16) || (buffer->format == VG_LITE_NV12_TILED) + || (buffer->format == VG_LITE_ANV12_TILED)) { + /* Allocate buffer memory: UV. */ + uv_allocate.bytes = buffer->yuv.uv_stride * buffer->yuv.uv_height; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &uv_allocate)); + buffer->yuv.uv_handle = uv_allocate.memory_handle; + buffer->yuv.uv_memory = uv_allocate.memory; + buffer->yuv.uv_planar = uv_allocate.memory_gpu; + + if ((buffer->format == VG_LITE_ANV12) || (buffer->format == VG_LITE_ANV12_TILED)) { + uv_allocate.bytes = yplane_size; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &uv_allocate)); + buffer->yuv.alpha_planar = uv_allocate.memory_gpu; + } + } else { + /* Allocate buffer memory: U, V. */ + uv_allocate.bytes = buffer->yuv.uv_stride * buffer->yuv.uv_height; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &uv_allocate)); + buffer->yuv.uv_handle = uv_allocate.memory_handle; + buffer->yuv.uv_memory = uv_allocate.memory; + buffer->yuv.uv_planar = uv_allocate.memory_gpu; + + v_allocate.bytes = buffer->yuv.v_stride * buffer->yuv.v_height; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &v_allocate)); + buffer->yuv.v_handle = v_allocate.memory_handle; + buffer->yuv.v_memory = v_allocate.memory; + buffer->yuv.v_planar = v_allocate.memory_gpu; + } + + return error; +} + +vg_lite_error_t vg_lite_allocate(vg_lite_buffer_t * buffer) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + vg_lite_kernel_allocate_t allocate; + + /* Reset planar. */ + buffer->yuv.uv_planar = + buffer->yuv.v_planar = + buffer->yuv.alpha_planar = 0; + + /* Align height in case format is tiled. */ + if (buffer->format >= VG_LITE_YUY2 && buffer->format <= VG_LITE_NV16) { + buffer->height = VG_LITE_ALIGN(buffer->height, 4); + buffer->yuv.swizzle = VG_LITE_SWIZZLE_UV; + } + + if (buffer->format >= VG_LITE_YUY2_TILED && buffer->format <= VG_LITE_AYUY2_TILED) { + buffer->height = VG_LITE_ALIGN(buffer->height, 4); + buffer->tiled = VG_LITE_TILED; + buffer->yuv.swizzle = VG_LITE_SWIZZLE_UV; + } + + if ((buffer->format >= VG_LITE_NV12 && buffer->format <= VG_LITE_ANV12_TILED + && buffer->format != VG_LITE_AYUY2 && buffer->format != VG_LITE_YUY2_TILED)) { + _allocate_tiled_yuv_planar(buffer); + } + else { + /* Driver need compute the stride always with RT500 project. */ + uint32_t mul, div, align; +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t* tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + get_format_bytes(buffer->format, &mul, &div, &align); + vg_lite_get_product_info(NULL,&ctx->chip_id,NULL); + buffer->stride = VG_LITE_ALIGN((buffer->width * mul / div), align); + /* Allocate the buffer. */ + allocate.bytes = buffer->stride * buffer->height; +#if VG_TARGET_FAST_CLEAR + allocate.bytes = VG_LITE_ALIGN(allocate.bytes, 64); +#endif + allocate.contiguous = 1; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &allocate)); + + /* Save the buffer allocation. */ + buffer->handle = allocate.memory_handle; + buffer->memory = allocate.memory; + buffer->address = allocate.memory_gpu; + + if ((buffer->format == VG_LITE_AYUY2) || (buffer->format == VG_LITE_AYUY2_TILED)) { + allocate.bytes = buffer->stride * buffer->height; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &allocate)); + buffer->yuv.alpha_planar = allocate.memory_gpu; + } + + } + + return VG_LITE_SUCCESS; +} + +#if defined(VG_DRIVER_SINGLE_THREAD) +vg_lite_error_t vg_lite_free(vg_lite_buffer_t * buffer) +{ + vg_lite_error_t error; + vg_lite_kernel_free_t free, uv_free, v_free; + + if(buffer == NULL) + return VG_LITE_INVALID_ARGUMENT; + if (!(memcmp(s_context.rtbuffer,buffer,sizeof(vg_lite_buffer_t))) ) { + if (VG_LITE_SUCCESS == submit(&s_context)) { + VG_LITE_RETURN_ERROR(stall(&s_context, 0, ~0)); + } + vglitemDUMP("@[swap 0x%08X %dx%d +%u]", + s_context.rtbuffer->address, + s_context.rtbuffer->width, s_context.rtbuffer->height, + s_context.rtbuffer->stride); + vglitemDUMP_BUFFER( + "framebuffer", + s_context.rtbuffer->address,s_context.rtbuffer->memory, + 0, + s_context.rtbuffer->stride*(s_context.rtbuffer->height)); + + memset(s_context.rtbuffer, 0, sizeof(vg_lite_buffer_t)); + } + + if (buffer->yuv.uv_planar) { + /* Free UV(U) planar buffer. */ + uv_free.memory_handle = buffer->yuv.uv_handle; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &uv_free)); + + /* Mark the buffer as freed. */ + buffer->yuv.uv_handle = NULL; + buffer->yuv.uv_memory = NULL; + } + + if (buffer->yuv.v_planar) { + /* Free V planar buffer. */ + v_free.memory_handle = buffer->yuv.v_handle; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &v_free)); + + /* Mark the buffer as freed. */ + buffer->yuv.v_handle = NULL; + buffer->yuv.v_memory = NULL; + } + + /* Make sure we have a valid memory handle. */ + if (buffer->handle == NULL) { + return VG_LITE_INVALID_ARGUMENT; + } + + /* Free the buffer. */ + free.memory_handle = buffer->handle; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &free)); + + /* Mark the buffer as freed. */ + buffer->handle = NULL; + buffer->memory = NULL; + + return VG_LITE_SUCCESS; +} +#else +vg_lite_error_t vg_lite_free(vg_lite_buffer_t * buffer) +{ + vg_lite_error_t error; + vg_lite_kernel_free_t free, uv_free, v_free; + vg_lite_tls_t* tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + if(buffer == NULL) + return VG_LITE_INVALID_ARGUMENT; + if (tls->t_context.rtbuffer == buffer && !(memcmp(tls->t_context.rtbuffer,buffer,sizeof(vg_lite_buffer_t))) ) { + if (VG_LITE_SUCCESS == submit(&tls->t_context)) { + VG_LITE_RETURN_ERROR(stall(&tls->t_context, 0)); + } + vglitemDUMP("@[swap 0x%08X %dx%d +%u]", + tls->t_context.rtbuffer->address, + tls->t_context.rtbuffer->width, tls->t_context.rtbuffer->height, + tls->t_context.rtbuffer->stride); + vglitemDUMP_BUFFER( + "framebuffer", + tls->t_context.rtbuffer->address,tls->t_context.rtbuffer->memory, + 0, + tls->t_context.rtbuffer->stride*(tls->t_context.rtbuffer->height)); + + memset(tls->t_context.rtbuffer, 0, sizeof(vg_lite_buffer_t)); + } + + if (buffer->yuv.uv_planar) { + /* Free UV(U) planar buffer. */ + uv_free.memory_handle = buffer->yuv.uv_handle; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &uv_free)); + + /* Mark the buffer as freed. */ + buffer->yuv.uv_handle = NULL; + buffer->yuv.uv_memory = NULL; + } + + if (buffer->yuv.v_planar) { + /* Free V planar buffer. */ + v_free.memory_handle = buffer->yuv.v_handle; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &v_free)); + + /* Mark the buffer as freed. */ + buffer->yuv.v_handle = NULL; + buffer->yuv.v_memory = NULL; + } + + /* Make sure we have a valid memory handle. */ + if (buffer->handle == NULL) { + return VG_LITE_INVALID_ARGUMENT; + } + + /* Free the buffer. */ + free.memory_handle = buffer->handle; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &free)); + + /* Mark the buffer as freed. */ + buffer->handle = NULL; + buffer->memory = NULL; + + return VG_LITE_SUCCESS; +} +#endif /* VG_DRIVER_SINGLE_THREAD */ + +vg_lite_error_t vg_lite_map(vg_lite_buffer_t * buffer) +{ + vg_lite_error_t error; + vg_lite_kernel_map_t map; + + /* We either need a logical or physical address. */ + if (buffer->memory == NULL && buffer->address == 0) { + return VG_LITE_INVALID_ARGUMENT; + } + + /* Check if we need to compute the stride. Usually map a pre-allocated memory, so the stride + usually should be set*/ + if (buffer->stride == 0) { + uint32_t mul, div, align; + get_format_bytes(buffer->format, &mul, &div, &align); + /* Compute the stride to be aligned. */ + buffer->stride = VG_LITE_ALIGN((buffer->width * mul / div), align); + } + + /* Map the buffer. */ + map.bytes = buffer->stride * buffer->height; + map.logical = buffer->memory; + map.physical = buffer->address; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_MAP, &map)); + + /* Save the buffer allocation. */ + buffer->handle = map.memory_handle; + buffer->address = map.memory_gpu; + + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_unmap(vg_lite_buffer_t * buffer) +{ + vg_lite_error_t error; + vg_lite_kernel_unmap_t unmap; + + /* Make sure we have a valid memory handle. */ + if (buffer->handle == NULL) { + return VG_LITE_INVALID_ARGUMENT; + } + + /* Unmap the buffer. */ + unmap.memory_handle = buffer->handle; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_UNMAP, &unmap)); + + /* Mark the buffer as freed. */ + buffer->handle = NULL; + + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_get_register(uint32_t address, uint32_t * result) +{ + vg_lite_error_t error; + vg_lite_kernel_info_t data; + + /* Get input register address. */ + data.addr = address; + + /* Get register info. */ + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_CHECK, &data)); + + /* Return register info. */ + *result = data.reg; + + return VG_LITE_SUCCESS; +} + +void vg_lite_get_info(vg_lite_info_t *info) +{ + if (info != NULL) + { + info->api_version = VGLITE_API_VERSION_2_0; + info->header_version = VGLITE_HEADER_VERSION; + info->release_version = VGLITE_RELEASE_VERSION; + info->reserved = 0; + } +} + +uint32_t vg_lite_get_product_info(char *name, uint32_t *chip_id, uint32_t *chip_rev) +{ + const char *product_name = "GCNanoLiteV"; + uint32_t name_len; + uint32_t rev = 0, id = 0; + + vg_lite_get_register(0x24, &rev); + vg_lite_get_register(0x20, &id); + + name_len = strlen(product_name) + 1; + if (name != NULL) + { + memcpy(name, product_name, name_len); + } + + if (chip_id != NULL) + { + *chip_id = id; + } + + if (chip_rev != NULL) + { + *chip_rev = rev; + } + return name_len; +} + +uint32_t vg_lite_query_feature(vg_lite_feature_t feature) +{ + uint32_t result; +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t *tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if (tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + if (feature < gcFEATURE_COUNT) + result = ctx->s_ftable.ftable[feature]; + else + result = 0; + + return result; +} + +#if defined(VG_DRIVER_SINGLE_THREAD) +vg_lite_error_t vg_lite_finish() +{ + vg_lite_error_t error; + + /* Return if there is nothing to submit. */ + if (CMDBUF_OFFSET(s_context) == 0) + { + if(submit_flag) + VG_LITE_RETURN_ERROR(stall(&s_context, 0, (uint32_t)~0)); + return VG_LITE_SUCCESS; + } + + /* Flush is moved from each draw to here. */ + VG_LITE_RETURN_ERROR(flush_target()); + VG_LITE_RETURN_ERROR(submit(&s_context)); + VG_LITE_RETURN_ERROR(stall(&s_context, 0, (uint32_t)~0)); + +#if VG_TARGET_FAST_CLEAR + /*Only used in cmodel/fpga. In final SOC this SW FC decoder should be removed. */ + if (s_context.rtbuffer != NULL) { +#if VG_TARGET_FC_DUMP + fc_buf_dump(s_context.rtbuffer, &s_context.fcBuffer); +#endif /* VG_TARGET_FC_DUMP */ + } +#endif + + CMDBUF_SWAP(s_context); + /* Reset command buffer. */ + CMDBUF_OFFSET(s_context) = 0; + + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_flush(void) +{ + vg_lite_error_t error; + + /* Return if there is nothing to submit. */ + if (CMDBUF_OFFSET(s_context) == 0) + return VG_LITE_SUCCESS; + + /* Wait if GPU has not completed previous CMD buffer */ + if (submit_flag) + { + VG_LITE_RETURN_ERROR(stall(&s_context, 0, (uint32_t)~0)); + } + + /* Submit the current command buffer. */ + VG_LITE_RETURN_ERROR(flush_target()); + VG_LITE_RETURN_ERROR(submit(&s_context)); + CMDBUF_SWAP(s_context); + /* Reset command buffer. */ + CMDBUF_OFFSET(s_context) = 0; + + return VG_LITE_SUCCESS; +} +#else +vg_lite_error_t vg_lite_finish() +{ + vg_lite_error_t error; + vg_lite_tls_t* tls; + uint32_t command_id, index; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + command_id = CMDBUF_INDEX(tls->t_context); + index = command_id ? 0 : 1; + + if (CMDBUF_OFFSET(tls->t_context) <= 8){ + /* Return if there is nothing to submit. */ + if (!CMDBUF_IN_QUEUE(&tls->t_context.context, 0) && !CMDBUF_IN_QUEUE(&tls->t_context.context, 1) ) + return VG_LITE_SUCCESS; + /* This frame has unfinished command. */ + else if(CMDBUF_IN_QUEUE(&tls->t_context.context, index)) + { + CMDBUF_SWAP(tls->t_context); + VG_LITE_RETURN_ERROR(stall(&tls->t_context, 0)); + } + /* This frame has unfinished command. */ + else if(CMDBUF_IN_QUEUE(&tls->t_context.context, command_id)) + { + VG_LITE_RETURN_ERROR(stall(&tls->t_context, 0)); + } + CMDBUF_OFFSET(tls->t_context) = 0; + VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A00, 0x0)); + return VG_LITE_SUCCESS; + } + else + { + /* Flush is moved from each draw to here. */ + VG_LITE_RETURN_ERROR(flush_target()); + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_LOCK, NULL)); + /* if context have been switched and this task need use index. */ + VG_LITE_RETURN_ERROR(update_context_buffer()); + VG_LITE_RETURN_ERROR(submit(&tls->t_context)); + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_UNLOCK, NULL)); + VG_LITE_RETURN_ERROR(stall(&tls->t_context, 0)); + } + +#if VG_TARGET_FAST_CLEAR + /*Only used in cmodel/fpga. In final SOC this SW FC decoder should be removed. */ + if (tls->t_context.rtbuffer != NULL) { +#if VG_TARGET_FC_DUMP + fc_buf_dump(tls->t_context.rtbuffer, &tls->t_context.fcBuffer); +#endif /* VG_TARGET_FC_DUMP */ + } +#endif + + CMDBUF_SWAP(tls->t_context); + CMDBUF_OFFSET(tls->t_context) = 0; + VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A00, 0x0)); + tls->t_context.ts_init_used = 0; + tls->t_context.ts_init_use = 0; + tls->t_context.ts_init = 0; + + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_flush(void) +{ + vg_lite_error_t error; + vg_lite_tls_t* tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + /* Return if there is nothing to submit. */ + if (CMDBUF_OFFSET(tls->t_context) == 0) + return VG_LITE_SUCCESS; + + /* Submit the current command buffer. */ + VG_LITE_RETURN_ERROR(flush_target()); + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_LOCK, NULL)); + /* if context have been switched and this task need use index. */ + VG_LITE_RETURN_ERROR(update_context_buffer()); + VG_LITE_RETURN_ERROR(submit(&tls->t_context)); + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_UNLOCK, NULL)); + + CMDBUF_SWAP(tls->t_context); + CMDBUF_OFFSET(tls->t_context) = 0; + VG_LITE_RETURN_ERROR(push_state(&tls->t_context, 0x0A00, 0x0)); + tls->t_context.ts_init_used = 0; + tls->t_context.ts_init_use = 0; + tls->t_context.ts_init = 0; + + return VG_LITE_SUCCESS; +} +#endif /* VG_DRIVER_SINGLE_THREAD */ + +vg_lite_error_t vg_lite_init_arc_path(vg_lite_path_t * path, + vg_lite_format_t data_format, + vg_lite_quality_t quality, + uint32_t path_length, + void * path_data, + vg_lite_float_t min_x, vg_lite_float_t min_y, + vg_lite_float_t max_x, vg_lite_float_t max_y) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + uint32_t i = 0,command = 0,offset = 0; + vg_lite_float_t moveToX,moveToY,lineToX,lineToY,controlX, controlY,quadToX, quadToY; + vg_lite_float_t controlX1, controlY1,controlX2, controlY2,cubicToX, cubicToY; + vg_lite_float_t horRadius,verRadius,rotAngle,endX,endY; + float *pfloat,*fpath; + char *cpath,*pathdata; + vg_lite_control_coord_t coords; + + if(path == NULL || path_data == NULL || data_format != VG_LITE_FP32) + return VG_LITE_INVALID_ARGUMENT; + + memset(path, 0, sizeof(*path)); + + if(!path_length) + { + path->format = data_format; + path->quality = quality; + path->bounding_box[0] = min_x; + path->bounding_box[1] = min_y; + path->bounding_box[2] = max_x; + path->bounding_box[3] = max_y; + + path->path_length = 0; + path->path = NULL; + path->pdata_internal = 1; + path->path_changed = 1; + path->uploaded.address = 0; + path->uploaded.bytes = 0; + path->uploaded.handle = NULL; + path->uploaded.memory = NULL; + return VG_LITE_SUCCESS; + } + + memset(&coords, 0, sizeof(vg_lite_control_coord_t)); + pathdata = (char *)vg_lite_os_malloc(path_length); + if (pathdata == NULL) + return VG_LITE_OUT_OF_MEMORY; + memset(pathdata, 0, path_length); + pfloat = (vg_lite_float_t *)path_data; + while(i < path_length) + { + cpath = (char *)pfloat; + command = (uint32_t)*cpath; + pfloat++; + switch (command) + { + case VLC_OP_END: + cpath = (char *)pathdata + offset; + fpath = (vg_lite_float_t *)cpath; + *cpath = VLC_OP_END; + offset += _commandSize_float[VLC_OP_END]; + i += _commandSize_float[VLC_OP_END]; + break; + case VLC_OP_CLOSE: + /* Update the control coordinates. */ + coords.lastX = coords.startX; + coords.lastY = coords.startY; + coords.controlX = coords.startX; + coords.controlY = coords.startY; + + cpath = (char *)pathdata + offset; + fpath = (vg_lite_float_t *)cpath; + *cpath = VLC_OP_CLOSE; + offset += _commandSize_float[VLC_OP_CLOSE]; + i += _commandSize_float[VLC_OP_CLOSE]; + break; + case VLC_OP_MOVE: + moveToX = *pfloat++; + moveToY = *pfloat++; + + /* Update the control coordinates. */ + coords.startX = moveToX; + coords.startY = moveToY; + coords.lastX = moveToX; + coords.lastY = moveToY; + coords.controlX = moveToX; + coords.controlY = moveToY; + + cpath = (char *)pathdata + offset; + fpath = (vg_lite_float_t *)cpath; + *cpath = VLC_OP_MOVE; + fpath++; + *fpath++ = moveToX; + *fpath++ = moveToY; + offset += _commandSize_float[VLC_OP_MOVE]; + i += _commandSize_float[VLC_OP_MOVE]; + break; + case VLC_OP_MOVE_REL: + moveToX = *pfloat++; + moveToY = *pfloat++; + + cpath = (char *)pathdata + offset; + fpath = (vg_lite_float_t *)cpath; + *cpath = VLC_OP_MOVE_REL; + fpath++; + *fpath++ = moveToX; + *fpath++ = moveToY; + offset += _commandSize_float[VLC_OP_MOVE_REL]; + i += _commandSize_float[VLC_OP_MOVE_REL]; + + /* Determine the absolute coordinates. */ + moveToX += coords.lastX; + moveToY += coords.lastY; + + /* Update the control coordinates. */ + coords.startX = moveToX; + coords.startY = moveToY; + coords.lastX = moveToX; + coords.lastY = moveToY; + coords.controlX = moveToX; + coords.controlY = moveToY; + break; + case VLC_OP_LINE: + lineToX = *pfloat++; + lineToY = *pfloat++; + + /* Update the control coordinates. */ + coords.lastX = lineToX; + coords.lastY = lineToY; + coords.controlX = lineToX; + coords.controlY = lineToY; + + cpath = (char *)pathdata + offset; + fpath = (vg_lite_float_t *)cpath; + *cpath = VLC_OP_LINE; + fpath++; + *fpath++ = lineToX; + *fpath++ = lineToY; + offset += _commandSize_float[VLC_OP_LINE]; + i += _commandSize_float[VLC_OP_LINE]; + break; + case VLC_OP_LINE_REL: + lineToX = *pfloat++; + lineToY = *pfloat++; + + cpath = (char *)pathdata + offset; + fpath = (vg_lite_float_t *)cpath; + *cpath = VLC_OP_LINE_REL; + fpath++; + *fpath++ = lineToX; + *fpath++ = lineToY; + offset += _commandSize_float[VLC_OP_LINE_REL]; + i += _commandSize_float[VLC_OP_LINE_REL]; + + /* Determine the absolute coordinates. */ + lineToX += coords.lastX; + lineToY += coords.lastY; + + /* Update the control coordinates. */ + coords.lastX = lineToX; + coords.lastY = lineToY; + coords.controlX = lineToX; + coords.controlY = lineToY; + break; + case VLC_OP_QUAD: + controlX = *pfloat++; + controlY = *pfloat++; + quadToX = *pfloat++; + quadToY = *pfloat++; + + /* Update the control coordinates. */ + coords.lastX = quadToX; + coords.lastY = quadToY; + coords.controlX = controlX; + coords.controlY = controlY; + + cpath = (char *)pathdata + offset; + fpath = (vg_lite_float_t *)cpath; + *cpath = VLC_OP_QUAD; + fpath++; + *fpath++ = controlX; + *fpath++ = controlY; + *fpath++ = quadToX; + *fpath++ = quadToY; + offset += _commandSize_float[VLC_OP_QUAD]; + i += _commandSize_float[VLC_OP_QUAD]; + break; + case VLC_OP_QUAD_REL: + controlX = *pfloat++; + controlY = *pfloat++; + quadToX = *pfloat++; + quadToY = *pfloat++; + + cpath = (char *)pathdata + offset; + fpath = (vg_lite_float_t *)cpath; + *cpath = VLC_OP_QUAD_REL; + fpath++; + *fpath++ = controlX; + *fpath++ = controlY; + *fpath++ = quadToX; + *fpath++ = quadToY; + offset += _commandSize_float[VLC_OP_QUAD_REL]; + i += _commandSize_float[VLC_OP_QUAD_REL]; + + /* Determine the absolute coordinates. */ + controlX += coords.lastX; + controlY += coords.lastY; + quadToX += coords.lastX; + quadToY += coords.lastY; + + /* Update the control coordinates. */ + coords.lastX = quadToX; + coords.lastY = quadToY; + coords.controlX = controlX; + coords.controlY = controlY; + break; + case VLC_OP_CUBIC: + controlX1 = *pfloat++; + controlY1 = *pfloat++; + controlX2 = *pfloat++; + controlY2 = *pfloat++; + cubicToX = *pfloat++; + cubicToY = *pfloat++; + + /* Update the control coordinates. */ + coords.lastX = cubicToX; + coords.lastY = cubicToY; + coords.controlX = controlX2; + coords.controlY = controlY2; + + cpath = (char *)pathdata + offset; + fpath = (vg_lite_float_t *)cpath; + *cpath = VLC_OP_CUBIC; + fpath++; + *fpath++ = controlX1; + *fpath++ = controlY1; + *fpath++ = controlX2; + *fpath++ = controlY2; + *fpath++ = cubicToX; + *fpath++ = cubicToY; + offset += _commandSize_float[VLC_OP_CUBIC]; + i += _commandSize_float[VLC_OP_CUBIC]; + break; + case VLC_OP_CUBIC_REL: + controlX1 = *pfloat++; + controlY1 = *pfloat++; + controlX2 = *pfloat++; + controlY2 = *pfloat++; + cubicToX = *pfloat++; + cubicToY = *pfloat++; + + cpath = (char *)pathdata + offset; + fpath = (vg_lite_float_t *)cpath; + *cpath = VLC_OP_CUBIC_REL; + fpath++; + *fpath++ = controlX1; + *fpath++ = controlY1; + *fpath++ = controlX2; + *fpath++ = controlY2; + *fpath++ = cubicToX; + *fpath++ = cubicToY; + offset += _commandSize_float[VLC_OP_CUBIC_REL]; + i += _commandSize_float[VLC_OP_CUBIC_REL]; + + /* Determine the absolute coordinates. */ + controlX2 += coords.lastX; + controlY2 += coords.lastY; + cubicToX += coords.lastX; + cubicToY += coords.lastY; + + /* Update the control coordinates. */ + coords.lastX = cubicToX; + coords.lastY = cubicToY; + coords.controlX = controlX2; + coords.controlY = controlY2; + break; + case VLC_OP_SCCWARC: + horRadius = *pfloat++; + verRadius = *pfloat++; + rotAngle = *pfloat++; + endX = *pfloat++; + endY = *pfloat++; + i += _commandSize_float[VLC_OP_SCCWARC]; + VG_LITE_ERROR_HANDLER(_convert_arc(horRadius,verRadius,rotAngle,endX,endY,FALSE,FALSE,FALSE,&coords,(void *)&pathdata,&offset,path_length - i)); + break; + case VLC_OP_SCCWARC_REL: + horRadius = *pfloat++; + verRadius = *pfloat++; + rotAngle = *pfloat++; + endX = *pfloat++; + endY = *pfloat++; + i += _commandSize_float[VLC_OP_SCCWARC_REL]; + VG_LITE_ERROR_HANDLER(_convert_arc(horRadius,verRadius,rotAngle,endX,endY,FALSE,FALSE,TURE,&coords,(void *)&pathdata,&offset,path_length - i)); + break; + case VLC_OP_SCWARC: + horRadius = *pfloat++; + verRadius = *pfloat++; + rotAngle = *pfloat++; + endX = *pfloat++; + endY = *pfloat++; + i += _commandSize_float[VLC_OP_SCCWARC_REL]; + VG_LITE_ERROR_HANDLER(_convert_arc(horRadius,verRadius,rotAngle,endX,endY,TURE,FALSE,FALSE,&coords,(void *)&pathdata,&offset,path_length - i)); + break; + case VLC_OP_SCWARC_REL: + horRadius = *pfloat++; + verRadius = *pfloat++; + rotAngle = *pfloat++; + endX = *pfloat++; + endY = *pfloat++; + i += _commandSize_float[VLC_OP_SCCWARC_REL]; + VG_LITE_ERROR_HANDLER(_convert_arc(horRadius,verRadius,rotAngle,endX,endY,TURE,FALSE,TURE,&coords,(void *)&pathdata,&offset,path_length - i)); + break; + case VLC_OP_LCCWARC: + horRadius = *pfloat++; + verRadius = *pfloat++; + rotAngle = *pfloat++; + endX = *pfloat++; + endY = *pfloat++; + i += _commandSize_float[VLC_OP_SCCWARC_REL]; + VG_LITE_ERROR_HANDLER(_convert_arc(horRadius,verRadius,rotAngle,endX,endY,FALSE,TURE,FALSE,&coords,(void *)&pathdata,&offset,path_length - i)); + break; + case VLC_OP_LCCWARC_REL: + horRadius = *pfloat++; + verRadius = *pfloat++; + rotAngle = *pfloat++; + endX = *pfloat++; + endY = *pfloat++; + i += _commandSize_float[VLC_OP_SCCWARC_REL]; + VG_LITE_ERROR_HANDLER(_convert_arc(horRadius,verRadius,rotAngle,endX,endY,FALSE,TURE,TURE,&coords,(void *)&pathdata,&offset,path_length - i)); + break; + case VLC_OP_LCWARC: + horRadius = *pfloat++; + verRadius = *pfloat++; + rotAngle = *pfloat++; + endX = *pfloat++; + endY = *pfloat++; + i += _commandSize_float[VLC_OP_SCCWARC_REL]; + VG_LITE_ERROR_HANDLER(_convert_arc(horRadius,verRadius,rotAngle,endX,endY,TURE,TURE,FALSE,&coords,(void *)&pathdata,&offset,path_length - i)); + break; + case VLC_OP_LCWARC_REL: + horRadius = *pfloat++; + verRadius = *pfloat++; + rotAngle = *pfloat++; + endX = *pfloat++; + endY = *pfloat++; + i += _commandSize_float[VLC_OP_SCCWARC_REL]; + VG_LITE_ERROR_HANDLER(_convert_arc(horRadius,verRadius,rotAngle,endX,endY,TURE,TURE,TURE,&coords,(void *)&pathdata,&offset,path_length - i)); + break; + default: + break; + } + } + + path->format = data_format; + path->quality = quality; + path->bounding_box[0] = min_x; + path->bounding_box[1] = min_y; + path->bounding_box[2] = max_x; + path->bounding_box[3] = max_y; + + path->path_length = offset; + path->path = pathdata; + path->pdata_internal = 1; + path->path_changed = 1; + path->uploaded.address = 0; + path->uploaded.bytes = 0; + path->uploaded.handle = NULL; + path->uploaded.memory = NULL; + + return VG_LITE_SUCCESS; + +ErrorHandler: + vg_lite_os_free(pathdata); + pathdata = NULL; + return error; +} + +vg_lite_error_t vg_lite_init_path(vg_lite_path_t * path, + vg_lite_format_t data_format, + vg_lite_quality_t quality, + uint32_t path_length, + void * path_data, + vg_lite_float_t min_x, vg_lite_float_t min_y, + vg_lite_float_t max_x, vg_lite_float_t max_y) +{ + if(path == NULL) + return VG_LITE_INVALID_ARGUMENT; + + memset(path, 0, sizeof(*path)); + path->format = data_format; + path->quality = quality; + path->bounding_box[0] = min_x; + path->bounding_box[1] = min_y; + path->bounding_box[2] = max_x; + path->bounding_box[3] = max_y; + + path->path_length = path_length; + path->path = path_data; + + path->path_changed = 1; + path->uploaded.address = 0; + path->uploaded.bytes = 0; + path->uploaded.handle = NULL; + path->uploaded.memory = NULL; + path->uploaded.property = 0; + path->pdata_internal = 0; + + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_clear_path(vg_lite_path_t * path) +{ + vg_lite_error_t error; + if (path->uploaded.handle != NULL) + { + vg_lite_kernel_free_t free_cmd; + free_cmd.memory_handle = path->uploaded.handle; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_FREE, &free_cmd)); + } + + path->uploaded.address = 0; + path->uploaded.bytes = 0; + path->uploaded.handle = NULL; + path->uploaded.memory = NULL; + + if(path->pdata_internal == 1 && path->path != NULL){ + vg_lite_os_free(path->path); + } + path->path = NULL; + + if(path->stroke_path_data) { + vg_lite_os_free(path->stroke_path_data); + path->stroke_path_data = NULL; + } + + if (path->stroke_conversion) { + if(path->stroke_conversion->path_point_list) { + vg_lite_path_point_ptr temp_point; + while(path->stroke_conversion->path_point_list) { + temp_point = path->stroke_conversion->path_point_list->next; + vg_lite_os_free(path->stroke_conversion->path_point_list); + path->stroke_conversion->path_point_list = temp_point; + } + temp_point = NULL; + } + + if(path->stroke_conversion->stroke_sub_path_list) { + vg_lite_sub_path_ptr temp_sub_path; + while(path->stroke_conversion->stroke_sub_path_list) { + temp_sub_path = path->stroke_conversion->stroke_sub_path_list->next; + if(path->stroke_conversion->stroke_sub_path_list->point_list) { + vg_lite_path_point_ptr temp_point; + while(path->stroke_conversion->stroke_sub_path_list->point_list) { + temp_point = path->stroke_conversion->stroke_sub_path_list->point_list->next; + vg_lite_os_free(path->stroke_conversion->stroke_sub_path_list->point_list); + path->stroke_conversion->stroke_sub_path_list->point_list = temp_point; + } + temp_point = NULL; + } + vg_lite_os_free(path->stroke_conversion->stroke_sub_path_list); + path->stroke_conversion->stroke_sub_path_list = temp_sub_path; + } + temp_sub_path = NULL; + } + + vg_lite_os_free(path->stroke_conversion); + path->stroke_conversion = NULL; + } + return VG_LITE_SUCCESS; +} + +#if defined(VG_DRIVER_SINGLE_THREAD) +vg_lite_error_t vg_lite_set_CLUT(uint32_t count, + uint32_t * colors) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + + uint32_t addr = 0x0B00; + + if(!s_context.s_ftable.ftable[gcFEATURE_BIT_VG_IM_INDEX_FORMAT]) + return VG_LITE_NOT_SUPPORT; + + switch (count) { + case 256: + addr = 0x0B00; + break; + + case 16: + addr = 0x0AA0; + break; + + case 4: + addr = 0x0A9C; + break; + + case 2: + addr = 0x0A98; + break; + + default: + error = VG_LITE_INVALID_ARGUMENT; + return error; + break; + } + + VG_LITE_RETURN_ERROR(push_states(&s_context, addr, count, colors)); + + return error; +} +#else +vg_lite_error_t vg_lite_set_CLUT(uint32_t count, + uint32_t * colors) +{ + vg_lite_tls_t* tls; + vg_lite_error_t error = VG_LITE_SUCCESS; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + if(!tls->t_context.s_ftable.ftable[gcFEATURE_BIT_VG_IM_INDEX_FORMAT]) + return VG_LITE_NOT_SUPPORT; + + switch (count) { + case 2: + tls->t_context.clut_dirty[0] = 1; + tls->t_context.clut_used[0] = 0; + if(!tls->t_context.colors[0]) + tls->t_context.colors[0] = (uint32_t *)malloc(count * sizeof(uint32_t)); + memcpy(tls->t_context.colors[0], colors, count * sizeof(uint32_t)); + break; + case 4: + tls->t_context.clut_dirty[1] = 1; + tls->t_context.clut_used[1] = 0; + if(!tls->t_context.colors[1]) + tls->t_context.colors[1] = (uint32_t *)malloc(count * sizeof(uint32_t)); + memcpy(tls->t_context.colors[1], colors, count * sizeof(uint32_t)); + break; + case 16: + tls->t_context.clut_dirty[2] = 1; + tls->t_context.clut_used[2] = 0; + if(!tls->t_context.colors[2]) + tls->t_context.colors[2] = (uint32_t *)malloc(count * sizeof(uint32_t)); + memcpy(tls->t_context.colors[2], colors, count * sizeof(uint32_t)); + break; + case 256: + tls->t_context.clut_dirty[3] = 1; + tls->t_context.clut_used[3] = 0; + if(!tls->t_context.colors[3]) + tls->t_context.colors[3] = (uint32_t *)malloc(count * sizeof(uint32_t)); + memcpy(tls->t_context.colors[3], colors, count * sizeof(uint32_t)); + break; + + default: + error = VG_LITE_INVALID_ARGUMENT; + return error; + break; + } + + return error; +} +#endif /* VG_DRIVER_SINGLE_THREAD */ + +vg_lite_error_t vg_lite_draw_pattern(vg_lite_buffer_t * target, + vg_lite_path_t * path, + vg_lite_fill_t fill_rule, + vg_lite_matrix_t * matrix0, + vg_lite_buffer_t * source, + vg_lite_matrix_t * matrix1, + vg_lite_blend_t blend, + vg_lite_pattern_mode_t pattern_mode, + vg_lite_color_t pattern_color, + vg_lite_filter_t filter) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + uint32_t imageMode; + uint32_t blend_mode; + uint32_t conversion = 0; + uint32_t tiled_source; + vg_lite_matrix_t * matrix = matrix1; + uint32_t pattern_tile = 0; + uint32_t transparency_mode = 0; + int32_t dst_align_width; + uint32_t mul, div, align; + +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t *tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + if(!path) + return VG_LITE_INVALID_ARGUMENT; + + if(!path->path_length) + return VG_LITE_SUCCESS; + + if(!path->path) + return VG_LITE_INVALID_ARGUMENT; + + /* The following code is from "draw path" */ + uint32_t format, quality, tiling, fill; + uint32_t tessellation_size; +#if DUMP_COMMAND + vg_lite_kernel_allocate_t memory; + uint32_t return_offset = 0; +#endif + vg_lite_point_t point_min = {0}, point_max = {0}, temp = {0}; + int x, y, width, height; + uint8_t ts_is_fullscreen = 0; + + if(!vg_lite_query_feature(gcFEATURE_BIT_VG_QUALITY_8X) && path->quality == VG_LITE_UPPER){ + return VG_LITE_NOT_SUPPORT; + } + + if(source->format == VG_LITE_A4 || source->format == VG_LITE_A8) { + return VG_LITE_NOT_SUPPORT; + } + + error = set_render_target(target); + if (error != VG_LITE_SUCCESS) { + return error; + } else if (error == VG_LITE_NO_CONTEXT) { + /* If scissoring is enabled and no valid scissoring rectangles + are present, no drawing occurs */ + return VG_LITE_SUCCESS; + } + + transparency_mode = (source->transparency_mode == VG_LITE_IMAGE_TRANSPARENT ? 0x8000:0); + width = ctx->tsbuffer.tessellation_width_height & 0xFFFF; + height = ctx->tsbuffer.tessellation_width_height >> 16; + get_format_bytes(target->format, &mul, &div, &align); + dst_align_width = target->stride * div / mul; + + if(width == 0 || height == 0) + return VG_LITE_NO_CONTEXT; + if ((dst_align_width <= width) && (target->height <= height)) + { + ts_is_fullscreen = 1; + point_min.x = 0; + point_min.y = 0; + point_max.x = dst_align_width; + point_max.y = target->height; + } + + /* If target is L8 and source is in YUV or RGB (not L8 or A8) then we have to convert RGB into L8. */ + if ((target->format == VG_LITE_L8) && ((source->format != VG_LITE_L8) && (source->format != VG_LITE_A8))) { + conversion = 0x80000000; + } + + /* Determine image mode (NORMAL or MULTIPLY) depending on the color. */ + imageMode = (source->image_mode == VG_LITE_NONE_IMAGE_MODE) ? 0 : (source->image_mode == VG_LITE_MULTIPLY_IMAGE_MODE) ? 0x00002000 : 0x00001000; + tiled_source = (source->tiled != VG_LITE_LINEAR) ? 0x10000000 : 0 ; + + if (pattern_mode == VG_LITE_PATTERN_COLOR) + { + uint8_t a,r,g,b; + pattern_tile = 0; + a = pattern_color >> 24; + r = pattern_color >> 16; + g = pattern_color >> 8; + b = pattern_color; + pattern_color = (a << 24) | (b << 16) | (g << 8) | r; + } + else if (pattern_mode == VG_LITE_PATTERN_PAD) + { + pattern_tile = 0x1000; + } + else + { + return VG_LITE_INVALID_ARGUMENT; + } + +#if !defined(VG_DRIVER_SINGLE_THREAD) + if(ctx->ts_dirty){ + memcpy(CMDBUF_BUFFER(*ctx) + CMDBUF_OFFSET(*ctx), ctx->ts_record, 80); + CMDBUF_OFFSET(*ctx) += 80; + ctx->ts_dirty = 0; + ctx->ts_init_used = 1; + } + else + { + ctx->ts_init_use = 1; + } + + /* Setup the command buffer. */ + if(source->format >= VG_LITE_INDEX_1 && source->format <= VG_LITE_INDEX_8) + { + /* this task will use index format,set index_flag to 1. */ + ctx->index_format = 1; + switch (source->format) { + case VG_LITE_INDEX_8: + if(ctx->clut_dirty[3]){ + VG_LITE_RETURN_ERROR(push_states(ctx, 0x0B00, 256, ctx->colors[3])); + ctx->clut_dirty[3] = 0; + } + else + { + ctx->clut_used[3] = 1; + } + break; + + case VG_LITE_INDEX_4: + if(ctx->clut_dirty[2]){ + VG_LITE_RETURN_ERROR(push_states(ctx, 0x0AA0, 16, ctx->colors[2])); + ctx->clut_dirty[2] = 0; + } + else + { + ctx->clut_used[2] = 1; + } + break; + + case VG_LITE_INDEX_2: + if(ctx->clut_dirty[1]){ + VG_LITE_RETURN_ERROR(push_states(ctx, 0x0A9C, 4, ctx->colors[1])); + ctx->clut_dirty[1] = 0; + } + else + { + ctx->clut_used[1] = 1; + } + break; + + default: + if(ctx->clut_dirty[0]){ + VG_LITE_RETURN_ERROR(push_states(ctx, 0x0A98, 2, ctx->colors[0])); + ctx->clut_dirty[0] = 0; + } + else + { + ctx->clut_used[0] = 1; + } + } + } +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + + VG_LITE_RETURN_ERROR(set_interpolation_steps(target, source->width, source->height, matrix)); + + if(!ctx->premultiply_enabled && source->format != VG_LITE_A8 && source->format != VG_LITE_A4) { + if(source->transparency_mode == VG_LITE_IMAGE_OPAQUE){ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | + filter | pattern_tile | conversion | 0x01000100)); + } else { + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | + filter | pattern_tile | conversion | 0x00000100)); + } + } else { + /* enable pre-multiplied in imager unit */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A25, convert_source_format(source->format) | + filter | pattern_tile | conversion)); + } + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A27, pattern_color)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A29, source->address)); + + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2B, source->stride | tiled_source)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2D, 0)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2F, source->width | (source->height << 16))); + + /* Work on path states. */ + matrix = matrix0; + + if (ts_is_fullscreen == 0){ + transform(&temp, (vg_lite_float_t)path->bounding_box[0], (vg_lite_float_t)path->bounding_box[1], matrix); + point_min = point_max = temp; + + transform(&temp, (vg_lite_float_t)path->bounding_box[2], (vg_lite_float_t)path->bounding_box[1], matrix); + if (temp.x < point_min.x) point_min.x = temp.x; + if (temp.y < point_min.y) point_min.y = temp.y; + if (temp.x > point_max.x) point_max.x = temp.x; + if (temp.y > point_max.y) point_max.y = temp.y; + + transform(&temp, (vg_lite_float_t)path->bounding_box[2], (vg_lite_float_t)path->bounding_box[3], matrix); + if (temp.x < point_min.x) point_min.x = temp.x; + if (temp.y < point_min.y) point_min.y = temp.y; + if (temp.x > point_max.x) point_max.x = temp.x; + if (temp.y > point_max.y) point_max.y = temp.y; + + transform(&temp, (vg_lite_float_t)path->bounding_box[0], (vg_lite_float_t)path->bounding_box[3], matrix); + if (temp.x < point_min.x) point_min.x = temp.x; + if (temp.y < point_min.y) point_min.y = temp.y; + if (temp.x > point_max.x) point_max.x = temp.x; + if (temp.y > point_max.y) point_max.y = temp.y; + + point_min.x = MAX(point_min.x, 0); + point_min.y = MAX(point_min.y, 0); + point_max.x = MIN(point_max.x, dst_align_width); + point_max.y = MIN(point_max.y, target->height); + } + + if (ctx->scissor_enabled) { + point_min.x = MAX(point_min.x, ctx->scissor[0]); + point_min.y = MAX(point_min.y, ctx->scissor[1]); + point_max.x = MIN(point_max.x, ctx->scissor[0] + ctx->scissor[2]); + point_max.y = MIN(point_max.y, ctx->scissor[1] + ctx->scissor[3]); + } + + /* Convert states into hardware values. */ + blend_mode = convert_blend(blend); + format = convert_path_format(path->format); + quality = convert_path_quality(path->quality); + tiling = (ctx->capabilities.cap.tiled == 2) ? 0x2000000 : 0; + fill = (fill_rule == VG_LITE_FILL_EVEN_ODD) ? 0x10 : 0; + tessellation_size = ( ctx->tsbuffer.tessellation_buffer_size[2] + ? ctx->tsbuffer.tessellation_buffer_size[2] + : ctx->tsbuffer.tessellation_buffer_size[1] + ); + + /* Setup the command buffer. */ + /* Program color register. */ + if(!ctx->premultiply_enabled && source->format != VG_LITE_A8 && source->format != VG_LITE_A4) { + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x10000000 | ctx->capabilities.cap.tiled | 0x00000002 | imageMode | blend_mode | transparency_mode)); + } else { + /* enable pre-multiplied from VG to VGPE */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, ctx->capabilities.cap.tiled | 0x00000002 | imageMode | blend_mode | transparency_mode)); + } + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0x01000400 | format | quality | tiling | fill)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3B, 0x3F800000)); /* Path tessellation SCALE. */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3C, 0x00000000)); /* Path tessellation BIAS. */ + /* Program matrix. */ + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A40, (void *) &matrix->m[0][0])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A41, (void *) &matrix->m[0][1])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A42, (void *) &matrix->m[0][2])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A43, (void *) &matrix->m[1][0])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A44, (void *) &matrix->m[1][1])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A45, (void *) &matrix->m[1][2])); + + if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { + + vglitemDUMP_BUFFER("path", path->uploaded.address, (uint8_t *)(path->uploaded.memory), 0, path->uploaded.bytes); + } + + vglitemDUMP("@[memory 0x%08X 0x%08X]", ctx->tsbuffer.tessellation_buffer_gpu[0], ctx->tsbuffer.tessellation_buffer_size[0]); + + /* Setup tessellation loop. */ + if((path->path_type & 0x1) == VG_LITE_DRAW_FILL_PATH) { + for (y = point_min.y; y < point_max.y; y += height) { + for (x = point_min.x; x < point_max.x; x += width) { + /* Tessellate path. */ + VG_LITE_RETURN_ERROR(push_stall(ctx, 15)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1B, 0x00011000)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A01, x | (y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A39, x | (y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3D, tessellation_size / 64)); + + if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { + VG_LITE_RETURN_ERROR(push_call(ctx, path->uploaded.address, path->uploaded.bytes)); +#if (DUMP_COMMAND) + if (strncmp(filename, "Commandbuffer", 13)) { + sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); + } + + fp = fopen(filename, "a"); + + if (fp == NULL) + printf("error!\n"); + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) memory.memory)[0], 0); + + unsigned char* pt = (unsigned char*) memory.memory; + + for(int i = 8; i <= return_offset * 4 - 1; i = i + 4) + { + if (i % 8 == 0) + fprintf(fp, "Command buffer: "); + + if (i % 4 == 0) + fprintf(fp, "0x"); + + for (int j = 3; j >= 0; --j) + fprintf(fp, "%02x", pt[i + j]); + + if ((i / 4 + 1) % 2 == 0) + fprintf(fp, ",\n"); + else + fprintf(fp, ", "); + } + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) memory.memory)[return_offset], 0); + + fclose(fp); + fp = NULL; +#endif + } else { + push_data(ctx, path->path_length, path->path); + } + } + } + } + /* Setup tessellation loop. */ + if(path->path_type == VG_LITE_DRAW_STROKE_PATH || path->path_type == VG_LITE_DRAW_FILL_STROKE_PATH) { + for (y = point_min.y; y < point_max.y; y += height) { + for (x = point_min.x; x < point_max.x; x += width) { + /* Tessellate path. */ + VG_LITE_RETURN_ERROR(push_stall(ctx, 15)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1B, 0x00011000)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A01, x | (y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A39, x | (y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3D, tessellation_size / 64)); + + if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { + VG_LITE_RETURN_ERROR(push_call(ctx, path->uploaded.address, path->uploaded.bytes)); +#if (DUMP_COMMAND) + if (strncmp(filename, "Commandbuffer", 13)) { + sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); + } + + fp = fopen(filename, "a"); + + if (fp == NULL) + printf("error!\n"); + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) memory.memory)[0], 0); + + unsigned char* pt = (unsigned char*) memory.memory; + + for(int i = 8; i <= return_offset * 4 - 1; i = i + 4) + { + if (i % 8 == 0) + fprintf(fp, "Command buffer: "); + + if (i % 4 == 0) + fprintf(fp, "0x"); + + for (int j = 3; j >= 0; --j) + fprintf(fp, "%02x", pt[i + j]); + + if ((i / 4 + 1) % 2 == 0) + fprintf(fp, ",\n"); + else + fprintf(fp, ", "); + } + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) memory.memory)[return_offset], 0); + + fclose(fp); + fp = NULL; +#endif + } else { + format = convert_path_format(VG_LITE_FP32); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0x01000200 | format | quality | tiling | 0x0)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A02, path->stroke_color)); + push_data(ctx, path->stroke_path_size, path->stroke_path_data); + } + } + } + } + + /* Finialize command buffer. */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0)); + VG_LITE_RETURN_ERROR(flush_target()); + + vglitemDUMP_BUFFER("image", source->address, source->memory, 0, (source->stride)*(source->height)); +#if DUMP_IMAGE + dump_img(source->memory, source->width, source->height, source->format); +#endif + +#if !defined(VG_DRIVER_SINGLE_THREAD) + tls->t_context.ts_init = 1; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + return error; +} + +vg_lite_error_t vg_lite_draw_linear_gradient(vg_lite_buffer_t * target, + vg_lite_path_t * path, + vg_lite_fill_t fill_rule, + vg_lite_matrix_t * path_matrix, + vg_lite_linear_gradient_ext_t *grad, + vg_lite_color_t paint_color, + vg_lite_blend_t blend, + vg_lite_filter_t filter) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + uint32_t image_mode; + uint32_t blend_mode; + uint32_t conversion = 0; + uint32_t tiled_source; + int32_t dst_align_width; + uint32_t mul, div, align; + vg_lite_matrix_t inverse_matrix; + vg_lite_buffer_t * source = &grad->image; + vg_lite_matrix_t * matrix = &grad->matrix; + uint32_t linear_tile = 0; + uint32_t transparency_mode = 0; + void *data; + + /* The following code is from "draw path" */ + uint32_t format, quality, tiling, fill; + uint32_t tessellation_size; + + vg_lite_kernel_allocate_t memory; + vg_lite_kernel_free_t free_memory; + uint32_t return_offset = 0; + + vg_lite_point_t point_min = {0}, point_max = {0}, temp = {0}; + int x, y, width, height; + uint8_t ts_is_fullscreen = 0; + + vg_lite_float_t dx, dy, dxdx_dydy; + vg_lite_float_t lg_step_x_lin, lg_step_y_lin, lg_constant_lin; + +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t* tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if (tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + if(!path) + return VG_LITE_INVALID_ARGUMENT; + + if(!path->path_length) + return VG_LITE_SUCCESS; + + if(!path->path) + return VG_LITE_INVALID_ARGUMENT; + + if(!vg_lite_query_feature(gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT)) + return VG_LITE_NOT_SUPPORT; + + if(!vg_lite_query_feature(gcFEATURE_BIT_VG_QUALITY_8X) && path->quality == VG_LITE_UPPER){ + return VG_LITE_NOT_SUPPORT; + } + + if(source->format == VG_LITE_A4 || source->format == VG_LITE_A8) { + return VG_LITE_NOT_SUPPORT; + } + + error = set_render_target(target); + if (error != VG_LITE_SUCCESS) { + return error; + } else if (error == VG_LITE_NO_CONTEXT) { + /* If scissoring is enabled and no valid scissoring rectangles + are present, no drawing occurs */ + return VG_LITE_SUCCESS; + } + + transparency_mode = (source->transparency_mode == VG_LITE_IMAGE_TRANSPARENT ? 0x8000:0); + width = ctx->tsbuffer.tessellation_width_height & 0xFFFF; + height = ctx->tsbuffer.tessellation_width_height >> 16; + get_format_bytes(target->format, &mul, &div, &align); + dst_align_width = target->stride * div / mul; + if(width == 0 || height == 0) + return VG_LITE_NO_CONTEXT; + if ((dst_align_width <= width) && (target->height <= height)) + { + ts_is_fullscreen = 1; + point_min.x = 0; + point_min.y = 0; + point_max.x = dst_align_width; + point_max.y = target->height; + } + + /* If target is L8 and source is in YUV or RGB (not L8 or A8) then we have to convert RGB into L8. */ + if ((target->format == VG_LITE_L8) && ((source->format != VG_LITE_L8) && (source->format != VG_LITE_A8))) { + conversion = 0x80000000; + } + + /* Determine image mode (NORMAL or MULTIPLY) depending on the color. */ + image_mode = (source->image_mode == VG_LITE_NONE_IMAGE_MODE) ? 0 : (source->image_mode == VG_LITE_MULTIPLY_IMAGE_MODE) ? 0x00002000 : 0x00001000; + tiled_source = (source->tiled != VG_LITE_LINEAR) ? 0x10000000 : 0 ; + + linear_tile = (grad->spread_mode == VG_LITE_RADIAL_GRADIENT_SPREAD_FILL) ? 0 : + (grad->spread_mode == VG_LITE_RADIAL_GRADIENT_SPREAD_PAD) ? 0x1000 : + (grad->spread_mode == VG_LITE_RADIAL_GRADIENT_SPREAD_REPEAT) ? 0x2000 : 0x3000; + + if (grad->spread_mode == VG_LITE_RADIAL_GRADIENT_SPREAD_FILL) + { + uint8_t a,r,g,b; + a = paint_color >> 24; + r = paint_color >> 16; + g = paint_color >> 8; + b = paint_color; + paint_color = (a << 24) | (b << 16) | (g << 8) | r; + } + + /* compute radial gradient paremeters */ + + if (!inverse(&inverse_matrix, matrix)) + return VG_LITE_INVALID_ARGUMENT; + + dx = grad->linear_gradient.X1 - grad->linear_gradient.X0; + dy = grad->linear_gradient.Y1 - grad->linear_gradient.Y0; + dxdx_dydy = dx * dx + dy * dy; + + /* + ** dx (T(x) - x0) + dy (T(y) - y0) + ** g = ------------------------------- + ** dx^2 + dy^2 + ** + ** where + ** + ** dx := x1 - x0 + ** dy := y1 - y1 + ** T(x) := (x + 0.5) m00 + (y + 0.5) m01 + m02 + ** = x m00 + y m01 + 0.5 (m00 + m01) + m02 + ** T(y) := (x + 0.5) m10 + (y + 0.5) m11 + m12 + ** = x m10 + y m11 + 0.5 (m10 + m11) + m12. + ** + ** We can factor the top line into: + ** + ** = dx (x m00 + y m01 + 0.5 (m00 + m01) + m02 - x0) + ** + dy (x m10 + y m11 + 0.5 (m10 + m11) + m12 - y0) + ** + ** = x (dx m00 + dy m10) + ** + y (dx m01 + dy m11) + ** + dx (0.5 (m00 + m01) + m02 - x0) + ** + dy (0.5 (m10 + m11) + m12 - y0). + */ + + lg_step_x_lin + = (dx * MAT(&inverse_matrix, 0, 0) + dy * MAT(&inverse_matrix, 1, 0)) + / dxdx_dydy; + + lg_step_y_lin + = (dx * MAT(&inverse_matrix, 0, 1) + dy * MAT(&inverse_matrix, 1, 1)) + / dxdx_dydy; + + lg_constant_lin = + ( + ( + 0.5f * ( MAT(&inverse_matrix, 0, 0) + MAT(&inverse_matrix, 0, 1) ) + + MAT(&inverse_matrix, 0, 2) - grad->linear_gradient.X0 + ) * dx + + + + + ( + 0.5f * ( MAT(&inverse_matrix, 1, 0) + MAT(&inverse_matrix, 1, 1) ) + + MAT(&inverse_matrix, 1, 2) - grad->linear_gradient.Y0 + ) * dy + ) + / dxdx_dydy; + +#if !defined(VG_DRIVER_SINGLE_THREAD) + if(ctx->ts_dirty){ + memcpy(CMDBUF_BUFFER(*ctx) + CMDBUF_OFFSET(*ctx), ctx->ts_record, 80); + CMDBUF_OFFSET(*ctx) += 80; + ctx->ts_dirty = 0; + ctx->ts_init_used = 1; + } + else + { + ctx->ts_init_use = 1; + } +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + + /* Setup the command buffer. */ + + /* linear gradient parameters*/ + data = &lg_constant_lin; + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A04,*(uint32_t*) data)); + data = &lg_step_x_lin; + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A06,*(uint32_t*) data)); + data = &lg_step_y_lin; + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A08,*(uint32_t*) data)); + + VG_LITE_RETURN_ERROR(set_interpolation_steps(target, source->width, source->height, matrix)); + + if(!ctx->premultiply_enabled) { + if(source->transparency_mode == VG_LITE_IMAGE_OPAQUE){ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A24, convert_source_format(source->format) | + filter | linear_tile | conversion | 0x01000100)); + } else { + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A24, convert_source_format(source->format) | + filter | linear_tile | conversion | 0x00000100)); + } + } else { + /* enable pre-multiplied in imager unit */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A24, convert_source_format(source->format) | + filter | linear_tile | conversion)); + } + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A26, paint_color)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A28, source->address)); + + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2A, tiled_source)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2C, 0)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2E, source->width)); + + /* Work on path states. */ + matrix = path_matrix; + + if (ts_is_fullscreen == 0){ + transform(&temp, (vg_lite_float_t)path->bounding_box[0], (vg_lite_float_t)path->bounding_box[1], matrix); + point_min = point_max = temp; + + transform(&temp, (vg_lite_float_t)path->bounding_box[2], (vg_lite_float_t)path->bounding_box[1], matrix); + if (temp.x < point_min.x) point_min.x = temp.x; + if (temp.y < point_min.y) point_min.y = temp.y; + if (temp.x > point_max.x) point_max.x = temp.x; + if (temp.y > point_max.y) point_max.y = temp.y; + + transform(&temp, (vg_lite_float_t)path->bounding_box[2], (vg_lite_float_t)path->bounding_box[3], matrix); + if (temp.x < point_min.x) point_min.x = temp.x; + if (temp.y < point_min.y) point_min.y = temp.y; + if (temp.x > point_max.x) point_max.x = temp.x; + if (temp.y > point_max.y) point_max.y = temp.y; + + transform(&temp, (vg_lite_float_t)path->bounding_box[0], (vg_lite_float_t)path->bounding_box[3], matrix); + if (temp.x < point_min.x) point_min.x = temp.x; + if (temp.y < point_min.y) point_min.y = temp.y; + if (temp.x > point_max.x) point_max.x = temp.x; + if (temp.y > point_max.y) point_max.y = temp.y; + + point_min.x = MAX(point_min.x, 0); + point_min.y = MAX(point_min.y, 0); + point_max.x = MIN(point_max.x, dst_align_width); + point_max.y = MIN(point_max.y, target->height); + } + + if (ctx->scissor_enabled) { + point_min.x = MAX(point_min.x, ctx->scissor[0]); + point_min.y = MAX(point_min.y, ctx->scissor[1]); + point_max.x = MIN(point_max.x, ctx->scissor[0] + ctx->scissor[2]); + point_max.y = MIN(point_max.y, ctx->scissor[1] + ctx->scissor[3]); + } + + /* Convert states into hardware values. */ + blend_mode = convert_blend(blend); + format = convert_path_format(path->format); + quality = convert_path_quality(path->quality); + tiling = (ctx->capabilities.cap.tiled == 2) ? 0x2000000 : 0; + fill = (fill_rule == VG_LITE_FILL_EVEN_ODD) ? 0x10 : 0; + tessellation_size = ( ctx->tsbuffer.tessellation_buffer_size[2] + ? ctx->tsbuffer.tessellation_buffer_size[2] + : ctx->tsbuffer.tessellation_buffer_size[1] + ); + + /* Setup the command buffer. */ + /* Program color register. */ + if(!ctx->premultiply_enabled) { + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x11000000 | ctx->capabilities.cap.tiled | 0x00000002 | image_mode | blend_mode | transparency_mode)); + } else { + /* enable pre-multiplied from VG to VGPE */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x01000000 | ctx->capabilities.cap.tiled | 0x00000002 | image_mode | blend_mode | transparency_mode)); + } + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0x01000400 | format | quality | tiling | fill)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3B, 0x3F800000)); /* Path tessellation SCALE. */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3C, 0x00000000)); /* Path tessellation BIAS. */ + /* Program matrix. */ + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A40, (void *) &matrix->m[0][0])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A41, (void *) &matrix->m[0][1])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A42, (void *) &matrix->m[0][2])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A43, (void *) &matrix->m[1][0])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A44, (void *) &matrix->m[1][1])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A45, (void *) &matrix->m[1][2])); + + if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) + { + if (path->path_changed != 0) { + if (path->uploaded.handle != NULL) { + free_memory.memory_handle = path->uploaded.handle; + vg_lite_kernel(VG_LITE_FREE, &free_memory); + path->uploaded.address = 0; + path->uploaded.memory = NULL; + path->uploaded.handle = NULL; + } + /* Allocate memory for the path data. */ + memory.bytes = 16 + VG_LITE_ALIGN(path->path_length, 8); + return_offset = (8 + VG_LITE_ALIGN(path->path_length, 8)) / 4; + memory.contiguous = 1; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &memory)); + ((uint64_t *) memory.memory)[(path->path_length + 7) / 8] = 0; + ((uint32_t *) memory.memory)[0] = VG_LITE_DATA((path->path_length + 7) / 8); + ((uint32_t *) memory.memory)[1] = 0; + memcpy((uint8_t *) memory.memory + 8, path->path, path->path_length); + ((uint32_t *) memory.memory)[return_offset] = VG_LITE_RETURN(); + ((uint32_t *) memory.memory)[return_offset + 1] = 0; + + path->uploaded.handle = memory.memory_handle; + path->uploaded.memory = memory.memory; + path->uploaded.address = memory.memory_gpu; + path->uploaded.bytes = memory.bytes; + path->path_changed = 0; + } + } + + if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { + + vglitemDUMP_BUFFER("path", path->uploaded.address, (uint8_t *)(path->uploaded.memory), 0, path->uploaded.bytes); + } + + vglitemDUMP("@[memory 0x%08X 0x%08X]", ctx->tsbuffer.tessellation_buffer_gpu[0], ctx->tsbuffer.tessellation_buffer_size[0]); + + /* Setup tessellation loop. */ + if((path->path_type & 0x1) == VG_LITE_DRAW_FILL_PATH) { + for (y = point_min.y; y < point_max.y; y += height) { + for (x = point_min.x; x < point_max.x; x += width) { + /* Tessellate path. */ + VG_LITE_RETURN_ERROR(push_stall(ctx, 15)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1B, 0x00011000)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A01, x | (y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A39, x | (y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3D, tessellation_size / 64)); + + if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { + VG_LITE_RETURN_ERROR(push_call(ctx, path->uploaded.address, path->uploaded.bytes)); +#if (DUMP_COMMAND) + if (strncmp(filename, "Commandbuffer", 13)) { + sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); + } + + fp = fopen(filename, "a"); + + if (fp == NULL) + printf("error!\n"); + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) memory.memory)[0], 0); + + unsigned char* pt = (unsigned char*) memory.memory; + + for(int i = 8; i <= return_offset * 4 - 1; i = i + 4) + { + if (i % 8 == 0) + fprintf(fp, "Command buffer: "); + + if (i % 4 == 0) + fprintf(fp, "0x"); + + for (int j = 3; j >= 0; --j) + fprintf(fp, "%02x", pt[i + j]); + + if ((i / 4 + 1) % 2 == 0) + fprintf(fp, ",\n"); + else + fprintf(fp, ", "); + } + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) memory.memory)[return_offset], 0); + + fclose(fp); + fp = NULL; +#endif + } else { + push_data(ctx, path->path_length, path->path); + } + } + } + } + /* Setup tessellation loop. */ + if(path->path_type == VG_LITE_DRAW_STROKE_PATH || path->path_type == VG_LITE_DRAW_FILL_STROKE_PATH) { + for (y = point_min.y; y < point_max.y; y += height) { + for (x = point_min.x; x < point_max.x; x += width) { + /* Tessellate path. */ + VG_LITE_RETURN_ERROR(push_stall(ctx, 15)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1B, 0x00011000)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A01, x | (y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A39, x | (y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3D, tessellation_size / 64)); + + if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { + VG_LITE_RETURN_ERROR(push_call(ctx, path->uploaded.address, path->uploaded.bytes)); +#if (DUMP_COMMAND) + if (strncmp(filename, "Commandbuffer", 13)) { + sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); + } + + fp = fopen(filename, "a"); + + if (fp == NULL) + printf("error!\n"); + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) memory.memory)[0], 0); + + unsigned char* pt = (unsigned char*) memory.memory; + + for(int i = 8; i <= return_offset * 4 - 1; i = i + 4) + { + if (i % 8 == 0) + fprintf(fp, "Command buffer: "); + + if (i % 4 == 0) + fprintf(fp, "0x"); + + for (int j = 3; j >= 0; --j) + fprintf(fp, "%02x", pt[i + j]); + + if ((i / 4 + 1) % 2 == 0) + fprintf(fp, ",\n"); + else + fprintf(fp, ", "); + } + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) memory.memory)[return_offset], 0); + + fclose(fp); + fp = NULL; +#endif + } else { + format = convert_path_format(VG_LITE_FP32); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0x01000200 | format | quality | tiling | 0x0)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A02, path->stroke_color)); + push_data(ctx, path->stroke_path_size, path->stroke_path_data); + } + } + } + } + + /* Finialize command buffer. */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0)); + + vglitemDUMP_BUFFER("image", source->address, source->memory, 0, (source->stride)*(source->height)); +#if DUMP_IMAGE + dump_img(source->memory, source->width, source->height, source->format); +#endif + +#if !defined(VG_DRIVER_SINGLE_THREAD) + tls->t_context.ts_init = 1; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + return error; +} + +vg_lite_error_t vg_lite_draw_radial_gradient(vg_lite_buffer_t * target, + vg_lite_path_t * path, + vg_lite_fill_t fill_rule, + vg_lite_matrix_t * path_matrix, + vg_lite_radial_gradient_t *grad, + vg_lite_color_t paint_color, + vg_lite_blend_t blend, + vg_lite_filter_t filter) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + uint32_t imageMode; + uint32_t blend_mode; + uint32_t conversion = 0; + uint32_t tiled_source; + int32_t dst_align_width; + uint32_t mul, div, align; + vg_lite_matrix_t inverse_matrix; + vg_lite_buffer_t * source = &grad->image; + vg_lite_matrix_t * matrix = &grad->matrix; + uint32_t rad_tile = 0; + uint32_t transparency_mode = 0; + void *data; + + /* The following code is from "draw path" */ + uint32_t format, quality, tiling, fill; + uint32_t tessellation_size; + + vg_lite_kernel_allocate_t memory; + vg_lite_kernel_free_t free_memory; + uint32_t return_offset = 0; + + vg_lite_point_t point_min = {0}, point_max = {0}, temp = {0}; + int x, y, width, height; + uint8_t ts_is_fullscreen = 0; + + vg_lite_float_t radius; + + vg_lite_float_t centerX, centerY; + vg_lite_float_t focalX, focalY; + vg_lite_float_t fx, fy; + vg_lite_float_t fxfy_2; + vg_lite_float_t radius2; + vg_lite_float_t r2_fx2, r2_fy2; + vg_lite_float_t r2_fx2_2, r2_fy2_2; + vg_lite_float_t r2_fx2_fy2; + vg_lite_float_t r2_fx2_fy2sq; + vg_lite_float_t cx, cy; + + vg_lite_float_t rgConstantLin, rgStepXLin, rgStepYLin; + vg_lite_float_t rgConstantRad, rgStepXRad, rgStepYRad; + vg_lite_float_t rgStepXXRad, rgStepYYRad, rgStepXYRad; + +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t* tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + if(!path) + return VG_LITE_INVALID_ARGUMENT; + + if(!path->path_length) + return VG_LITE_SUCCESS; + + if(!path->path) + return VG_LITE_INVALID_ARGUMENT; + + if(!vg_lite_query_feature(gcFEATURE_BIT_VG_RADIAL_GRADIENT)) + return VG_LITE_NOT_SUPPORT; + + if(!vg_lite_query_feature(gcFEATURE_BIT_VG_QUALITY_8X) && path->quality == VG_LITE_UPPER){ + return VG_LITE_NOT_SUPPORT; + } + + if(source->format == VG_LITE_A4 || source->format == VG_LITE_A8) { + return VG_LITE_NOT_SUPPORT; + } + + radius = grad->radialGradient.r; + if(radius <= 0) + return VG_LITE_INVALID_ARGUMENT; + + error = set_render_target(target); + if (error != VG_LITE_SUCCESS) { + return error; + } else if (error == VG_LITE_NO_CONTEXT) { + /* If scissoring is enabled and no valid scissoring rectangles + are present, no drawing occurs */ + return VG_LITE_SUCCESS; + } + + transparency_mode = (source->transparency_mode == VG_LITE_IMAGE_TRANSPARENT ? 0x8000:0); + width = ctx->tsbuffer.tessellation_width_height & 0xFFFF; + height = ctx->tsbuffer.tessellation_width_height >> 16; + get_format_bytes(target->format, &mul, &div, &align); + dst_align_width = target->stride * div / mul; + if(width == 0 || height == 0) + return VG_LITE_NO_CONTEXT; + if ((dst_align_width <= width) && (target->height <= height)) + { + ts_is_fullscreen = 1; + point_min.x = 0; + point_min.y = 0; + point_max.x = dst_align_width; + point_max.y = target->height; + } + + /* If target is L8 and source is in YUV or RGB (not L8 or A8) then we have to convert RGB into L8. */ + if ((target->format == VG_LITE_L8) && ((source->format != VG_LITE_L8) && (source->format != VG_LITE_A8))) { + conversion = 0x80000000; + } + + /* Determine image mode (NORMAL or MULTIPLY) depending on the color. */ + imageMode = (source->image_mode == VG_LITE_NONE_IMAGE_MODE) ? 0 : (source->image_mode == VG_LITE_MULTIPLY_IMAGE_MODE) ? 0x00002000 : 0x00001000; + tiled_source = (source->tiled != VG_LITE_LINEAR) ? 0x10000000 : 0 ; + + rad_tile = (grad->SpreadMode == VG_LITE_RADIAL_GRADIENT_SPREAD_FILL) ? 0 : + (grad->SpreadMode == VG_LITE_RADIAL_GRADIENT_SPREAD_PAD) ? 0x1000 : + (grad->SpreadMode == VG_LITE_RADIAL_GRADIENT_SPREAD_REPEAT) ? 0x2000 : 0x3000; + + if (grad->SpreadMode == VG_LITE_RADIAL_GRADIENT_SPREAD_FILL) + { + uint8_t a,r,g,b; + a = paint_color >> 24; + r = paint_color >> 16; + g = paint_color >> 8; + b = paint_color; + paint_color = (a << 24) | (b << 16) | (g << 8) | r; + } + + /* compute radial gradient paremeters */ + + /* Compute inverse matrix. */ + if (!inverse(&inverse_matrix, matrix)) + return VG_LITE_INVALID_ARGUMENT; + + /* Make shortcuts to the gradient information. */ + centerX = grad->radialGradient.cx; + centerY = grad->radialGradient.cy; + focalX = grad->radialGradient.fx; + focalY = grad->radialGradient.fy; + + /* Compute constants of the equation. */ + fx = focalX - centerX; + fy = focalY - centerY; + radius2 = radius * radius; + if (fx*fx + fy*fy > radius2) + { + /* If the focal point is outside the circle, let's move it + to inside the circle. Per vg11 spec pg125 "If (fx, fy) lies outside ... + For here, we set it at 0.9 ratio to the center. + */ + vg_lite_float_t fr = (vg_lite_float_t)sqrt(fx*fx + fy*fy); + fx = radius * fx / fr * 0.9f; + fy = radius * fy / fr * 0.9f; + focalX = grad->radialGradient.fx + fx; + focalY = grad->radialGradient.fy + fy; + } + + fxfy_2 = 2.0f * fx * fy; + r2_fx2 = radius2 - fx * fx; + r2_fy2 = radius2 - fy * fy; + r2_fx2_2 = 2.0f * r2_fx2; + r2_fy2_2 = 2.0f * r2_fy2; + r2_fx2_fy2 = r2_fx2 - fy * fy; + r2_fx2_fy2sq = r2_fx2_fy2 * r2_fx2_fy2; + + /* _____________________________________ + ** dx fx + dy fy + \/r^2 (dx^2 + dy^2) - (dx fy - dy fx)^2 + ** g = ------------------------------------------------------- + ** r^2 - fx^2 - fy^2 + ** + ** Where + ** + ** dx := F(x) - focalX + ** dy := F(y) - focalY + ** fx := focalX - centerX + ** fy := focalX - centerY + ** + ** and + ** + ** F(x) := (x + 0.5) m00 + (y + 0.5) m01 + m02 + ** F(y) := (x + 0.5) m10 + (y + 0.5) m11 + m12 + ** + ** So, dx can be factored into + ** + ** dx = (x + 0.5) m00 + (y + 0.5) m01 + m02 - focalX + ** = x m00 + y m01 + 0.5 m00 + 0.5 m01 + m02 - focalX + ** + ** = x m00 + y m01 + cx + ** + ** where + ** + ** cx := 0.5 m00 + 0.5 m01 + m02 - focalX + ** + ** The same way we can factor dy into + ** + ** dy = x m10 + y m11 + cy + ** + ** where + ** + ** cy := 0.5 m10 + 0.5 m11 + m12 - focalY. + ** + ** Now we can rewrite g as + ** ______________________________________ + ** dx fx + dy fy / r^2 (dx^2 + dy^2) - (dx fy - dy fx)^2 + ** g = ----------------- + \ / ------------------------------------- + ** r^2 - fx^2 - fy^2 \/ (r^2 - fx^2 - fy^2)^2 + ** ____ + ** = gLin + \/gRad + ** + ** where + ** + ** dx fx + dy fy + ** gLin := ----------------- + ** r^2 - fx^2 - fy^2 + ** + ** r^2 (dx^2 + dy^2) - (dx fy - dy fx)^2 + ** gRad := ------------------------------------- + ** (r^2 - fx^2 - fy^2)^2 + */ + + cx + = 0.5f * ( MAT(&inverse_matrix, 0, 0) + MAT(&inverse_matrix, 0, 1) ) + + MAT(&inverse_matrix, 0, 2) + - focalX; + + cy + = 0.5f * ( MAT(&inverse_matrix, 1, 0) + MAT(&inverse_matrix, 1, 1) ) + + MAT(&inverse_matrix, 1, 2) + - focalY; + + /* + ** dx fx + dy fy + ** gLin := ----------------- + ** r^2 - fx^2 - fy^2 + ** + ** We can factor the top half into + ** + ** = (x m00 + y m01 + cx) fx + (x m10 + y m11 + cy) fy + ** + ** = x (m00 fx + m10 fy) + ** + y (m01 fx + m11 fy) + ** + cx fx + cy fy. + */ + + rgStepXLin + = ( MAT(&inverse_matrix, 0, 0) * fx + MAT(&inverse_matrix, 1, 0) * fy ) + / r2_fx2_fy2; + + rgStepYLin + = ( MAT(&inverse_matrix, 0, 1) * fx + MAT(&inverse_matrix, 1, 1) * fy ) + / r2_fx2_fy2; + + rgConstantLin = ( cx * fx + cy * fy ) / r2_fx2_fy2; + + /* + ** r^2 (dx^2 + dy^2) - (dx fy - dy fx)^2 + ** gRad := ------------------------------------- + ** (r^2 - fx^2 - fy^2)^2 + ** + ** r^2 (dx^2 + dy^2) - dx^2 fy^2 - dy^2 fx^2 + 2 dx dy fx fy + ** := --------------------------------------------------------- + ** (r^2 - fx^2 - fy^2)^2 + ** + ** dx^2 (r^2 - fy^2) + dy^2 (r^2 - fx^2) + 2 dx dy fx fy + ** := ----------------------------------------------------- + ** (r^2 - fx^2 - fy^2)^2 + ** + ** First, lets factor dx^2 into + ** + ** dx^2 = (x m00 + y m01 + cx)^2 + ** = x^2 m00^2 + y^2 m01^2 + 2 x y m00 m01 + ** + 2 x m00 cx + 2 y m01 cx + cx^2 + ** + ** = x^2 (m00^2) + ** + y^2 (m01^2) + ** + x y (2 m00 m01) + ** + x (2 m00 cx) + ** + y (2 m01 cx) + ** + cx^2. + ** + ** The same can be done for dy^2: + ** + ** dy^2 = x^2 (m10^2) + ** + y^2 (m11^2) + ** + x y (2 m10 m11) + ** + x (2 m10 cy) + ** + y (2 m11 cy) + ** + cy^2. + ** + ** Let's also factor dx dy into + ** + ** dx dy = (x m00 + y m01 + cx) (x m10 + y m11 + cy) + ** = x^2 m00 m10 + y^2 m01 m11 + x y m00 m11 + x y m01 m10 + ** + x m00 cy + x m10 cx + y m01 cy + y m11 cx + cx cy + ** + ** = x^2 (m00 m10) + ** + y^2 (m01 m11) + ** + x y (m00 m11 + m01 m10) + ** + x (m00 cy + m10 cx) + ** + y (m01 cy + m11 cx) + ** + cx cy. + ** + ** Now that we have all this, lets look at the top of gRad. + ** + ** = dx^2 (r^2 - fy^2) + dy^2 (r^2 - fx^2) + 2 dx dy fx fy + ** = x^2 m00^2 (r^2 - fy^2) + y^2 m01^2 (r^2 - fy^2) + ** + x y 2 m00 m01 (r^2 - fy^2) + x 2 m00 cx (r^2 - fy^2) + ** + y 2 m01 cx (r^2 - fy^2) + cx^2 (r^2 - fy^2) + ** + x^2 m10^2 (r^2 - fx^2) + y^2 m11^2 (r^2 - fx^2) + ** + x y 2 m10 m11 (r^2 - fx^2) + x 2 m10 cy (r^2 - fx^2) + ** + y 2 m11 cy (r^2 - fx^2) + cy^2 (r^2 - fx^2) + ** + x^2 m00 m10 2 fx fy + y^2 m01 m11 2 fx fy + ** + x y (m00 m11 + m01 m10) 2 fx fy + ** + x (m00 cy + m10 cx) 2 fx fy + y (m01 cy + m11 cx) 2 fx fy + ** + cx cy 2 fx fy + ** + ** = x^2 ( m00^2 (r^2 - fy^2) + ** + m10^2 (r^2 - fx^2) + ** + m00 m10 2 fx fy + ** ) + ** + y^2 ( m01^2 (r^2 - fy^2) + ** + m11^2 (r^2 - fx^2) + ** + m01 m11 2 fx fy + ** ) + ** + x y ( 2 m00 m01 (r^2 - fy^2) + ** + 2 m10 m11 (r^2 - fx^2) + ** + (m00 m11 + m01 m10) 2 fx fy + ** ) + ** + x ( 2 m00 cx (r^2 - fy^2) + ** + 2 m10 cy (r^2 - fx^2) + ** + (m00 cy + m10 cx) 2 fx fy + ** ) + ** + y ( 2 m01 cx (r^2 - fy^2) + ** + 2 m11 cy (r^2 - fx^2) + ** + (m01 cy + m11 cx) 2 fx fy + ** ) + ** + cx^2 (r^2 - fy^2) + cy^2 (r^2 - fx^2) + cx cy 2 fx fy. + */ + + rgStepXXRad = + ( + MAT(&inverse_matrix, 0, 0) * MAT(&inverse_matrix, 0, 0) * r2_fy2 + + MAT(&inverse_matrix, 1, 0) * MAT(&inverse_matrix, 1, 0) * r2_fx2 + + MAT(&inverse_matrix, 0, 0) * MAT(&inverse_matrix, 1, 0) * fxfy_2 + ) + / r2_fx2_fy2sq; + + rgStepYYRad = + ( + MAT(&inverse_matrix, 0, 1) * MAT(&inverse_matrix, 0, 1) * r2_fy2 + + MAT(&inverse_matrix, 1, 1) * MAT(&inverse_matrix, 1, 1) * r2_fx2 + + MAT(&inverse_matrix, 0, 1) * MAT(&inverse_matrix, 1, 1) * fxfy_2 + ) + / r2_fx2_fy2sq; + + rgStepXYRad = + ( + MAT(&inverse_matrix, 0, 0) * MAT(&inverse_matrix, 0, 1) * r2_fy2_2 + + MAT(&inverse_matrix, 1, 0) * MAT(&inverse_matrix, 1, 1) * r2_fx2_2 + + ( + MAT(&inverse_matrix, 0, 0) * MAT(&inverse_matrix, 1, 1) + + MAT(&inverse_matrix, 0, 1) * MAT(&inverse_matrix, 1, 0) + ) + * fxfy_2 + ) + / r2_fx2_fy2sq; + + rgStepXRad = + ( + MAT(&inverse_matrix, 0, 0) * cx * r2_fy2_2 + + MAT(&inverse_matrix, 1, 0) * cy * r2_fx2_2 + + ( + MAT(&inverse_matrix, 0, 0) * cy + + MAT(&inverse_matrix, 1, 0) * cx + ) + * fxfy_2 + ) + / r2_fx2_fy2sq; + + rgStepYRad = + ( + MAT(&inverse_matrix, 0, 1) * cx * r2_fy2_2 + + MAT(&inverse_matrix, 1, 1) * cy * r2_fx2_2 + + ( + MAT(&inverse_matrix, 0, 1) * cy + + MAT(&inverse_matrix, 1, 1) * cx + ) + * fxfy_2 + ) + / r2_fx2_fy2sq; + + rgConstantRad = + ( + cx * cx * r2_fy2 + + cy * cy * r2_fx2 + + cx * cy * fxfy_2 + ) + / r2_fx2_fy2sq; + +#if !defined(VG_DRIVER_SINGLE_THREAD) + if(ctx->ts_dirty){ + memcpy(CMDBUF_BUFFER(*ctx) + CMDBUF_OFFSET(*ctx), ctx->ts_record, 80); + CMDBUF_OFFSET(*ctx) += 80; + ctx->ts_dirty = 0; + ctx->ts_init_used = 1; + } + else + { + ctx->ts_init_use = 1; + } +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + + /* Setup the command buffer. */ + + /* rad gradient parameters*/ + data = &rgConstantLin; + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A04,*(uint32_t*) data)); + data = &rgStepXLin; + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A06,*(uint32_t*) data)); + data = &rgStepYLin; + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A08,*(uint32_t*) data)); + data = &rgConstantRad; + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A05,*(uint32_t*) data)); + data = &rgStepXRad; + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A07,*(uint32_t*) data)); + data = &rgStepYRad; + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A09,*(uint32_t*) data)); + data = &rgStepXXRad; + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A03,*(uint32_t*) data)); + data = &rgStepYYRad; + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A0A,*(uint32_t*) data)); + data = &rgStepXYRad; + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A0B,*(uint32_t*) data)); + VG_LITE_RETURN_ERROR(set_interpolation_steps(target, source->width, source->height, matrix)); + + if(!ctx->premultiply_enabled) { + if(source->transparency_mode == VG_LITE_IMAGE_OPAQUE){ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A24, convert_source_format(source->format) | + filter | rad_tile | conversion | 0x01000100)); + } else { + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A24, convert_source_format(source->format) | + filter | rad_tile | conversion | 0x00000100)); + } + } else { + /* enable pre-multiplied in imager unit */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A24, convert_source_format(source->format) | + filter | rad_tile | conversion)); + } + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A26, paint_color)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A28, source->address)); + + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2A, tiled_source)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2C, 0)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A2E, source->width)); + + /* Work on path states. */ + matrix = path_matrix; + + if (ts_is_fullscreen == 0){ + transform(&temp, (vg_lite_float_t)path->bounding_box[0], (vg_lite_float_t)path->bounding_box[1], matrix); + point_min = point_max = temp; + + transform(&temp, (vg_lite_float_t)path->bounding_box[2], (vg_lite_float_t)path->bounding_box[1], matrix); + if (temp.x < point_min.x) point_min.x = temp.x; + if (temp.y < point_min.y) point_min.y = temp.y; + if (temp.x > point_max.x) point_max.x = temp.x; + if (temp.y > point_max.y) point_max.y = temp.y; + + transform(&temp, (vg_lite_float_t)path->bounding_box[2], (vg_lite_float_t)path->bounding_box[3], matrix); + if (temp.x < point_min.x) point_min.x = temp.x; + if (temp.y < point_min.y) point_min.y = temp.y; + if (temp.x > point_max.x) point_max.x = temp.x; + if (temp.y > point_max.y) point_max.y = temp.y; + + transform(&temp, (vg_lite_float_t)path->bounding_box[0], (vg_lite_float_t)path->bounding_box[3], matrix); + if (temp.x < point_min.x) point_min.x = temp.x; + if (temp.y < point_min.y) point_min.y = temp.y; + if (temp.x > point_max.x) point_max.x = temp.x; + if (temp.y > point_max.y) point_max.y = temp.y; + + point_min.x = MAX(point_min.x, 0); + point_min.y = MAX(point_min.y, 0); + point_max.x = MIN(point_max.x, dst_align_width); + point_max.y = MIN(point_max.y, target->height); + } + + if (ctx->scissor_enabled) { + point_min.x = MAX(point_min.x, ctx->scissor[0]); + point_min.y = MAX(point_min.y, ctx->scissor[1]); + point_max.x = MIN(point_max.x, ctx->scissor[0] + ctx->scissor[2]); + point_max.y = MIN(point_max.y, ctx->scissor[1] + ctx->scissor[3]); + } + + /* Convert states into hardware values. */ + blend_mode = convert_blend(blend); + format = convert_path_format(path->format); + quality = convert_path_quality(path->quality); + tiling = (ctx->capabilities.cap.tiled == 2) ? 0x2000000 : 0; + fill = (fill_rule == VG_LITE_FILL_EVEN_ODD) ? 0x10 : 0; + tessellation_size = ( ctx->tsbuffer.tessellation_buffer_size[2] + ? ctx->tsbuffer.tessellation_buffer_size[2] + : ctx->tsbuffer.tessellation_buffer_size[1] + ); + + /* Setup the command buffer. */ + /* Program color register. */ + if(!ctx->premultiply_enabled) { + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x12000000 | ctx->capabilities.cap.tiled | 0x00000002 | imageMode | blend_mode | transparency_mode)); + } else { + /* enable pre-multiplied from VG to VGPE */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A00, 0x02000000 | ctx->capabilities.cap.tiled | 0x00000002 | imageMode | blend_mode | transparency_mode)); + } + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0x01000400 | format | quality | tiling | fill)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3B, 0x3F800000)); /* Path tessellation SCALE. */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3C, 0x00000000)); /* Path tessellation BIAS. */ + /* Program matrix. */ + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A40, (void *) &matrix->m[0][0])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A41, (void *) &matrix->m[0][1])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A42, (void *) &matrix->m[0][2])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A43, (void *) &matrix->m[1][0])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A44, (void *) &matrix->m[1][1])); + VG_LITE_RETURN_ERROR(push_state_ptr(ctx, 0x0A45, (void *) &matrix->m[1][2])); + + if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) + { + if (path->path_changed != 0) { + if (path->uploaded.handle != NULL) { + free_memory.memory_handle = path->uploaded.handle; + vg_lite_kernel(VG_LITE_FREE, &free_memory); + path->uploaded.address = 0; + path->uploaded.memory = NULL; + path->uploaded.handle = NULL; + } + /* Allocate memory for the path data. */ + memory.bytes = 16 + VG_LITE_ALIGN(path->path_length, 8); + return_offset = (8 + VG_LITE_ALIGN(path->path_length, 8)) / 4; + memory.contiguous = 1; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_ALLOCATE, &memory)); + ((uint64_t *) memory.memory)[(path->path_length + 7) / 8] = 0; + ((uint32_t *) memory.memory)[0] = VG_LITE_DATA((path->path_length + 7) / 8); + ((uint32_t *) memory.memory)[1] = 0; + memcpy((uint8_t *) memory.memory + 8, path->path, path->path_length); + ((uint32_t *) memory.memory)[return_offset] = VG_LITE_RETURN(); + ((uint32_t *) memory.memory)[return_offset + 1] = 0; + + path->uploaded.handle = memory.memory_handle; + path->uploaded.memory = memory.memory; + path->uploaded.address = memory.memory_gpu; + path->uploaded.bytes = memory.bytes; + path->path_changed = 0; + } + } + + if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { + + vglitemDUMP_BUFFER("path", path->uploaded.address, (uint8_t *)(path->uploaded.memory), 0, path->uploaded.bytes); + } + + vglitemDUMP("@[memory 0x%08X 0x%08X]", ctx->tsbuffer.tessellation_buffer_gpu[0], ctx->tsbuffer.tessellation_buffer_size[0]); + + /* Setup tessellation loop. */ + if((path->path_type & 0x1) == VG_LITE_DRAW_FILL_PATH) { + for (y = point_min.y; y < point_max.y; y += height) { + for (x = point_min.x; x < point_max.x; x += width) { + /* Tessellate path. */ + VG_LITE_RETURN_ERROR(push_stall(ctx, 15)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1B, 0x00011000)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A01, x | (y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A39, x | (y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3D, tessellation_size / 64)); + + if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { + VG_LITE_RETURN_ERROR(push_call(ctx, path->uploaded.address, path->uploaded.bytes)); +#if (DUMP_COMMAND) + if (strncmp(filename, "Commandbuffer", 13)) { + sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); + } + + fp = fopen(filename, "a"); + + if (fp == NULL) + printf("error!\n"); + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) memory.memory)[0], 0); + + unsigned char* pt = (unsigned char*) memory.memory; + + for(int i = 8; i <= return_offset * 4 - 1; i = i + 4) + { + if (i % 8 == 0) + fprintf(fp, "Command buffer: "); + + if (i % 4 == 0) + fprintf(fp, "0x"); + + for (int j = 3; j >= 0; --j) + fprintf(fp, "%02x", pt[i + j]); + + if ((i / 4 + 1) % 2 == 0) + fprintf(fp, ",\n"); + else + fprintf(fp, ", "); + } + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) memory.memory)[return_offset], 0); + + fclose(fp); + fp = NULL; +#endif + } else { + push_data(ctx, path->path_length, path->path); + } + } + } + } + /* Setup tessellation loop. */ + if(path->path_type == VG_LITE_DRAW_STROKE_PATH || path->path_type == VG_LITE_DRAW_FILL_STROKE_PATH) { + for (y = point_min.y; y < point_max.y; y += height) { + for (x = point_min.x; x < point_max.x; x += width) { + /* Tessellate path. */ + VG_LITE_RETURN_ERROR(push_stall(ctx, 15)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A1B, 0x00011000)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A01, x | (y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A39, x | (y << 16))); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A3D, tessellation_size / 64)); + + if (VLM_PATH_GET_UPLOAD_BIT(*path) == 1) { + VG_LITE_RETURN_ERROR(push_call(ctx, path->uploaded.address, path->uploaded.bytes)); +#if (DUMP_COMMAND) + if (strncmp(filename, "Commandbuffer", 13)) { + sprintf(filename, "Commandbuffer_pid%d.txt", getpid()); + } + + fp = fopen(filename, "a"); + + if (fp == NULL) + printf("error!\n"); + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) memory.memory)[0], 0); + + unsigned char* pt = (unsigned char*) memory.memory; + + for(int i = 8; i <= return_offset * 4 - 1; i = i + 4) + { + if (i % 8 == 0) + fprintf(fp, "Command buffer: "); + + if (i % 4 == 0) + fprintf(fp, "0x"); + + for (int j = 3; j >= 0; --j) + fprintf(fp, "%02x", pt[i + j]); + + if ((i / 4 + 1) % 2 == 0) + fprintf(fp, ",\n"); + else + fprintf(fp, ", "); + } + + fprintf(fp, "Command buffer: 0x%08x, 0x%08x,\n", + ((uint32_t *) memory.memory)[return_offset], 0); + + fclose(fp); + fp = NULL; +#endif + } else { + format = convert_path_format(VG_LITE_FP32); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0x01000200 | format | quality | tiling | 0x0)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A02, path->stroke_color)); + push_data(ctx, path->stroke_path_size, path->stroke_path_data); + } + } + } + } + + /* Finialize command buffer. */ + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A34, 0)); + + vglitemDUMP_BUFFER("image", source->address, source->memory, 0, (source->stride)*(source->height)); +#if DUMP_IMAGE + dump_img(source->memory, src_align_width, source->height, source->format); +#endif + +#if !defined(VG_DRIVER_SINGLE_THREAD) + tls->t_context.ts_init = 1; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + return error; +} + +vg_lite_error_t vg_lite_init_grad(vg_lite_linear_gradient_t *grad) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + + /* Set the member values according to driver defaults. */ + grad->image.width = VLC_GRADBUFFER_WIDTH; + grad->image.height = 1; + grad->image.stride = 0; + grad->image.format = VG_LITE_BGRA8888; + + /* Allocate the image for gradient. */ + error = vg_lite_allocate(&grad->image); + + grad->count = 0; + + return error; +} + +vg_lite_error_t vg_lite_set_linear_grad(vg_lite_linear_gradient_ext_t *grad, + uint32_t count, + vg_lite_color_ramp_t *vg_color_ramp, + vg_lite_linear_gradient_parameter_t linear_gradient, + vg_lite_radial_gradient_spreadmode_t spread_mode, + uint8_t color_ramp_premultiplied) +{ + int i; + static vg_lite_color_ramp_t default_ramp[] = + { + { + 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }, + { + 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f + } + }; + + uint32_t trg_count; + vg_lite_float_t prev_stop; + vg_lite_color_ramp_ptr src_ramp; + vg_lite_color_ramp_ptr src_ramp_last; + vg_lite_color_ramp_ptr trg_ramp; + + /* Reset the count. */ + trg_count = 0; + + if ((linear_gradient.X0 == linear_gradient.X1) && (linear_gradient.Y0 == linear_gradient.Y1)) + return VG_LITE_INVALID_ARGUMENT; + + grad->linear_gradient = linear_gradient; + grad->color_ramp_premultiplied = color_ramp_premultiplied; + grad->spread_mode = spread_mode; + + if (!count || count > MAX_COLOR_RAMP_STOPS || vg_color_ramp == NULL) + goto Empty_sequence_handler; + + for(i = 0; i < count;i++) + grad->vg_color_ramp[i] = vg_color_ramp[i]; + grad->vg_color_ramp_length = count; + + /* Determine the last source ramp. */ + src_ramp_last + = grad->vg_color_ramp + + grad->vg_color_ramp_length; + + /* Set the initial previous stop. */ + prev_stop = -1; + + /* Reset the count. */ + trg_count = 0; + + /* Walk through the source ramp. */ + for ( + src_ramp = grad->vg_color_ramp, trg_ramp = grad->int_color_ramp; + (src_ramp < src_ramp_last) && (trg_count < MAX_COLOR_RAMP_STOPS + 2); + src_ramp += 1 + ) + { + /* Must be in increasing order. */ + if (src_ramp->stop < prev_stop) + { + /* Ignore the entire sequence. */ + trg_count = 0; + break; + } + + /* Update the previous stop value. */ + prev_stop = src_ramp->stop; + + /* Must be within [0..1] range. */ + if ((src_ramp->stop < 0.0f) || (src_ramp->stop > 1.0f)) + { + /* Ignore. */ + continue; + } + + /* Clamp color. */ + ClampColor(COLOR_FROM_RAMP(src_ramp),COLOR_FROM_RAMP(trg_ramp),0); + + /* First stop greater then zero? */ + if ((trg_count == 0) && (src_ramp->stop > 0.0f)) + { + /* Force the first stop to 0.0f. */ + trg_ramp->stop = 0.0f; + + /* Replicate the entry. */ + trg_ramp[1] = *trg_ramp; + trg_ramp[1].stop = src_ramp->stop; + + /* Advance. */ + trg_ramp += 2; + trg_count += 2; + } + else + { + /* Set the stop value. */ + trg_ramp->stop = src_ramp->stop; + + /* Advance. */ + trg_ramp += 1; + trg_count += 1; + } + } + + /* Empty sequence? */ + if (trg_count == 0) + { + memcpy(grad->int_color_ramp,default_ramp,sizeof(default_ramp)); + grad->int_color_ramp_length = sizeof(default_ramp) / 5; + } + else + { + /* The last stop must be at 1.0. */ + if (trg_ramp[-1].stop != 1.0f) + { + /* Replicate the last entry. */ + *trg_ramp = trg_ramp[-1]; + + /* Force the last stop to 1.0f. */ + trg_ramp->stop = 1.0f; + + /* Update the final entry count. */ + trg_count += 1; + } + + /* Set new length. */ + grad->int_color_ramp_length = trg_count; + } + return VG_LITE_SUCCESS; + +Empty_sequence_handler: + memcpy(grad->int_color_ramp,default_ramp,sizeof(default_ramp)); + grad->int_color_ramp_length = sizeof(default_ramp) / 5; + + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_update_linear_grad(vg_lite_linear_gradient_ext_t *grad) +{ + uint32_t color_ramp_length; + vg_lite_color_ramp_ptr color_ramp; + uint32_t common, stop; + uint32_t i, width; + uint8_t* bits; + vg_lite_float_t x0,y0,x1,y1,length; + vg_lite_error_t error = VG_LITE_SUCCESS; + + /* Get shortcuts to the color ramp. */ + color_ramp_length = grad->int_color_ramp_length; + color_ramp = grad->int_color_ramp; + + x0 = grad->linear_gradient.X0; + y0 = grad->linear_gradient.Y0; + x1 = grad->linear_gradient.X1; + y1 = grad->linear_gradient.Y1; + length = (vg_lite_float_t)sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); + + if(length <= 0) + return VG_LITE_INVALID_ARGUMENT; + /* Find the common denominator of the color ramp stops. */ + if (length < 1) + { + common = 1; + } + else + { + common = (uint32_t)length; + } + + for (i = 0; i < color_ramp_length; ++i) + { + if (color_ramp[i].stop != 0.0f) + { + vg_lite_float_t mul = common * color_ramp[i].stop; + vg_lite_float_t frac = mul - (vg_lite_float_t) floor(mul); + if (frac > 0.00013f) /* Suppose error for zero is 0.00013 */ + { + common = MAX(common, (uint32_t) (1.0f / frac + 0.5f)); + } + } + } + + /* Compute the width of the required color array. */ + width = common + 1; + + /* Allocate the color ramp surface. */ + memset(&grad->image, 0, sizeof(grad->image)); + grad->image.width = width; + grad->image.height = 1; + grad->image.stride = 0; + grad->image.image_mode = VG_LITE_NONE_IMAGE_MODE; + grad->image.format = VG_LITE_ABGR8888; + + /* Allocate the image for gradient. */ + VG_LITE_RETURN_ERROR(vg_lite_allocate(&grad->image)); + + grad->image.width = width; + + /* Set pointer to color array. */ + bits = (uint8_t *)grad->image.memory; + + /* Start filling the color array. */ + stop = 0; + for (i = 0; i < width; ++i) + { + vg_lite_float_t gradient; + vg_lite_float_t color[4]; + vg_lite_float_t color1[4]; + vg_lite_float_t color2[4]; + vg_lite_float_t weight; + + /* Compute gradient for current color array entry. */ + gradient = (vg_lite_float_t) i / (vg_lite_float_t) (width - 1); + + /* Find the entry in the color ramp that matches or exceeds this + ** gradient. */ + while ((stop < color_ramp_length - 1) && (gradient > color_ramp[stop].stop)) + { + ++stop; + } + + if (gradient == color_ramp[stop].stop) + { + /* Perfect match weight 1.0. */ + weight = 1.0f; + + /* Use color ramp color. */ + color1[3] = color_ramp[stop].alpha; + color1[2] = color_ramp[stop].blue; + color1[1] = color_ramp[stop].green; + color1[0] = color_ramp[stop].red; + + color2[3] = + color2[2] = + color2[1] = + color2[0] = 0.0f; + } + else + { + /* Compute weight. */ + weight = (color_ramp[stop].stop - gradient) + / (color_ramp[stop].stop - color_ramp[stop - 1].stop); + + /* Grab color ramp color of previous stop. */ + color1[3] = color_ramp[stop - 1].alpha; + color1[2] = color_ramp[stop - 1].blue; + color1[1] = color_ramp[stop - 1].green; + color1[0] = color_ramp[stop - 1].red; + + /* Grab color ramp color of current stop. */ + color2[3] = color_ramp[stop].alpha; + color2[2] = color_ramp[stop].blue; + color2[1] = color_ramp[stop].green; + color2[0] = color_ramp[stop].red; + } + + if (grad->color_ramp_premultiplied) + { + /* Pre-multiply the first color. */ + color1[2] *= color1[3]; + color1[1] *= color1[3]; + color1[0] *= color1[3]; + + /* Pre-multiply the second color. */ + color2[2] *= color2[3]; + color2[1] *= color2[3]; + color2[0] *= color2[3]; + } + + /* Filter the colors per channel. */ + color[3] = LERP(color1[3], color2[3], weight); + color[2] = LERP(color1[2], color2[2], weight); + color[1] = LERP(color1[1], color2[1], weight); + color[0] = LERP(color1[0], color2[0], weight); + + /* Pack the final color. */ + *bits++ = PackColorComponent(color[3]); + *bits++ = PackColorComponent(color[2]); + *bits++ = PackColorComponent(color[1]); + *bits++ = PackColorComponent(color[0]); + } + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_set_rad_grad(vg_lite_radial_gradient_t *grad, + uint32_t count, + vg_lite_color_ramp_t *vgColorRamp, + vg_lite_radial_gradient_parameter_t radialGradient, + vg_lite_radial_gradient_spreadmode_t SpreadMode, + uint8_t colorRampPremultiplied) +{ + int i; + static vg_lite_color_ramp_t defaultRamp[] = + { + { + 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }, + { + 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f + } + }; + + uint32_t trgCount; + vg_lite_float_t prevStop; + vg_lite_color_ramp_ptr srcRamp; + vg_lite_color_ramp_ptr srcRampLast; + vg_lite_color_ramp_ptr trgRamp; + + /* Reset the count. */ + trgCount = 0; + + if(radialGradient.r <= 0) + return VG_LITE_INVALID_ARGUMENT; + + grad->radialGradient = radialGradient; + grad->colorRampPremultiplied = colorRampPremultiplied; + grad->SpreadMode = SpreadMode; + + if (!count || count > MAX_COLOR_RAMP_STOPS || vgColorRamp == NULL) + goto Empty_sequence_handler; + + for(i = 0; i < count;i++) + grad->vgColorRamp[i] = vgColorRamp[i]; + grad->vgColorRampLength = count; + + /* Determine the last source ramp. */ + srcRampLast + = grad->vgColorRamp + + grad->vgColorRampLength; + + /* Set the initial previous stop. */ + prevStop = -1; + + /* Reset the count. */ + trgCount = 0; + + /* Walk through the source ramp. */ + for ( + srcRamp = grad->vgColorRamp, trgRamp = grad->intColorRamp; + (srcRamp < srcRampLast) && (trgCount < MAX_COLOR_RAMP_STOPS + 2); + srcRamp += 1 + ) + { + /* Must be in increasing order. */ + if (srcRamp->stop < prevStop) + { + /* Ignore the entire sequence. */ + trgCount = 0; + break; + } + + /* Update the previous stop value. */ + prevStop = srcRamp->stop; + + /* Must be within [0..1] range. */ + if ((srcRamp->stop < 0.0f) || (srcRamp->stop > 1.0f)) + { + /* Ignore. */ + continue; + } + + /* Clamp color. */ + ClampColor(COLOR_FROM_RAMP(srcRamp),COLOR_FROM_RAMP(trgRamp),0); + + /* First stop greater then zero? */ + if ((trgCount == 0) && (srcRamp->stop > 0.0f)) + { + /* Force the first stop to 0.0f. */ + trgRamp->stop = 0.0f; + + /* Replicate the entry. */ + trgRamp[1] = *trgRamp; + trgRamp[1].stop = srcRamp->stop; + + /* Advance. */ + trgRamp += 2; + trgCount += 2; + } + else + { + /* Set the stop value. */ + trgRamp->stop = srcRamp->stop; + + /* Advance. */ + trgRamp += 1; + trgCount += 1; + } + } + + /* Empty sequence? */ + if (trgCount == 0) + { + memcpy(grad->intColorRamp,defaultRamp,sizeof(defaultRamp)); + grad->intColorRampLength = sizeof(defaultRamp) / 5; + } + else + { + /* The last stop must be at 1.0. */ + if (trgRamp[-1].stop != 1.0f) + { + /* Replicate the last entry. */ + *trgRamp = trgRamp[-1]; + + /* Force the last stop to 1.0f. */ + trgRamp->stop = 1.0f; + + /* Update the final entry count. */ + trgCount += 1; + } + + /* Set new length. */ + grad->intColorRampLength = trgCount; + } + return VG_LITE_SUCCESS; + +Empty_sequence_handler: + memcpy(grad->intColorRamp,defaultRamp,sizeof(defaultRamp)); + grad->intColorRampLength = sizeof(defaultRamp) / 5; + + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_update_rad_grad(vg_lite_radial_gradient_t *grad) +{ + uint32_t colorRampLength; + vg_lite_color_ramp_ptr colorRamp; + uint32_t common, stop; + uint32_t i, width; + uint8_t* bits; + vg_lite_float_t r; + vg_lite_error_t error = VG_LITE_SUCCESS; + + /* Get shortcuts to the color ramp. */ + colorRampLength = grad->intColorRampLength; + colorRamp = grad->intColorRamp; + + r = grad->radialGradient.r; + + if(r <= 0) + return VG_LITE_INVALID_ARGUMENT; + /* Find the common denominator of the color ramp stops. */ + if (r < 1) + { + common = 1; + } + else + { + common = (uint32_t)r; + } + + for (i = 0; i < colorRampLength; ++i) + { + if (colorRamp[i].stop != 0.0f) + { + vg_lite_float_t mul = common * colorRamp[i].stop; + vg_lite_float_t frac = mul - (vg_lite_float_t) floor(mul); + if (frac > 0.00013f) /* Suppose error for zero is 0.00013 */ + { + common = MAX(common, (uint32_t) (1.0f / frac + 0.5f)); + } + } + } + + /* Compute the width of the required color array. */ + width = common + 1; + + /* Allocate the color ramp surface. */ + memset(&grad->image, 0, sizeof(grad->image)); + grad->image.width = width; + grad->image.height = 1; + grad->image.stride = 0; + grad->image.image_mode = VG_LITE_NONE_IMAGE_MODE; + grad->image.format = VG_LITE_ABGR8888; + + /* Allocate the image for gradient. */ + VG_LITE_RETURN_ERROR(vg_lite_allocate(&grad->image)); + + grad->image.width = width; + + /* Set pointer to color array. */ + bits = (uint8_t *)grad->image.memory; + + /* Start filling the color array. */ + stop = 0; + for (i = 0; i < width; ++i) + { + vg_lite_float_t gradient; + vg_lite_float_t color[4]; + vg_lite_float_t color1[4]; + vg_lite_float_t color2[4]; + vg_lite_float_t weight; + + /* Compute gradient for current color array entry. */ + gradient = (vg_lite_float_t) i / (vg_lite_float_t) (width - 1); + + /* Find the entry in the color ramp that matches or exceeds this + ** gradient. */ + while ((stop < colorRampLength - 1) && (gradient > colorRamp[stop].stop)) + { + ++stop; + } + + if (gradient == colorRamp[stop].stop) + { + /* Perfect match weight 1.0. */ + weight = 1.0f; + + /* Use color ramp color. */ + color1[3] = colorRamp[stop].alpha; + color1[2] = colorRamp[stop].blue; + color1[1] = colorRamp[stop].green; + color1[0] = colorRamp[stop].red; + + color2[3] = + color2[2] = + color2[1] = + color2[0] = 0.0f; + } + else + { + /* Compute weight. */ + weight = (colorRamp[stop].stop - gradient) + / (colorRamp[stop].stop - colorRamp[stop - 1].stop); + + /* Grab color ramp color of previous stop. */ + color1[3] = colorRamp[stop - 1].alpha; + color1[2] = colorRamp[stop - 1].blue; + color1[1] = colorRamp[stop - 1].green; + color1[0] = colorRamp[stop - 1].red; + + /* Grab color ramp color of current stop. */ + color2[3] = colorRamp[stop].alpha; + color2[2] = colorRamp[stop].blue; + color2[1] = colorRamp[stop].green; + color2[0] = colorRamp[stop].red; + } + + if (grad->colorRampPremultiplied) + { + /* Pre-multiply the first color. */ + color1[2] *= color1[3]; + color1[1] *= color1[3]; + color1[0] *= color1[3]; + + /* Pre-multiply the second color. */ + color2[2] *= color2[3]; + color2[1] *= color2[3]; + color2[0] *= color2[3]; + } + + /* Filter the colors per channel. */ + color[3] = LERP(color1[3], color2[3], weight); + color[2] = LERP(color1[2], color2[2], weight); + color[1] = LERP(color1[1], color2[1], weight); + color[0] = LERP(color1[0], color2[0], weight); + + /* Pack the final color. */ + *bits++ = PackColorComponent(color[3]); + *bits++ = PackColorComponent(color[2]); + *bits++ = PackColorComponent(color[1]); + *bits++ = PackColorComponent(color[0]); + } + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_set_grad(vg_lite_linear_gradient_t *grad, + uint32_t count, + uint32_t * colors, + uint32_t * stops) +{ + uint32_t i; + + grad->count = 0; /* Opaque B&W gradient */ + if (!count || count > VLC_MAX_GRAD || colors == NULL || stops == NULL) + return VG_LITE_SUCCESS; + /* Check stops validity */ + for (i = 0; i < count; i++) + if (stops[i] <= 255) { + if (!grad->count || stops[i] > grad->stops[grad->count - 1]) { + grad->stops[grad->count] = stops[i]; + grad->colors[grad->count] = colors[i]; + grad->count++; + } else if (stops[i] == grad->stops[grad->count - 1]) { + /* Equal stops : use the color corresponding to the last stop + in the sequence */ + grad->colors[grad->count - 1] = colors[i]; + } + } + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_update_grad(vg_lite_linear_gradient_t *grad) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + int32_t r0, g0, b0, a0; + int32_t r1, g1, b1, a1; + int32_t lr, lg, lb, la; + uint32_t i; + int32_t j; + int32_t ds, dr, dg, db, da; + uint32_t *buffer = (uint32_t *)grad->image.memory; + + if (grad->count == 0) { + /* If no valid stops have been specified (e.g., due to an empty input + * array, out-of-range, or out-of-order stops), a stop at 0 with color + * 0xFF000000 (opaque black) and a stop at 255 with color 0xFFFFFFFF + * (opaque white) are implicitly defined. */ + grad->stops[0] = 0; + grad->colors[0] = 0xFF000000; /* Opaque black */ + grad->stops[1] = 255; + grad->colors[1] = 0xFFFFFFFF; /* Opaque white */ + grad->count = 2; + } else if (grad->count && grad->stops[0] != 0) { + /* If at least one valid stop has been specified, but none has been + * defined with an offset of 0, an implicit stop is added with an + * offset of 0 and the same color as the first user-defined stop. */ + for (i = 0; i < grad->stops[0]; i++) + buffer[i] = grad->colors[0]; + } + a0 = A(grad->colors[0]); + r0 = R(grad->colors[0]); + g0 = G(grad->colors[0]); + b0 = B(grad->colors[0]); + + /* Calculate the colors for each pixel of the image. */ + for (i = 0; i < grad->count - 1; i++) { + buffer[grad->stops[i]] = grad->colors[i]; + ds = grad->stops[i + 1] - grad->stops[i]; + a1 = A(grad->colors[i + 1]); + r1 = R(grad->colors[i + 1]); + g1 = G(grad->colors[i + 1]); + b1 = B(grad->colors[i + 1]); + + da = a1 - a0; + dr = r1 - r0; + dg = g1 - g0; + db = b1 - b0; + + for (j = 1; j < ds; j++) { + la = a0 + da * j / ds; + lr = r0 + dr * j / ds; + lg = g0 + dg * j / ds; + lb = b0 + db * j / ds; + + buffer[grad->stops[i] + j] = ARGB(la, lr, lg, lb); + } + + a0 = a1; + r0 = r1; + g0 = g1; + b0 = b1; + } + /* If at least one valid stop has been specified, but none has been defined + * with an offset of 255, an implicit stop is added with an offset of 255 + * and the same color as the last user-defined stop. */ + for (i = grad->stops[grad->count - 1]; i < 255; i++) + buffer[i] = grad->colors[grad->count - 1]; + /* Last pixel */ + buffer[i] = grad->colors[grad->count - 1]; + return error; +} + +vg_lite_error_t vg_lite_clear_grad(vg_lite_linear_gradient_t *grad) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + + grad->count = 0; + /* Release the image resource. */ + if (grad->image.handle != NULL) + { + error = vg_lite_free(&grad->image); + } + + return error; +} + +vg_lite_error_t vg_lite_clear_rad_grad(vg_lite_radial_gradient_t *grad) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + + grad->count = 0; + /* Release the image resource. */ + if (grad->image.handle != NULL) + { + error = vg_lite_free(&grad->image); + } + + return error; +} + +vg_lite_error_t vg_lite_clear_linear_grad(vg_lite_linear_gradient_ext_t *grad) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + + grad->count = 0; + /* Release the image resource. */ + if (grad->image.handle != NULL) + { + error = vg_lite_free(&grad->image); + } + + return error; +} + +vg_lite_matrix_t * vg_lite_get_linear_grad_matrix(vg_lite_linear_gradient_ext_t *grad) +{ + return &grad->matrix; +} + +vg_lite_matrix_t * vg_lite_get_grad_matrix(vg_lite_linear_gradient_t *grad) +{ + return &grad->matrix; +} + +vg_lite_matrix_t * vg_lite_get_rad_grad_matrix(vg_lite_radial_gradient_t *grad) +{ + return &grad->matrix; +} + +vg_lite_error_t vg_lite_draw_gradient(vg_lite_buffer_t * target, + vg_lite_path_t * path, + vg_lite_fill_t fill_rule, + vg_lite_matrix_t * matrix, + vg_lite_linear_gradient_t * grad, + vg_lite_blend_t blend) +{ + return vg_lite_draw_pattern(target, path, fill_rule, matrix, + &grad->image, &grad->matrix, blend, VG_LITE_PATTERN_PAD, 0, VG_LITE_FILTER_LINEAR); +} + +vg_lite_error_t vg_lite_set_command_buffer_size(uint32_t size) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t* tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + +#if defined(VG_DRIVER_SINGLE_THREAD) + if(!ctx->init){ + if(!size) + return VG_LITE_INVALID_ARGUMENT; + command_buffer_size = size; + } + else{ +#else + if(CMDBUF_IN_QUEUE(&ctx->context, 0) || + CMDBUF_IN_QUEUE(&ctx->context, 1)) + return VG_LITE_INVALID_ARGUMENT; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + VG_LITE_RETURN_ERROR(_free_command_buffer()); + VG_LITE_RETURN_ERROR(_allocate_command_buffer(size)); + VG_LITE_RETURN_ERROR(program_tessellation(ctx)); + +#if defined(VG_DRIVER_SINGLE_THREAD) + } +#endif /* VG_DRIVER_SINGLE_THREAD */ + + return error; +} + +vg_lite_error_t vg_lite_set_scissor(int32_t x, int32_t y, int32_t width, int32_t height) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; + + /* Scissor dirty. */ + ctx->scissor_dirty = 1; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t* tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + /* Save scissor Box States. */ + ctx->scissor[0] = x; + ctx->scissor[1] = y; + ctx->scissor[2] = width; + ctx->scissor[3] = height; + + return error; +} + +vg_lite_error_t vg_lite_enable_scissor(void) +{ +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; + + /* Scissor dirty. */ + ctx->scissor_dirty = 1; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t* tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + /* Enable scissor Mode. */ + ctx->scissor_enabled = 1; + + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_disable_scissor(void) +{ +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; + + /* Scissor dirty. */ + ctx->scissor_dirty = 1; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t* tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + /* disable scissor Mode. */ + ctx->scissor_enabled = 0; + + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_mem_avail(uint32_t *size) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + vg_lite_kernel_mem_t mem; + VG_LITE_RETURN_ERROR(vg_lite_kernel(VG_LITE_QUERY_MEM,&mem)); + *size = mem.bytes; + + return error; +} + +vg_lite_error_t vg_lite_enable_premultiply(void) +{ +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t *tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if (tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) + return VG_LITE_NOT_SUPPORT; + + /* Enable premultiply Mode. */ + ctx->premultiply_enabled = 1; + + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_disable_premultiply(void) +{ +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t* tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) + return VG_LITE_NOT_SUPPORT; + + /* disable premultiply Mode. */ + ctx->premultiply_enabled = 0; + + return VG_LITE_SUCCESS; +} + +vg_lite_error_t vg_lite_set_dither(int enable) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + uint32_t table_low = 0x7B48F3C0; + uint32_t table_high = 0x596AD1E2; + int dither_enable = enable; +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_tls_t* tls; + vg_lite_context_t *ctx; + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + if(!vg_lite_query_feature(gcFEATURE_BIT_VG_DITHER)) { + return VG_LITE_NOT_SUPPORT; + } + + if(dither_enable) { + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A5A, table_low)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A5B, table_high)); + } + else { + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A5A, 0xFFFFFFFF)); + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A5B, 0xFFFFFFFF)); + } + + return error; +} + +vg_lite_error_t vg_lite_set_color_key(vg_lite_color_key4_t colorkey) +{ + uint8_t i; + uint32_t value_low = 0; + uint32_t value_high = 0; + uint8_t r, g, b, a, e; + vg_lite_error_t error = VG_LITE_SUCCESS; +#if defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_context_t *ctx = &s_context; +#else + vg_lite_context_t *ctx; + vg_lite_tls_t* tls; + + tls = (vg_lite_tls_t *) vg_lite_os_get_tls(); + if(tls == NULL) + return VG_LITE_NO_CONTEXT; + + ctx = &tls->t_context; +#endif /* VG_DRIVER_SINGLE_THREAD */ + + if(!vg_lite_query_feature(gcFEATURE_BIT_VG_COLOR_KEY)) + return VG_LITE_NOT_SUPPORT; + + /* Set color key states. */ + for (i = 0; i < 4; i++) + { + /* Set gcregVGPEColorKeyLow. Layout "E/R/G/B". */ + r = colorkey[i].low_r; + g = colorkey[i].low_g; + b = colorkey[i].low_b; + e = colorkey[i].enable; + value_low = (e << 24) | (r << 16) | (g << 8) | b; + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A90 + i , value_low)); + + /* Set gcregVGPEColorKeyHigh. Layout "A/R/G/B". */ + r = colorkey[i].hign_r; + g = colorkey[i].hign_g; + b = colorkey[i].hign_b; + a = colorkey[i].alpha; + value_high = (a << 24) | (r << 16) | (g << 8) | b; + VG_LITE_RETURN_ERROR(push_state(ctx, 0x0A94 + i , value_high)); + } + + return error; +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite.h new file mode 100644 index 0000000000..3c952deca2 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite.h @@ -0,0 +1,2060 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright 2012 - 2020 Vivante Corporation, Santa Clara, California. +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#ifndef _vg_lite_h_ +#define _vg_lite_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_MSC_VER) +#define inline __inline +#endif + +#include +#include + +#define VGLITE_RELEASE_VERSION 0x03000f + +#define VGLITE_HEADER_VERSION 6 + +#ifndef VGLITE_VERSION_2_0 +#define VGLITE_VERSION_2_0 1 + +#define VGLITE_MAKE_VERSION(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch)) + +#define VGLITE_VERSION_MAJOR(version) (((uint32_t)(version) >> 16) & 0xff) +#define VGLITE_VERSION_MINOR(version) (((uint32_t)(version) >> 8) & 0xff) +#define VGLITE_VERSION_PATCH(version) ((uint32_t)(version) & 0xff) + +#define VGLITE_API_VERSION_2_0 VGLITE_MAKE_VERSION(2, 0, 0) + + +#/* Macros *********************************************************************************************************************/ + +/* Path command (op code). */ +#define VLC_OP_END 0x00 +#define VLC_OP_CLOSE 0x01 +#define VLC_OP_MOVE 0x02 +#define VLC_OP_MOVE_REL 0x03 +#define VLC_OP_LINE 0x04 +#define VLC_OP_LINE_REL 0x05 +#define VLC_OP_QUAD 0x06 +#define VLC_OP_QUAD_REL 0x07 +#define VLC_OP_CUBIC 0x08 +#define VLC_OP_CUBIC_REL 0x09 +#define VLC_OP_SCCWARC 0x0A +#define VLC_OP_SCCWARC_REL 0x0B +#define VLC_OP_SCWARC 0x0C +#define VLC_OP_SCWARC_REL 0x0D +#define VLC_OP_LCCWARC 0x0E +#define VLC_OP_LCCWARC_REL 0x0F +#define VLC_OP_LCWARC 0x10 +#define VLC_OP_LCWARC_REL 0x11 + +/* Macros for path manipulating: See path definitions. "VLM" means "VGLite Macros" */ +#define VLM_PATH_ENABLE_UPLOAD(path) (path).uploaded.property |= 1 +#define VLM_PATH_DISABLE_UPLOAD(path) (path).uploaded.property &= (~1) +#define VLM_PATH_GET_UPLOAD_BIT(path) ((path).uploaded.property & 1) + +/* Types ***********************************************************************************************************************/ + +#ifndef VG_LITE_ERROR +#define VG_LITE_ERROR 1 + /*! + @abstract Error codes that the vg_lite functions can return. + + @discussion + All API functions return a status code. On success, VG_LITE_SUCCESS will be returned when a function is + successful. This value is set to zero, so if any function returns a non-zero value, an error has occured. + */ + typedef enum vg_lite_error + { + VG_LITE_SUCCESS = 0, /*! Success. */ + VG_LITE_INVALID_ARGUMENT, /*! An invalid argument was specified. */ + VG_LITE_OUT_OF_MEMORY, /*! Out of memory. */ + VG_LITE_NO_CONTEXT, /*! No context or an unintialized context specified. */ + VG_LITE_TIMEOUT, /*! A timeout has occured during a wait. */ + VG_LITE_OUT_OF_RESOURCES, /*! Out of system resources. */ + VG_LITE_GENERIC_IO, /*! Cannot communicate with the kernel driver. */ + VG_LITE_NOT_SUPPORT, /*! Function call not supported. */ + VG_LITE_MULTI_THREAD_FAIL, /*! Multi-thread/tasks fail. */ + VG_LITE_ALREADY_EXISTS, /*! Object already exists */ + VG_LITE_NOT_ALIGNED, /*! Data alignment error */ + } + vg_lite_error_t; +#endif + + /*! + @abstract The floating point type used by the VGLite API. + */ + typedef float vg_lite_float_t; + + /*! + @abstract A 32-bit color value used by the VGLite API. + + @discussion + The color value specifies the color used in various functions. The color is formed using 8-bit RGBA channels. The red channel + is in the lower 8-bit of the color value, followed by the green and blue channels. The alpha channel is in the upper 8-bit of + the color value. + + For L8 target formats, the RGB color is converted to L8 by using the default ITU-R BT.709 conversion rules. + */ + typedef uint32_t vg_lite_color_t; + +/* Enumerations ***********************************************************************************************************************/ + + /*! + @abstract Quality enumeration for a given path. + + @discussion + Each path should specify a quality hint for the hardware. The path generation tool will generate the quality hint based on the + complexity of the path. + */ + typedef enum vg_lite_quality { + VG_LITE_HIGH, /*! High quality 16x anti-aliasing path. */ + VG_LITE_UPPER, /*! Upper quality 8x anti-aliasing path. */ + VG_LITE_MEDIUM, /*! Medium quality 4x anti-aliasing path. */ + VG_LITE_LOW, /*! Low quality pat without any anti-aliasing. */ + } vg_lite_quality_t; + + /*! + @abstract Format of path coordinates. + + @discussion + Each path can have a separate coordinate system. The path generation tool will find the most optimal coordinate system for any + given path based on its dimensions and input coordinates. + */ + typedef enum vg_lite_format { + VG_LITE_S8, /*! Signed 8-bit coordinates. */ + VG_LITE_S16, /*! Signed 16-bit coordinates. */ + VG_LITE_S32, /*! Signed 32-bit coordinates. */ + VG_LITE_FP32, /*! 32-bit floating point coordinates. */ + } vg_lite_format_t; + + /*! + @abstract Format of a buffer. + + @discussion + The pixel type for a vg_lite_buffer_t structure. + */ + typedef enum vg_lite_buffer_format { + VG_LITE_RGBA8888, /*! 32-bit RGBA format with 8 bits per color channel. Red is in bits 7:0, green in bits 15:8, blue in + bits 23:16, and the alpha channel is in bits 31:24. */ + VG_LITE_BGRA8888, /*! 32-bit RGBA format with 8 bits per color channel. Red is in bits 23:16, green in bits 15:8, blue in + bits 7:0, and the alpha channel is in bits 31:24. */ + VG_LITE_RGBX8888, /*! 32-bit RGBX format with 8 bits per color channel. Red is in bits 7:0, green in bits 15:8, blue in + bits 23:16, and the x channel is in bits 31:24. */ + VG_LITE_BGRX8888, /*! 32-bit RGBX format with 8 bits per color channel. Red is in bits 23:16, green in bits 15:8, blue in + bits 7:0, and the x channel is in bits 31:24. */ + VG_LITE_RGB565, /*! 16-bit RGB format with 5 and 6 bits per color channel. Red is in bits 4:0, green in bits 10:5, and + the blue color channel is in bits 15:11. */ + VG_LITE_BGR565, /*! 16-bit RGB format with 5 and 6 bits per color channel. Red is in bits 15:11, green in bits 10:5, + and the blue color channel is in bits 4:0. */ + VG_LITE_RGBA4444, /*! 16-bit RGBA format with 4 bits per color channel. Red is in bits 3:0, green in bits 7:4, blue in + bits 11:8 and the alpha channel is in bits 15:12. */ + VG_LITE_BGRA4444, /*! 16-bit RGBA format with 4 bits per color channel. Red is in bits 11:8, green in bits 7:4, blue in + bits 3:0 and the alpha channel is in bits 15:12. */ + VG_LITE_BGRA5551, /*! 16-bit RGBA format with 4 bits per color channel. Red is in bits 14:10, green in bits 9:5, blue in + bits 4:0 and the alpha channel is in bit 15:15. */ + VG_LITE_A4, /*! 4-bit alpha format. There are no RGB values. */ + VG_LITE_A8, /*! 8-bit alpha format. There are no RGB values. */ + VG_LITE_L8, /*! 8-bit luminance value. There is no alpha value. */ + VG_LITE_YUYV, /*! Packed YUV format, 32-bit for 2 pixels. Y0 is in bits 7:0 and V is in bits 31:23. */ + + VG_LITE_YUY2, /*! New formats. */ + VG_LITE_NV12, + VG_LITE_ANV12, + VG_LITE_AYUY2, + + VG_LITE_YV12, + VG_LITE_YV24, + VG_LITE_YV16, + VG_LITE_NV16, + + VG_LITE_YUY2_TILED, /*! Tiled YUV formats. */ + VG_LITE_NV12_TILED, + VG_LITE_ANV12_TILED, + VG_LITE_AYUY2_TILED, + + VG_LITE_INDEX_1 = 100, /*! Indexed format. */ + VG_LITE_INDEX_2, + VG_LITE_INDEX_4, + VG_LITE_INDEX_8, + + VG_LITE_RGBA2222, /*! 8-bit RGBA format with 2 bits per color channel.Red is in bits 1:0,green in bits 3:2,blue in + bits 5:4 and the alpha channel is in bits 7:6*/ + VG_LITE_BGRA2222, /*! 8-bit RGBA format with 2 bits per color channel.Blue is in bits 1:0,green in bits 3:2,red in + bits 5:4 and the alpha channel is in bits 7:6*/ + VG_LITE_ABGR2222, /*! 8-bit RGBA format with 2 bits per color channel.Alpha is in bits 1:0,blue in bits 3:2,green in + bits 5:4 and the red channel is in bits 7:6*/ + VG_LITE_ARGB2222, /*! 8-bit RGBA format with 2 bits per color channel.Alpha is in bits 1:0,red in bits 3:2,green in + bits 5:4 and the blue channel is in bits 7:6*/ + VG_LITE_ABGR4444, /*! 16-bit RGBA format with 4 bits per color channel. Alpha is in bits 3:0, blue in bits 7:4, green in + bits 11:8 and the red channel is in bits 15:12. */ + VG_LITE_ARGB4444, /*! 16-bit RGBA format with 4 bits per color channel. Alpha is in bits 3:0, red in bits 7:4, green in + bits 11:8 and the blue channel is in bits 15:12. */ + VG_LITE_ABGR8888, /*! 32-bit RGBA format with 8 bits per color channel. Alpha is in bits 7:0, blue in bits 15:8, green in + bits 23:16, and the red channel is in bits 31:24. */ + VG_LITE_ARGB8888, /*! 32-bit RGBA format with 8 bits per color channel. Alpha is in bits 7:0, red in bits 15:8, green in + bits 23:16, and the blue channel is in bits 31:24. */ + VG_LITE_ABGR1555, /*! 16-bit RGBA format with 4 bits per color channel. Red is in bits 15:11, green in bits 10:6, blue in + bits 5:1 and the alpha channel is in bit 0:0. */ + VG_LITE_RGBA5551, /*! 16-bit RGBA format with 4 bits per color channel. Blue is in bits 14:10, green in bits 9:5, red in + bits 4:0 and the alpha channel is in bit 15:15. */ + VG_LITE_ARGB1555, /*! 16-bit RGBA format with 4 bits per color channel. Blue is in bits 15:11, green in bits 10:6, red in + bits 5:1 and the alpha channel is in bit 0:0. */ + VG_LITE_XBGR8888, /*! 32-bit RGBX format with 8 bits per color channel. X channel is in bits 7:0, blue in bits 15:8, green in + bits 23:16, and the red is in bits 31:24. */ + VG_LITE_XRGB8888 /*! 32-bit RGBX format with 8 bits per color channel. X channel is in bits 7:0, red in bits 15:8, green in + bits 23:16, and the blue is in bits 31:24. */ + } vg_lite_buffer_format_t; + + /*! + @abstract Swizzle of packed YUV format UV channels. + + @discussion + The swizzle of packed YUV format UV channels. + */ + typedef enum vg_lite_swizzle { + VG_LITE_SWIZZLE_UV, + VG_LITE_SWIZZLE_VU, + } vg_lite_swizzle_t; + + /*! + @abstract The YUV<->RGB conversion rule. + + @discussion + Indicate the rule how to convert rgb and yuv colors. + */ + typedef enum vg_lite_yuv2rgb { + VG_LITE_YUV601, + VG_LITE_YUV709, + } vg_lite_yuv2rgb_t; + + /*! + @abstract The pixel layout in a buffer. + + @discussion + Pixels in a buffer may be tiled or linear. + */ + typedef enum vg_lite_buffer_layout { + VG_LITE_LINEAR, + VG_LITE_TILED, + } vg_lite_buffer_layout_t; + + /*! + @abstract The image (buffer) rendering mode. + + @discussion + This defines how an image are rendered onto a buffer. There are 3 modes. + */ + typedef enum vg_lite_buffer_image_mode { + VG_LITE_NORMAL_IMAGE_MODE, + VG_LITE_NONE_IMAGE_MODE, + VG_LITE_MULTIPLY_IMAGE_MODE + } vg_lite_buffer_image_mode_t; + + /*! + @abstract The image (buffer) transparency mode. + OPAQUE, All image pixels are copied to the VGPE for rasterization; + TRANSPARENT,Only the non-transparent image pixels are copied to the VGPE. + Note: This mode is valid when IMAGE_MODE(vg_lite_buffer_image_mode_t) isn't NONE. + */ + typedef enum vg_lite_buffer_transparency_mode { + VG_LITE_IMAGE_OPAQUE, + VG_LITE_IMAGE_TRANSPARENT + } vg_lite_buffer_transparency_mode_t; + + typedef struct vg_lite_yuvinfo { + vg_lite_swizzle_t swizzle; /* UV swizzle. */ + vg_lite_yuv2rgb_t yuv2rgb; /* 601 or 709 conversion standard. */ + uint32_t uv_planar; /* UV(U) planar address. */ + uint32_t v_planar; /* V planar address. */ + uint32_t alpha_planar; /* Alpha planar address. */ + uint32_t uv_stride; /* UV(U) stride. */ + uint32_t v_stride; /* V stride. */ + uint32_t alpha_stride; /* Alpha stride. */ + uint32_t uv_height; /* UV(U) height. */ + uint32_t v_height; /* V height. */ + void * uv_memory; /* The logical pointer to the UV(U) planar memory. */ + void * v_memory; /* The logical pointer to the V planar memory. */ + void * uv_handle; /* The memory handle of the UV(U) planar. */ + void * v_handle; /* The memory handle of the V planar. */ + } vg_lite_yuvinfo_t; + + /*! + @abstract Blending modes. + + @discussion + Some of the VGLite API functions calls support blending. S and D represent source and destination color channels and Sa and Da + represent the source and destination alpha channels. + */ + typedef enum vg_lite_blend { + VG_LITE_BLEND_NONE, /*! S, i.e. no blending. */ + VG_LITE_BLEND_SRC_OVER, /*! S + (1 - Sa) * D */ + VG_LITE_BLEND_DST_OVER, /*! (1 - Da) * S + D */ + VG_LITE_BLEND_SRC_IN, /*! Da * S */ + VG_LITE_BLEND_DST_IN, /*! Sa * D */ + VG_LITE_BLEND_SCREEN, /*! S + D - S * D */ + VG_LITE_BLEND_MULTIPLY, /*! S * (1 - Da) + D * (1 - Sa) + S * D */ + VG_LITE_BLEND_ADDITIVE, /*! S + D */ + VG_LITE_BLEND_SUBTRACT, /*! D * (1 - S) */ + } vg_lite_blend_t; + + /*! + @abstract Fill rules. + + @discussion + For drawing any path, the hardware supports both non-zero and odd-even fill rules. + + To determine whether any point is contained inside an object, imagine drawing a line from that point out to infinity in any + direction such that the line does not cross any vertex of the path. For each edge that is crossed by the line, add 1 to the + counter if the edge crosses from left to right, as seen by an observer walking across the line towards infinity, and subtract 1 + if the edge crosses from right to left. In this way, each region of the plane will receive an integer value. + + The non-zero fill rule says that a point is inside the shape if the resulting sum is not equal to zero. The even/odd rule says + that a point is inside the shape if the resulting sum is odd, regardless of sign. + */ + typedef enum vg_lite_fill { + VG_LITE_FILL_NON_ZERO, /*! Non-zero fill rule. A pixel is drawn if it crosses at least one path pixel. */ + VG_LITE_FILL_EVEN_ODD, /*! Even-odd fill rule. A pixel is drawn it it crosses an odd number of path pixels. */ + } vg_lite_fill_t; + + /* Chip features. */ + typedef enum vg_lite_feature + { + gcFEATURE_BIT_VG_IM_INDEX_FORMAT, + gcFEATURE_BIT_VG_PE_PREMULTIPLY, + gcFEATURE_BIT_VG_BORDER_CULLING, + gcFEATURE_BIT_VG_RGBA2_FORMAT, + gcFEATURE_BIT_VG_QUALITY_8X, + gcFEATURE_BIT_VG_RADIAL_GRADIENT, + gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT, + gcFEATURE_BIT_VG_COLOR_KEY, + gcFEATURE_BIT_VG_DITHER, + /* Insert features above this comment only. */ + gcFEATURE_COUNT /* Not a feature. */ + } + vg_lite_feature_t; + + /* Filter modes. */ + typedef enum vg_lite_filter + { + VG_LITE_FILTER_POINT = 0, /* Only the nearest image pixel is fetched. */ + VG_LITE_FILTER_LINEAR = 0x10000, /* Used for linear paint. */ + VG_LITE_FILTER_BI_LINEAR = 0x20000, /* Use a 2x2 box around the image pixel and perform an interpolation. */ + } vg_lite_filter_t; + + /* Pattern padding mode. */ + typedef enum vg_lite_pattern_mode + { + VG_LITE_PATTERN_COLOR = 0, + VG_LITE_PATTERN_PAD, + } vg_lite_pattern_mode_t; + + /* radial gradient padding mode. */ + typedef enum { + VG_LITE_RADIAL_GRADIENT_SPREAD_FILL = 0, + VG_LITE_RADIAL_GRADIENT_SPREAD_PAD, + VG_LITE_RADIAL_GRADIENT_SPREAD_REPEAT, + VG_LITE_RADIAL_GRADIENT_SPREAD_REFLECT, + } vg_lite_radial_gradient_spreadmode_t; + + /* draw path type. */ + typedef enum vg_lite_draw_path_type{ + VG_LITE_DRAW_FILL_PATH = 0, /*! draw fill path. */ + VG_LITE_DRAW_STROKE_PATH, /*! draw stroke path. */ + VG_LITE_DRAW_FILL_STROKE_PATH, /*! draw both fill and stroke path. */ + } vg_lite_draw_path_type_t; + + /* End cap style. */ + typedef enum vg_lite_cap_style + { + VG_LITE_CAP_BUTT, /*! The Butt end cap style terminates each segment with a line perpendicular to the tangent at each endpoint. */ + VG_LITE_CAP_ROUND, /*! The Round end cap style appends a semicircle with a diameter equal to the line width centered around each endpoint. */ + VG_LITE_CAP_SQUARE /*! The Square end cap style appends a rectangle with two sides of length equal to the line width + perpendicular to the tangent, and two sides of length equal to half the line width parallel + to the tangent, at each endpoint. */ + } + vg_lite_cap_style_t; + + /* Line join styles. */ + typedef enum vg_lite_join_style + { + VG_LITE_JOIN_MITER,/*! The Miter join style appends a trapezoid with one vertex at the intersection point of the two original + lines, two adjacent vertices at the outer endpoints of the two “fattened” lines and a fourth vertex at + the extrapolated intersection point of the outer perimeters of the two “fattened” lines. */ + VG_LITE_JOIN_ROUND,/*! The Round join style appends a wedge-shaped portion of a circle,centered at the intersection point + of the two original lines, having a radius equal to half the line width. */ + VG_LITE_JOIN_BEVEL /*! The Bevel join style appends a triangle with two vertices at the outer endpoints of the two "fattened" + lines and a third vertex at the intersection point of the two original lines. */ + } + vg_lite_join_style_t; + +/* Structures *******************************************************************************************************************/ + + typedef struct vg_lite_path_point * vg_lite_path_point_ptr; + typedef struct vg_lite_path_point + { + /* X coordinate. */ + vg_lite_float_t x; + + /* Y coordinate. */ + vg_lite_float_t y; + + /* Flatten flag for flattened path. */ + uint8_t flatten_flag; + + /* Curve type for stroke path. */ + uint8_t curve_type; + + /* X tangent. */ + vg_lite_float_t tangentX; + + /* Y tangent. */ + vg_lite_float_t tangentY; + + /* Length of the line. */ + vg_lite_float_t length; + + /* Pointer to next point node. */ + vg_lite_path_point_ptr next; + + /* Pointer to previous point node. */ + vg_lite_path_point_ptr prev; + + }vg_lite_path_point_t; + + typedef struct vg_lite_sub_path * vg_lite_sub_path_ptr; + typedef struct vg_lite_sub_path + { + /* Pointer to next sub path. */ + vg_lite_sub_path_ptr next; + + /* Number of points. */ + uint32_t point_count; + + /* Point list. */ + vg_lite_path_point_ptr point_list; + + /* Last point. */ + vg_lite_path_point_ptr last_point; + + /* Whether is path is closed. */ + uint8_t closed; + + /* Sub path length. */ + vg_lite_float_t length; + } + vg_lite_sub_path_t; + + typedef struct vg_lite_stroke_conversion + { + /* Stroke parameters */ + vg_lite_cap_style_t stroke_cap_style; + vg_lite_join_style_t stroke_join_style; + vg_lite_float_t stroke_line_width; + vg_lite_float_t stroke_miter_limit; + vg_lite_float_t * stroke_dash_pattern; + uint32_t stroke_dash_pattern_count; + vg_lite_float_t stroke_dash_phase; + vg_lite_float_t stroke_dash_initial_length; + uint32_t stroke_dash_initial_index; + + vg_lite_float_t half_line_width; + + /* Total length of stroke dash patterns. */ + vg_lite_float_t stroke_dash_pattern_length; + + /* For fast checking. */ + vg_lite_float_t stroke_miter_limit_square; + + /* Temp storage of stroke subPath. */ + vg_lite_path_point_ptr path_point_list; + vg_lite_path_point_ptr path_last_point; + uint32_t point_count; + vg_lite_path_point_ptr left_stroke_point; + vg_lite_path_point_ptr last_right_stroke_point; + vg_lite_path_point_ptr stroke_point_list; + vg_lite_path_point_ptr stroke_last_point; + uint32_t stroke_point_count; + + /* Sub path list. */ + vg_lite_sub_path_ptr stroke_sub_path_list; + + /* Last sub path. */ + vg_lite_sub_path_ptr last_stroke_sub_path; + + /* Swing area handling. */ + uint8_t swing_need_to_handle; + uint32_t swing_handling; + uint8_t swing_counter_clockwise; + vg_lite_float_t swing_stroke_deltax; + vg_lite_float_t swing_stroke_deltay; + vg_lite_path_point_ptr swing_start_point; + vg_lite_path_point_ptr swing_start_stroke_point; + vg_lite_float_t swing_accu_length; + vg_lite_float_t swing_center_length; + uint32_t swing_count; + + vg_lite_float_t stroke_path_length; + uint32_t stroke_path_size; + /* The stroke line is fat line. */ + uint8_t is_fat; + uint8_t closed; + } + vg_lite_stroke_conversion_t; + + /* A 2D Point definition. */ + typedef struct vg_lite_point { + int x; + int y; + } + vg_lite_point_t; + + /* Four 2D Point that form a polygon */ + typedef vg_lite_point_t vg_lite_point4_t[4]; + + /* This structure is used to query VGLite driver information */ + typedef struct vg_lite_info { + uint32_t api_version; /*! VGLite API version. */ + uint32_t header_version; /*! VGLite API header version. */ + uint32_t release_version; /*! VGLite release version. */ + uint32_t reserved; /*! Reserved for future use. */ + } vg_lite_info_t; + + /*! + @abstract A 3x3 matrix. + + @discussion + For those functions that need a matrix, this is the structure that defines it. The contents are a simple 3x3 matrix + consisting of floating pointer numbers. + */ + typedef struct vg_lite_matrix { + vg_lite_float_t m[3][3]; /*! The 3x3 matrix itself, in [row][column] order. */ + } vg_lite_matrix_t; + + /*! + @abstract A wrapper structure for any image or render target. + + @discussion + Each piece of memory, whether it is an image used as a source or a buffer used as a target, requires a structure to define it. + This structure contains all the information the VGLite API requires to access the buffer's memory by the hardware. + */ + typedef struct vg_lite_buffer { + int32_t width; /*! Width of the buffer in pixels. */ + int32_t height; /*! Height of the buffer in pixels. */ + int32_t stride; /*! The number of bytes to move from one line in the buffer to the next line. */ + vg_lite_buffer_layout_t tiled; /*! Indicating the buffer memory layout is linear or tiled. */ + vg_lite_buffer_format_t format; /*! The pixel format of the buffer. */ + void * handle; /*! The memory handle of the buffer's memory as allocated by the VGLite kernel. */ + void * memory; /*! The logical pointer to the buffer's memory for the CPU. */ + uint32_t address; /*! The address to the buffer's memory for the hardware. */ + vg_lite_yuvinfo_t yuv; /*! The yuv format details. */ + vg_lite_buffer_image_mode_t image_mode; /*! The blit image mode. */ + vg_lite_buffer_transparency_mode_t transparency_mode; /*image transparency mode*/ + } vg_lite_buffer_t; + + /* This structure simply records the memory allocation info by kernel. */ + typedef struct vg_lite_hw_memory { + void * handle; /*! gpu memory object handle. */ + void * memory; /*! logical memory address. */ + uint32_t address; /*! GPU memory address. */ + uint32_t bytes; /*! Size of memory. */ + uint32_t property; /*! Currently bit0 is used for path upload: + 1 to enable auto path data uploading; + 0 to disable path data uploading (always embedded into command buffer). + */ + } vg_lite_hw_memory_t; + + /*! + @abstract A path used by the drawing command. + + @discussion + Each path needs a few parameters. This structure defines those parameters, so the VGLite driver knows the detail of a path. + */ + typedef struct vg_lite_path { + vg_lite_float_t bounding_box[4]; /*! Bounding box specified as left, top, right, and bottom. */ + vg_lite_quality_t quality; /*! Quality hint for the path. */ + vg_lite_format_t format; /*! Coordinate format. */ + vg_lite_hw_memory_t uploaded; /*! Path data that has been upload into GPU addressable memory. */ + int32_t path_length; /*! Number of bytes in the path data. */ + void *path; /*! Pointer to the physical description of the path. */ + int8_t path_changed; /* Indicate whether path data is synced with command buffer (uploaded) or not. */ + int8_t pdata_internal; /*! Indicate whether path data memory is allocated by driver. */ + vg_lite_stroke_conversion_t *stroke_conversion; /*! Refer to the definition by vg_lite_stroke_conversion_t.*/ + vg_lite_draw_path_type_t path_type; /*! Refer to the definition by vg_lite_draw_path_type_t. */ + void *stroke_path_data; /*! Pointer to the physical description of the stroke path. */ + int32_t stroke_path_size; /*! Number of bytes in the stroke path data. */ + vg_lite_color_t stroke_color; /*! The stroke path fill color.Refer to the definition by vg_lite_color_t.*/ + } vg_lite_path_t; + + /*! + @abstract A rectangle. + + @discussion + A rectangle defines a rectangular definition of the screen. + */ + typedef struct vg_lite_rectangle { + int32_t x; /*! Left coordinate of the rectangle. */ + int32_t y; /*! Top coordinate of the rectangle. */ + int32_t width; /*! Width of the rectangle. */ + int32_t height; /*! Height of the rectangle. */ + } vg_lite_rectangle_t; + + /*! + @abstract Tessellation buffer information. + + @discussion + The tessellation buffer information for access. + */ + typedef struct vg_lite_tsbuffer_info { + uint32_t tessellation_buffer_gpu[3]; /*! HW physical address. */ + uint8_t *tessellation_buffer_logic[3]; /*! Logical address. */ + uint32_t tessellation_buffer_size[3]; /*! Buffer size for tessellation buffer, l1, l2. */ + uint32_t tessellation_stride; /*! Buffer stride. */ + uint32_t tessellation_width_height; /*! Combination of buffer width and height. */ + uint32_t tessellation_shift; /*! Tessellation config: shift. */ + uint32_t tessellation_origin[2]; + } vg_lite_tsbuffer_info_t; + + /* Linear Gradient definitions. */ +#define VLC_MAX_GRAD 16 /*! The max number of gradient stops. */ +#define VLC_GRADBUFFER_WIDTH 256 /*! The internal buffer width.*/ + + /*! + @abstract Linear gradient definition. + + @discussion + Linear gradient is applied to filling a path. It will generate a 256x1 image according the settings. + */ + typedef struct vg_lite_linear_gradient { + uint32_t colors[VLC_MAX_GRAD]; /*! Colors for stops. */ + uint32_t count; /*! Count of colors, up to 16. */ + uint32_t stops[VLC_MAX_GRAD]; /*! Color stops, value from 0 to 255. */ + vg_lite_matrix_t matrix; /*! The matrix to transform the gradient. */ + vg_lite_buffer_t image; /*! The image for rendering as gradient pattern. */ + } vg_lite_linear_gradient_t; + + /* radial Gradient definitions. */ +#define MAX_COLOR_RAMP_STOPS 256 /*! The max number of radial gradient stops. */ + + /*! + @abstract color ramp definition. + + @discussion + This is the stop for the radial gradient.The number of parameters is 5,and give the offset and + color of the stop.Each stop is defined by a floating-point offset value and four floating-point values + containing the sRGBA color and alpha value associated with each stop, in the form of a non-premultiplied + (R, G, B, alpha) quad.And the range of all parameters in it is [0,1].[0,1] of the color channel value is + mapped to [0,255]. + */ + typedef struct vg_lite_color_ramp + { + vg_lite_float_t stop; /* Value for the color stop. */ + vg_lite_float_t red; /* Red color channel value for the color stop. */ + vg_lite_float_t green; /* Green color channel value for the color stop. */ + vg_lite_float_t blue; /* Blue color channel value for the color stop. */ + vg_lite_float_t alpha; /* Alpha color channel value for the color stop. */ + } + vg_lite_color_ramp_t, *vg_lite_color_ramp_ptr; + + typedef struct vg_lite_radial_gradient_parameter + { + vg_lite_float_t cx; /* the x coordinate of the center point. */ + vg_lite_float_t cy; /* the y coordinate of the center point. */ + vg_lite_float_t r; /* the radius. */ + vg_lite_float_t fx; /* the x coordinate of the focal point. */ + vg_lite_float_t fy; /* the y coordinate of the focal point. */ + } + vg_lite_radial_gradient_parameter_t; + + /*! + @abstract radial gradient definition. + + @discussion + radial gradient is applied to filling a path. + */ + typedef struct vg_lite_radial_gradient { + uint32_t count; /*! Count of colors, up to 256. */ + vg_lite_matrix_t matrix; /*! The matrix to transform the gradient. */ + vg_lite_buffer_t image; /*! The image for rendering as gradient pattern. */ + vg_lite_radial_gradient_parameter_t radialGradient; /* include center point,focal point and radius.*/ + vg_lite_radial_gradient_spreadmode_t SpreadMode; /* The tiling mode that applied to the pixels out of the image after transformed. */ + + uint32_t vgColorRampLength; /* Color ramp parameters for gradient paints provided to the driver. */ + vg_lite_color_ramp_t vgColorRamp[MAX_COLOR_RAMP_STOPS]; + + uint32_t intColorRampLength; /* Converted internal color ramp. */ + vg_lite_color_ramp_t intColorRamp[MAX_COLOR_RAMP_STOPS + 2]; + + uint8_t colorRampPremultiplied; /* if this value is set to 1,the color value of vgColorRamp will multiply by alpha value of vgColorRamp.*/ + } vg_lite_radial_gradient_t; + + /*! + @abstract linear gradient parameter definition. + + @discussion + The line connecting point (X0,Y0) to point (X1,Y1) is the radial direction of the linear gradient. + This radial direction line called line0,the line perpendicular to line0 and passing through the point (X0,Y0) + called line1,the line perpendicular to line0 and passing through the point (X1,Y1) called line2,the linear gradient + starts form line1 and end to line2. + */ + typedef struct vg_lite_linear_gradient_parameter + { + vg_lite_float_t X0; + vg_lite_float_t Y0; + vg_lite_float_t X1; + vg_lite_float_t Y1; + } + vg_lite_linear_gradient_parameter_t; + + /*! + @abstract linear gradient definition. + + @discussion + linear gradient is applied to filling a path.vg_lite_linear_gradient_ext and vg_lite_linear_gradient for hardware and software implementation + of linear gradient respectively. + */ + typedef struct vg_lite_linear_gradient_ext { + uint32_t count; /*! Count of colors, up to 256. */ + vg_lite_matrix_t matrix; /*! The matrix to transform the gradient. */ + vg_lite_buffer_t image; /*! The image for rendering as gradient pattern. */ + vg_lite_linear_gradient_parameter_t linear_gradient; /* Refer to the definition by vg_lite_linear_gradient_parameter_t.*/ + + uint32_t vg_color_ramp_length; /* Color ramp parameters for gradient paints provided to the driver. */ + vg_lite_color_ramp_t vg_color_ramp[MAX_COLOR_RAMP_STOPS]; + + uint32_t int_color_ramp_length; /* Converted internal color ramp. */ + vg_lite_color_ramp_t int_color_ramp[MAX_COLOR_RAMP_STOPS + 2]; + + uint8_t color_ramp_premultiplied; /* if this value is set to 1,the color value of vgColorRamp will multiply by alpha value of vgColorRamp.*/ + vg_lite_radial_gradient_spreadmode_t spread_mode; /* Use tge same spread mode enumeration type as radial gradient. */ + } vg_lite_linear_gradient_ext_t; + + /*! + @abstract color key definition. + + @discussion + The colorkey have two sections,each section contain R,G,B chanels.Debited as hign_rgb and low_rgb respectively. + Can be used for blit operation or draw_pattern operation.when enable is ture,the alpha value is used to replace + the alpha channel of destination pixel when its RGB channels in range [low_rgb,hign_rgb].After use color key this + frame,and if the color key is not need in the next frame,disable the color key before next frame. + */ + typedef struct vg_lite_color_key + { + uint8_t enable; /* when enable is ture,this color key is effective. */ + uint8_t low_r; /* The R chanel of low_rgb. */ + uint8_t low_g; /* The G chanel of low_rgb. */ + uint8_t low_b; /* The B chanel of low_rgb. */ + uint8_t alpha; /* The alpha channel to replace destination pixel alpha channel.*/ + uint8_t hign_r; /* The R chanel of hign_rgb. */ + uint8_t hign_g; /* The G chanel of hign_rgb. */ + uint8_t hign_b; /* The B chanel of hign_rgb. */ + } vg_lite_color_key_t; + + /*! + @abstract colorkey definition. + + @discussion + There are 4 groups of color key states. + rgb_hi_0, rgb_lo_0, alpha_0, enable_0; + rgb_hi_1, rgb_lo_1, alpha_1, enable_1; + rgb_hi_2, rgb_lo_2, alpha_2, enable_2; + rgb_hi_3, rgb_lo_3, alpha_3, enable_3; + Priority order:color_key_0 > color_key_1 > color_key_2 > color_key_3. + */ + typedef vg_lite_color_key_t vg_lite_color_key4_t[4]; + +/* API Function prototypes *****************************************************************************************************/ + + /*! + @abstract Get a 3*3 homogenous transform matrix by source coordinates and target coordinates. + + @param src + Pointer to the four 2D points that form a source polygon. + + @param dst + Pointer to the four 2D points that form a destination polygon. + + @param mat + Output parameter,pointer to 3*3 homogenous matrix that transform source polygon to destination polygon. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_get_transform_matrix(vg_lite_point4_t src, vg_lite_point4_t dst,vg_lite_matrix_t *mat); + + /*! + @abstract Allocate a buffer from hardware accessible memory. + + @discussion + In order for the hardware to access some memory, like a source image or a target buffer, it needs to be allocated first. The + supplied vg_lite_buffer_t structure needs to be initialized with the size (width and height) and format of the + requested buffer. If the stride is set to zero, this function will fill it in. + + This function will call the kernel to actually allocate the memory and the memory handle and logical and hardware addresses + will be filled in by the kernel. + + @param buffer + Pointer to the buffer that holds the size and format of the buffer being allocated. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_allocate(vg_lite_buffer_t *buffer); + + /*! + @abstract Free a buffer that was previously allocated by {@link vg_lite_allocate}. + + @discussion + Free any memory resources allocated by a previous call to {@link vg_lite_allocate}. + + @param buffer + Pointer to a buffer structure that was filled in by {@link vg_lite_allocate}. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_free(vg_lite_buffer_t *buffer); + + /*! + @abstract Upload the pixel data to the buffer object. + + @discussion + The function uploads the pixel data to the buffer object. According to the + buffer format, there are 3 planes' data at most (for YUV planars). Note that + the format of the data (pixel) to upload must be the same as described in + the buffer object. The input data memory pointers should be big enough to + hold all the data needed by the buffer. + + @param buffer + The image buffer object. + + @param data + Pixel data. For YUV format, it may be up to 3 pointers. + + @param stride + Stride for pixel data. + + @result + Any error status during uploading. + */ + vg_lite_error_t vg_lite_buffer_upload(vg_lite_buffer_t *buffer, uint8_t *data[3], uint32_t stride[3]); + + /*! + @abstract Map a buffer into hardware accessible address space. + + @discussion + If you want the use a frame buffer directly as an target buffer, you need to wrap a vg_lite_buffer_t structure + around it and call the kernel to map the supplied logical or physical address into hardware accessible memory. + + For example, if you know the logical address of the frame buffer, set the memory field of the vg_lite_buffer_t structure + with that address and call this function. If you know the physical address, set the memory field to NULL and + program the address field with the physical address. + + @param buffer + Pointer to the buffer that holds the size and format of the buffer being allocated. Either the memory or address field + needs to be set to a non-zero value to map either a logical or physical address into hardware accessible memory. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_map(vg_lite_buffer_t *buffer); + + /*! + @abstract Unmap a buffer that was previously mapped by {@link vg_lite_map}. + + @discussion + Free any memory resources allocated by a previous call to {@link vg_lite_map}. + + @param buffer + Pointer to a buffer structure that was filled in by {@link vg_lite_map}. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_unmap(vg_lite_buffer_t *buffer); + + /*! + @abstract Fill a (partial) buffer with a specified color. + + @discussion + Either an entire buffer or a partial rectangle of a buffer will be filled with a specific color. + + This function will wait until the hardware is complete, i.e. it is synchronous. + + @param target + Pointer to a vg_lite_buffer_t structure that describes the buffer to be filled. + + @param rectangle + Pointer to a rectangle that specifies the area to be filled. If rectangle is NULL, the entire target + buffer will be filled with the specified color. + + @param color + The color value to use for filling the buffer. If the buffer is in L8 format, the RGBA color will be converted into a + luminance value. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_clear(vg_lite_buffer_t *target, + vg_lite_rectangle_t *rectangle, + vg_lite_color_t color); + + /*! + @abstract Copy a source image to the the destination window with a specified matrix that can include translation, rotation, + scaling, and perspective correction. + + @discussion + A source image is copied to the target using the specified matrix. If the specified matrix is NULL, an identity + matrix is assumed, meaning the source will be copied directly on the target at 0,0 location. + + An optional blend mode can be specified that defines the blending of the source onto the target. + + Also, an optional mix color can be specified. The mix color will be multiplied by the source color. If you don't need a mix + color, set the color parameter to 0. + + Note that on hardware that doesn't support border scissoring (GC355) the blend mode will be forced to + VG_LITE_BLEND_SRC_OVER if rotation or perspective is involved. + + @param target + Pointer to a vg_lite_buffer_t structure that describes the target of the blit. + + @param source + Pointer to a vg_lite_buffer_t structure that describes the source of the blit. + + @param matrix + Pointer to a 3x3 matrix that defines the transformation matrix of source pixels into the target. If matrix is + NULL, an identity matrix is assumed. + + @param blend + The blending mode to be applied to each image pixel. If no blending is required, set this value to + VG_LITE_BLEND_NONE (0). + + @param color + If non-zero, this color value will be used as a mix color. The mix color gets multiplied with each source pixel before + blending happens. + + @param filter + The filter mode to be applied. If no filter mode is required, set this value to + VG_LITE_FILTER_BI_LINEAR (0x20000). + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_blit(vg_lite_buffer_t *target, + vg_lite_buffer_t *source, + vg_lite_matrix_t *matrix, + vg_lite_blend_t blend, + vg_lite_color_t color, + vg_lite_filter_t filter); + + /* In additional to vg_lite_blit: + @brief + This API draws a porting of the image to the screen. + + @param + rect The source rectangle to blit. rect[0]/[1]/[2]/[3] are x, y, width and height of the source rectangle. */ + vg_lite_error_t vg_lite_blit_rect(vg_lite_buffer_t *target, + vg_lite_buffer_t *source, + uint32_t *rect, + vg_lite_matrix_t *matrix, + vg_lite_blend_t blend, + vg_lite_color_t color, + vg_lite_filter_t filter); + + /*! + @abstract Initialize a vglite context. + + @discussion + The {@link vg_lite_draw} function requires a draw context to be initialized. There is only one draw context per process, so + this function has be called once in your application if any draw command will be used. If this would be the first context that + accesses the hardware, the hardware will be turned on and initialized. + + The difference between a blit and draw context is that the draw context has a larger command buffer and allocates a + tessellation buffer for the hardware. The size of the tessellation buffer can be specified, and that size will be aligned to + the minimum required alignment of the hardware by the kernel. If you make the tessellation buffer smaller, less memory will + be allocated, but a path might be sent down to the hardware multiple times because the hardware will walk the target with the + provided tessellation window size, so performance might go down. It is good practice to set the tessellation buffer size to the + most common path size. For example, if all you do is render up to 24-pt fonts, you can set the tessellation buffer to be + 24x24. + + @param tessellation_width + The width of the tessellation window. + + @param tessellation_height + The height of the tessellation window. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_init(int32_t tessellation_width, int32_t tessellation_height); + + /*! + @abstract Destroy a vglite context. + + @discussion + Destroy a draw context that was previously initialized by {@link vg_lite_draw_init}. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_close(void); + + /*! + @abstract This api explicitly submits the command buffer to GPU and waits for it to complete. + + @param none. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_finish(void); + + /*! + @abstract This api explicitly submits the command buffer to GPU without waiting for it to complete. + + @param none. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_flush(void); + + /*! + @abstract Draw a path to a target buffer. + + @discussion + The specified path will be transformed by the given matrix and drawn into the specified target buffer using the supplied color. + Blending can be specified. + + @param target + Pointer to a vg_lite_buffer_t structure that describes the target of the draw. + + @param path + Pointer to a vg_lite_path_t structure that describes the path to draw. + + @param fill_rule + Specified fill rule for the path. + + @param matrix + Pointer to a 3x3 matrix that defines the transformation matrix of the path. If matrix is NULL, an + identity matrix is assumed which is usually a bad idea since the path can be anything. + + @param blend + The blending mode to be applied to each drawn pixel. If no blending is required, set this value to + VG_LITE_BLEND_NONE (0). + + @param color + The color applied to each pixel drawn by the path. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_draw(vg_lite_buffer_t *target, + vg_lite_path_t *path, + vg_lite_fill_t fill_rule, + vg_lite_matrix_t *matrix, + vg_lite_blend_t blend, + vg_lite_color_t color); + + /*! + @abstract Set stroke path's attributes. + + @discussion + This function use the input parameters to set stroke attributes. + + @param path + Pointer to a vg_lite_path_t structure that describes the path. + + @param stroke_cap_style + The end cap style defined by vg_lite_cap_style_t. + + @param stroke_join_style + The line join style defined by vg_lite_join_style_t. + + @param stroke_line_width + The line width of stroke path.A line width less than or equal to 0 prevents stroking from taking place. + + @param stroke_miter_limit + When stroking using the Miter join style, the miter length (i.e., the length between the + intersection points of the inner and outer perimeters of the two “fattened” lines) is compared + to the product of the user-set miter limit and the line width. If the miter length exceeds this + product, the Miter join is not drawn and a Bevel join is substituted.Miter limit values less + than 1 are silently clamped to 1. + + @param stroke_dash_pattern + The dash pattern consists of a sequence of lengths of alternating "on" and "off" dash + segments. The first value of the dash array defines the length, in user coordinates, of the + first "on" dash segment. The second value defines the length of the following "off" + segment. Each subsequent pair of values defines one "on" and one "off" segment.If the dash + pattern has an odd number of elements, the final element is ignored. + + @param stroke_dash_pattern_count + The count of dash on/off segments. + + @param stroke_dash_phase + The dash phase defines the starting point in the dash pattern that is associated with the + start of the first segment of the path. For example, if the dash pattern is [10 20 30 40] + and the dash phase is 35, the path will be stroked with an "on" segment of length 25 + (skipping the first "on" segment of length 10, the following "off" segment of length 20, + and the first 5 units of the next "on" segment), followed by an "off" segment of length + 40. The pattern will then repeat from the beginning, with an “on” segment of length 10, + an "off" segment of length 20, an "on" segment of length 30. + + @param stroke_color + The color fill in stroke path. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_set_stroke(vg_lite_path_t *path, + vg_lite_cap_style_t stroke_cap_style, + vg_lite_join_style_t stroke_join_style, + vg_lite_float_t stroke_line_width, + vg_lite_float_t stroke_miter_limit, + vg_lite_float_t *stroke_dash_pattern, + uint32_t stroke_dash_pattern_count, + vg_lite_float_t stroke_dash_phase, + vg_lite_color_t stroke_color); + /*! + @abstract Update stroke path. + + @discussion + This function use the given path and stroke attributes given by function vg_lite_set_stroke + to update stroke path's parameters and generate stroke path data. + + @param path + Pointer to a vg_lite_path_t structure that describes the path. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_update_stroke(vg_lite_path_t *path); + + /*! + @abstract Set path type. + + @discussion + This function set the path type.It can be VG_LITE_DRAW_FILL_PATH ,VG_LITE_DRAW_STROKE_PATH or + VG_LITE_DRAW_FILL_PATH | VG_LITE_DRAW_STROKE_PATH. + + @param path + Pointer to a vg_lite_path_t structure that describes the path. + + @param path_type + Pointer to a vg_lite_draw_path_type_t structure that describes the path. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_set_draw_path_type(vg_lite_path_t * path,vg_lite_draw_path_type_t path_type); + + /*! + @abstract Get the value of register from register's address. + + @discussion + This address will be the AHB Byte address of the register whose value you want to dump. + Refer to the Vivante AHB Register Specification document for register descriptions. + The valid range for VGLite cores is usually 0x0 to 0x1FF and 0xA00 to 0xA7F. + + @param address + Address of register which is needed to get its value. + + @param result + The register's value. + + */ + vg_lite_error_t vg_lite_get_register(uint32_t address, uint32_t *result); + + /* + @abstract Get the VGLite driver information. + + @param info + Pointer to vg_lite_info_t structure. + */ + void vg_lite_get_info(vg_lite_info_t *info); + + /* + @abstract Get the name of the VGLite Product. + + @param name + Character array to store the name of the chip. + + @param chip_id + Store the chip id. + + @param chip_rev + Store the chip revision number. + + @return + Length of the name string, including the ending '\0'. + */ + uint32_t vg_lite_get_product_info(char *name, uint32_t *chip_id, uint32_t *chip_rev); + + /*! + @abstract Queried whether the specified feature is available. + + @param feature + Feature to be verified. + + @return + The feature is supported (1) or not (0). + */ + uint32_t vg_lite_query_feature(vg_lite_feature_t feature); + + /*! + @abstract This api initializes a path object by given member values. + + @param path + The path object. + + @param data_format + The coordinate data format of the path. One of S8, S16, S32 and FP32. + + @param quality + The rendering quality (AA level) of the path. + + @param path_length + The memory length of the path data. + + @param path_data + The path data. + + @param min_x + The min x of the bounding box. + + @param min_y + The min y of the bounding box. + + @param max_x + The max x of the bounding box. + + @param max_y + The max y of the bounding box. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_init_path(vg_lite_path_t *path, + vg_lite_format_t data_format, + vg_lite_quality_t quality, + uint32_t path_length, + void *path_data, + vg_lite_float_t min_x, vg_lite_float_t min_y, + vg_lite_float_t max_x, vg_lite_float_t max_y); + + /*! + @abstract This api initializes a path object which include arc command by given member values. + + @param path + The path object. + + @param data_format + The coordinate data format of the path. Should be FP32. + + @param quality + The rendering quality (AA level) of the path. + + @param path_length + The memory length of the path data. + + @param path_data + The given path data which inlcude arc command. + + @param min_x + The min x of the bounding box. + + @param min_y + The min y of the bounding box. + + @param max_x + The max x of the bounding box. + + @param max_y + The max y of the bounding box. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_init_arc_path(vg_lite_path_t * path, + vg_lite_format_t data_format, + vg_lite_quality_t quality, + uint32_t path_length, + void * path_data, + vg_lite_float_t min_x, vg_lite_float_t min_y, + vg_lite_float_t max_x, vg_lite_float_t max_y); + + /*! + @abstract This api clears the path member values. + + @discussion It frees the hw memory if path was ever uploaded. + + @param path + The path object. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_clear_path(vg_lite_path_t *path); + + /*! + @abstract Calculate the path command buffer length (in bytes). + + @discussion The app should be response for allocating a buffer according to + the buffer length calculated by this function. Then the buffer is used by + the path as command buffer. The driver does not do allocation for the buffer. + + @param cmd + The opcode array to construct the path. + + @param count + The count of opcodes. + + @param format + The data format of the coordinate (VG_LITE_S8, S16, S32, FP32) + + @result + Return the actual length of the path command buffer. + */ + int32_t vg_lite_path_calc_length(uint8_t *cmd, + uint32_t count, + vg_lite_format_t format); + + /*! + @abstract Assemble the command buffer for the path. + + @discussion The command buffer is allocated by the application and assigned + to the path. The function make the final GPU command buffer for the path based + on the input opcodes (cmd) and coordinates (data). Note that the Application + must be responsible to alloate a big enough buffer for the path. + + @param path + The path object. + + @param cmd + The opcode array to construct the path. + + @param data + The coordinate data array to construct the path. + + @param seg_count + The count of the opcodes. + + */ + vg_lite_error_t vg_lite_path_append(vg_lite_path_t *path, + uint8_t *cmd, + void *data, + uint32_t seg_count); + + /*! + @abstract Upload a path to GPU memory. + + @discussion + In normal cases, the VGLite driver will copy any path data into a command buffer structure during runtime. This does take some + time if there are many paths to be rendered. Also, in an embedded system the path data wont change - so it makes sense to + upload the path data into GPU memory in such a form the GPU can directly access it. + + This function will allocate a buffer that will contain the path data and the required command buffer header and footer data for + the GPU to access the data directly. + + @param path + Pointer to a vg_lite_path_t structure that contains the path to be uploaded. Some fields in this structure will be + modified to point to a command buffer instead of the native path data. + + @result + A pointer to a vg_lite_buffer_t structure that contains the command buffer and path data after uploading it to GPU + memory. NULL is returned if there is an error. + */ + vg_lite_error_t vg_lite_upload_path(vg_lite_path_t *path); + + /*! + @abstract Set the current CLUT (Color Look Up Table) for index image to use. + + @discussion + This is a global context state. Once it's set (Not NULL), when an indexed format image is rendered, the image color will + be got from the CLUT by the image's pixels as indecies. + + @param count + This is the count of the colors in the look up table. + For index 1, up to 2 colors in the table; + For index 2, up to 4 colors in the table; + For index 4, up to 16 colors in the table; + For index 8, up to 256 colros in the table. + Driver is not responsible to check the validation of the CLUT. + + @param colors + This pointer is directly programmed to the command buffer. So it won't take effect + unless the command buffer is submitted. The color is in ARGB format with A staying at the high bits. + + @result + Error code. Currently always returns VG_LITE_SUCCESS since it does not do any checks. + */ + vg_lite_error_t vg_lite_set_CLUT(uint32_t count, + uint32_t *colors); + + /*! + @abstract Fill a path with an image pattern. + + @discussion + The specified path will be transformed by the given matrix and filled by the tranformed image pattern. + + @param path + Pointer to a vg_lite_path_t structure that describes the path to draw. + + @param fill_rule + Specified fill rule for the path. + + @param matrix0 + Pointer to a 3x3 matrix that defines the transformation matrix of the path. If matrix is NULL, an + identity matrix is assumed which is usually a bad idea since the path can be anything. + + @param source + Pointer to a vg_lite_buffer_t structure that describes the source of the image pattern. + + @param matrix1 + Pointer to a 3x3 matrix that defines the transformation matrix of source pixels into the target. If matrix is + NULL, an identity matrix is assumed. + + @param blend + The blending mode to be applied to each drawn pixel. If no blending is required, set this value to + VG_LITE_BLEND_NONE (0). + + @param pattern_mode + The tiling mode that applied to the pixels out of the image after transformed. + + @param pattern_color + The pattern_color applied by pattern_mode VG_LITE_PATTERN_COLOR. When pixels are out of the image after transformed, + they are applied "pattern_color". + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_draw_pattern(vg_lite_buffer_t *target, + vg_lite_path_t *path, + vg_lite_fill_t fill_rule, + vg_lite_matrix_t *matrix0, + vg_lite_buffer_t *source, + vg_lite_matrix_t *matrix1, + vg_lite_blend_t blend, + vg_lite_pattern_mode_t pattern_mode, + vg_lite_color_t pattern_color, + vg_lite_filter_t filter); + + /*! + @abstract Init the linear gradient object. + + @discussion + This API initialize the grad object to its default settings. Since grad has + an internal buffer object, this API will init the buffer object for rendering use. + + @param grad + This is the vg_lite_linear_gradient_t object to be initialized. + + @result + Error code, in case the buffer can't be created. + */ + vg_lite_error_t vg_lite_init_grad(vg_lite_linear_gradient_t *grad); + + /*! + @abstract Set the linear gradient members. + + @discussion + This API sets the values for the members of the gradient definition. + + @param grad + This is the vg_lite_linear_gradient_t object to be set. + + @param count + This is the count of the colors in grad. + The maxmum color stop count is defined by VLC_MAX_GRAD, which is currently 16. + + @param colors + This is the color array for the gradient stops. The color is in ARGB8888 format + with alpha at the higher byte. + + @result + Error code. VG_LITE_INVALID_ARGUMENTS to indicate the parameters are wrong. + */ + vg_lite_error_t vg_lite_set_grad(vg_lite_linear_gradient_t *grad, + uint32_t count, + uint32_t *colors, + uint32_t *stops); + + /*! + @abstract Set the radial gradient members. + + @discussion + This API sets the values for the members of the radial gradient definition. + + @param grad + This is the vg_lite_radial_gradient_t object to be set. + + @param count + This is the count of the colors in grad. + The maxmum color stop count is defined by MAX_COLOR_RAMP_STOPS, which is currently 256. + + @param vgColorRamp + This is the stop for the radial gradient.The number of parameters is 5,and give the offset and + color of the stop.Each stop is defined by a floating-point offset value and four floating-point values + containing the sRGBA color and alpha value associated with each stop, in the form of a non-premultiplied + (R, G, B, alpha) quad.And the range of all parameters in it is [0,1]. + + @param radialGradient + The radial gradient parameters are supplied as a vector of 5 floats in the order {cx,cy,fx,fy,r}. + the range of all parameters in it is [0,1].The meaning of the parameters in it is:(cx,cy) is center point, + (fx,fy) is focal point, and r is radius. + + @param SpreadMode + The tiling mode that applied to the pixels out of the paint after transformed. + + @param colorRampPremultiplied + The parameter controls whether color and alpha values are interpolated in premultiplied or non-premultiplied + form. + + @result + Error code. VG_LITE_INVALID_ARGUMENTS to indicate the parameters are wrong. + */ + vg_lite_error_t vg_lite_set_rad_grad(vg_lite_radial_gradient_t *grad, + uint32_t count, + vg_lite_color_ramp_t *vgColorRamp, + vg_lite_radial_gradient_parameter_t radialGradient, + vg_lite_radial_gradient_spreadmode_t SpreadMode, + uint8_t colorRampPremultiplied); + + /*! + @abstract Set the linear gradient members. + + @discussion + This API sets the values for the members of the linear gradient definition. + + @param grad + This is the vg_lite_linear_gradient_ext_t object to be set. + + @param count + This is the count of the colors in grad. + The maxmum color stop count is defined by MAX_COLOR_RAMP_STOPS, which is currently 256. + + @param vg_color_ramp + This is the stop for the linear gradient.The number of parameters is 5,and give the offset and + color of the stop.Each stop is defined by a floating-point offset value and four floating-point values + containing the sRGBA color and alpha value associated with each stop, in the form of a non-premultiplied + (R, G, B, alpha) quad.And the range of all parameters in it is [0,1]. + + @param linear_gradient + Refer to the definition by vg_lite_linear_gradient_parameter_t. + + @param spread_mode + The tiling mode that applied to the pixels out of the paint after transformed.Use tge same spread mode enumeration type as radial gradient. + + @param color_ramp_premultiplied + The parameter controls whether color and alpha values are interpolated in premultiplied or non-premultiplied + form. + + @result + Error code. VG_LITE_INVALID_ARGUMENTS to indicate the parameters are wrong. + */ + vg_lite_error_t vg_lite_set_linear_grad(vg_lite_linear_gradient_ext_t *grad, + uint32_t count, + vg_lite_color_ramp_t *vg_color_ramp, + vg_lite_linear_gradient_parameter_t linear_gradient, + vg_lite_radial_gradient_spreadmode_t spread_mode, + uint8_t color_ramp_premultiplied); + + /*! + @abstract Update or generate the corresponding image object to render with. + + @discussion + The vg_lite_linear_gradient_ext_t object has an image buffer which is used to render + the linear gradient paint. The image buffer will be create/updated by the corresponding + grad parameters. + + @param grad + This is the vg_lite_linear_gradient_ext_t object to be updated from. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_update_linear_grad(vg_lite_linear_gradient_ext_t *grad); + + /*! + @abstract Update or generate the corresponding image object to render with. + + @discussion + The vg_lite_linear_gradient_t object has an image buffer which is used to render + the gradient pattern. The image buffer will be create/updated by the corresponding + grad parameters. + + @param grad + This is the vg_lite_linear_gradient_t object to be upated from. + + @result + Error code. + */ + vg_lite_error_t vg_lite_update_grad(vg_lite_linear_gradient_t *grad); + + /*! + @abstract Update or generate the corresponding image object to render with. + + @discussion + The vg_lite_radial_gradient_t object has an image buffer which is used to render + the radial gradient paint. The image buffer will be create/updated by the corresponding + grad parameters. + + @param grad + This is the vg_lite_radial_gradient_t object to be upated from. + + @result + Error code. + */ + vg_lite_error_t vg_lite_update_rad_grad(vg_lite_radial_gradient_t *grad); + + /*! + @abstract Clear the gradient object. + + @discussion + This will reset the grad members and free the image buffer's memory. + + @param grad + This is the vg_lite_linear_gradient_t object to be cleared. + + @result + Error code. + */ + vg_lite_error_t vg_lite_clear_grad(vg_lite_linear_gradient_t *grad); + + /*! + @abstract Clear the radial gradient object. + + @discussion + This will reset the grad members and free the image buffer's memory. + + @param grad + This is the vg_lite_radial_gradient_t object to be cleared. + + @result + Error code. + */ + vg_lite_error_t vg_lite_clear_rad_grad(vg_lite_radial_gradient_t *grad); + + /*! + @abstract Clear the linear gradient object. + + @discussion + This will reset the grad members and free the image buffer's memory. + + @param grad + This is the vg_lite_linear_gradient_ext_t object to be cleared. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_clear_linear_grad(vg_lite_linear_gradient_ext_t *grad); + + /*! + @abstract Get the pointer to the grad object's matrix. + + @discussion + This function get the pointer to the gradient object's matrix. Thus the app + can manipulate the matrix to render the gradient path correctly. + + @param grad + This is the vg_lite_linear_gradient_t object where to get the matrix. + + @result + The pointer to the matrix. + */ + vg_lite_matrix_t * vg_lite_get_grad_matrix(vg_lite_linear_gradient_t *grad); + + /*! + @abstract Get the pointer to the grad object's matrix. + + @discussion + This function get the pointer to the gradient object's matrix. Thus the app + can manipulate the matrix to render the gradient path correctly. + + @param grad + This is the vg_lite_linear_gradient_ext_t object where to get the matrix. + + @result + The pointer to the matrix. + */ + vg_lite_matrix_t * vg_lite_get_linear_grad_matrix(vg_lite_linear_gradient_ext_t *grad); + + /*! + @abstract Get the pointer to the grad object's matrix. + + @discussion + This function get the pointer to the radial gradient object's matrix. Thus the app + can manipulate the matrix to render the radial gradient path correctly. + + @param grad + This is the vg_lite_radial_gradient_t object where to get the matrix. + + @result + The pointer to the matrix. + */ + vg_lite_matrix_t * vg_lite_get_rad_grad_matrix(vg_lite_radial_gradient_t *grad); + + /*! + @abstract Fill a path with an image pattern. + + @discussion + The specified path will be transformed by the given matrix and filled by the tranformed image pattern. + + @param path + Pointer to a vg_lite_path_t structure that describes the path to draw. + + @param fill_rule + Specified fill rule for the path. + + @param matrix0 + Pointer to a 3x3 matrix that defines the transformation matrix of the path. If matrix is NULL, an + identity matrix is assumed which is usually a bad idea since the path can be anything. + + @param grad + Pointer to the gradient object that will be filled the path with. + + @param blend + The blending mode to be applied to each drawn pixel. If no blending is required, set this value to + VG_LITE_BLEND_NONE (0). + + @param pattern_mode + The tiling mode that applied to the pixels out of the image after transformed. + + @param pattern_color + The pattern_color applied by pattern_mode VG_LITE_PATTERN_COLOR. When pixels are out of the image after transformed, + they are applied "pattern_color". + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_draw_gradient(vg_lite_buffer_t *target, + vg_lite_path_t *path, + vg_lite_fill_t fill_rule, + vg_lite_matrix_t *matrix, + vg_lite_linear_gradient_t *grad, + vg_lite_blend_t blend); + + /*! + @abstract Fill a path with a linear gradient. + + @discussion + The specified path will be transformed by the given matrix and filled by the tranformed linear gradient. + + @param path + Pointer to a vg_lite_path_t structure that describes the path to draw. + + @param fill_rule + Specified fill rule for the path. + + @param path_matrix + Pointer to a 3x3 matrix that defines the transformation matrix of the path. If matrix is NULL, an + identity matrix is assumed which is usually a bad idea since the path can be anything. + + @param grad + This is the vg_lite_linear_gradient_ext_t object to be set. + + @param paint_color + Specifies the paint color vg_lite_color_t RGBA value to applied by VG_LITE_RADIAL_GRADIENT_SPREAD_FILL,which set by fuction + vg_lite_set_linear_grad. When pixels are out of the image after transformed,this paint_color is applied to them,See enum + vg_lite_radial_gradient_spreadmode_t. + + @param blend + The blending mode to be applied to each drawn pixel. If no blending is required, set this value to + VG_LITE_BLEND_NONE (0). + + @param filter + Specified the filter mode vg_lite_filter_t enum value to be applied to each drawn pixel. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_draw_linear_gradient(vg_lite_buffer_t * target, + vg_lite_path_t * path, + vg_lite_fill_t fill_rule, + vg_lite_matrix_t * path_matrix, + vg_lite_linear_gradient_ext_t *grad, + vg_lite_color_t paint_color, + vg_lite_blend_t blend, + vg_lite_filter_t filter); + + /*! + @abstract Fill a path with a radial gradient. + + @discussion + The specified path will be transformed by the given matrix and filled by the tranformed radial gradient. + + @param path + Pointer to a vg_lite_path_t structure that describes the path to draw. + + @param fill_rule + Specified fill rule for the path. + + @param path_matrix + Pointer to a 3x3 matrix that defines the transformation matrix of the path. If matrix is NULL, an + identity matrix is assumed which is usually a bad idea since the path can be anything. + + @param grad + This is the vg_lite_radial_gradient_t object to be set. + + @param paint_color + Specifies the paint color vg_lite_color_t RGBA value to applied by VG_LITE_RADIAL_GRADIENT_SPREAD_FILL,which set by fuction + vg_lite_set_rad_grad. When pixels are out of the image after transformed,this paint_color is applied to them,See enum + vg_lite_radial_gradient_spreadmode_t. + + @param blend + The blending mode to be applied to each drawn pixel. If no blending is required, set this value to + VG_LITE_BLEND_NONE (0). + + @param filter + Specified the filter mode vg_lite_filter_t enum value to be applied to each drawn pixel. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_draw_radial_gradient(vg_lite_buffer_t * target, + vg_lite_path_t * path, + vg_lite_fill_t fill_rule, + vg_lite_matrix_t * path_matrix, + vg_lite_radial_gradient_t *grad, + vg_lite_color_t paint_color, + vg_lite_blend_t blend, + vg_lite_filter_t filter); + + /*! + @abstract Load an identity matrix. + + @discussion + Load an identity matrix into a matrix variable. + + @param matrix + Pointer to a vg_lite_matrix_t structure that will be loaded with an identity matrix. + */ + void vg_lite_identity(vg_lite_matrix_t *matrix); + + /*! + @abstract Translate a matrix. + + @discussion + Translate a matrix to a new position. + + @param x + X location of the transformation. + + @param y + Y location of the transformation. + + @param matrix + Pointer to a vg_lite_matrix_t structure that will be translated. + */ + void vg_lite_translate(vg_lite_float_t x, vg_lite_float_t y, vg_lite_matrix_t *matrix); + + /*! + @abstract Scale a matrix. + + @discussion + Scale a matrix in both x and y directions. + + @param scale_x + Horizontal scale. + + @param scale_y + Vertical scale. + + @param matrix + Pointer to a vg_lite_matrix_t structure that will be scaled. + */ + void vg_lite_scale(vg_lite_float_t scale_x, vg_lite_float_t scale_y, vg_lite_matrix_t *matrix); + + /*! + @abstract Rotate a matrix. + + @discussion + Rotate a matrix a certain number of degrees. + + @param degrees + Number of degrees to rotate the matrix around. Positive numbers rotate counter clock wise. + + @param matrix + Pointer to a vg_lite_matrix_t structure that will be rotated. + */ + void vg_lite_rotate(vg_lite_float_t degrees, vg_lite_matrix_t *matrix); + + /*! + @abstract Set the command buffer size. + + @discussion + In the rt device, the memory was limited, need to set the command buffer + size by the chip. + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_set_command_buffer_size(uint32_t size); + + /*! + @abstract Set scissor used for render target's boundary. + + @discussion + This function is used to set a scissor into render target so that the out region + of scissor boundary is not drawn. + + @param x, y, width, height + The scissor bounds which specifies the x, y, width, and height of the region. + + @result + Returns the status as defined by vg_lite_error_t.*/ + vg_lite_error_t vg_lite_set_scissor(int32_t x, int32_t y, int32_t width, int32_t height); + + /*! + @abstract Enable scissor. + + @result + Returns the status as defined by vg_lite_error_t.*/ + vg_lite_error_t vg_lite_enable_scissor(void); + + /*! + @abstract Disable scissor. + + @result + Returns the status as defined by vg_lite_error_t.*/ + vg_lite_error_t vg_lite_disable_scissor(void); + + /*! + @abstract query the remaining allocate contiguous video memory. + + @param size + This is a pointer to remaining allocate contiguous video memory. + + @result + Returns the status as defined by vg_lite_error_t.The result correctly returns VG_LITE_SUCCESS, + return VG_LITE_NO_CONTEXT if not initialized.*/ + vg_lite_error_t vg_lite_mem_avail(uint32_t *size); + + /*! + @abstract Enable premultiply. + + @result + Returns the status as defined by vg_lite_error_t.*/ + vg_lite_error_t vg_lite_enable_premultiply(void); + + /*! + @abstract Disable premultiply. + + @result + Returns the status as defined by vg_lite_error_t.*/ + vg_lite_error_t vg_lite_disable_premultiply(void); + + /*! + @abstract This api use to control dither function switch.Dither is turned off by default. + + @param enable + 0 means turn off the dither function. 1 means turn on the dither function. + + @result + Returns the status as defined by vg_lite_error_t. + */ + vg_lite_error_t vg_lite_set_dither(int enable); + + /*! + @abstract use to set the colorkey. + + @param colorkey + Defined by vg_lite_color_key4_t. + + @result + Returns the status as defined by vg_lite_error_t. + Possible return value in this function: + VG_LITE_SUCCESS,the result correctly + VG_LITE_NOT_SUPPORT, if not support colorkey.*/ + vg_lite_error_t vg_lite_set_color_key(vg_lite_color_key4_t colorkey); + +#endif /* VGLITE_VERSION_2_0 */ + + +/**************************** Capture ********************************************/ +#ifndef vgliteDUMP_PATH +# define vgliteDUMP_PATH "./" +#endif + +#ifndef vgliteDUMP_KEY +# define vgliteDUMP_KEY "process" +#endif + +#define DUMP_CAPTURE 0 + +#if DUMP_CAPTURE +void _SetDumpFileInfo(); + +vg_lite_error_t + vglitefDump( + char * String, + ... + ); +# define vglitemDUMP vglitefDump + +vg_lite_error_t + vglitefDumpBuffer( + char* Tag, + unsigned int Physical, + void * Logical, + unsigned int Offset, + size_t Bytes + ); +# define vglitemDUMP_BUFFER vglitefDumpBuffer +#else +inline static void __dummy_dump( + char * Message, + ... + ) +{ +} +# define vglitemDUMP __dummy_dump + +inline static void + __dummy_dump_buffer( + char* Tag, + unsigned int Physical, + void * Logical, + unsigned int Offset, + size_t Bytes + ) +{ +} +# define vglitemDUMP_BUFFER __dummy_dump_buffer +#endif +/**************************** Capture ********************************************/ + +#ifdef __cplusplus +} +#endif +#endif /* _vg_lite_h_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_flat.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_flat.c new file mode 100644 index 0000000000..1ebfd0a189 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_flat.c @@ -0,0 +1,535 @@ + +/**************************************************************************** +* +* Copyright Raph Levien 2022 +* Copyright Nicolas Silva 2022 +* Copyright NXP 2022 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +*****************************************************************************/ + +#include + +#include "vg_lite_flat.h" + +/* + * Stop IAR compiler from warning about implicit conversions from float to + * double + */ +#if (defined(__ICCARM__)) +#pragma diag_suppress = Pa205 +#endif + +#ifndef VG_CURVE_FLATTENING_TOLERANCE +#define VG_CURVE_FLATTENING_TOLERANCE 0.25 +#endif /* defined(VG_CURVE_FLATTENING_TOLERANCE) */ + +#define FABSF(x) ((vg_lite_float_t) fabs(x)) +#define SQRTF(x) ((vg_lite_float_t) sqrt(x)) +#define CEILF(x) ((vg_lite_float_t) ceil(x)) + +#define VG_LITE_ERROR_HANDLER(func) \ +if ((error = func) != VG_LITE_SUCCESS) \ +goto ErrorHandler + +/* Point flatten type for flattened line segments. */ +#define vgcFLATTEN_NO 0 +#define vgcFLATTEN_START 1 +#define vgcFLATTEN_MIDDLE 2 +#define vgcFLATTEN_END 3 + +/* + * Algorithm originally created by Raph Levien: + * https://raphlinus.github.io/graphics/curves/2019/12/23/flatten-quadbez.html + */ + +#define FHYPOTF(x, y) ((vg_lite_float_t) hypotf(x, y)) +#define FPOWF(x, y) ((vg_lite_float_t) powf(x, y)) + +/* + * Contains the fields that are used to represent the quadratic Bezier curve + * as a 'y = x^2' parabola. + */ +typedef struct parabola_approx { + vg_lite_float_t x0; + vg_lite_float_t x2; + vg_lite_float_t scale; + vg_lite_float_t cross; +} parabola_approx_t; + +/* + * Keeps the quadratic Bezier's control points. This makes life easier when + * passing quadratics as parameters, so we don't have to give 6 floats every + * time. + */ +typedef struct quad_bezier { + vg_lite_float_t X0; + vg_lite_float_t Y0; + vg_lite_float_t X1; + vg_lite_float_t Y1; + vg_lite_float_t X2; + vg_lite_float_t Y2; +} quad_bezier_t; + +/* + * Parameters which are used by the flattening algorithm. + */ +typedef struct quad_bezier_flatten_params { + vg_lite_float_t a0; + vg_lite_float_t a2; + int num_points; + vg_lite_float_t u0; + vg_lite_float_t u2; +} quad_bezier_flatten_params_t; + +/* + * Keeps the cubic Bezier's control points. + */ +typedef struct cubic_bezier { + vg_lite_float_t X0; + vg_lite_float_t Y0; + vg_lite_float_t X1; + vg_lite_float_t Y1; + vg_lite_float_t X2; + vg_lite_float_t Y2; + vg_lite_float_t X3; + vg_lite_float_t Y3; +} cubic_bezier_t; + + +vg_lite_error_t _add_point_to_point_list( + vg_lite_stroke_conversion_t * stroke_conversion, + vg_lite_float_t X, + vg_lite_float_t Y, + uint8_t flatten_flag); + +vg_lite_error_t _add_point_to_point_list_wdelta( + vg_lite_stroke_conversion_t * stroke_conversion, + vg_lite_float_t X, + vg_lite_float_t Y, + vg_lite_float_t DX, + vg_lite_float_t DY, + uint8_t flatten_flag); + + +/* + * Evaluates the Bernstein polynomial that represents the curve, at 't'. + * 't' should be a value between 0.0 and 1.0 (though it can be any float, but + * the relevant values are between 0 and 1). + * 'x' and 'y' will contain the coordinates of the evaluated point. + */ +static void quad_bezier_eval( + const quad_bezier_t *q, + vg_lite_float_t t, + vg_lite_float_t *x, + vg_lite_float_t *y + ) +{ + const vg_lite_float_t omt = 1.0 - t; + *x = q->X0 * omt * omt + 2.0 * q->X1 * t * omt + q->X2 * t * t; + *y = q->Y0 * omt * omt + 2.0 * q->Y1 * t * omt + q->Y2 * t * t; +} + +/* + * Approximates the integral which uses the arclength and curvature of the + * parabola. + */ +static vg_lite_float_t approx_integral(vg_lite_float_t x) +{ + const vg_lite_float_t D = 0.67; + return x / (1.0 - D + FPOWF(FPOWF(D, 4) + 0.25 * x * x, 0.25)); +} + +/* + * Approximates the inverse of the previous integral. + */ +static vg_lite_float_t approx_inverse_integral(vg_lite_float_t x) +{ + const vg_lite_float_t B = 0.39; + return x * (1.0 - B + SQRTF(B * B + 0.25 * x * x)); +} + +/* + * Represents a quadratic Bezier curve as a parabola. + */ +static parabola_approx_t map_to_parabola(const quad_bezier_t *q) +{ + const vg_lite_float_t ddx = 2 * q->X1 - q->X0 - q->X2; + const vg_lite_float_t ddy = 2 * q->Y1 - q->Y0 - q->Y2; + const vg_lite_float_t u0 = (q->X1 - q->X0) * ddx + (q->Y1 - q->Y0) * ddy; + const vg_lite_float_t u2 = (q->X2 - q->X1) * ddx + (q->Y2 - q->Y1) * ddy; + const vg_lite_float_t cross = (q->X2 - q->X0) * ddy - (q->Y2 - q->Y0) * ddx; + const vg_lite_float_t x0 = u0 / cross; + const vg_lite_float_t x2 = u2 / cross; + const vg_lite_float_t scale = FABSF(cross) / (FHYPOTF(ddx, ddy) * FABSF(x2 - x0)); + + return (parabola_approx_t) { + .x0 = x0, + .x2 = x2, + .scale = scale, + .cross = cross + }; +} + +/* + * Tolerance influences the number of lines generated. The lower the tolerance, + * the more lines it generates, thus the flattening will have a higher quality, + * but it will also consume more memory. The bigger the tolerance, the less lines + * will be generated, so the quality will be worse, but the memory consumption + * will be better. + * + * A good default value could be 0.25. + */ +static quad_bezier_flatten_params_t quad_bezier_flatten_params_init( + const quad_bezier_t *q, + vg_lite_float_t tolerance + ) +{ + const parabola_approx_t params = map_to_parabola(q); + const vg_lite_float_t a0 = approx_integral(params.x0); + const vg_lite_float_t a2 = approx_integral(params.x2); + const vg_lite_float_t count = 0.5 * FABSF(a2 - a0) * SQRTF(params.scale / tolerance); + const int num_points = (int)CEILF(count); + const vg_lite_float_t u0 = approx_inverse_integral(a0); + const vg_lite_float_t u2 = approx_inverse_integral(a2); + + return (quad_bezier_flatten_params_t) { + .a0 = a0, + .a2 = a2, + .num_points = num_points, + .u0 = u0, + .u2 = u2 + }; +} + +/* + * Puts into (x, y) the coordinate to which a line should be drawn given the step. + * This should be used in a loop to flatten a curve, like this: + * ``` + * params = quad_bezier_flatten_params_init(&q, tolerance); + * for (int i = 1; i < params.num_points; ++i) { + * vg_lite_float_t x, y; + * quad_bezier_flatten_at(&q, ¶ms, i, &x, &y); + * draw_line_to(x, y); + * } + * ``` + */ +static void quad_bezier_flatten_at( + const quad_bezier_t *q, + const quad_bezier_flatten_params_t *params, + int step, + vg_lite_float_t *x, + vg_lite_float_t *y + ) +{ + const vg_lite_float_t a0 = params->a0, a2 = params->a2, u0 = params->u0, u2 = params->u2; + const int num_points = params->num_points; + const vg_lite_float_t u = approx_inverse_integral(a0 + ((a2 - a0) * step) / num_points); + const vg_lite_float_t t = (u - u0) / (u2 - u0); + + quad_bezier_eval(q, t, x, y); +} + +vg_lite_error_t +_flatten_quad_bezier( + vg_lite_stroke_conversion_t *stroke_conversion, + vg_lite_float_t X0, + vg_lite_float_t Y0, + vg_lite_float_t X1, + vg_lite_float_t Y1, + vg_lite_float_t X2, + vg_lite_float_t Y2 + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + vg_lite_path_point_ptr point0, point1; + vg_lite_float_t x, y; + + const vg_lite_float_t tolerance = VG_CURVE_FLATTENING_TOLERANCE; + const quad_bezier_t q = { + .X0 = X0, + .Y0 = Y0, + .X1 = X1, + .Y1 = Y1, + .X2 = X2, + .Y2 = Y2 + }; + const quad_bezier_flatten_params_t params = quad_bezier_flatten_params_init(&q, tolerance); + + if(!stroke_conversion) + return VG_LITE_INVALID_ARGUMENT; + + /* Add extra P0 for incoming tangent. */ + point0 = stroke_conversion->path_last_point; + /* First add P1 to calculate incoming tangent, which is saved in P0. */ + VG_LITE_ERROR_HANDLER(_add_point_to_point_list(stroke_conversion, X1, Y1, vgcFLATTEN_START)); + + point1 = stroke_conversion->path_last_point; + /* Change the point1's coordinates back to P0. */ + point1->x = X0; + point1->y = Y0; + point0->length = 0.0f; + + for (int i = 1; i < params.num_points; ++i) { + quad_bezier_flatten_at(&q, ¶ms, i, &x, &y); + _add_point_to_point_list(stroke_conversion, x, y, vgcFLATTEN_MIDDLE); + } + + /* Add point 2 separately to avoid cumulative errors. */ + VG_LITE_ERROR_HANDLER(_add_point_to_point_list(stroke_conversion, X2, Y2, vgcFLATTEN_END)); + + /* Add extra P2 for outgoing tangent. */ + /* First change P2(point0)'s coordinates to P1. */ + point0 = stroke_conversion->path_last_point; + point0->x = X1; + point0->y = Y1; + + /* Add P2 to calculate outgoing tangent. */ + VG_LITE_ERROR_HANDLER(_add_point_to_point_list(stroke_conversion, X2, Y2, vgcFLATTEN_NO)); + + point1 = stroke_conversion->path_last_point; + + /* Change point0's coordinates back to P2. */ + point0->x = X2; + point0->y = Y2; + point0->length = 0.0f; + +ErrorHandler: + return error; +} + +/* + * Like eval_quad_bezier, computes the coordinates of the point which resides at + * `t` for the cubic. + */ +static void cubic_bezier_eval( + const cubic_bezier_t *c, + vg_lite_float_t t, + vg_lite_float_t *x, + vg_lite_float_t *y + ) +{ + const vg_lite_float_t omt = 1.0 - t; + const vg_lite_float_t omt2 = omt * omt; + const vg_lite_float_t omt3 = omt * omt2; + const vg_lite_float_t t2 = t * t; + const vg_lite_float_t t3 = t * t2; + + *x = omt3 * c->X0 + 3.0 * t * omt2 * c->X1 + 3.0 * t2 * omt * c->X2 + t3 * c->X3; + *y = omt3 * c->Y0 + 3.0 * t * omt2 * c->Y1 + 3.0 * t2 * omt * c->Y2 + t3 * c->Y3; +} + +static quad_bezier_t cubic_bezier_derivative(const cubic_bezier_t *c) +{ + const vg_lite_float_t x0 = 3.0 * (c->X1 - c->X0); + const vg_lite_float_t y0 = 3.0 * (c->Y1 - c->Y0); + const vg_lite_float_t x1 = 3.0 * (c->X2 - c->X1); + const vg_lite_float_t y1 = 3.0 * (c->Y2 - c->Y1); + const vg_lite_float_t x2 = 3.0 * (c->X3 - c->X2); + const vg_lite_float_t y2 = 3.0 * (c->Y3 - c->Y2); + + return (quad_bezier_t) { + .X0 = x0, + .Y0 = y0, + .X1 = x1, + .Y1 = y1, + .X2 = x2, + .Y2 = y2 + }; +} + +/* + * Returns the cubic bezier that is between t0 and t1 of c. + */ +static cubic_bezier_t cubic_bezier_split_at( + const cubic_bezier_t *c, + vg_lite_float_t t0, + vg_lite_float_t t1 + ) +{ + vg_lite_float_t p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y, d1x, d1y, d2x, d2y; + vg_lite_float_t scale; + quad_bezier_t derivative; + + cubic_bezier_eval(c, t0, &p0x, &p0y); + cubic_bezier_eval(c, t1, &p3x, &p3y); + derivative = cubic_bezier_derivative(c); + scale = (t1 - t0) * (1.0 / 3.0); + quad_bezier_eval(&derivative, t0, &d1x, &d1y); + quad_bezier_eval(&derivative, t1, &d2x, &d2y); + p1x = p0x + scale * d1x; + p1y = p0y + scale * d1y; + p2x = p3x - scale * d2x; + p2y = p3y - scale * d2y; + + return (cubic_bezier_t) { + .X0 = p0x, + .Y0 = p0y, + .X1 = p1x, + .Y1 = p1y, + .X2 = p2x, + .Y2 = p2y, + .X3 = p3x, + .Y3 = p3y + }; +} + +/* + * This function returns the number of quadratic Bezier curves that are needed to + * represent the given cubic, respecting the tolerance. + * + * As with the flattening of quadratics, the lower the tolerance, the better the + * quality. The higher the tolerance, the worse the quality, but better performance + * or memory consumption. + * + * The algorithm comes from: + * https://web.archive.org/web/20210108052742/http://caffeineowl.com/graphics/2d/vectorial/cubic2quad01.html + * + * Implementation adapted from: + * https://github.com/linebender/kurbo/blob/master/src/cubicbez.rs + * and: + * https://scholarsarchive.byu.edu/cgi/viewcontent.cgi?article=1000&context=facpub#section.10.6 + */ +static int cubic_bezier_get_flatten_count( + const cubic_bezier_t *c, + vg_lite_float_t tolerance + ) +{ + const vg_lite_float_t x = c->X0 - 3.0 * c->X1 + 3.0 * c->X2 - c->X3; + const vg_lite_float_t y = c->Y0 - 3.0 * c->Y1 + 3.0 * c->Y2 - c->Y3; + const vg_lite_float_t err = x * x + y * y; + vg_lite_float_t result; + + result = FPOWF(err / (432.0 * tolerance * tolerance), 1.0 / 6.0); + result = CEILF(result); + + return result > 1.0 ? (int)result : 1; +} + +vg_lite_error_t +_flatten_cubic_bezier( + vg_lite_stroke_conversion_t * stroke_conversion, + vg_lite_float_t X0, + vg_lite_float_t Y0, + vg_lite_float_t X1, + vg_lite_float_t Y1, + vg_lite_float_t X2, + vg_lite_float_t Y2, + vg_lite_float_t X3, + vg_lite_float_t Y3 + ) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + vg_lite_path_point_ptr point0, point1; + const cubic_bezier_t c = { + .X0 = X0, + .Y0 = Y0, + .X1 = X1, + .Y1 = Y1, + .X2 = X2, + .Y2 = Y2, + .X3 = X3, + .Y3 = Y3 + }; + const vg_lite_float_t tolerance = VG_CURVE_FLATTENING_TOLERANCE; + int num_curves = cubic_bezier_get_flatten_count(&c, tolerance); + vg_lite_float_t fnum_curves = (vg_lite_float_t)num_curves; + vg_lite_float_t fi, t0, t1, p1x, p1y, p2x, p2y, x, y; + cubic_bezier_t subsegment; + quad_bezier_t current_curve; + quad_bezier_flatten_params_t params; + + if(!stroke_conversion) + return VG_LITE_INVALID_ARGUMENT; + + /* Add extra P0 for incoming tangent. */ + point0 = stroke_conversion->path_last_point; + /* First add P1/P2/P3 to calculate incoming tangent, which is saved in P0. */ + if (X0 != X1 || Y0 != Y1) + { + VG_LITE_ERROR_HANDLER(_add_point_to_point_list(stroke_conversion, X1, Y1, vgcFLATTEN_START)); + } + else if (X0 != X2 || Y0 != Y2) + { + VG_LITE_ERROR_HANDLER(_add_point_to_point_list(stroke_conversion, X2, Y2, vgcFLATTEN_START)); + } + else + { + VG_LITE_ERROR_HANDLER(_add_point_to_point_list(stroke_conversion, X3, Y3, vgcFLATTEN_START)); + } + point1 = stroke_conversion->path_last_point; + /* Change the point1's coordinates back to P0. */ + point1->x = X0; + point1->y = Y0; + point0->length = 0.0f; + + for (int i = 0; i < num_curves; ++i) { + fi = (vg_lite_float_t)i; + t0 = fi / fnum_curves; + t1 = (fi + 1.0) / fnum_curves; + subsegment = cubic_bezier_split_at(&c, t0, t1); + p1x = 3.0 * subsegment.X1 - subsegment.X0; + p1y = 3.0 * subsegment.Y1 - subsegment.Y0; + p2x = 3.0 * subsegment.X2 - subsegment.X3; + p2y = 3.0 * subsegment.Y2 - subsegment.Y3; + current_curve = (quad_bezier_t) { + .X0 = subsegment.X0, + .Y0 = subsegment.Y0, + .X1 = (p1x + p2x) / 4.0, + .Y1 = (p1y + p2y) / 4.0, + .X2 = subsegment.X3, + .Y2 = subsegment.Y3 + }; + params = quad_bezier_flatten_params_init(¤t_curve, tolerance); + for (int j = 0; j < params.num_points; ++j) { + quad_bezier_flatten_at(¤t_curve, ¶ms, j, &x, &y); + _add_point_to_point_list(stroke_conversion, x, y, vgcFLATTEN_MIDDLE); + } + } + + /* Add point 3 separately to avoid cumulative errors. */ + VG_LITE_ERROR_HANDLER(_add_point_to_point_list(stroke_conversion, X3, Y3, vgcFLATTEN_END)); + + /* Add extra P3 for outgoing tangent. */ + /* First change P3(point0)'s coordinates to P0/P1/P2. */ + point0 = stroke_conversion->path_last_point; + if (X3 != X2 || Y3 != Y2) + { + point0->x = X2; + point0->y = Y2; + } + else if (X3 != X1 || Y3 != Y1) + { + point0->x = X1; + point0->y = Y1; + } + else + { + point0->x = X0; + point0->y = Y0; + } + + /* Add P3 to calculate outgoing tangent. */ + VG_LITE_ERROR_HANDLER(_add_point_to_point_list(stroke_conversion, X3, Y3, vgcFLATTEN_NO)); + + point1 = stroke_conversion->path_last_point; + + /* Change point0's coordinates back to P3. */ + point0->x = X3; + point0->y = Y3; + point0->length = 0.0f; + +ErrorHandler: + return error; +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_flat.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_flat.h new file mode 100644 index 0000000000..e0b4024756 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_flat.h @@ -0,0 +1,55 @@ + +/**************************************************************************** +* +* Copyright Raph Levien 2022 +* Copyright Nicolas Silva 2022 +* Copyright NXP 2022 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +*****************************************************************************/ + +#ifndef _vg_lite_flat_h_ +#define _vg_lite_flat_h_ + +#include "vg_lite.h" + +#ifdef __cplusplus +extern "C" { +#endif + +vg_lite_error_t _flatten_quad_bezier( + vg_lite_stroke_conversion_t *stroke_conversion, + vg_lite_float_t X0, + vg_lite_float_t Y0, + vg_lite_float_t X1, + vg_lite_float_t Y1, + vg_lite_float_t X2, + vg_lite_float_t Y2); + +vg_lite_error_t _flatten_cubic_bezier( + vg_lite_stroke_conversion_t * stroke_conversion, + vg_lite_float_t X0, + vg_lite_float_t Y0, + vg_lite_float_t X1, + vg_lite_float_t Y1, + vg_lite_float_t X2, + vg_lite_float_t Y2, + vg_lite_float_t X3, + vg_lite_float_t Y3); + +#ifdef __cplusplus +} +#endif + +#endif /* _vg_lite_flat_h_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hal.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hal.c new file mode 100644 index 0000000000..729f11282f --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hal.c @@ -0,0 +1,499 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright (c) 2014 - 2020 Vivante Corporation +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#include "vg_lite_platform.h" +#include "vg_lite_kernel.h" +#include "vg_lite_hal.h" +#include "vg_lite_hw.h" +#include "vg_lite_os.h" + +#if !_BAREMETAL +#include "rtthread.h" +#else +#include "xil_cache.h" +#endif + +#if _BAREMETAL +/* The followings should be configured by FPGA. */ +static uint32_t registerMemBase = 0x43c80000; +#else +static uint32_t registerMemBase = 0x40240000; +#endif + +#define HEAP_NODE_USED 0xABBAF00D + +volatile void* contiguousMem = NULL; +uint32_t gpuMemBase = 0; + +/* Default heap size is 16MB. */ +static int heap_size = MAX_CONTIGUOUS_SIZE; + +void vg_lite_init_mem(uint32_t register_mem_base, + uint32_t gpu_mem_base, + volatile void * contiguous_mem_base, + uint32_t contiguous_mem_size) +{ + registerMemBase = register_mem_base; + gpuMemBase = gpu_mem_base; + contiguousMem = contiguous_mem_base; + heap_size = contiguous_mem_size; +} + +/* Implementation of list. ****************************************/ +typedef struct list_head { + struct list_head *next; + struct list_head *prev; +}list_head_t; + +#define INIT_LIST_HEAD(entry) \ + (entry)->next = (entry);\ + (entry)->prev = (entry); + +/* Add the list item in front of "head". */ +static inline void add_list(list_head_t *to_add, list_head_t *head) +{ + /* Link the new item. */ + to_add->next = head; + to_add->prev = head->prev; + + /* Modify the neighbor. */ + head->prev = to_add; + if (to_add->prev != NULL) { + to_add->prev->next = to_add; + } +} + +/* Remove an entry out of the list. */ +static inline void delete_list(list_head_t *entry) +{ + if (entry->prev != NULL) { + entry->prev->next = entry->next; + } + if (entry->next != NULL) { + entry->next->prev = entry->prev; + } +} + +/* End of list implementation. ***********/ +static inline void _memset(void *mem, unsigned char value, int size) +{ + int i; + for (i = 0; i < size; i++) { + ((unsigned char*)mem)[i] = value; + } +} + +typedef struct heap_node { + list_head_t list; /* TODO: Linux specific, needs to rewrite. */ + uint32_t offset; + unsigned long size; + uint32_t status; +}heap_node_t; + +struct memory_heap { + uint32_t free; + list_head_t list; +}; + +struct mapped_memory { + void * logical; + uint32_t physical; + int page_count; + struct page ** pages; +}; + +struct vg_lite_device { + /* void * gpu; */ + uint32_t gpu; /* Always use physical for register access in RTOS. */ + /* struct page * pages; */ + volatile void * contiguous; + unsigned int order; + unsigned int heap_size; + void * virtual; + uint32_t physical; + uint32_t size; + struct memory_heap heap; + int irq_enabled; + +#if defined(VG_DRIVER_SINGLE_THREAD) + volatile uint32_t int_flags; +#if _BAREMETAL + /* wait_queue_head_t int_queue; */ + xSemaphoreHandle int_queue; +#else + /* wait_queue_head_t int_queue; */ + rt_sem_t int_queue; +#endif +#endif /* VG_DRIVER_SINGLE_THREAD */ + + void * device; + int registered; + int major; + struct class * class; + int created; +}; + +struct client_data { + struct vg_lite_device * device; + struct vm_area_struct * vm; + void * contiguous_mapped; +}; + +static struct vg_lite_device Device, * device; + +void vg_lite_hal_delay(uint32_t ms) +{ + vg_lite_os_sleep(ms); +} + +void vg_lite_hal_barrier(void) +{ + /*Memory barrier. */ +#if _BAREMETAL + Xil_DCacheFlush(); +#else + __asm("DSB"); +#endif +} + +static int vg_lite_init(void); +vg_lite_error_t vg_lite_hal_initialize(void) +{ + int32_t error = VG_LITE_SUCCESS; + /* TODO: Turn on the power. */ + vg_lite_init(); + /* TODO: Turn on the clock. */ + error = vg_lite_os_initialize(); + + return (vg_lite_error_t)error; +} + +void vg_lite_hal_deinitialize(void) +{ + /* TODO: Remove clock. */ + vg_lite_os_deinitialize(); + /* TODO: Remove power. */ +} + +static int split_node(heap_node_t * node, unsigned long size) +{ + /* TODO: the original is linux specific list based, needs rewrite. + */ + heap_node_t * split; + + /* + * If the newly allocated object fits exactly the size of the free + * node, there is no need to split. + */ + if (node->size - size == 0) + return 0; + + /* Allocate a new node. */ + split = (heap_node_t *)vg_lite_os_malloc(sizeof(heap_node_t)); + + if (split == NULL) + return -1; + + /* Fill in the data of this node of the remaning size. */ + split->offset = node->offset + size; + split->size = node->size - size; + split->status = 0; + + /* Add the new node behind the current node. */ + add_list(&split->list, &node->list); + + /* Adjust the size of the current node. */ + node->size = size; + return 0; +} + +vg_lite_error_t vg_lite_hal_allocate_contiguous(unsigned long size, void ** logical, uint32_t * physical,void ** node) +{ + unsigned long aligned_size; + heap_node_t * pos; + + /* Align the size to 64 bytes. */ + aligned_size = (size + 63) & ~63; + + /* Check if there is enough free memory available. */ + if (aligned_size > device->heap.free) { + return VG_LITE_OUT_OF_MEMORY; + } + + /* Walk the heap backwards. */ + for (pos = (heap_node_t*)device->heap.list.prev; + &pos->list != &device->heap.list; + pos = (heap_node_t*) pos->list.prev) { + /* Check if the current node is free and is big enough. */ + if (pos->status == 0 && pos->size >= aligned_size) { + /* See if we the current node is big enough to split. */ + if (0 != split_node(pos, aligned_size)) + { + return VG_LITE_OUT_OF_RESOURCES; + } + /* Mark the current node as used. */ + pos->status = HEAP_NODE_USED; + + /* Return the logical/physical address. */ + /* *logical = (uint8_t *) private_data->contiguous_mapped + pos->offset; */ + *logical = (uint8_t *)device->virtual + pos->offset; + *physical = gpuMemBase + (uint32_t)(*logical);/* device->physical + pos->offset; */ + device->heap.free -= aligned_size; + + *node = pos; + return VG_LITE_SUCCESS; + } + } + + /* Out of memory. */ + return VG_LITE_OUT_OF_MEMORY; +} + +void vg_lite_hal_free_contiguous(void * memory_handle) +{ + /* TODO: no list available in RTOS. */ + heap_node_t * pos, * node; + + /* Get pointer to node. */ + node = memory_handle; + + if (node->status != HEAP_NODE_USED) { + return; + } + + /* Mark node as free. */ + node->status = 0; + + /* Add node size to free count. */ + device->heap.free += node->size; + + /* Check if next node is free. */ + pos = node; + for (pos = (heap_node_t *)pos->list.next; + &pos->list != &device->heap.list; + pos = (heap_node_t *)pos->list.next) { + if (pos->status == 0) { + /* Merge the nodes. */ + node->size += pos->size; + if(node->offset > pos->offset) + node->offset = pos->offset; + /* Delete the next node from the list. */ + delete_list(&pos->list); + vg_lite_os_free(pos); + } + break; + } + + /* Check if the previous node is free. */ + pos = node; + for (pos = (heap_node_t *)pos->list.prev; + &pos->list != &device->heap.list; + pos = (heap_node_t *)pos->list.prev) { + if (pos->status == 0) { + /* Merge the nodes. */ + pos->size += node->size; + if(pos->offset > node->offset) + pos->offset = node->offset; + /* Delete the current node from the list. */ + delete_list(&node->list); + vg_lite_os_free(node); + } + break; + } + /* when release command buffer node and ts buffer node to exit,release the linked list*/ + if(device->heap.list.next == device->heap.list.prev) { + delete_list(&pos->list); + vg_lite_os_free(pos); + } +} + +void vg_lite_hal_free_os_heap(void) +{ + struct heap_node *pos, *n; + + /* Check for valid device. */ + if (device != NULL) { + /* Process each node. */ + for (pos = (heap_node_t *)device->heap.list.next, + n = (heap_node_t *)pos->list.next; + &pos->list != &device->heap.list; + pos = n, n = (heap_node_t *)n->list.next) { + /* Remove it from the linked list. */ + delete_list(&pos->list); + /* Free up the memory. */ + vg_lite_os_free(pos); + } + } +} + +/* Portable: read register value. */ +uint32_t vg_lite_hal_peek(uint32_t address) +{ + /* Read data from the GPU register. */ + return (uint32_t) (*(volatile uint32_t *) (device->gpu + address)); +} + +/* Portable: write register. */ +void vg_lite_hal_poke(uint32_t address, uint32_t data) +{ + /* Write data to the GPU register. */ + uint32_t *LocalAddr = (uint32_t *)(device->gpu + address); + *LocalAddr = data; +} + +vg_lite_error_t vg_lite_hal_query_mem(vg_lite_kernel_mem_t *mem) +{ + if(device != NULL){ + mem->bytes = device->heap.free; + return VG_LITE_SUCCESS; + } + mem->bytes = 0; + return VG_LITE_NO_CONTEXT; +} + +void vg_lite_IRQHandler(void) +{ + vg_lite_os_IRQHandler(); +} + +int32_t vg_lite_hal_wait_interrupt(uint32_t timeout, uint32_t mask, uint32_t * value) +{ + return vg_lite_os_wait_interrupt(timeout,mask,value); +} + +void * vg_lite_hal_map(unsigned long bytes, void * logical, uint32_t physical, uint32_t * gpu) +{ + + (void) bytes; + (void) logical; + (void) physical; + (void) gpu; + return (void *)0; +} + +void vg_lite_hal_unmap(void * handle) +{ + + (void) handle; +} + +#if !defined(VG_DRIVER_SINGLE_THREAD) +vg_lite_error_t vg_lite_hal_submit(uint32_t context,uint32_t physical, uint32_t offset, uint32_t size, vg_lite_os_async_event_t *event) +{ + return (vg_lite_error_t)vg_lite_os_submit(context,physical,offset,size,event); +} + +vg_lite_error_t vg_lite_hal_wait(uint32_t timeout, vg_lite_os_async_event_t *event) +{ + return (vg_lite_error_t)vg_lite_os_wait(timeout,event); +} +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +static void vg_lite_exit(void) +{ + heap_node_t * pos; + heap_node_t * n; + + /* Check for valid device. */ + if (device != NULL) { + /* TODO: unmap register mem should be unnecessary. */ + device->gpu = 0; + + /* Process each node. */ + for (pos = (heap_node_t *)device->heap.list.next, n = (heap_node_t *)pos->list.next; + &pos->list != &device->heap.list; + pos = n, n = (heap_node_t *)n->list.next) { + /* Remove it from the linked list. */ + delete_list(&pos->list); + + /* Free up the memory. */ + vg_lite_os_free(pos); + } + + /* Free up the device structure. */ + vg_lite_os_free(device); + } +} + +static int vg_lite_init(void) +{ + heap_node_t * node; + + /* Initialize memory and objects ***************************************/ + /* Create device structure. */ + device = &Device; + + /* Zero out the enture structure. */ + _memset(device, 0, sizeof(struct vg_lite_device)); + + /* Setup register memory. **********************************************/ + device->gpu = registerMemBase; + + /* Initialize contiguous memory. ***************************************/ + /* Allocate the contiguous memory. */ + device->heap_size = heap_size; + device->contiguous = (volatile void *)contiguousMem; + _memset((void *)device->contiguous, 0, heap_size); + /* Make 64byte aligned. */ + while ((((uint32_t)device->contiguous) & 63) != 0) + { + device->contiguous = ((unsigned char*) device->contiguous) + 4; + device->heap_size -= 4; + } + + /* Check if we allocated any contiguous memory or not. */ + if (device->contiguous == NULL) { + vg_lite_exit(); + return -1; + } + + device->virtual = (void *)device->contiguous; + device->physical = gpuMemBase + (uint32_t)device->virtual; + device->size = device->heap_size; + + /* Create the heap. */ + INIT_LIST_HEAD(&device->heap.list); + device->heap.free = device->size; + + node = (heap_node_t *)vg_lite_os_malloc(sizeof(heap_node_t)); + + if (node == NULL) { + vg_lite_exit(); + return -1; + } + node->offset = 0; + node->size = device->size; + node->status = 0; + add_list(&node->list, &device->heap.list); +#if defined(VG_DRIVER_SINGLE_THREAD) +#if !_BAREMETAL /*for rt500*/ + device->int_queue = rt_sem_create("diq", 0, RT_IPC_FLAG_PRIO); + device->int_flags = 0; +#endif +#endif /* VG_DRIVER_SINGLE_THREAD */ + /* Success. */ + return 0; +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hal.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hal.h new file mode 100644 index 0000000000..b4cd3e3418 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hal.h @@ -0,0 +1,272 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright 2012 - 2020 Vivante Corporation, Santa Clara, California. +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#ifndef _vg_lite_hal_h_ +#define _vg_lite_hal_h_ + +#include "vg_lite_platform.h" +#include "vg_lite_os.h" +#include "vg_lite_kernel.h" + +#define VGLITE_MEM_ALIGNMENT 128 +#define THREAD_LENGTH 8 + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + @brief Wait a number of milliseconds. + + @discussion + The VGLite hardware requires some waiting when changing clock frequencies or issuing a reset. This is the wrapper function + for the delay function. + + @param milliseconds + The number of milliseconds to wait. + */ +void vg_lite_hal_delay(uint32_t milliseconds); + +/*! + @brief Initialize the hardware. + + @discussion + The VGLite kernel knows how to program its own hardware, but in any SOC there might be additional control required for + turning on the power or initializing the clocks. This function gets called by the VGLite kernel before the VGLite graphics + hardware gets initialized by the VGLite kernel itself and allows for SOC power management control. + + The implementer should make sure that on exit of this function the power and clock to the VGLite graphics hardware is + turned on and stable. + */ +vg_lite_error_t vg_lite_hal_initialize(void); + +/*! + @brief Uninitialize the hardware. + + @discussion + The VGLite kernel knows how to program its own hardware, but in any SOC there might be additional control required for + turning off the power or uninitializing the clocks. This function gets called by the VGLite kernel after the VGLite + graphics hardware gets uninitialized by the VGLite kernel itself and allows for SOC power management control. + + On exit of this function it is okay to have the power and/or clock to the VGLite graphics hardware turned off. + */ +void vg_lite_hal_deinitialize(void); + +/*! + @brief Allocate contiguous video memory. + + @discussion + Any memory the VGLite graphics hardware will see should be allocated as contiguous memory. Any allocated memory will be + addressed through an opaque handle, usually a pointer to an opaque structure. The porting layer can put any information it + needs inside this structure. + + @param size + The number of bytes to allocate. + + @param logical + A pointer to a variable that will receive the logical address of the allocated memory for the CPU. + + @param gpu + A pointer to a variable that will receive the physical address of the allocated memory for the VGLite graphics hardware. + + @result + A pointer to an opaque structure that will be used as the memory handle. NULL should be returned if there is not + enough memory. + */ +vg_lite_error_t vg_lite_hal_allocate_contiguous(unsigned long size, void ** logical, uint32_t * physical,void ** node); + +/*! + @brief Free contiguous video memory. + + @discussion + Free the memory allocated by {@link vg_lite_hal_allocate_contiguous}. After this function returns, the associated memory + handle is no longer a valid handle. + + @param memory_handle + A pointer to an opaque structure returned by {@link vg_lite_hal_allocate_contiguous}. + */ +void vg_lite_hal_free_contiguous(void * memory_handle); + +/*! + @brief remove unfree node when continuously allocate buffer without free buffer. + + @discussion + Free the node allocated by {@link kmalloc}. After this function returns, the associated memory + handle is no longer a valid handle. + */ +void vg_lite_hal_free_os_heap(void); + +/*! + @brief Map contiguous logical or physical memory into the VGLite graphics hardware space. + + @discussion + Any memory, like a frame buffer or some pre-allocated image or path data, needs to be mapped into the VGLite graphics + hardware address space and wrapped by a memory handle. This allows the VGLite graphics hardware access that memory + directly. + + Either a logical or a physical address should be passed in to map. + + @param size + The number of bytes to map. + + @param logical + The logical address of the memory region to map or NULL if the logical address is not known. + + @param physical + The physical address of the memory region to map if logical is NULL. + + @param gpu + A pointer to a variable that will receive the VGLite graphics hardware addressable address of the mapped region. + + @result + A pointer to an opaque structure that will be used as the memory handle. NULL should be returned if there is + not enough system resources to map the region. + */ +void * vg_lite_hal_map(unsigned long size, void * logical, uint32_t physical, uint32_t * gpu); + +/*! + @brief Unmap a previously mapped region. + + @discussion + If a mapped region by {@link vg_lite_hal_map} is no longer needed, it should be unmapped to free up any allocated system + resources used when mapping the region. + + @param memory_handle + A pointer to an opaque structure returned by {@link vg_lite_hal_map}. + */ +void vg_lite_hal_unmap(void * memory_handle); + +/*! + @brief Execute a memory barrier. + + @discussion + Some systems require a a memory barrier to make sure all store operations in the CPU have been handled. This is the wrapper + function for a memory barrier. + */ +void vg_lite_hal_barrier(void); + +/*! + @brief Read data from a register from the VGLite graphics hardware. + + @discussion + In order to communicate with the VGLite graphics hardware, the kernel needs to read and write to some hardware registers. + In each SOC those registers could be allocated at a different space in the physical memory map. + + @param address + The relative address of the VGLite graphics hardware register to read from. + + @result + The 32-bit value returned from reading the register. + */ +uint32_t vg_lite_hal_peek(uint32_t address); + +/*! + @brief Write data to a register from the VGLite graphics hardware. + + @discussion + In order to communicate with the VGLite graphics hardware, the kernel needs to read and write to some hardware registers. + In each SOC those registers could be allocated at a different space in the physical memory map. + + @param address + The relative address of the VGLite graphics hardware register to write to. + + @param data + The data to write to the VGLite graphics hardware register. + */ +void vg_lite_hal_poke(uint32_t address, uint32_t data); + +/*! + @brief query the remaining allocate contiguous video memory. + + @param data + The data to get the remaining allocate contiguous video memory bytes. + */ +vg_lite_error_t vg_lite_hal_query_mem(vg_lite_kernel_mem_t *mem); + +/*! + @brief Wait until an interrupt from the VGLite graphics hardware has been received. + + @discussion + Currently, the VGLite API is synchronous. This means that after each call it will wait until the VGLite graphics hardware + has completed. The VGLite graphics hardware will send an interrupt when it is finished, and this function will wait until + that interrupt has been received by the operating system. + + A timeout value is specified in order if the kernel wants to wait for a specific number of milliseconds fir the interrupt to + occur. If the interrupt does not occur in the specified timeout, a timeout error will be returned. + + @param timeout + The number of milliseconds to wait for the interrupt before returning a timeout error. If timeout = 0xFFFFFFFF + then {@link vg_lite_hal_wait_interrupt} will wait forever for the interrupt. + + @param mask + Irq event mask to wait for. + + @result + A boolean value indicating whether the interrupt was received (1) or not (0). + */ +int32_t vg_lite_hal_wait_interrupt(uint32_t timeout, uint32_t mask, uint32_t * value); + +#if !defined(VG_DRIVER_SINGLE_THREAD) +/*! + @brief Submit the current command buffer to the command queue. + + @param context + Address of kernel context. + + @param physical + Current command buffer physical address. + + @param offset + Current command buffer offset. + + @param size + Current command buffer size. + + @param event + The async event to use to track the response for this request. + */ +vg_lite_error_t vg_lite_hal_submit(uint32_t context,uint32_t physical, uint32_t offset, uint32_t size, vg_lite_os_async_event_t *event); + +/*! + @brief Wait for the current command buffer to be executed. + + @param timeout + Timeout in milliseconds. + + @param event + The async event to wait for. If the event's signal is 1, the current command + buffer has been executed. + */ +vg_lite_error_t vg_lite_hal_wait(uint32_t timeout, vg_lite_os_async_event_t *event); +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +#ifdef __cplusplus +} +#endif +#endif /* _vg_lite_hal_h_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hw.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hw.h new file mode 100644 index 0000000000..2603119d99 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hw.h @@ -0,0 +1,64 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright (c) 2014 - 2020 Vivante Corporation +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#ifndef _vg_lite_hw_h +#define _vg_lite_hw_h + +#define VG_LITE_HW_CLOCK_CONTROL 0x000 +#define VG_LITE_HW_IDLE 0x004 +#define VG_LITE_INTR_STATUS 0x010 +#define VG_LITE_INTR_ENABLE 0x014 +#define VG_LITE_HW_CHIP_ID 0x020 +#define VG_LITE_HW_CMDBUF_ADDRESS 0x500 +#define VG_LITE_HW_CMDBUF_SIZE 0x504 +#define VG_LITE_HW_POWER_CONTROL 0x100 +#define VG_LITE_HW_POWER_MODULE_CONTROL 0x104 + +#define VG_LITE_EXT_WORK_CONTROL 0x520 +#define VG_LITE_EXT_VIDEO_SIZE 0x524 +#define VG_LITE_EXT_CLEAR_VALUE 0x528 + +#define VG_LITE_EXT_VIDEO_CONTROL 0x51C + +typedef struct clock_control { + uint32_t reserved0 : 1; + uint32_t clock_gate : 1; + uint32_t scale : 7; + uint32_t scale_load : 1; + uint32_t reserved10 : 2; + uint32_t soft_reset : 1; + uint32_t reserved13 : 6; + uint32_t isolate : 1; +} clock_control_t; + +typedef union vg_lite_hw_clock_control { + clock_control_t control; + uint32_t data; +} vg_lite_hw_clock_control_t; + +#define VG_LITE_HW_IDLE_STATE 0x0B05 + +#endif /* defined(_vg_lite_hw_h) */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_image.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_image.c new file mode 100644 index 0000000000..136524336b --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_image.c @@ -0,0 +1,160 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright 2012 - 2020 Vivante Corporation, Santa Clara, California. +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#include + +#include "vg_lite.h" + +static void _memcpy(void *dst, void *src, int size) { + int i; + for (i = 0; i < size; i++) { + ((unsigned char*)dst)[i] = ((unsigned char*)src)[i]; + } +} + +/* Get the plane memory pointer and strides info. */ +static uint32_t get_buffer_planes(vg_lite_buffer_t *buffer, + uint8_t **memory, + uint32_t *strides) +{ + uint32_t count = 1; + + switch (buffer->format) { + case VG_LITE_RGBA8888: + case VG_LITE_BGRA8888: + case VG_LITE_RGBX8888: + case VG_LITE_BGRX8888: + case VG_LITE_RGB565: + case VG_LITE_BGR565: + case VG_LITE_RGBA4444: + case VG_LITE_BGRA4444: + case VG_LITE_BGRA5551: + case VG_LITE_A8: + case VG_LITE_L8: + case VG_LITE_A4: + case VG_LITE_INDEX_1: + case VG_LITE_INDEX_2: + case VG_LITE_INDEX_4: + case VG_LITE_INDEX_8: + case VG_LITE_YUYV: + case VG_LITE_YUY2: + case VG_LITE_RGBA2222: + count = 1; + memory[0] = (uint8_t *)buffer->memory; + memory[1] = memory[2] = ((uint8_t*)0); + strides[0] = buffer->stride; + strides[1] = strides[2] = 0; + break; + + case VG_LITE_NV12: + case VG_LITE_NV16: + count = 2; + memory[0] = (uint8_t *)buffer->memory; + memory[1] = (uint8_t *)buffer->yuv.uv_memory; + memory[2] = 0; + strides[0] = buffer->stride; + strides[1] = buffer->yuv.uv_stride; + strides[2] = 0; + break; + + case VG_LITE_AYUY2: + count = 2; + memory[0] = (uint8_t *)buffer->memory; + memory[1] = 0; + memory[2] = (uint8_t *)buffer->yuv.v_memory; + strides[0] = buffer->stride; + strides[1] = 0; + strides[2] = buffer->yuv.alpha_stride; + break; + + case VG_LITE_ANV12: + count = 3; + memory[0] = (uint8_t *)buffer->memory; + memory[1] = (uint8_t *)buffer->yuv.uv_memory; + memory[2] = (uint8_t *)buffer->yuv.v_memory; + strides[0] = buffer->stride; + strides[1] = buffer->yuv.uv_stride; + strides[2] = buffer->yuv.alpha_stride; + break; + + case VG_LITE_YV12: + case VG_LITE_YV24: + case VG_LITE_YV16: + count = 3; + memory[0] = (uint8_t *)buffer->memory; + memory[1] = (uint8_t *)buffer->yuv.uv_memory; + memory[2] = (uint8_t *)buffer->yuv.v_memory; + strides[0] = buffer->stride; + strides[1] = buffer->yuv.uv_stride; + strides[2] = buffer->yuv.v_stride; + break; + + case VG_LITE_YUY2_TILED: + case VG_LITE_NV12_TILED: + case VG_LITE_ANV12_TILED: + case VG_LITE_AYUY2_TILED: + default: + count = 0; + + break; + } + return count; +} + +vg_lite_error_t vg_lite_buffer_upload(vg_lite_buffer_t *buffer, + uint8_t *data[3], + uint32_t stride[3]) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + int32_t plane_count; + uint8_t *buffer_memory[3] = {((uint8_t*)0)}; + uint32_t buffer_strides[3] = {0}; + uint8_t *pdata; + int32_t i, j; + + /* Get buffer memory info. */ + plane_count = get_buffer_planes(buffer, buffer_memory, buffer_strides); + + if (plane_count > 0 && plane_count <= 3) { + /* Copy the data to buffer. */ + for (i = 0; i < plane_count; i++) { + pdata = data[i]; + for (j = 0; j < buffer->height; j++) { + _memcpy(buffer_memory[i], pdata, buffer_strides[i]); + buffer_memory[i] += buffer_strides[i]; + pdata += stride[i]; + } + } + } + else { + error = VG_LITE_INVALID_ARGUMENT; + } + + return error; +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_kernel.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_kernel.c new file mode 100644 index 0000000000..a0d5d7e816 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_kernel.c @@ -0,0 +1,1020 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright (c) 2014 - 2020 Vivante Corporation +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#include "vg_lite_platform.h" +#include "vg_lite_kernel.h" +#include "vg_lite_hal.h" +#include "vg_lite_hw.h" +#if defined(__linux__) && !EMULATOR +#include +#include +#endif + +static int s_reference = 0; + +#if !defined(VG_DRIVER_SINGLE_THREAD) +static int task_num = 0; +static vg_lite_kernel_initialize_t ts_initialize = {0}; +static uint8_t ts_init = 0; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +#if defined(VG_DRIVER_SINGLE_THREAD) + +#define VG_LITE_OS_LOCK() VG_LITE_SUCCESS +#define VG_LITE_OS_UNLOCK() + +#else + +#define VG_LITE_OS_LOCK() vg_lite_os_lock() +#define VG_LITE_OS_UNLOCK() vg_lite_os_unlock() + +#endif /* VG_DRIVER_SINGLE_THREAD */ + +static vg_lite_error_t do_terminate(vg_lite_kernel_terminate_t * data); + +static void soft_reset(void); + +static void gpu(int enable) +{ + vg_lite_hw_clock_control_t value; + uint32_t reset_timer = 2; +#ifdef VG_GPU_AUTO_CLOCK_GATING + uint32_t temp; +#endif /* VG_GPU_AUTO_CLOCK_GATING */ + const uint32_t reset_timer_limit = 1000; + + if (enable) { + /* Disable clock gating. */ + value.data = vg_lite_hal_peek(VG_LITE_HW_CLOCK_CONTROL); + value.control.clock_gate = 0; + vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); + vg_lite_hal_delay(1); + + /* Set clock speed. */ + value.control.scale = 64; + value.control.scale_load = 1; + vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); + vg_lite_hal_delay(1); + value.control.scale_load = 0; + vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); + vg_lite_hal_delay(5); + + do { + /* Perform a soft reset. */ + soft_reset(); + vg_lite_hal_delay(reset_timer); + reset_timer *= 2; // If reset failed, try again with a longer wait. Need to check why if dead lopp happens here. + } while (!VG_LITE_KERNEL_IS_GPU_IDLE()); +#ifdef VG_GPU_AUTO_CLOCK_GATING + temp = vg_lite_hal_peek(VG_LITE_HW_POWER_CONTROL); + temp |= 0x1; + vg_lite_hal_poke(VG_LITE_HW_POWER_CONTROL, temp); + vg_lite_hal_delay(1); +#endif /* VG_GPU_AUTO_CLOCK_GATING */ + } + else + { + while (!VG_LITE_KERNEL_IS_GPU_IDLE() && + (reset_timer < reset_timer_limit) // Force shutdown if timeout. + ) { + vg_lite_hal_delay(reset_timer); + reset_timer *= 2; + } + + /* Set idle speed. */ + value.data = vg_lite_hal_peek(VG_LITE_HW_CLOCK_CONTROL); + value.control.scale = 1; + value.control.scale_load = 1; + vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); + vg_lite_hal_delay(1); + value.control.scale_load = 0; + vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); + vg_lite_hal_delay(5); + + /* Enable clock gating. */ + value.control.clock_gate = 1; + vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); + vg_lite_hal_delay(1); + } +} + +/* Initialize some customized modeuls [DDRLess]. */ +static vg_lite_error_t init_3rd(vg_lite_kernel_initialize_t * data) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + + /* TODO: Init the YUV<->RGB converters. Reserved for SOC. */ +/* vg_lite_hal_poke(0x00514, data->yuv_pre); + vg_lite_hal_poke(0x00518, data->yuv_post); */ + + return error; +} + +#if defined(VG_DRIVER_SINGLE_THREAD) +static vg_lite_error_t init_vglite(vg_lite_kernel_initialize_t * data) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + + vg_lite_kernel_context_t * context; + uint32_t id; + int i; + uint32_t chip_id = 0; + +#if defined(__linux__) && !EMULATOR + vg_lite_kernel_context_t __user * context_usr; + vg_lite_kernel_context_t mycontext = { 0 }; + + // Construct the context. + context_usr = (vg_lite_kernel_context_t __user *) data->context; +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0) + if (!access_ok(VERIFY_READ, context_usr, sizeof(*context_usr)) || + !access_ok(VERIFY_WRITE, context_usr, sizeof(*context_usr))) { +#else + if (!access_ok(context_usr, sizeof(*context_usr)) || + !access_ok(context_usr, sizeof(*context_usr))) { +#endif + /* Out of memory. */ + return VG_LITE_OUT_OF_MEMORY; + } + context = &mycontext; +#else + // Construct the context. + context = data->context; + if (context == NULL) + { + /* Out of memory. */ + return VG_LITE_OUT_OF_MEMORY; + } +#endif + + /* Zero out all pointers. */ + for (i = 0; i < CMDBUF_COUNT; i++){ + context->command_buffer[i] = NULL; + context->command_buffer_logical[i] = NULL; + context->command_buffer_physical[i] = 0; + } + context->tessellation_buffer = NULL; + context->tessellation_buffer_logical = NULL; + context->tessellation_buffer_physical = 0; + + /* Increment reference counter. */ + if (s_reference++ == 0) { + /* Initialize the SOC. */ + vg_lite_hal_initialize(); + + /* Enable the GPU. */ + gpu(1); + } + + /* Fill in hardware capabilities. */ + data->capabilities.data = 0; + id = vg_lite_hal_peek(VG_LITE_HW_CHIP_ID); + if (id >= 0x300) { + data->capabilities.cap.l2_cache = 1; + } + + /* Allocate the command buffer. */ + if (data->command_buffer_size) { + int32_t i; + for (i = 0; i < 2; i ++) + { + /* Allocate the memory. */ + error = vg_lite_hal_allocate_contiguous(data->command_buffer_size, + &context->command_buffer_logical[i], + &context->command_buffer_physical[i], + &context->command_buffer[i]); + if (error != VG_LITE_SUCCESS) { + /* Free any allocated memory. */ + vg_lite_kernel_terminate_t terminate = { context }; + do_terminate(&terminate); + + /* Out of memory. */ + return error; + } + + /* Return command buffer logical pointer and GPU address. */ + data->command_buffer[i] = context->command_buffer_logical[i]; + data->command_buffer_gpu[i] = context->command_buffer_physical[i]; + } + } + + /* Allocate the tessellation buffer. */ + if ((data->tessellation_width > 0) && (data->tessellation_height > 0)) + { + int width = data->tessellation_width; + int height = 0; + unsigned long stride, buffer_size, l1_size, l2_size; + + height = VG_LITE_ALIGN(data->tessellation_height, 16); + + chip_id = vg_lite_hal_peek(0x20); + if(chip_id == GPU_CHIP_ID_GC355) + width = VG_LITE_ALIGN(width, 128); + /* Check if we can used tiled tessellation (128x16). */ + if (((width & 127) == 0) && ((height & 15) == 0)) { + data->capabilities.cap.tiled = 0x3; + } else { + data->capabilities.cap.tiled = 0x2; + } + + /* Compute tessellation buffer size. */ + stride = VG_LITE_ALIGN(width * 8, 64); + buffer_size = VG_LITE_ALIGN(stride * height, 64); + /* Each bit in the L1 cache represents 64 bytes of tessellation data. */ + l1_size = VG_LITE_ALIGN(VG_LITE_ALIGN(buffer_size / 64, 64) / 8, 64); + /* Each bit in the L2 cache represents 32 bytes of L1 data. */ + l2_size = data->capabilities.cap.l2_cache ? VG_LITE_ALIGN(VG_LITE_ALIGN(l1_size / 32, 64) / 8, 64) : 0; + + /* Allocate the memory. */ + error = vg_lite_hal_allocate_contiguous(buffer_size + l1_size + l2_size, + &context->tessellation_buffer_logical, + &context->tessellation_buffer_physical, + &context->tessellation_buffer); + if (error != VG_LITE_SUCCESS) { + /* Free any allocated memory. */ + vg_lite_kernel_terminate_t terminate = { context }; + do_terminate(&terminate); + + /* Out of memory. */ + return error; + } + + /* Return the tessellation buffer pointers and GPU addresses. */ + data->tessellation_buffer_gpu[0] = context->tessellation_buffer_physical; + data->tessellation_buffer_gpu[1] = context->tessellation_buffer_physical + buffer_size; + data->tessellation_buffer_gpu[2] = (l2_size ? data->tessellation_buffer_gpu[1] + l1_size + : data->tessellation_buffer_gpu[1]); + data->tessellation_buffer_logic[0] = (uint8_t *)context->tessellation_buffer_logical; + data->tessellation_buffer_logic[1] = data->tessellation_buffer_logic[0] + buffer_size; + data->tessellation_buffer_logic[2] = (l2_size ? data->tessellation_buffer_logic[1] + l1_size + : data->tessellation_buffer_logic[1]); + data->tessellation_buffer_size[0] = buffer_size; + data->tessellation_buffer_size[1] = l1_size; + data->tessellation_buffer_size[2] = l2_size; + + data->tessellation_stride = stride; + data->tessellation_width_height = width | (height << 16); + data->tessellation_shift = 0; + } + + /* Enable all interrupts. */ + vg_lite_hal_poke(VG_LITE_INTR_ENABLE, 0xFFFFFFFF); + +#if defined(__linux__) && !EMULATOR + if (copy_to_user(context_usr, context, sizeof(vg_lite_kernel_context_t)) != 0) { + // Free any allocated memory. + vg_lite_kernel_terminate_t terminate = { context }; + do_terminate(&terminate); + + return VG_LITE_NO_CONTEXT; + } +#endif + return error; +} +#else +static vg_lite_error_t init_vglite(vg_lite_kernel_initialize_t * data) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + + vg_lite_kernel_context_t * context; + uint32_t id; + int i; + uint32_t chip_id = 0; + uint32_t semaphore_id = 0; + +#if defined(__linux__) && !EMULATOR + vg_lite_kernel_context_t __user * context_usr; + vg_lite_kernel_context_t mycontext = { 0 }; + + // Construct the context. + context_usr = (vg_lite_kernel_context_t __user *) data->context; +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0) + if (!access_ok(VERIFY_READ, context_usr, sizeof(*context_usr)) || + !access_ok(VERIFY_WRITE, context_usr, sizeof(*context_usr))) { +#else + if (!access_ok(context_usr, sizeof(*context_usr)) || + !access_ok(context_usr, sizeof(*context_usr))) { +#endif + /* Out of memory. */ + return VG_LITE_OUT_OF_MEMORY; + } + context = &mycontext; +#else + // Construct the context. + context = data->context; + if (context == NULL) + { + /* Out of memory. */ + return VG_LITE_OUT_OF_MEMORY; + } +#endif + + /* Zero out all pointers. */ + for (i = 0; i < CMDBUF_COUNT; i++){ + context->command_buffer[i] = NULL; + context->command_buffer_logical[i] = NULL; + context->command_buffer_physical[i] = 0; + } + context->tessellation_buffer = NULL; + context->tessellation_buffer_logical = NULL; + context->tessellation_buffer_physical = 0; + + /* Increment reference counter. */ + if (s_reference++ == 0) { + /* Initialize the SOC. */ + error = vg_lite_hal_initialize(); + if(error != VG_LITE_SUCCESS) + { + s_reference--; + vg_lite_hal_free_os_heap(); + vg_lite_hal_deinitialize(); + + return error; + } + + /* Enable the GPU. */ + gpu(1); + } + else + { + while(!task_num) + { + vg_lite_hal_delay(5); + } + } + + if((error = (vg_lite_error_t)VG_LITE_OS_LOCK()) == VG_LITE_SUCCESS){ + ++task_num; + for(semaphore_id = 0; semaphore_id < THREAD_LENGTH ; semaphore_id++) + { + if (vg_lite_os_init_event(&context->async_event[0], + semaphore_id, + VG_LITE_IDLE) == VG_LITE_SUCCESS) + + { + for (i = 1; i < CMDBUF_COUNT; i++) + vg_lite_os_config_event(&context->async_event[i], + semaphore_id, + VG_LITE_IDLE); + + break; + } + } + VG_LITE_OS_UNLOCK(); + } + else + return error; + + if(semaphore_id == THREAD_LENGTH) + return VG_LITE_MULTI_THREAD_FAIL; + + /* Fill in hardware capabilities. */ + data->capabilities.data = 0; + id = vg_lite_hal_peek(VG_LITE_HW_CHIP_ID); + if (id >= 0x300) { + data->capabilities.cap.l2_cache = 1; + } + + /* Allocate the command buffer. */ + if (data->command_buffer_size) { + int32_t i; + for (i = 0; i < CMDBUF_COUNT; i ++) + { + /* Allocate the memory. */ + VG_LITE_OS_LOCK(); + error = vg_lite_hal_allocate_contiguous(data->command_buffer_size, + &context->command_buffer_logical[i], + &context->command_buffer_physical[i], + &context->command_buffer[i]); + VG_LITE_OS_UNLOCK(); + + if (error != VG_LITE_SUCCESS) { + /* Free any allocated memory. */ + vg_lite_kernel_terminate_t terminate = { context }; + do_terminate(&terminate); + + /* Out of memory. */ + return error; + } + + /* Return command buffer logical pointer and GPU address. */ + data->command_buffer[i] = context->command_buffer_logical[i]; + data->command_buffer_gpu[i] = context->command_buffer_physical[i]; + } + } + + /* Allocate the context buffer. */ + if (data->context_buffer_size) { + int32_t i; + for (i = 0; i < CMDBUF_COUNT; i ++) + { + /* Allocate the memory. */ + VG_LITE_OS_LOCK(); + error = vg_lite_hal_allocate_contiguous(data->context_buffer_size, + &context->context_buffer_logical[i], + &context->context_buffer_physical[i], + &context->context_buffer[i]); + VG_LITE_OS_UNLOCK(); + + if (error != VG_LITE_SUCCESS) { + /* Free any allocated memory. */ + vg_lite_kernel_terminate_t terminate = { context }; + do_terminate(&terminate); + + /* Out of memory. */ + return error; + } + + /* Return context buffer logical pointer and GPU address. */ + data->context_buffer[i] = context->context_buffer_logical[i]; + data->context_buffer_gpu[i] = context->context_buffer_physical[i]; + } + } + + + /* Allocate the tessellation buffer. */ + if ((data->tessellation_width > 0) && (data->tessellation_height > 0)) + { + int width = data->tessellation_width; + int height = 0; + height = VG_LITE_ALIGN(data->tessellation_height, 16); + + chip_id = vg_lite_hal_peek(0x20); + if(chip_id == GPU_CHIP_ID_GC355) + width = VG_LITE_ALIGN(width, 128); + /* Check if we can used tiled tessellation (128x16). */ + if (((width & 127) == 0) && ((height & 15) == 0)) { + data->capabilities.cap.tiled = 0x3; + } else { + data->capabilities.cap.tiled = 0x2; + } + + if(ts_init++ == 0) + { + unsigned long stride, buffer_size, l1_size, l2_size; + + /* Compute tessellation buffer size. */ + stride = VG_LITE_ALIGN(width * 8, 64); + buffer_size = VG_LITE_ALIGN(stride * height, 64); + /* Each bit in the L1 cache represents 64 bytes of tessellation data. */ + l1_size = VG_LITE_ALIGN(VG_LITE_ALIGN(buffer_size / 64, 64) / 8, 64); + /* Each bit in the L2 cache represents 32 bytes of L1 data. */ + l2_size = data->capabilities.cap.l2_cache ? VG_LITE_ALIGN(VG_LITE_ALIGN(l1_size / 32, 64) / 8, 64) : 0; + + /* Allocate the memory. */ + VG_LITE_OS_LOCK(); + error = vg_lite_hal_allocate_contiguous(buffer_size + l1_size + l2_size, + &context->tessellation_buffer_logical, + &context->tessellation_buffer_physical, + &context->tessellation_buffer); + VG_LITE_OS_UNLOCK(); + + if (error != VG_LITE_SUCCESS) { + /* Free any allocated memory. */ + vg_lite_kernel_terminate_t terminate = { context }; + do_terminate(&terminate); + + /* Out of memory. */ + return error; + } + + /* Return the tessellation buffer pointers and GPU addresses. */ + ts_initialize.tessellation_buffer_gpu[0] = context->tessellation_buffer_physical; + ts_initialize.tessellation_buffer_gpu[1] = context->tessellation_buffer_physical + buffer_size; + ts_initialize.tessellation_buffer_gpu[2] = (l2_size ? ts_initialize.tessellation_buffer_gpu[1] + l1_size + : ts_initialize.tessellation_buffer_gpu[1]); + ts_initialize.tessellation_buffer_logic[0] = (uint8_t *)context->tessellation_buffer_logical; + ts_initialize.tessellation_buffer_logic[1] = ts_initialize.tessellation_buffer_logic[0] + buffer_size; + ts_initialize.tessellation_buffer_logic[2] = (l2_size ? ts_initialize.tessellation_buffer_logic[1] + l1_size + : ts_initialize.tessellation_buffer_logic[1]); + ts_initialize.tessellation_buffer_size[0] = buffer_size; + ts_initialize.tessellation_buffer_size[1] = l1_size; + ts_initialize.tessellation_buffer_size[2] = l2_size; + + ts_initialize.tessellation_stride = stride; + ts_initialize.tessellation_width_height = width | (height << 16); + ts_initialize.tessellation_shift = 0; + } + data->tessellation_buffer_gpu[0] = ts_initialize.tessellation_buffer_gpu[0]; + data->tessellation_buffer_gpu[1] = ts_initialize.tessellation_buffer_gpu[1]; + data->tessellation_buffer_gpu[2] = ts_initialize.tessellation_buffer_gpu[2]; + data->tessellation_buffer_logic[0] = ts_initialize.tessellation_buffer_logic[0]; + data->tessellation_buffer_logic[1] = ts_initialize.tessellation_buffer_logic[1]; + data->tessellation_buffer_logic[2] = ts_initialize.tessellation_buffer_logic[2]; + data->tessellation_buffer_size[0] = ts_initialize.tessellation_buffer_size[0]; + data->tessellation_buffer_size[1] = ts_initialize.tessellation_buffer_size[1]; + data->tessellation_buffer_size[2] = ts_initialize.tessellation_buffer_size[2]; + + data->tessellation_stride = ts_initialize.tessellation_stride; + data->tessellation_width_height = ts_initialize.tessellation_width_height; + data->tessellation_shift = ts_initialize.tessellation_shift; + } + + if(task_num == 1) + /* Enable all interrupts. */ + vg_lite_hal_poke(VG_LITE_INTR_ENABLE, 0xFFFFFFFF); + +#if defined(__linux__) && !EMULATOR + if (copy_to_user(context_usr, context, sizeof(vg_lite_kernel_context_t)) != 0) { + // Free any allocated memory. + vg_lite_kernel_terminate_t terminate = { context }; + do_terminate(&terminate); + + return VG_LITE_NO_CONTEXT; + } +#endif + return error; +} +#endif /* VG_DRIVER_SINGLE_THREAD */ + +static vg_lite_error_t do_initialize(vg_lite_kernel_initialize_t * data) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + /* Free any allocated memory for the context. */ + do { + error = init_vglite(data); + if (error != VG_LITE_SUCCESS) + break; + + error = init_3rd(data); + if (error != VG_LITE_SUCCESS) + break; + } while (0); + + return error; +} + +#if defined(VG_DRIVER_SINGLE_THREAD) +static vg_lite_error_t terminate_vglite(vg_lite_kernel_terminate_t * data) +{ + vg_lite_kernel_context_t *context = NULL; +#if defined(__linux__) && !EMULATOR + vg_lite_kernel_context_t mycontext = {0}; + if (copy_from_user(&mycontext, data->context, sizeof(vg_lite_kernel_context_t)) != 0) { + return VG_LITE_NO_CONTEXT; + } + context = &mycontext; +#else + context = data->context; +#endif + + /* Free any allocated memory for the context. */ + if (context->command_buffer[0]) { + /* Free the command buffer. */ + vg_lite_hal_free_contiguous(context->command_buffer[0]); + context->command_buffer[0] = NULL; + } + + if (context->command_buffer[1]) { + /* Free the command buffer. */ + vg_lite_hal_free_contiguous(context->command_buffer[1]); + context->command_buffer[1] = NULL; + } + + if (context->tessellation_buffer) { + /* Free the tessellation buffer. */ + vg_lite_hal_free_contiguous(context->tessellation_buffer); + context->tessellation_buffer = NULL; + } + vg_lite_hal_free_os_heap(); + /* Decrement reference counter. */ + if (--s_reference == 0) { + /* Disable the GPU. */ + gpu(0); + + /* De-initialize the SOC. */ + vg_lite_hal_deinitialize(); + } +#if defined(__linux__) && !EMULATOR + if (copy_to_user((vg_lite_kernel_context_t __user *) data->context, + &mycontext, sizeof(vg_lite_kernel_context_t)) != 0) { + return VG_LITE_NO_CONTEXT; + } +#endif + return VG_LITE_SUCCESS; +} +#else +static vg_lite_error_t terminate_vglite(vg_lite_kernel_terminate_t * data) +{ + vg_lite_kernel_context_t *context = NULL; + vg_lite_error_t error = VG_LITE_SUCCESS; + int32_t i; + +#if defined(__linux__) && !EMULATOR + vg_lite_kernel_context_t mycontext = {0}; + if (copy_from_user(&mycontext, data->context, sizeof(vg_lite_kernel_context_t)) != 0) { + return VG_LITE_NO_CONTEXT; + } + context = &mycontext; +#else + context = data->context; +#endif + + /* Free any allocated memory for the context. */ + if (context->command_buffer[0]) { + /* Free the command buffer. */ + vg_lite_hal_free_contiguous(context->command_buffer[0]); + context->command_buffer[0] = NULL; + } + + if (context->command_buffer[1]) { + /* Free the command buffer. */ + vg_lite_hal_free_contiguous(context->command_buffer[1]); + context->command_buffer[1] = NULL; + } + + if (context->context_buffer[0]) { + /* Free the context buffer. */ + vg_lite_hal_free_contiguous(context->context_buffer[0]); + context->context_buffer[0] = NULL; + } + + if (context->context_buffer[1]) { + /* Free the context buffer. */ + vg_lite_hal_free_contiguous(context->context_buffer[1]); + context->context_buffer[1] = NULL; + } + + if((error = (vg_lite_error_t)VG_LITE_OS_LOCK()) == VG_LITE_SUCCESS){ + --task_num; + --s_reference; + VG_LITE_OS_UNLOCK(); + } + else + return error; + + /* Delete all async events associated to command buffers */ + for (i = 0; i < CMDBUF_COUNT; i++) + vg_lite_os_delete_event(&context->async_event[i]); + + if(task_num == 0){ + if (context->tessellation_buffer) { + /* Free the tessellation buffer. */ + vg_lite_hal_free_contiguous(context->tessellation_buffer); + context->tessellation_buffer = NULL; + } + ts_init = 0; + /* Disable the GPU. */ + gpu(0); + + vg_lite_hal_free_os_heap(); + + /* De-initialize the SOC. */ + vg_lite_hal_deinitialize(); + } + +#if defined(__linux__) && !EMULATOR + if (copy_to_user((vg_lite_kernel_context_t __user *) data->context, + &mycontext, sizeof(vg_lite_kernel_context_t)) != 0) { + return VG_LITE_NO_CONTEXT; + } +#endif + return VG_LITE_SUCCESS; +} +#endif /* VG_DRIVER_SINGLE_THREAD */ + +static vg_lite_error_t terminate_3rd(vg_lite_kernel_terminate_t * data) +{ + /* TODO: Terminate the converters. */ + + return VG_LITE_SUCCESS; +} + +static vg_lite_error_t do_terminate(vg_lite_kernel_terminate_t * data) +{ + terminate_vglite(data); + terminate_3rd(data); + + return VG_LITE_SUCCESS; +} + +static vg_lite_error_t do_allocate(vg_lite_kernel_allocate_t * data) +{ + vg_lite_error_t error; + + if((error = (vg_lite_error_t)VG_LITE_OS_LOCK()) == VG_LITE_SUCCESS) + { + error = vg_lite_hal_allocate_contiguous(data->bytes, &data->memory, &data->memory_gpu, &data->memory_handle); + VG_LITE_OS_UNLOCK(); + } + + return error; +} + +static vg_lite_error_t do_free(vg_lite_kernel_free_t * data) +{ + vg_lite_hal_free_contiguous(data->memory_handle); + + return VG_LITE_SUCCESS; +} + +#if defined(VG_DRIVER_SINGLE_THREAD) +static vg_lite_error_t do_submit(vg_lite_kernel_submit_t * data) +{ + uint32_t offset; + vg_lite_kernel_context_t *context = NULL; + uint32_t physical = data->context->command_buffer_physical[data->command_id]; + +#if defined(__linux__) && !EMULATOR + vg_lite_kernel_context_t mycontext = { 0 }; + + if (copy_from_user(&mycontext, data->context, sizeof(vg_lite_kernel_context_t)) != 0) { + return VG_LITE_NO_CONTEXT; + } + context = &mycontext; + physical = context->command_buffer_physical[data->command_id]; +#else + context = data->context; + if (context == NULL) + { + return VG_LITE_NO_CONTEXT; + } +#endif + /* Perform a memory barrier. */ + vg_lite_hal_barrier(); + + offset = (uint8_t *) data->commands - (uint8_t *)context->command_buffer_logical[data->command_id]; + +#if defined(PRINT_COMMAND_BUFFER) + int i = 0; + for(i=0;i < (peek_queue->cmd_size + 3) / 4; i++) + { + if(i % 4 == 0) + printf("\r\n"); + printf("0x%08x ",((uint32_t*)(peek_queue->cmd_physical + peek_queue->cmd_offset))[i]); + } +#endif + + /* Write the registers to kick off the command execution (CMDBUF_SIZE). */ + vg_lite_hal_poke(VG_LITE_HW_CMDBUF_ADDRESS, physical + offset); + vg_lite_hal_poke(VG_LITE_HW_CMDBUF_SIZE, (data->command_size + 7) / 8); + + return VG_LITE_SUCCESS; +} + +static vg_lite_error_t do_wait(vg_lite_kernel_wait_t * data) +{ + /* Wait for interrupt. */ + if (!vg_lite_hal_wait_interrupt(data->timeout_ms, data->event_mask, &data->event_got)) { + /* Timeout. */ +#if defined(PRINT_DEBUG_REGISTER) + unsigned int debug; + unsigned int iter; + for(iter =0; iter < 16 ; iter ++) + { + vg_lite_hal_poke(0x470, iter); + debug = vg_lite_hal_peek(0x450); + printf("0x450[%d] = 0x%x\n", iter,debug); + } + for(iter =0; iter < 16 ; iter ++) + { + vg_lite_hal_poke(0x470, iter <<16); + debug = vg_lite_hal_peek(0x454); + printf("0x454[%d] = 0x%x\n", iter,debug); + } + for(iter =0; iter < 16 ; iter ++) + { + vg_lite_hal_poke(0x478, iter); + debug = vg_lite_hal_peek(0x468); + printf("0x468[%d] = 0x%x\n", iter,debug); + } + for(iter =0; iter < 16 ; iter ++) + { + vg_lite_hal_poke(0x478, iter); + debug = vg_lite_hal_peek(0x46C); + printf("0x46C[%d] = 0x%x\n", iter,debug); + } +#endif + return VG_LITE_TIMEOUT; + } + + return VG_LITE_SUCCESS; +} +#else +static vg_lite_error_t do_submit(vg_lite_kernel_submit_t * data) +{ + vg_lite_error_t error; + uint32_t offset; + vg_lite_kernel_context_t *context = NULL; + uint32_t physical; + +#if defined(__linux__) && !EMULATOR + vg_lite_kernel_context_t mycontext = { 0 }; + + if (copy_from_user(&mycontext, data->context, sizeof(vg_lite_kernel_context_t)) != 0) { + return VG_LITE_NO_CONTEXT; + } + context = &mycontext; + physical = context->command_buffer_physical[data->command_id]; +#else + context = data->context; + if (context == NULL) + { + return VG_LITE_NO_CONTEXT; + } +#endif + /* Perform a memory barrier. */ + vg_lite_hal_barrier(); + + physical = data->context->command_buffer_physical[data->command_id]; + offset = (uint8_t *) data->commands - (uint8_t *)context->command_buffer_logical[data->command_id]; + + /* Send the current command buffer to the command queue. */ + error = vg_lite_hal_submit((uint32_t)context, physical, offset, data->command_size, + &data->context->async_event[data->command_id]); + if(error != VG_LITE_SUCCESS) + return error; + + return VG_LITE_SUCCESS; +} + +static vg_lite_error_t do_wait(vg_lite_kernel_wait_t * data) +{ + vg_lite_error_t error; + /* Wait for the signal of current command buffer to 1. */ + error = vg_lite_hal_wait(data->timeout_ms, + &data->context->async_event[data->command_id]); + + return error; +} +#endif /* VG_DRIVER_SINGLE_THREAD */ + +static vg_lite_error_t do_reset(void) +{ + /* Disable and enable the GPU. */ + gpu(1); + vg_lite_hal_poke(VG_LITE_INTR_ENABLE, 0xFFFFFFFF); + + return VG_LITE_SUCCESS; +} + +static vg_lite_error_t do_debug(void) +{ + return VG_LITE_SUCCESS; +} + +static vg_lite_error_t do_map(vg_lite_kernel_map_t * data) +{ data->memory_handle = vg_lite_hal_map(data->bytes, data->logical, data->physical, &data->memory_gpu); + if (data->memory_handle == NULL) + { + return VG_LITE_OUT_OF_RESOURCES; + } + + return VG_LITE_SUCCESS; +} + +static vg_lite_error_t do_unmap(vg_lite_kernel_unmap_t * data) +{ + vg_lite_hal_unmap(data->memory_handle); + + return VG_LITE_SUCCESS; +} + +static vg_lite_error_t do_peek(vg_lite_kernel_info_t * data) +{ + data->reg = vg_lite_hal_peek(data->addr); + + return VG_LITE_SUCCESS; +} + +static vg_lite_error_t do_query_mem(vg_lite_kernel_mem_t * data) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + error = vg_lite_hal_query_mem(data); + + return error; +} + +#if !defined(VG_DRIVER_SINGLE_THREAD) +static vg_lite_error_t do_query_context_switch(vg_lite_kernel_context_switch_t * data) +{ + data->isContextSwitched = vg_lite_os_query_context_switch(data->context); + return VG_LITE_SUCCESS; +} +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +static void soft_reset(void) +{ + vg_lite_hw_clock_control_t value; + value.data = vg_lite_hal_peek(VG_LITE_HW_CLOCK_CONTROL); + + /* Perform a soft reset. */ + value.control.isolate = 1; + vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); + value.control.soft_reset = 1; + vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); + vg_lite_hal_delay(5); + value.control.soft_reset = 0; + vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); + value.control.isolate = 0; + vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); +} + +#if !defined(VG_DRIVER_SINGLE_THREAD) +static vg_lite_error_t do_mutex_lock() +{ + return (vg_lite_error_t)VG_LITE_OS_LOCK(); +} + +static vg_lite_error_t do_mutex_unlock() +{ + return (vg_lite_error_t)VG_LITE_OS_UNLOCK(); +} +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +vg_lite_error_t vg_lite_kernel(vg_lite_kernel_command_t command, void * data) +{ + /* Dispatch on command. */ + switch (command) { + case VG_LITE_INITIALIZE: + /* Initialize the context. */ + return do_initialize(data); + + case VG_LITE_TERMINATE: + /* Terminate the context. */ + return do_terminate(data); + + case VG_LITE_ALLOCATE: + /* Allocate contiguous memory. */ + return do_allocate(data); + + case VG_LITE_FREE: + /* Free contiguous memory. */ + return do_free(data); + + case VG_LITE_SUBMIT: + /* Submit a command buffer. */ + return do_submit(data); + + case VG_LITE_WAIT: + /* Wait for the GPU. */ + return do_wait(data); + + case VG_LITE_RESET: + /* Reset the GPU. */ + return do_reset(); + + case VG_LITE_DEBUG: + /* Perform debugging features. */ + return do_debug(); + + case VG_LITE_MAP: + /* Map some memory. */ + return do_map(data); + + case VG_LITE_UNMAP: + /* Unmap some memory. */ + return do_unmap(data); + + /* Get register info. */ + case VG_LITE_CHECK: + /* Get register value. */ + return do_peek(data); + + case VG_LITE_QUERY_MEM: + return do_query_mem(data); + +#if !defined(VG_DRIVER_SINGLE_THREAD) + case VG_LITE_LOCK: + /* Mutex lock */ + return do_mutex_lock(); + + case VG_LITE_UNLOCK: + /* Mutex unlock */ + return do_mutex_unlock(); + + case VG_LITE_QUERY_CONTEXT_SWITCH: + /* query context switch */ + return do_query_context_switch(data); +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + + default: + break; + } + + /* Invalid command. */ + return VG_LITE_INVALID_ARGUMENT; +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_kernel.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_kernel.h new file mode 100644 index 0000000000..39a9c14ffb --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_kernel.h @@ -0,0 +1,444 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright (c) 2014 - 2020 Vivante Corporation +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#ifndef _vg_lite_kernel_h_ +#define _vg_lite_kernel_h_ + +#include "vg_lite_os.h" + +/* Interrupt IDs from GPU. */ +#define EVENT_UNEXPECTED_MESH 0x80000000 +#define EVENT_CMD_BAD_WRITE 0x40000000 +#define EVENT_ERROR_RECOVER 0x20000000 +#define EVENT_CMD_SWITCH 0x10000000 +#define EVENT_MCU_BAD_WRITE 0x08000000 +#define EVENT_END 0 + +#define MAX_CONTIGUOUS_SIZE 0x02000000 + +#define VG_LITE_INFINITE 0xFFFFFFFF +#define VG_LITE_MAX_WAIT_TIME 0x130000 +#define CMDBUF_COUNT 2 + +#define VG_LITE_ALIGN(number, alignment) \ + (((number) + ((alignment) - 1)) & ~((alignment) - 1)) + +/* Available function optimization levels */ +#if (defined(__ICCARM__)) +#define VG_LITE_ATTR_OPTIMIZE_LOW _Pragma("optimize=none") +#define VG_LITE_ATTR_OPTIMIZE_MEDIUM _Pragma("optimize=medium") +#define VG_LITE_ATTR_OPTIMIZE_HIGH _Pragma("optimize=high") +#else /* ARMGCC */ +#define VG_LITE_ATTR_OPTIMIZE_LOW __attribute__((optimize(1))) +#define VG_LITE_ATTR_OPTIMIZE_MEDIUM __attribute__((optimize(2))) +#define VG_LITE_ATTR_OPTIMIZE_HIGH __attribute__((optimize(3))) +#endif /* defined(__ICCARM__) */ + +/* Allow develpers to force a function optimization level */ +#define VG_LITE_OPTIMIZE(level) VG_LITE_ATTR_OPTIMIZE_##level + +#define VG_LITE_KERNEL_IS_GPU_IDLE() \ +((vg_lite_hal_peek(VG_LITE_HW_IDLE) & VG_LITE_HW_IDLE_STATE) == VG_LITE_HW_IDLE_STATE) + +/* Hardware chip Ids */ +#define GPU_CHIP_ID_GCNanoliteV 0x255 +#define GPU_CHIP_ID_GC355 0x355 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef VG_LITE_ERROR +#define VG_LITE_ERROR 1 +/*! + @abstract Error codes that the vg_lite functions can return. + + @discussion + All API functions return a status code. On success, VG_LITE_SUCCESS will be returned when a function is + successful. This value is set to zero, so if any function returns a non-zero value, an error has occured. + */ +typedef enum vg_lite_error +{ + VG_LITE_SUCCESS = 0, /*! Success. */ + VG_LITE_INVALID_ARGUMENT, /*! An invalid argument was specified. */ + VG_LITE_OUT_OF_MEMORY, /*! Out of memory. */ + VG_LITE_NO_CONTEXT, /*! No context or an unintialized context specified. */ + VG_LITE_TIMEOUT, /*! A timeout has occured during a wait. */ + VG_LITE_OUT_OF_RESOURCES, /*! Out of system resources. */ + VG_LITE_GENERIC_IO, /*! Cannot communicate with the kernel driver. */ + VG_LITE_NOT_SUPPORT, /*! Function call not supported. */ + VG_LITE_MULTI_THREAD_FAIL, /*! Multi-thread/tasks fail. */ + VG_LITE_ALREADY_EXISTS, /*! Object already exists */ + VG_LITE_NOT_ALIGNED, /*! Data alignment error */ +} +vg_lite_error_t; +#endif + +#if !defined(VG_DRIVER_SINGLE_THREAD) +typedef enum vg_lite_buffer_signal +{ + VG_LITE_IDLE = 0, /*! Buffer available. */ + VG_LITE_HW_FINISHED, /*! HW has completed command buffer. */ + VG_LITE_IN_QUEUE, /*! Buffer has been send to queue. */ +} +vg_lite_buffer_signal_t; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +typedef enum vg_lite_kernel_counter +{ + /* Dont't touch the counter. */ + VG_LITE_NONE, + + /* Turn the counter on. */ + VG_LITE_ON, + + /* Turn the counter off. */ + VG_LITE_OFF, + + /* Query the counter and reset its values. */ + VG_LITE_QUERY, +} +vg_lite_kernel_counter_t; + +typedef enum vg_lite_kernel_command +{ + /* Initialize the GPU. */ + VG_LITE_INITIALIZE, + + /* Terminate the GPU. */ + VG_LITE_TERMINATE, + + /* Allocate memory. */ + VG_LITE_ALLOCATE, + + /* Free memory. */ + VG_LITE_FREE, + + /* Submit a command buffer to the GPU. */ + VG_LITE_SUBMIT, + + /* Wait for the GPU to be completed. */ + VG_LITE_WAIT, + + /* Reset the GPU. */ + VG_LITE_RESET, + + /* Debug commands. */ + VG_LITE_DEBUG, + + /* Map memory. */ + VG_LITE_MAP, + + /* Unmap memory. */ + VG_LITE_UNMAP, + + /* Check info. */ + VG_LITE_CHECK, + + /* Query mem. */ + VG_LITE_QUERY_MEM, + +#if !defined(VG_DRIVER_SINGLE_THREAD) + /* Mutex lock. */ + VG_LITE_LOCK, + + /* Mutex unlock. */ + VG_LITE_UNLOCK, + + /* query context switch. */ + VG_LITE_QUERY_CONTEXT_SWITCH, +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +} +vg_lite_kernel_command_t; + +struct vg_lite_kernel_context { + /* Command buffer. */ + void * command_buffer[CMDBUF_COUNT]; + void * command_buffer_logical[CMDBUF_COUNT]; + uint32_t command_buffer_physical[CMDBUF_COUNT]; + +#if !defined(VG_DRIVER_SINGLE_THREAD) + vg_lite_os_async_event_t async_event[CMDBUF_COUNT]; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + + /* Tessellation buffer. */ + void * tessellation_buffer; + void * tessellation_buffer_logical; + uint32_t tessellation_buffer_physical; + +#if !defined(VG_DRIVER_SINGLE_THREAD) + /* context buffer. */ + void * context_buffer[CMDBUF_COUNT]; + void * context_buffer_logical[CMDBUF_COUNT]; + uint32_t context_buffer_physical[CMDBUF_COUNT]; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +}; + +/* Context structure. */ +typedef struct vg_lite_kernel_context vg_lite_kernel_context_t; + +typedef struct capabilities +{ + uint32_t tiled : 2; + uint32_t l2_cache : 1; +} +capabilities_t; + +typedef union vg_lite_capabilities +{ + capabilities_t cap; + uint32_t data; +} +vg_lite_capabilities_t; + +typedef struct vg_lite_kernel_initialize +{ + /* Command buffer size. */ + uint32_t command_buffer_size; + +#if !defined(VG_DRIVER_SINGLE_THREAD) + /* Context buffer size. */ + uint32_t context_buffer_size; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + + /* Tessellation buffer width. */ + int32_t tessellation_width; + + /* Tessellation buffer height. */ + int32_t tessellation_height; + + /* OUTPUT */ + + /* Context pointer. */ + vg_lite_kernel_context_t * context; + + /* Capabilities. */ + vg_lite_capabilities_t capabilities; + + /* Allocated command buffer. */ + void * command_buffer[CMDBUF_COUNT]; + + /* GPU address for command buffer. */ + uint32_t command_buffer_gpu[CMDBUF_COUNT]; + +#if !defined(VG_DRIVER_SINGLE_THREAD) + /* Allocated context buffer. */ + void * context_buffer[CMDBUF_COUNT]; + + /* GPU address for context buffer. */ + uint32_t context_buffer_gpu[CMDBUF_COUNT]; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + + /* GPU addresses for tesselation buffers. */ + uint32_t tessellation_buffer_gpu[3]; + + /* Logic addresses for tessellation buffers: used by SW Tessellator. */ + uint8_t *tessellation_buffer_logic[3]; + + /* Size of each level of the tesselation buffer. */ + uint32_t tessellation_buffer_size[3]; + + /* Stride of the tessellation buffer. */ + uint32_t tessellation_stride; + + /* Width and height of tessellation buffer. */ + uint32_t tessellation_width_height; + + /* Tessellation config: shift. */ + uint32_t tessellation_shift; +} +vg_lite_kernel_initialize_t; + +typedef struct vg_lite_kernel_terminate +{ + /* Context to terminate. */ + vg_lite_kernel_context_t * context; +} +vg_lite_kernel_terminate_t; + +typedef struct vg_lite_kernel_allocate +{ + /* Number of bytes to allocate. */ + uint32_t bytes; + + /* Flag to indicate whether the allocated memory is contiguous or not. */ + int32_t contiguous; + + /* OUTPUT */ + + /* Memory handle. */ + void * memory_handle; + + /* Allocated memory. */ + void * memory; + + /* GPU address of allocated memory. */ + uint32_t memory_gpu; +} +vg_lite_kernel_allocate_t; + +typedef struct vg_lite_kernel_free +{ + /* Memory handle to free. */ + void * memory_handle; +} +vg_lite_kernel_free_t; + +typedef struct vg_lite_kernel_submit +{ + /* Context to submit to. */ + vg_lite_kernel_context_t * context; + + /* Pointer to command buffer. */ + void * commands; + + /* Number of bytes in command buffer. */ + uint32_t command_size; + + /* Command Buffer ID. */ + uint32_t command_id; +} +vg_lite_kernel_submit_t; + +typedef struct vg_lite_kernel_wait +{ + /* Context to wait for. */ + vg_lite_kernel_context_t * context; + + /* Timeout in milliseconds. */ + uint32_t timeout_ms; + +#if defined(VG_DRIVER_SINGLE_THREAD) + /* The event to wait. */ + uint32_t event_mask; + + /* The event(s) got after waiting. */ + uint32_t event_got; +#else + /* Command Buffer ID. */ + uint32_t command_id; +#endif /* VG_DRIVER_SINGLE_THREAD */ +} +vg_lite_kernel_wait_t; + +typedef struct vg_lite_kernel_reset +{ + /* Context to reset. */ + vg_lite_kernel_context_t * context; +} +vg_lite_kernel_reset_t; + +typedef struct vg_lite_kernel_debug +{ + /* Context to debug. */ + vg_lite_kernel_context_t * context; + + /* Bandwidth counter enabler. */ + vg_lite_kernel_counter_t bandwidth_counter; + + /* Pixel counter enabler. */ + vg_lite_kernel_counter_t pixel_counters; + + /* OUTPUT */ + + /* Bandwidth counters: + * [0] - burst of 8. + * [1] - burst of 16. + * [2] - burst of 32. + * [3] - burst of 64. + */ + uint32_t bandwidth[4]; + + /* Pixel counters:. + * [0] - Number of tessellated pixels. + * [1] - Number of imaged pixels. + * [2] - Number of rendered pixels. + */ + uint32_t pixels[3]; +} +vg_lite_kernel_debug_t; + +typedef struct vg_lite_kernel_map +{ + /* Number of bytes to map. */ + uint32_t bytes; + + /* Logical memory address or NULL. */ + void * logical; + + /* Physical memory address or 0. */ + uint32_t physical; + + /* OUTPUT */ + + /* Memory handle for mapped memory. */ + void * memory_handle; + + /* GPU address of mapped memory. */ + uint32_t memory_gpu; +} +vg_lite_kernel_map_t; + +typedef struct vg_lite_kernel_unmap +{ + /* Memory handle to unmap. */ + void * memory_handle; +} +vg_lite_kernel_unmap_t; + +typedef struct vg_lite_kernel_info +{ + /* Register's address. */ + uint32_t addr; + + /* Check register info. */ + uint32_t reg; +} +vg_lite_kernel_info_t; + +typedef struct vg_lite_kernel_mem +{ + uint32_t bytes; +} +vg_lite_kernel_mem_t; + +#if !defined(VG_DRIVER_SINGLE_THREAD) +typedef struct vg_lite_kernel_context_switch +{ + uint8_t isContextSwitched; + uint32_t context; +} +vg_lite_kernel_context_switch_t; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +vg_lite_error_t vg_lite_kernel(vg_lite_kernel_command_t command, void * data); + +#ifdef __cplusplus +} +#endif +#endif /* _vg_lite_kernel_h_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_matrix.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_matrix.c new file mode 100644 index 0000000000..2411ab0ed0 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_matrix.c @@ -0,0 +1,113 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright 2012 - 2020 Vivante Corporation, Santa Clara, California. +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#include +#include +#include "vg_lite.h" + + +void vg_lite_identity(vg_lite_matrix_t * matrix) +{ + /* Set identify matrix. */ + matrix->m[0][0] = 1.0f; + matrix->m[0][1] = 0.0f; + matrix->m[0][2] = 0.0f; + matrix->m[1][0] = 0.0f; + matrix->m[1][1] = 1.0f; + matrix->m[1][2] = 0.0f; + matrix->m[2][0] = 0.0f; + matrix->m[2][1] = 0.0f; + matrix->m[2][2] = 1.0f; +} + +static void multiply(vg_lite_matrix_t * matrix, vg_lite_matrix_t * mult) +{ + vg_lite_matrix_t temp; + int row, column; + + /* Process all rows. */ + for (row = 0; row < 3; row++) { + /* Process all columns. */ + for (column = 0; column < 3; column++) { + /* Compute matrix entry. */ + temp.m[row][column] = (matrix->m[row][0] * mult->m[0][column]) + + (matrix->m[row][1] * mult->m[1][column]) + + (matrix->m[row][2] * mult->m[2][column]); + } + } + + /* Copy temporary matrix into result. */ + memcpy(matrix, &temp, sizeof(temp)); +} + +void vg_lite_translate(vg_lite_float_t x, vg_lite_float_t y, vg_lite_matrix_t * matrix) +{ + /* Set translation matrix. */ + vg_lite_matrix_t t = { { {1.0f, 0.0f, x}, + {0.0f, 1.0f, y}, + {0.0f, 0.0f, 1.0f} + } }; + + /* Multiply with current matrix. */ + multiply(matrix, &t); +} + +void vg_lite_scale(vg_lite_float_t scale_x, vg_lite_float_t scale_y, vg_lite_matrix_t * matrix) +{ + /* Set scale matrix. */ + vg_lite_matrix_t s = { { {scale_x, 0.0f, 0.0f}, + {0.0f, scale_y, 0.0f}, + {0.0f, 0.0f, 1.0f} + } }; + + /* Multiply with current matrix. */ + multiply(matrix, &s); +} + +void vg_lite_rotate(vg_lite_float_t degrees, vg_lite_matrix_t * matrix) +{ +#ifndef M_PI +#define M_PI 3.1415926f +#endif + /* Convert degrees into radians. */ + vg_lite_float_t angle = degrees / 180.0f * M_PI; + + /* Compuet cosine and sine values. */ + vg_lite_float_t cos_angle = cosf(angle); + vg_lite_float_t sin_angle = sinf(angle); + + /* Set rotation matrix. */ + vg_lite_matrix_t r = { { {cos_angle, -sin_angle, 0.0f}, + {sin_angle, cos_angle, 0.0f}, + {0.0f, 0.0f, 1.0f} + } }; + + /* Multiply with current matrix. */ + multiply(matrix, &r); +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_os.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_os.c new file mode 100644 index 0000000000..c9b3855e7e --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_os.c @@ -0,0 +1,473 @@ +#include "vg_lite_os.h" + +#include "rtthread.h" +#include "vg_lite_hw.h" +#include "vg_lite_hal.h" + +/* If bit31 is activated this indicates a bus error */ +#define IS_AXI_BUS_ERR(x) ((x)&(1U << 31)) + +#if !defined(VG_DRIVER_SINGLE_THREAD) +#define ISR_WAIT_TIME 0x1FFFF +#define MAX_MUTEX_TIME 100 +#define THREAD_WAIT_TIME 20 + +/* command queue task parameter */ +#define QUEUE_THREAD_NAME "queue_thread" +#ifndef QUEUE_THREAD_PRIO +// #define QUEUE_THREAD_PRIO (configMAX_PRIORITIES - 1) +#define QUEUE_THREAD_PRIO 0 +#endif /* QUEUE_THREAD_PRIO */ +#define QUEUE_THREAD_SIZE 1024 +#define QUEUE_LENGTH 8 +#define MAX_QUEUE_WAIT_NUM 10 +/* The array stores one or more tlss, which is pointed by user_data of current thread. Set it to 1 when only vglite is used, otherwise set it to 2 if elementary is applied. */ +#define TLS_ARRAY_LENGTH 2 + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TURE +#define TURE 1 +#endif + +typedef struct vg_lite_queue{ + uint32_t cmd_physical; + uint32_t cmd_offset; + uint32_t cmd_size; + vg_lite_os_async_event_t *event; +} +vg_lite_queue_t; + +rt_uint32_t tls_array[TLS_ARRAY_LENGTH] = {NULL}; +typedef struct vg_lite_os{ + rt_thread_t task_hanlde; + rt_mq_t queue_handle; +} +vg_lite_os_t; + +static rt_mutex_t mutex; +static vg_lite_os_t os_obj = {0}; + +rt_sem_t semaphore[THREAD_LENGTH] = {NULL}; +rt_sem_t command_semaphore = NULL; +uint32_t curContext; +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ +rt_sem_t int_queue; +volatile uint32_t int_flags; + +void __attribute__((weak)) vg_lite_bus_error_handler() +{ + /* + * Default implementation of the bus error handler does nothing. Application + * should override this handler if it requires to be notified when a bus + * error event occurs. + */ + return; +} + +#if !defined(VG_DRIVER_SINGLE_THREAD) +/* command queue function */ +void command_queue(void * parameters) +{ + vg_lite_queue_t* peek_queue; + uint32_t even_got; + uint32_t len; + + os_obj.queue_handle = rt_mq_create("queue_vglite", sizeof(vg_lite_queue_t * ), QUEUE_LENGTH, RT_IPC_FLAG_PRIO); + if(os_obj.queue_handle == RT_NULL) + { + /*command queue create fail, delete queue task */ + rt_thread_delete(rt_thread_self()); + } + + command_semaphore = rt_sem_create("cs", 0, RT_IPC_FLAG_PRIO); + while(1) + { + even_got = 0; + if (rt_sem_take((rt_sem_t)command_semaphore, RT_WAITING_FOREVER) == RT_EOK) { + if(os_obj.queue_handle->entry) + { + len = rt_mq_recv(os_obj.queue_handle, (void*) &peek_queue, os_obj.queue_handle->msg_size, (rt_int32_t) ((rt_int64_t)THREAD_WAIT_TIME * RT_TICK_PER_SECOND / 1000)); + if(len != 0) + { +#if defined(PRINT_COMMAND_BUFFER) + int i = 0; + for(i=0;i < (peek_queue->cmd_size + 3) / 4; i++) + { + if(i % 4 == 0) + printf("\r\n"); + printf("0x%08x ",((uint32_t*)(peek_queue->cmd_physical + peek_queue->cmd_offset))[i]); + } +#endif + vg_lite_hal_poke(VG_LITE_HW_CMDBUF_ADDRESS, peek_queue->cmd_physical + peek_queue->cmd_offset); + vg_lite_hal_poke(VG_LITE_HW_CMDBUF_SIZE, (peek_queue->cmd_size +7)/8 ); + + if(vg_lite_hal_wait_interrupt(ISR_WAIT_TIME, (uint32_t)~0, &even_got)) + peek_queue->event->signal = VG_LITE_HW_FINISHED; + else +#if defined(PRINT_DEBUG_REGISTER) + { + unsigned int debug; + unsigned int iter; + for(iter =0; iter < 16 ; iter ++) + { + vg_lite_hal_poke(0x470, iter); + debug = vg_lite_hal_peek(0x450); + printf("0x450[%d] = 0x%x\n", iter,debug); + } + for(iter =0; iter < 16 ; iter ++) + { + vg_lite_hal_poke(0x470, iter <<16); + debug = vg_lite_hal_peek(0x454); + printf("0x454[%d] = 0x%x\n", iter,debug); + } + for(iter =0; iter < 16 ; iter ++) + { + vg_lite_hal_poke(0x478, iter); + debug = vg_lite_hal_peek(0x468); + printf("0x468[%d] = 0x%x\n", iter,debug); + } + for(iter =0; iter < 16 ; iter ++) + { + vg_lite_hal_poke(0x478, iter); + debug = vg_lite_hal_peek(0x46C); + printf("0x46C[%d] = 0x%x\n", iter,debug); + } +#endif + /* wait timeout */ + peek_queue->event->signal = VG_LITE_IDLE; +#if defined(PRINT_DEBUG_REGISTER) + } +#endif + if(semaphore[peek_queue->event->semaphore_id]){ + rt_sem_release(semaphore[peek_queue->event->semaphore_id]); + } + + vg_lite_os_free((void *) peek_queue); + } + } + } + } +} + +int32_t vg_lite_os_init_tls_array(void) +{ + rt_thread_t rt_TCB; + + rt_TCB = rt_thread_self(); + RT_ASSERT( rt_TCB != NULL ); + + rt_TCB->user_data = (rt_uint32_t) tls_array; + + return VG_LITE_SUCCESS; +} + +void vg_lite_os_deinit_tls_array(void) +{ + rt_thread_t rt_TCB; + + rt_TCB = rt_thread_self(); + RT_ASSERT( rt_TCB != NULL ); + rt_TCB->user_data = NULL; +} + +int32_t vg_lite_os_set_tls(void* tls) +{ + if(tls == NULL) + return VG_LITE_INVALID_ARGUMENT; + + rt_thread_t rt_TCB; + + rt_TCB = rt_thread_self(); + RT_ASSERT( rt_TCB != NULL ); + + rt_uint32_t * tls_ptr = (rt_uint32_t *) rt_TCB->user_data; + *tls_ptr = (rt_uint32_t) tls; + return VG_LITE_SUCCESS; +} + +void * vg_lite_os_get_tls( ) +{ + rt_thread_t rt_TCB; + + void * pvReturn = NULL; + + rt_TCB = rt_thread_self(); + + rt_uint32_t * tls_ptr = (rt_uint32_t *) rt_TCB->user_data; + pvReturn = (void *) (*tls_ptr); + + return pvReturn; +} +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +void * vg_lite_os_malloc(uint32_t size) +{ + return rt_malloc((rt_size_t)size); +} + +void vg_lite_os_free(void * memory) +{ + rt_free(memory); +} + +#if !defined(VG_DRIVER_SINGLE_THREAD) +void vg_lite_os_reset_tls() +{ + rt_thread_t rt_TCB; + + rt_TCB = rt_thread_self(); + RT_ASSERT( rt_TCB != NULL ); + + rt_uint32_t * tls_ptr = (rt_uint32_t *) rt_TCB->user_data; + *tls_ptr = NULL; +} +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +void vg_lite_os_sleep(uint32_t msec) +{ + rt_thread_mdelay(msec); +} + +int32_t vg_lite_os_initialize(void) +{ +#if !defined(VG_DRIVER_SINGLE_THREAD) + static int task_number = 0; + +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + + int_queue = rt_sem_create("iq", 0, RT_IPC_FLAG_PRIO); + int_flags = 0; + +#if !defined(VG_DRIVER_SINGLE_THREAD) + if(mutex == NULL) + { + mutex = rt_mutex_create("mut", RT_IPC_FLAG_PRIO); + if(mutex == NULL) + return VG_LITE_MULTI_THREAD_FAIL; + } + + if(task_number == 0) + { + if(rt_mutex_take(mutex, (rt_int32_t) ((rt_int64_t)THREAD_WAIT_TIME * RT_TICK_PER_SECOND / 1000)) == RT_EOK) + { + if(os_obj.task_hanlde == NULL) + { + os_obj.task_hanlde = rt_thread_create(QUEUE_THREAD_NAME, command_queue, NULL, QUEUE_THREAD_SIZE, QUEUE_THREAD_PRIO, 1); + if(os_obj.task_hanlde == RT_NULL) + { + /* command queue task create fail */ + rt_mutex_release(mutex); + return VG_LITE_MULTI_THREAD_FAIL; + } + else + rt_thread_startup(os_obj.task_hanlde); + } + task_number++; + rt_mutex_release(mutex); + return VG_LITE_SUCCESS; + } + } +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + return VG_LITE_SUCCESS; +} + +void vg_lite_os_deinitialize(void) +{ + /* TODO: Remove clock. */ +#if !defined(VG_DRIVER_SINGLE_THREAD) + rt_mutex_delete(mutex); + mutex = 0; +#endif /* VG_DRIVER_SINGLE_THREAD */ + rt_sem_delete(int_queue); + /* TODO: Remove power. */ +} + +#if !defined(VG_DRIVER_SINGLE_THREAD) +int32_t vg_lite_os_lock() +{ + if(mutex == NULL) + return VG_LITE_NOT_SUPPORT; + + if(rt_mutex_take(mutex, (rt_int32_t) ((rt_int64_t)MAX_MUTEX_TIME * RT_TICK_PER_SECOND / 1000)) != RT_EOK) + return VG_LITE_MULTI_THREAD_FAIL; + + return VG_LITE_SUCCESS; +} + +int32_t vg_lite_os_unlock() +{ + if(rt_mutex_release(mutex) != RT_EOK) + return VG_LITE_MULTI_THREAD_FAIL; + + return VG_LITE_SUCCESS; +} + +int32_t vg_lite_os_submit(uint32_t context, uint32_t physical, uint32_t offset, uint32_t size, vg_lite_os_async_event_t *event) +{ + vg_lite_queue_t* queue_node; + + if(os_obj.queue_handle == RT_NULL) + return VG_LITE_NOT_SUPPORT; + + queue_node = (vg_lite_queue_t*) vg_lite_os_malloc(sizeof(vg_lite_queue_t)); + if(queue_node == NULL) + return VG_LITE_MULTI_THREAD_FAIL; + + queue_node->cmd_physical = physical; + queue_node->cmd_offset = offset; + queue_node->cmd_size = size; + queue_node->event = event; + + /* Current command buffer has been sent to the command queue. */ + event->signal = VG_LITE_IN_QUEUE; + + if(rt_mq_send_wait(os_obj.queue_handle, (void *) &queue_node, os_obj.queue_handle->msg_size, (rt_int32_t) ((rt_int64_t)ISR_WAIT_TIME * RT_TICK_PER_SECOND / 1000)) != RT_EOK) + return VG_LITE_MULTI_THREAD_FAIL; + curContext = context; + + if (vg_lite_os_wait_event(event) == VG_LITE_SUCCESS) { + if(rt_sem_release(command_semaphore) != RT_EOK) + return VG_LITE_MULTI_THREAD_FAIL; + return VG_LITE_SUCCESS; + } + + return VG_LITE_MULTI_THREAD_FAIL; +} + +int32_t vg_lite_os_wait(uint32_t timeout, vg_lite_os_async_event_t *event) +{ + if (semaphore[event->semaphore_id]) { + if (rt_sem_take(semaphore[event->semaphore_id], RT_WAITING_FOREVER) == RT_EOK) { + if(event->signal == VG_LITE_HW_FINISHED){ + rt_sem_release(semaphore[event->semaphore_id]); + return VG_LITE_SUCCESS; + } + else{ + rt_sem_release(semaphore[event->semaphore_id]); + return VG_LITE_TIMEOUT; + } + } + } + return VG_LITE_TIMEOUT; +} +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +void vg_lite_os_IRQHandler(void) +{ + uint32_t flags = vg_lite_hal_peek(VG_LITE_INTR_STATUS); + + if (flags) { + /* Combine with current interrupt flags. */ + int_flags |= flags; + + /* Wake up any waiters. */ + if(int_queue){ + rt_sem_release(int_queue); + } + } +} + +int32_t vg_lite_os_wait_interrupt(uint32_t timeout, uint32_t mask, uint32_t * value) +{ +#if _BAREMETAL + uint32_t int_status=0; + int_status = vg_lite_hal_peek(VG_LITE_INTR_STATUS); + (void)value; + + while (int_status==0){ + int_status = vg_lite_hal_peek(VG_LITE_INTR_STATUS); + usleep(1); + } + + if (IS_AXI_BUS_ERR(*value)) + { + vg_lite_bus_error_handler(); + } + return 1; +#else /*for rt500*/ + if(int_queue) { + if (rt_sem_take(int_queue, (rt_int32_t) ((rt_int64_t)timeout * RT_TICK_PER_SECOND / 1000)) == RT_EOK) { + if (value != NULL) { + *value = int_flags & mask; + if (IS_AXI_BUS_ERR(*value)) + { + vg_lite_bus_error_handler(); + } + } + int_flags = 0; + + return 1; + } + } + return 0; +#endif +} + +#if !defined(VG_DRIVER_SINGLE_THREAD) +int32_t vg_lite_os_init_event(vg_lite_os_async_event_t *event, + uint32_t semaphore_id, + int32_t state) +{ + if (event->semaphore_id >= THREAD_LENGTH) + return VG_LITE_INVALID_ARGUMENT; + + if (semaphore[semaphore_id]) + return VG_LITE_ALREADY_EXISTS; + + char name[RT_NAME_MAX] = {0}; + rt_snprintf(name, RT_NAME_MAX, "s%d", semaphore_id); + semaphore[semaphore_id] = rt_sem_create(name, 0, RT_IPC_FLAG_PRIO); + if (!semaphore[semaphore_id]) + return VG_LITE_OUT_OF_MEMORY; + + rt_sem_release(semaphore[semaphore_id]); + + event->semaphore_id = semaphore_id; + event->signal = state; + + return VG_LITE_SUCCESS; +} + +int32_t vg_lite_os_delete_event(vg_lite_os_async_event_t *event) +{ + if (event->semaphore_id >= THREAD_LENGTH) + return VG_LITE_INVALID_ARGUMENT; + + if (semaphore[event->semaphore_id]){ + rt_sem_delete(semaphore[event->semaphore_id]); + semaphore[event->semaphore_id] = NULL; + } + + return VG_LITE_SUCCESS; +} + +int32_t vg_lite_os_wait_event(vg_lite_os_async_event_t *event) +{ + if (event->semaphore_id >= THREAD_LENGTH) + return VG_LITE_INVALID_ARGUMENT; + + if (rt_sem_take(semaphore[event->semaphore_id], RT_WAITING_FOREVER) != RT_EOK) + return VG_LITE_MULTI_THREAD_FAIL; + + return VG_LITE_SUCCESS; +} + +int32_t vg_lite_os_signal_event(vg_lite_os_async_event_t *event) +{ + if (event->semaphore_id >= THREAD_LENGTH) + return VG_LITE_INVALID_ARGUMENT; + + rt_sem_release(semaphore[event->semaphore_id]); + return VG_LITE_SUCCESS; +} + +int8_t vg_lite_os_query_context_switch(uint32_t context) +{ + if(!curContext || curContext == context) + return FALSE; + return TURE; +} +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_os.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_os.h new file mode 100644 index 0000000000..aef7d0f66f --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_os.h @@ -0,0 +1,134 @@ +#ifndef _VG_LITE_OS_H +#define _VG_LITE_OS_H + +#include + +#if !defined(VG_DRIVER_SINGLE_THREAD) + +#define vg_lite_os_set_event_state(event, state) (event)->signal = state + +#define vg_lite_os_event_state(event) (event)->signal + +#define vg_lite_os_config_event(event, sem_id, state) \ + { \ + (event)->semaphore_id = sem_id; \ + (event)->signal = state; \ + } + +typedef struct vg_lite_os_async_event +{ + uint32_t semaphore_id; /*! The Id of the semaphore assigned to this event */ + int32_t signal; /*! The command buffer status */ +} +vg_lite_os_async_event_t; + +int32_t vg_lite_os_init_tls_array(void); + +void vg_lite_os_deinit_tls_array(void); + +/*! +@brief Set the value in a task’s thread local storage array. +*/ +int32_t vg_lite_os_set_tls(void* tls); + +/*! +@brief Get the current task’s thread local storage array. +*/ +void * vg_lite_os_get_tls( ); + +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +/*! +@brief Memory allocate. +*/ +void * vg_lite_os_malloc(uint32_t size); + +/*! +@brief Memory free. +*/ +void vg_lite_os_free(void * memory); + +#if !defined(VG_DRIVER_SINGLE_THREAD) +/*! +@brief Reset the value in a task’s thread local storage array. +*/ +void vg_lite_os_reset_tls(); +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +/*! +@brief sleep a number of milliseconds. +*/ +void vg_lite_os_sleep(uint32_t msec); + +/*! +@brief initialize the os parameters. +*/ +int32_t vg_lite_os_initialize(); + +/*! +@brief deinitialize the os parameters. +*/ +void vg_lite_os_deinitialize(); + +#if !defined(VG_DRIVER_SINGLE_THREAD) +/*! +@brief Mutex semaphore take. +*/ +int32_t vg_lite_os_lock(); + +/*! +@brief Mutex semaphore give. +*/ +int32_t vg_lite_os_unlock(); + +/*! +@brief Submit the current command buffer to the command queue. +*/ +int32_t vg_lite_os_submit(uint32_t context, uint32_t physical, uint32_t offset, uint32_t size, vg_lite_os_async_event_t *event); + +/*! +@brief Wait for the current command buffer to be executed. +*/ +int32_t vg_lite_os_wait(uint32_t timeout, vg_lite_os_async_event_t *event); +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ + +/*! +@brief IRQ Handler. +*/ +void vg_lite_os_IRQHandler(void); + +/*! +@brief Wait until an interrupt from the VGLite graphics hardware has been received. +*/ +int32_t vg_lite_os_wait_interrupt(uint32_t timeout, uint32_t mask, uint32_t * value); + +#if !defined(VG_DRIVER_SINGLE_THREAD) +/*! +@brief +*/ +int32_t vg_lite_os_init_event(vg_lite_os_async_event_t *event, + uint32_t semaphore_id, + int32_t state); + +/*! +@brief +*/ +int32_t vg_lite_os_delete_event(vg_lite_os_async_event_t *event); + +/*! +@brief +*/ +int32_t vg_lite_os_wait_event(vg_lite_os_async_event_t *event); + +/*! +@brief +*/ +int32_t vg_lite_os_signal_event(vg_lite_os_async_event_t *event); + +/*! +@brief +*/ +int8_t vg_lite_os_query_context_switch(uint32_t context); + +#endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ +#endif diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_path.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_path.c new file mode 100644 index 0000000000..c69c6bc05b --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_path.c @@ -0,0 +1,353 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright 2012 - 2020 Vivante Corporation, Santa Clara, California. +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#include +#include +#include +#include +#include "vg_lite.h" + +vg_lite_error_t vg_lite_upload_path(vg_lite_path_t * path) +{ + uint32_t bytes; + vg_lite_buffer_t Buf, *buffer; + buffer = &Buf; + + /* Compute the number of bytes required for path + command buffer prefix/postfix. */ + bytes = (8 + path->path_length + 7 + 8) & ~7; + + /* Allocate GPU memory. */ + buffer->width = bytes; + buffer->height = 1; + buffer->stride = 0; + buffer->format = VG_LITE_A8; + if (vg_lite_allocate(buffer) != VG_LITE_SUCCESS) { + return VG_LITE_OUT_OF_MEMORY; + } + + /* Initialize command buffer prefix. */ + ((uint32_t *) buffer->memory)[0] = 0x40000000 | ((path->path_length + 7) / 8); + ((uint32_t *) buffer->memory)[1] = 0; + + /* Copy the path data. */ + memcpy((uint32_t *) buffer->memory + 2, path->path, path->path_length); + + /* Initialize command buffer postfix. */ + ((uint32_t *) buffer->memory)[bytes / 4 - 2] = 0x70000000; + ((uint32_t *) buffer->memory)[bytes / 4 - 1] = 0; + + /* Mark path as uploaded. */ + path->uploaded.handle = buffer->handle; + path->uploaded.address = buffer->address; + path->uploaded.memory = buffer->memory; + path->uploaded.bytes = bytes; + path->path_changed = 0; + VLM_PATH_ENABLE_UPLOAD(*path); /* Implicitly enable path uploading. */ + + /* Return pointer to vg_lite_buffer structure. */ + return VG_LITE_SUCCESS; +} + +/* Path data operations. */ +#define CDALIGN(value, by) (((value) + (by) - 1) & ~((by) - 1)) +#define CDMIN(x, y) ((x) > (y) ? (y) : (x)) +#define CDMAX(x, y) ((x) > (y) ? (x) : (y)) + +static int32_t get_data_count(uint8_t cmd) +{ + static int32_t count[] = { + 0, + 0, + 2, + 2, + 2, + 2, + 4, + 4, + 6, + 6, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5 + }; + + if (cmd > VLC_OP_LCWARC_REL) { + return -1; + } + else { + return count[cmd]; + } +} + +static void compute_pathbounds(float *xmin, float *ymin, float *xmax, float *ymax, float x, float y) +{ + if (xmin != NULL) + { + *xmin = *xmin < x ? *xmin : x; + } + + if (xmax != NULL) + { + *xmax = *xmax > x ? *xmax : x; + } + + if (ymin != NULL) + { + *ymin = *ymin < y ? *ymin : y; + } + + if (ymax != NULL) + { + *ymax = *ymax > y ? *ymax : y; + } +} + +static int32_t get_data_size(vg_lite_format_t format) +{ + int32_t data_size = 0; + + switch (format) { + case VG_LITE_S8: + data_size = sizeof(int8_t); + break; + + case VG_LITE_S16: + data_size = sizeof(int16_t); + break; + + case VG_LITE_S32: + data_size = sizeof(int32_t); + break; + + default: + data_size = sizeof(vg_lite_float_t); + break; + } + + return data_size; +} + +int32_t vg_lite_path_calc_length(uint8_t *cmd, uint32_t count, vg_lite_format_t format) +{ + int32_t size = 0; + int32_t dCount = 0; + uint32_t i = 0; + int32_t data_size = 0; + + data_size = get_data_size(format); + + for (i = 0; i < count; i++) { + size++; /* OP CODE. */ + + dCount = get_data_count(cmd[i]); + if (dCount > 0) { + size = CDALIGN(size, data_size); + size += dCount * data_size; + } + } + + return size; +} + +vg_lite_error_t vg_lite_path_append(vg_lite_path_t *path, + uint8_t *cmd, + void *data, + uint32_t seg_count) +{ + vg_lite_error_t error = VG_LITE_SUCCESS; + uint32_t i; + int32_t j; + int32_t offset = 0; + int32_t dataCount = 0; + float *dataf = (float*) data; + float *pathf = NULL; + int32_t *data_s32 = (int32_t*) data; + int32_t *path_s32 = NULL; + int16_t *data_s16 = (int16_t*) data; + int16_t *path_s16 = NULL; + int8_t *data_s8 = (int8_t*) data; + int8_t *path_s8 = NULL; + uint8_t *pathc = NULL; + int32_t data_size; + uint8_t arc_path = 0; + float px = 0.0f, py = 0.0f, cx = 0.0f, cy = 0.0f; + int rel = 0; + + if(cmd == NULL || data == NULL || path == NULL || path->path == NULL) + return VG_LITE_INVALID_ARGUMENT; + + for(i = 0; i < seg_count; i++) { + if(cmd[i] > VLC_OP_LCWARC_REL) + return VG_LITE_INVALID_ARGUMENT; + } + + data_size = get_data_size(path->format); + path->path_changed= 1; + pathf = (float *)path->path; + path_s32 = (int32_t *)path->path; + path_s16 = (int16_t *)path->path; + path_s8 = (int8_t *)path->path; + pathc = (uint8_t *)path->path; + + /* Loop to fill path data. */ + for (i = 0; i < seg_count; i++) { + *(pathc + offset) = cmd[i]; + offset++; + + dataCount = get_data_count(cmd[i]); + if (dataCount > 0) { + offset = CDALIGN(offset, data_size); + if ((cmd[i] > VLC_OP_CLOSE) && + ((cmd[i] & 0x01) == 1)){ + rel = 1; + } + else { + rel = 0; + } + if(cmd[i] < VLC_OP_SCCWARC) { + for (j = 0; j < dataCount / 2; j++) { + switch (path->format) { + case VG_LITE_S8: + path_s8 = (int8_t *)(pathc + offset); + path_s8[j * 2] = *data_s8++; + path_s8[j * 2 + 1] = *data_s8++; + + if (rel) { + cx = px + path_s8[j * 2]; + cy = py + path_s8[j * 2 + 1]; + } + else { + cx = path_s8[j * 2]; + cy = path_s8[j * 2 + 1]; + } + break; + case VG_LITE_S16: + path_s16 = (int16_t *)(pathc + offset); + path_s16[j * 2] = *data_s16++; + path_s16[j * 2 + 1] = *data_s16++; + + if (rel) { + cx = px + path_s16[j * 2]; + cy = py + path_s16[j * 2 + 1]; + } + else { + cx = path_s16[j * 2]; + cy = path_s16[j * 2 + 1]; + } + break; + case VG_LITE_S32: + path_s32 = (int32_t *)(pathc + offset); + path_s32[j * 2] = *data_s32++; + path_s32[j * 2 + 1] = *data_s32++; + + if (rel) { + cx = px + path_s32[j * 2]; + cy = py + path_s32[j * 2 + 1]; + } + else { + cx = path_s32[j * 2]; + cy = path_s32[j * 2 + 1]; + } + break; + case VG_LITE_FP32: + pathf = (float *)(pathc + offset); + pathf[j * 2] = *dataf++; + pathf[j * 2 + 1] = *dataf++; + + if (rel) { + cx = px + pathf[j * 2]; + cy = py + pathf[j * 2 + 1]; + } + else { + cx = pathf[j * 2]; + cy = pathf[j * 2 + 1]; + } + break; + + default: + return VG_LITE_INVALID_ARGUMENT; + } + + /* Update path bounds. */ + path->bounding_box[0] = CDMIN(path->bounding_box[0], cx); + path->bounding_box[2] = CDMAX(path->bounding_box[2], cx); + path->bounding_box[1] = CDMIN(path->bounding_box[1], cy); + path->bounding_box[3] = CDMAX(path->bounding_box[3], cy); + } + } + else { + arc_path = 1; + pathf = (float *)(pathc + offset); + pathf[0] = *dataf++; + pathf[1] = *dataf++; + pathf[2] = *dataf++; + pathf[3] = *dataf++; + pathf[4] = *dataf++; + + if (rel) { + cx = px + pathf[3]; + cy = py + pathf[4]; + } + else { + cx = pathf[3]; + cy = pathf[4]; + } + + /* Update path bounds. */ + compute_pathbounds(&path->bounding_box[0], &path->bounding_box[1], &path->bounding_box[2], &path->bounding_box[3],cx + 2 * pathf[0],cy + 2 * pathf[1]); + compute_pathbounds(&path->bounding_box[0], &path->bounding_box[1], &path->bounding_box[2], &path->bounding_box[3],px + 2 * pathf[1],py + 2 * pathf[1]); + compute_pathbounds(&path->bounding_box[0], &path->bounding_box[1], &path->bounding_box[2], &path->bounding_box[3],cx - 2 * pathf[0],cy - 2 * pathf[1]); + compute_pathbounds(&path->bounding_box[0], &path->bounding_box[1], &path->bounding_box[2], &path->bounding_box[3],px - 2 * pathf[1],py - 2 * pathf[1]); + } + px = cx; + py = cy; + + offset += dataCount * data_size; + } + } + + path->path_length = offset; + + if(arc_path) { + error = vg_lite_init_arc_path(path, + VG_LITE_FP32, + path->quality, + path->path_length, + path->path, + path->bounding_box[0], path->bounding_box[1], + path->bounding_box[2], path->bounding_box[3]); + } + + return error; +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_platform.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_platform.h new file mode 100644 index 0000000000..03bf2484e6 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_platform.h @@ -0,0 +1,48 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright (c) 2014 - 2020 Vivante Corporation +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +#ifndef _VG_LITE_PLATFORM_H +#define _VG_LITE_PLATFORM_H + +#include "stdint.h" +#include "stdlib.h" + +#define _BAREMETAL 0 + +/*! +@brief Initialize the hardware mem setting. +*/ +void vg_lite_init_mem(uint32_t register_mem_base, + uint32_t gpu_mem_base, + volatile void * contiguous_mem_base, + uint32_t contiguous_mem_size); + +/*! +@brief The hardware IRQ handler. +*/ +void vg_lite_IRQHandler(void); + +#endif diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_text.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_text.c new file mode 100644 index 0000000000..57dd8e12e0 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_text.c @@ -0,0 +1,359 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright 2020 NXP +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ + +/** Include Files */ +#include "vg_lite.h" +#include "vg_lite_text.h" +#include +#include + +#include +#include "vft_draw.h" + +/** Macros */ + +/** Data structures */ +typedef struct { + /* Font related parameters */ + vg_lite_font_attributes_t *attributes; + vg_lite_buffer_t buffer; + uint16_t width; + uint16_t height; + uint16_t y; + const struct mf_font_s *rcd_font; +} text_context_t; + +/** Internal or external API prototypes */ +struct mf_font_s *_vg_lite_get_raster_font(vg_lite_font_t font_idx); +int vg_lite_is_font_valid(vg_lite_font_t font); + +/** Globals */ +vg_lite_font_attributes_t g_font_attribs; +vg_lite_font_t g_last_font = VG_LITE_INVALID_FONT; +int g_last_font_attrib_idx; + +/** Externs if any */ + +/* Capture unique values of alpha */ +static unsigned int g_index_table[257]; + +/* text_color is in ARGB8888 format */ +int init_256pallet_color_table(unsigned int bg_color, unsigned int fg_color) +{ + int i; + g_index_table[0] = 0; /* Background color */ + int fg_r = ((fg_color>>0)&0xff); + int fg_g = ((fg_color>>8)&0xff); + int fg_b = ((fg_color>>16)&0xff); + + int bg_r = ((bg_color>>0)&0xff); + int bg_g = ((bg_color>>8)&0xff); + int bg_b = ((bg_color>>16)&0xff); + + for (i=1; i<256; i++) { + int r, g, b; + int a = 0xff; + register int mult, mult2; + + mult = ((i*1024)/256); + mult2 = (((256-i)*1024)/256); + + /* Blend with white bg */ + r = ( ((bg_r * mult2)>>10) +((fg_r * mult)>>10) ); + g = ( ((bg_g * mult2)>>10) +((fg_g * mult)>>10) ); + b = ( ((bg_b * mult2)>>10) +((fg_b * mult)>>10) ); + g_index_table[i] = ((a) + (r<<8) + (g<<16)+(b<<24)); + } + return 0; +} + +/* Callback to write to a memory buffer. */ +static void pixel_callback(int16_t x, int16_t y, uint8_t count, uint8_t alpha, + void *state) +{ + text_context_t *s = (text_context_t*)state; + uint32_t pos; + uint32_t value; + uint32_t *raw_pixel_buffer = (uint32_t *)s->buffer.memory; + int stride = s->buffer.stride; + + if (y < 0 || y >= s->height) return; + if (x < 0 || x + count >= s->width) return; + + while (count--) + { + pos = (uint32_t)stride * y + x; + value = g_index_table[alpha]; + + raw_pixel_buffer[pos] = value; + + x++; + } +} + +/* Callback to render characters. */ +static uint8_t character_callback(int16_t x, int16_t y, mf_char character, + void *state) +{ + text_context_t *s = (text_context_t*)state; + return mf_render_character(s->rcd_font, x, y, character, pixel_callback, state); +} + +/* Callback to render lines. */ +static bool line_callback(const char *line, uint16_t count, void *state) +{ + text_context_t *s = (text_context_t*)state; + + if (s->attributes->justify) + { + mf_render_justified(s->rcd_font, s->attributes->anchor, s->y, + s->width - s->attributes->margin * 2, + line, count, character_callback, state); + } + else + { + mf_render_aligned(s->rcd_font, s->attributes->anchor, s->y, + (enum mf_align_t)s->attributes->alignment, line, count, + character_callback, state); + } + s->y += s->rcd_font->line_height; + return true; +} + +/* Callback to just count the lines. + * Used to decide the image height */ +bool count_lines(const char *line, uint16_t count, void *state) +{ + int *linecount = (int*)state; + (*linecount)++; + return true; +} + +vg_lite_error_t alloc_font_buffer(vg_lite_buffer_t *buffer, int width , int height) +{ + vg_lite_error_t error; + + /* Align width to 16 pixels, heigh to 16 pixels */ + width = ((width+15)&(~15)); + height = ((height+15)&(~15)); + + /* Allocate memory from VGLITE space */ + buffer->width = width; + buffer->height = height; + buffer->format = VG_LITE_ARGB8888; + buffer->stride = 0; + error = vg_lite_allocate(buffer); + buffer->stride = width; + buffer->tiled = VG_LITE_LINEAR; + + return error; +} + +static vg_lite_error_t free_font_buffer(vg_lite_buffer_t *buffer) +{ + vg_lite_error_t error; + + error = vg_lite_free(buffer); + + return error; +} + +void matrix_multiply(vg_lite_matrix_t * matrix, vg_lite_matrix_t * mult) +{ + vg_lite_matrix_t temp; + int row, column; + + /* Process all rows. */ + for (row = 0; row < 3; row++) { + /* Process all columns. */ + for (column = 0; column < 3; column++) { + /* Compute matrix entry. */ + temp.m[row][column] = (matrix->m[row][0] * mult->m[0][column]) + + (matrix->m[row][1] * mult->m[1][column]) + + (matrix->m[row][2] * mult->m[2][column]); + } + } + + /* Copy temporary matrix into result. */ + memcpy(matrix, &temp, sizeof(temp)); +} + +vg_lite_error_t vg_lite_draw_text(vg_lite_buffer_t *target, + char *text, + vg_lite_font_t font, + int x, + int y, + vg_lite_matrix_t *matrix, + vg_lite_blend_t blend, + vg_lite_font_attributes_t *attributes) +{ + vg_lite_error_t error; + int height; + text_context_t ctx_text; + vg_lite_matrix_t m_text; + int text_img_size = 0; + font_face_desc_t* font_face = NULL; + int text_width_in_pixels = 0; + int tmpX; + + memset(&ctx_text, 0, sizeof(ctx_text)); + ctx_text.attributes = attributes; + + if ( vg_lite_is_font_valid(font) != 0 ) { + return VG_LITE_INVALID_ARGUMENT; + } + + error = vg_lite_load_font_data(font, + attributes->font_height); + if ( error != 0 ) { + return VG_LITE_INVALID_ARGUMENT; + } + + if(attributes->tspan_has_dx_dy != 0) + { + if ( x < 0 ) + x = attributes->last_x + attributes->last_dx; + if ( y < 0 ) + y = attributes->last_y; + } + + // Dynamic decision + if ( attributes->is_vector_font == 0 ) { + init_256pallet_color_table(attributes->bg_color, attributes->text_color); + + /* Application specifies actual font by reading proper rcd file */ + ctx_text.rcd_font = _vg_lite_get_raster_font(font); + + /* Count number of lines to decide font buffer size. */ + height = 0; + mf_text_draw_area(ctx_text.rcd_font, attributes->width - 2 * attributes->margin, + text, &height, &text_width_in_pixels); + height *= attributes->font_height; + height += 4; + + if( attributes->tspan_has_dx_dy == 0) { + y -= attributes->font_height; + } + + tmpX = x; + if(attributes->alignment == eTextAlignCenter) { + tmpX -= text_width_in_pixels/2; + } else if(attributes->alignment == eTextAlignRight) { + tmpX -= text_width_in_pixels; + } + /* Manually calculate X-offset for text-alignemnt; mcufont just + * doesn't render half part(left-part) for center alignment and + * full string skipped for right-alignment, So again set it to + * left-alignment for font-attrib, as offsets are already + * calculated and alignment handled in other way */ + attributes->alignment = 0; + + /* Allocate and initialize vg_lite_buffer that can hold font text + * Note: ctx_text.width and ctx_text.height get used by internal + * state of MF rendering engine. Based on amount of text to render + * This buffer gets allocated, and buffer width gets aligned to + * 16 pixel boundary + */ + ctx_text.width = attributes->width; + /* Memory optimization */ + ctx_text.width = text_width_in_pixels; + /* Align width to 16 pixel boundary */ + if (ctx_text.width & 15) { + ctx_text.width += 15; + ctx_text.width &= (~15); + } + + ctx_text.height = height; + error = alloc_font_buffer(&ctx_text.buffer, ctx_text.width, ctx_text.height); + if ( error != VG_LITE_SUCCESS) { + printf("WARNING: alloc_font_buffer failed(%d).\r\n",error); + } + ctx_text.y = 2; + + /* Initialize vg_lite buffer with transperant color */ + /* Due to alignment requirement of vg_lite, font buffer can be larger */ + if ( ctx_text.buffer.format == VG_LITE_ARGB8888 ) + text_img_size = ctx_text.buffer.width * ctx_text.buffer.height * 4; + else + text_img_size = ctx_text.buffer.width * ctx_text.buffer.height; + memset(ctx_text.buffer.memory, 0, + text_img_size); + + /* Render font text into vg_lite_buffer */ + mf_wordwrap(ctx_text.rcd_font, attributes->width - 2 * attributes->margin, + text, line_callback, &ctx_text); + + /* Draw font bitmap on render target */ + vg_lite_identity(&m_text); + matrix_multiply(&m_text, matrix); + vg_lite_translate(x, y, &m_text); + vg_lite_scale(1.0, 1.0, &m_text); + if ( ctx_text.buffer.format == VG_LITE_ARGB8888 ) + ctx_text.buffer.stride = ctx_text.width*4; + + error = vg_lite_blit(target, &ctx_text.buffer, &m_text, blend, + 0, VG_LITE_FILTER_POINT); + if ( error != VG_LITE_SUCCESS) { + printf("WARNING: vg_lite_blit failed(%d).\r\n",error); + } + + error = vg_lite_finish(); + if ( error != VG_LITE_SUCCESS) { + printf("WARNING: vg_lite_finish failed(%d).\r\n",error); + } + + error = free_font_buffer(&ctx_text.buffer); + if ( error != VG_LITE_SUCCESS) { + printf("WARNING: vg_lite_finish failed(%d).\r\n",error); + } + attributes->last_dx = text_width_in_pixels; + } else { + error = (vg_lite_error_t)vg_lite_vtf_draw_text(target, + x, y, + blend, + font, + matrix, + attributes, + text); + /* Note: vg_lite_vtf_draw_text updates attributes->last_dx internally + This assignment is just to keep code similar to rcd code */ + attributes->last_dx = attributes->last_dx; + + error = vg_lite_finish(); + if ( error != VG_LITE_SUCCESS) { + printf("WARNING: vg_lite_finish failed(%d).\r\n",error); + } + + vft_unload(font_face); + } + attributes->last_x = x; + attributes->last_y = y; + + return error; +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_text.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_text.h new file mode 100644 index 0000000000..3c519b1e56 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_text.h @@ -0,0 +1,372 @@ +/**************************************************************************** +* +* The MIT License (MIT) +* +* Copyright 2020 NXP +* All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* 'Software'), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sub license, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject +* to the following conditions: +* +* The above copyright notice and this permission notice (including the +* next paragraph) shall be included in all copies or substantial +* portions of the Software. +* +* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +* IN NO EVENT SHALL VIVANTE AND/OR ITS SUPPLIERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*****************************************************************************/ +#ifndef _vg_lite_text_h_ +#define _vg_lite_text_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "vg_lite.h" + +/* Macros *********************************************************************/ + +#define MAX_FONT_NAME_LEN (64) +#define VG_LITE_INVALID_FONT (-1) +#define INVALID_FONT_PROPERTY_IDX (-1) + +/* Types **********************************************************************/ + + /*! + @abstract Font Type enumeration + + @discussion + This enumeration defines supported high level font type type. + */ + typedef enum eFontType { + eFontTypeVector, + eFontTypeRaster + } eFontType_t; + + /*! + @abstract Font weight enumeration + + @discussion + This enumeration defines font weight that maps to css specification + */ + typedef enum eFontWeight { + eFontWeightThin = 100, /*! Thin, Hairline, Ultra-light, Extra-light */ + eFontWeightLight = 200, /*! Light */ + eFontWeightBook = 300, /*! Book */ + eFontWeightRegular = 400, /*! Regular, Normal, Plain, Roman, Standard */ + eFontWeightMedium = 500, /*! Medium */ + eFontWeightSemiBold = 600, /*! Semi-bold, Demi-bold */ + eFontWeightBold = 700, /*! Bold */ + eFontWeightHeavy = 800, /*! Heavy, Black, Extra-bold */ + eFontUltraBlack = 900, /*! Ultra-black, Extra-black, Ultra-bold, + Heavy-black, Fat, Poster */ + } eFontWeight_t; + + /*! + @abstract Font stretch enumeration + + @discussion + This enumeration defines font stretch that maps to css specification + */ + typedef enum eFontStretch { + eFontStretchUltraCondensed = 1, /*! ultra-condensed */ + eFontStretchExtraCondensed = 2, /*! extra-condensed */ + eFontStretchCondensed = 3, /*! condensed */ + eFontStretchSemiCondensed = 4, /*! semi-condensed */ + eFontStretchNormal = 5, /*! normal */ + eFontStretchSemiExpanded = 6, /*! semi-expanded */ + eFontStretchExpanded = 7, /*! expanded */ + eFontStretchExtraExpanded = 8, /*! extra-expanded */ + eFontStretchUltraExpanded = 9, /*! ultra-expanded */ + } eFontStretch_t; + + /*! + @abstract Font style enumeration + + @discussion + This enumeration defines font style that maps to css specification + */ + typedef enum eFontStyle { + eFontStyleNormal = 1, /*! normal */ + eFontStyleItalic = 2, /*! italic, oblique */ + } eFontStyle_t; + + /*! + @abstract Text alignment enumeration + + @discussion + This enumeration defines text alignment that maps to css specification + */ + typedef enum eTextAlign { + eTextAlignLeft, + eTextAlignCenter, + eTextAlignRight, + eTextAlignJustify, + } eTextAlign_t; + +/* Structures *****************************************************************/ + + /*! + @abstract Font parameters + + @discussion + This datastructure specifies application font and its data. Application + can register as many font as required using vg_lite_register_font + And lateron refer them in vg_lite_draw_text API + + for raster fonts mandatory fields are: + name, + font_weight, font_stretch, font_style, font_height + data, data_len + for vector fonts mandatory fields are: + name, + data, data_len + */ + typedef struct vg_lite_font_params + { + char name[MAX_FONT_NAME_LEN]; /*! font-family name */ + eFontType_t font_type; /*! Raster/Vector font */ + eFontWeight_t font_weight; /*! Font weight enum value */ + eFontStretch_t font_stretch; /*! Font stretch enum value */ + eFontStyle_t font_style; /*! Font style enum value */ + int font_height; /*! Font height in pixels */ + int data_len; /*! Font data buffer length */ + void *data; /*! the address where the actual font data is stored; it is the + * responsibility of the user/application to load it there */ + } vg_lite_font_params_t; + + /*! + @abstract Opaque type for font descriptor + + @discussion + This is an index of into font-table. Font table can have atmost + MAX_SYSTEM_FONTS font, registering more font results in an error. + */ + typedef uint32_t vg_lite_font_t; + + /*! + @abstract Runtime parameter to render text using given font + + @discussion + These parameters controls rendering of text using given font. + */ + typedef struct { + /* Application controllable parameters */ + int justify; /*! Equal justify given text in text display area */ + int alignment; /*! Ailgn text to left, center or right */ + + int width; /*! Internal variable computed based on active font */ + int height; /*! Internal variable computed based on active font */ + + unsigned int text_color; /*! Foreground text color */ + unsigned int bg_color; /*! Background text color */ + + int tspan_has_dx_dy; /*! 0 means tspan element has x,y values + 1 means tspan element has dx, dy values + so use last_x+dx for x, + last_y+dy for y + */ + int is_vector_font; /*! 1 when active font is vector font, 0 otherwise */ + + int margin; /*! Left and right margin in pixels that should be skipped + by text rendering engine */ + int anchor; /*! Anchor text */ + int scale; /*! Flag that indicate if text rendering engine should + scale text */ + + /* Internal parameters of text rendering engine. + Application code should not modify these parameters + */ + int font_height; /*! Font height in pixels, parameter from svg */ + int last_x; /*! Last x position of text element */ + int last_y; /*! Last y position of text element */ + int last_dx; /*! Horizontal width of text in pixels, for last text */ + } vg_lite_font_attributes_t; + + /* API Function prototypes ****************************************************/ + + /*! + @abstract Registers application specific font in vg_ltie driver. + + @discussion + Using vg_lite_register_font application can register active + fonts that vg_lite_draw_text uses to render text. + + for raster fonts mandatory fields of vg_lite_font_params_t are: + name, + font_weight, font_stretch, font_style, font_height + data, data_len + for vector fonts mandatory fields of vg_lite_font_params_t are: + name, + data, data_len + + On successful registeration font poiter will get non-negative + application handle. + + @param font + Pointer to font handle + + @param params + Pointer to font parameters that are used by vg_lite_find_font + to select specific font for rendering text + + @result + Returns the status as defined by vg_lite_error_t. + VG_LITE_SUCCESS when font registation is success + VG_LITE_INVALID_ARGUMENT When parameter pointer is invalid + VG_LITE_ALREADY_EXISTS if font name already exists + VG_LITE_OUT_OF_RESOURCES if active font exceeds MAX_SYSTEM_FONTS + */ + vg_lite_error_t vg_lite_register_font( + vg_lite_font_t *font, + vg_lite_font_params_t *params); + + /*! + @abstract Un-registers application specific font in vg_ltie driver. + + @discussion + vg_lite_unregister_font unregisters application speciific + font form vg_lite driver. This font can not be used lateron by + vg_lite_draw_text API. + + @param font + Pointer to font handle + + @result + Returns the status as defined by vg_lite_error_t. + VG_LITE_SUCCESS when font registation is success + VG_LITE_INVALID_ARGUMENT if font handle is invalid + */ + vg_lite_error_t vg_lite_unregister_font(vg_lite_font_t font); + + + /*! + @abstract Check if given font is vector/raster ? + + @discussion + vg_lite_is_vector_font API lookups active fonts in + vg_lite driver and if font it found it return 1 if it points to vector font + otherwise it return 0; + + @param font + Pointer to font handle + + @result + Returns the status as defined by vg_lite_error_t. + VG_LITE_SUCCESS when font registation is success + VG_LITE_INVALID_ARGUMENT if font handle is invalid + */ + int vg_lite_is_vector_font(vg_lite_font_t font); + + /*! + @abstract This API renders text with specified font on render target. + + @discussion + This API can reder text using user supplied font. Text rendering can be + controlled by vg_lite_font_attributes_t. + + @param target + Pointer to render target + + @param text + ASCII text that needs to be rendered on render + + @param font + Pointer to font handle + + @param x + x position in pixels in X-axis for text rendering + + @param y + y position in pixels in Y-axis for text rendering + + @param matrix + Translation matrix that is used while rendering text. + @attention Scaling and rotation matrix are not supported. + + @param blend + Specifies how text gets blened in text area. Typical value is ELM_BLEND_SRC_OVER + + @param attributes + Font attributes that controls how text gets rendered in render buffer. + + @result + Returns the status as defined by vg_lite_error_t. + VG_LITE_SUCCESS when font registation is success + VG_LITE_INVALID_ARGUMENT if input parameters have any issue + */ + vg_lite_error_t vg_lite_draw_text( + vg_lite_buffer_t *target, + char *text, + vg_lite_font_t font, + int x, + int y, + vg_lite_matrix_t *matrix, + vg_lite_blend_t blend, + vg_lite_font_attributes_t *attributes); + + /*! + @abstract This API searches registered font for given name with + requested rendering capabilities. + + @discussion + This API searches registered font for given name with + requested rendering capabilities. + + for raster fonts following fields are compared + name, + font_weight, font_stretch, font_style, font_height + + for vector fonts following fields are compared + name + + @param font_name + Font name + + @param font_weight + Font weight value from eFontWeight_t + + @param font_stretch + Font stretch value from eFontStretch_t + + @param font_style + Font style value from eFontStyle_t + + @param font_height + Font height in pixels + + If during font lookup a validate font is found then it retuns its handle. + + @result + Returns valid font handle or an error code. + Valid font handle if input parameters matches any of registerd font. + INVALID_FONT if input parameters don't match registered fonts. + */ + vg_lite_font_t vg_lite_find_font( + char *font_name, + eFontWeight_t font_weight, + eFontStretch_t font_stretch, + eFontStyle_t font_style, + int font_height); + + /*! + @abstract Initializes support for text drawing. + */ + void vg_lite_text_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _vg_lite_text_h_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_support.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_support.c new file mode 100644 index 0000000000..77ef33e168 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_support.c @@ -0,0 +1,87 @@ +/* + * Copyright 2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "vglite_support.h" +#include "fsl_clock.h" +#include "vg_lite.h" +#include "vg_lite_platform.h" +#include "display_support.h" +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define MAX_CONTIGUOUS_SIZE 0x200000 +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +static uint32_t registerMemBase = 0x41800000; +static uint32_t gpu_mem_base = 0x0; + +/* + * In case custom VGLite memory parameters are used, the application needs to + * allocate and publish the VGLite heap base, its size and the size of the + * command buffer(s) using the following global variables: + */ +extern void *vglite_heap_base; +extern uint32_t vglite_heap_size; + +#if (CUSTOM_VGLITE_MEMORY_CONFIG == 0) +/* VGLite driver heap */ +AT_NONCACHEABLE_SECTION_ALIGN(static uint8_t contiguous_mem[MAX_CONTIGUOUS_SIZE], FRAME_BUFFER_ALIGN); + +void *vglite_heap_base = &contiguous_mem; +uint32_t vglite_heap_size = MAX_CONTIGUOUS_SIZE; +#endif /* CUSTOM_VGLITE_MEMORY_CONFIG */ + +/******************************************************************************* + * Code + ******************************************************************************/ +void GPU2D_IRQHandler(void) +{ + vg_lite_IRQHandler(); +} + +static status_t BOARD_InitVGliteClock(void) +{ + const clock_root_config_t gc355ClockConfig = { + .clockOff = false, + .mux = kCLOCK_GC355_ClockRoot_MuxVideoPllOut, /*!< 984MHz */ + .div = 2, + }; + + CLOCK_SetRootClock(kCLOCK_Root_Gc355, &gc355ClockConfig); + + CLOCK_GetRootClockFreq(kCLOCK_Root_Gc355); + + CLOCK_EnableClock(kCLOCK_Gpu2d); + + NVIC_SetPriority(GPU2D_IRQn, 3); + + EnableIRQ(GPU2D_IRQn); + + return kStatus_Success; +} + +status_t BOARD_PrepareVGLiteController(void) +{ + status_t status; + + status = BOARD_InitVGliteClock(); + + if (kStatus_Success != status) + { + return status; + } + + vg_lite_init_mem(registerMemBase, gpu_mem_base, vglite_heap_base, vglite_heap_size); + + return kStatus_Success; +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_support.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_support.h new file mode 100644 index 0000000000..a2cfa43be6 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_support.h @@ -0,0 +1,36 @@ +/* + * Copyright 2019, 2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _VGLITE_SUPPORT_H_ +#define _VGLITE_SUPPORT_H_ + +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * API + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +#define VG_LITE_COMMAND_BUFFER_SIZE (256 << 10) /* 256 KB */ + +/* Default tessellation window width and height, in pixels */ +#define DEFAULT_VG_LITE_TW_WIDTH 128 /* pixels */ +#define DEFAULT_VG_LITE_TW_HEIGHT 128 /* pixels */ + +status_t BOARD_PrepareVGLiteController(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif /* _VGLITE_SUPPORT_H_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_window.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_window.c new file mode 100644 index 0000000000..509f5d4906 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_window.c @@ -0,0 +1,181 @@ +/* + * Copyright 2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include "vglite_support.h" +#include "vg_lite_platform.h" +#include "vglite_window.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#if !DEMO_BUFFER_FIXED_ADDRESS +AT_NONCACHEABLE_SECTION_ALIGN( + static uint8_t s_frameBuffer[APP_BUFFER_COUNT][LCD_HEIGHT][LCD_WIDTH][DEMO_BUFFER_BYTE_PER_PIXEL], + FRAME_BUFFER_ALIGN); + +#define DEMO_BUFFER0_ADDR (uint32_t) s_frameBuffer[0] + +#if APP_BUFFER_COUNT > 1 +#define DEMO_BUFFER1_ADDR (uint32_t) s_frameBuffer[1] +#endif + +#if APP_BUFFER_COUNT > 2 +#define DEMO_BUFFER2_ADDR (uint32_t) s_frameBuffer[2] +#endif + +#endif + +static const uint32_t s_frameBufferAddress[APP_BUFFER_COUNT] = {DEMO_BUFFER0_ADDR, +#if APP_BUFFER_COUNT > 1 + DEMO_BUFFER1_ADDR, +#endif +#if APP_BUFFER_COUNT > 2 + DEMO_BUFFER2_ADDR +#endif +}; +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +static vg_lite_buffer_format_t video_format_to_vglite(video_pixel_format_t format) +{ + vg_lite_buffer_format_t fmt; + switch (format) + { + case kVIDEO_PixelFormatRGB565: + fmt = VG_LITE_BGR565; + break; + + case kVIDEO_PixelFormatBGR565: + fmt = VG_LITE_RGB565; + break; + + case kVIDEO_PixelFormatXRGB8888: + fmt = VG_LITE_BGRX8888; + break; + + default: + fmt = VG_LITE_RGB565; + break; + } + + return fmt; +} + +vg_lite_error_t VGLITE_CreateDisplay(vg_lite_display_t *display) +{ + if (!display) + return VG_LITE_INVALID_ARGUMENT; + + BOARD_PrepareDisplayController(); + FBDEV_Open(&display->g_fbdev, &g_dc, 0); + + return VG_LITE_SUCCESS; +} + +vg_lite_error_t VGLITE_CreateWindow(vg_lite_display_t *display, vg_lite_window_t *window) +{ + vg_lite_error_t ret = VG_LITE_SUCCESS; + status_t status; + void *buffer; + vg_lite_buffer_t *vg_buffer; + fbdev_t *g_fbdev = &(display->g_fbdev); + fbdev_fb_info_t *g_fbInfo = &(display->g_fbInfo); + + window->bufferCount = APP_BUFFER_COUNT; + window->display = display; + window->width = DEMO_BUFFER_WIDTH; + window->height = DEMO_BUFFER_HEIGHT; + window->current = -1; + FBDEV_GetFrameBufferInfo(g_fbdev, g_fbInfo); + + g_fbInfo->bufInfo.pixelFormat = DEMO_BUFFER_PIXEL_FORMAT; + g_fbInfo->bufInfo.startX = DEMO_BUFFER_START_X; + g_fbInfo->bufInfo.startY = DEMO_BUFFER_START_Y; + g_fbInfo->bufInfo.width = window->width; + g_fbInfo->bufInfo.height = window->height; + g_fbInfo->bufInfo.strideBytes = DEMO_BUFFER_STRIDE_BYTE; + + g_fbInfo->bufferCount = window->bufferCount; + for (uint8_t i = 0; i < window->bufferCount; i++) + { + vg_buffer = &(window->buffers[i]); + g_fbInfo->buffers[i] = (void *)s_frameBufferAddress[i]; + vg_buffer->memory = g_fbInfo->buffers[i]; + vg_buffer->address = s_frameBufferAddress[i]; + vg_buffer->width = g_fbInfo->bufInfo.width; + vg_buffer->height = g_fbInfo->bufInfo.height; + vg_buffer->stride = g_fbInfo->bufInfo.strideBytes; + vg_buffer->format = video_format_to_vglite(DEMO_BUFFER_PIXEL_FORMAT); + } + + status = FBDEV_SetFrameBufferInfo(g_fbdev, g_fbInfo); + if (status != kStatus_Success) + { + while (1) + ; + } + + buffer = FBDEV_GetFrameBuffer(g_fbdev, 0); + + assert(buffer != NULL); + + memset(buffer, 0, g_fbInfo->bufInfo.height * g_fbInfo->bufInfo.strideBytes); + + FBDEV_SetFrameBuffer(g_fbdev, buffer, 0); + + FBDEV_Enable(g_fbdev); + + return ret; +} + +vg_lite_error_t VGLITE_DestoryWindow(void) +{ + return VG_LITE_SUCCESS; +} + +vg_lite_error_t VGLITE_DestroyDisplay(void) +{ + return VG_LITE_SUCCESS; +} + +vg_lite_buffer_t *VGLITE_GetRenderTarget(vg_lite_window_t *window) +{ + vg_lite_buffer_t *rt = NULL; + void *memory = FBDEV_GetFrameBuffer(&window->display->g_fbdev, 0); + for (uint8_t i = 0; i < window->bufferCount; i++) + { + rt = &(window->buffers[i]); + if (memory == rt->memory) + { + window->current = i; + return rt; + } + } + return NULL; +} + +void VGLITE_SwapBuffers(vg_lite_window_t *window) +{ + vg_lite_buffer_t *rt; + if (window->current >= 0 && window->current < window->bufferCount) + rt = &(window->buffers[window->current]); + else + return; + + vg_lite_finish(); + + FBDEV_SetFrameBuffer(&window->display->g_fbdev, rt->memory, 0); +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_window.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_window.h new file mode 100644 index 0000000000..c617b61e22 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_window.h @@ -0,0 +1,62 @@ +/* + * Copyright 2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _VGLITE_WINDOW_H_ +#define _VGLITE_WINDOW_H_ + +#include "fsl_common.h" +#include "vg_lite.h" +#include "vglite_support.h" +#include "display_support.h" +#include "fsl_fbdev.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#define APP_BUFFER_COUNT 2 + +typedef struct vg_lite_display +{ + fbdev_t g_fbdev; + fbdev_fb_info_t g_fbInfo; +} vg_lite_display_t; + +typedef struct vg_lite_window +{ + vg_lite_display_t *display; + vg_lite_buffer_t buffers[APP_BUFFER_COUNT]; + int width; + int height; + int bufferCount; + int current; +} vg_lite_window_t; + +/******************************************************************************* + * API + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +vg_lite_error_t VGLITE_CreateDisplay(vg_lite_display_t *display); + +vg_lite_error_t VGLITE_CreateWindow(vg_lite_display_t *display, vg_lite_window_t *window); + +vg_lite_error_t VGLITE_DestoryWindow(void); + +vg_lite_error_t VGLITE_DestroyDisplay(void); + +vg_lite_buffer_t *VGLITE_GetRenderTarget(vg_lite_window_t *window); + +void VGLITE_SwapBuffers(vg_lite_window_t *window); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif /* _VGLITE_WINDOW_H_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/SConscript b/bsp/imxrt/libraries/MIMXRT1170/SConscript index 0ec189ee6a..f547acc889 100644 --- a/bsp/imxrt/libraries/MIMXRT1170/SConscript +++ b/bsp/imxrt/libraries/MIMXRT1170/SConscript @@ -52,6 +52,64 @@ if GetDepend(['RT_USING_CAN']): if GetDepend(['BSP_USING_FLEXSPI']): src += ['MIMXRT1176/drivers/fsl_flexspi.c'] +if GetDepend(['BSP_USING_VGLITE']): + src += ['MIMXRT1176/drivers/fsl_soc_src.c'] + src += ['MIMXRT1176/drivers/fsl_mipi_dsi.c'] + src += ['MIMXRT1176/drivers/fsl_video_common.c'] + src += ['MIMXRT1176/drivers/display_support.c'] + src += ['MIMXRT1176/drivers/fsl_fbdev.c'] + src += ['MIMXRT1176/drivers/fsl_mipi_dsi_cmd.c'] + + if GetDepend(['VGLITE_USING_LCDIFV2']): + src += ['MIMXRT1176/drivers/fsl_dc_fb_lcdifv2.c'] + src += ['MIMXRT1176/drivers/fsl_lcdifv2.c'] + else: + src += ['MIMXRT1176/drivers/fsl_dc_fb_elcdif.c'] + src += ['MIMXRT1176/drivers/fsl_elcdif.c'] + + if GetDepend(['VGLITE_USING_RK055AHD091']): + src += ['MIMXRT1176/drivers/fsl_rm68200.c'] + elif GetDepend(['VGLITE_USING_RK055IQH091']): + src += ['MIMXRT1176/drivers/fsl_rm68191.c'] + else: + src += ['MIMXRT1176/drivers/fsl_hx8394.c'] + + src += ['MIMXRT1176/drivers/mf_bwfont.c'] + src += ['MIMXRT1176/drivers/mf_encoding.c'] + src += ['MIMXRT1176/drivers/mf_font.c'] + src += ['MIMXRT1176/drivers/mf_justify.c'] + src += ['MIMXRT1176/drivers/mf_kerning.c'] + src += ['MIMXRT1176/drivers/mf_rlefont.c'] + src += ['MIMXRT1176/drivers/mf_scaledfont.c'] + src += ['MIMXRT1176/drivers/mf_wordwrap.c'] + + src += ['MIMXRT1176/drivers/buf_reader.c'] + src += ['MIMXRT1176/drivers/rle_font_read.c'] + src += ['MIMXRT1176/drivers/vft_debug.c'] + src += ['MIMXRT1176/drivers/vft_draw.c'] + src += ['MIMXRT1176/drivers/vg_lite_text.c'] + + src += ['MIMXRT1176/drivers/vg_lite_os.c'] + src += ['MIMXRT1176/drivers/vg_lite.c'] + src += ['MIMXRT1176/drivers/vg_lite_flat.c'] + src += ['MIMXRT1176/drivers/vg_lite_image.c'] + src += ['MIMXRT1176/drivers/vg_lite_matrix.c'] + src += ['MIMXRT1176/drivers/vg_lite_path.c'] + + src += ['MIMXRT1176/drivers/vglite_support.c'] + src += ['MIMXRT1176/drivers/vglite_window.c'] + + src += ['MIMXRT1176/drivers/vg_lite_hal.c'] + src += ['MIMXRT1176/drivers/vg_lite_kernel.c'] + + if GetDepend(['VGLITE_USING_ELM']): + src += ['MIMXRT1176/drivers/elm_buffer.c'] + src += ['MIMXRT1176/drivers/elm_draw.c'] + src += ['MIMXRT1176/drivers/elm_init.c'] + src += ['MIMXRT1176/drivers/elm_object.c'] + src += ['MIMXRT1176/drivers/elm_os.c'] + src += ['MIMXRT1176/drivers/elm_text.c'] + #fsl os abstract files src += ['MIMXRT1176/drivers/fsl_os_abstraction_rtthread.c'] src += ['MIMXRT1176/drivers/generic_list.c']