summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrogrey <[email protected]>2023-09-20 17:00:30 +0800
committerguo <[email protected]>2023-09-26 10:52:24 +0800
commitf941dfcf138131aadb04a63b98fec1b608f4dda1 (patch)
tree630b2603753b3366de04417dca70f8f43b5f49c0
parenta7e210d7016835ae99dc8e276046a0013aa2d1dd (diff)
fix uart1 pin bug, delete and update wrong icf files, add vglite support for rt1170 in IAR environment.
-rw-r--r--bsp/imxrt/imxrt1170-nxp-evk/m7/.config98
-rw-r--r--bsp/imxrt/imxrt1170-nxp-evk/m7/board/Kconfig36
-rw-r--r--bsp/imxrt/imxrt1170-nxp-evk/m7/board/board.c44
-rw-r--r--bsp/imxrt/imxrt1170-nxp-evk/m7/board/linker_scripts/link.icf98
-rw-r--r--bsp/imxrt/imxrt1170-nxp-evk/m7/board/linker_scripts/link_ram.icf40
-rw-r--r--bsp/imxrt/imxrt1170-nxp-evk/m7/project.ewd107
-rw-r--r--bsp/imxrt/imxrt1170-nxp-evk/m7/project.ewp73
-rw-r--r--bsp/imxrt/imxrt1170-nxp-evk/m7/rtconfig.h35
-rw-r--r--bsp/imxrt/imxrt1170-nxp-evk/m7/rtconfig.py4
-rw-r--r--bsp/imxrt/imxrt1170-nxp-evk/m7/template.ewd87
-rw-r--r--bsp/imxrt/imxrt1170-nxp-evk/m7/template.ewp50
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/Elm.h681
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/buf_reader.c221
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/buf_reader.h63
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/display_support.c474
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/display_support.h189
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_buffer.c321
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_draw.c483
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_headers.h158
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_init.c160
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_object.c2238
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_os.c43
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_os.h13
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_precom.h55
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_text.c732
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_text.h207
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fonts.h30
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb.h81
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_elcdif.c264
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_elcdif.h101
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_lcdifv2.c288
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_lcdifv2.h109
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_display.h140
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_fbdev.c243
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_fbdev.h227
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_hx8394.c187
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_hx8394.h57
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_mipi_dsi_cmd.c351
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_mipi_dsi_cmd.h354
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68191.c251
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68191.h62
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68200.c409
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68200.h67
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_video_common.c301
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_video_common.h364
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mcufont.h14
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_bwfont.c134
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_bwfont.h77
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_config.h144
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_encoding.c84
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_encoding.h45
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_font.c122
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_font.h137
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_justify.c332
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_justify.h74
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_kerning.c118
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_kerning.h27
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_rlefont.c286
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_rlefont.h82
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_scaledfont.c83
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_scaledfont.h23
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_wordwrap.c357
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_wordwrap.h35
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/rle_font_read.c716
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/velm.h351
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_debug.c317
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_debug.h111
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_draw.c463
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_draw.h119
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite.c10894
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite.h2060
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_flat.c535
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_flat.h55
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hal.c499
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hal.h272
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hw.h64
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_image.c160
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_kernel.c1020
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_kernel.h444
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_matrix.c113
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_os.c473
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_os.h134
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_path.c353
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_platform.h48
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_text.c359
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_text.h372
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_support.c87
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_support.h36
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_window.c181
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_window.h62
-rw-r--r--bsp/imxrt/libraries/MIMXRT1170/SConscript58
91 files changed, 32890 insertions, 236 deletions
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
-**
-** ###################################################################
-*/
-
-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 @@
<?xml version="1.0" encoding="UTF-8"?>
<project>
- <fileVersion>3</fileVersion>
+ <fileVersion>4</fileVersion>
<configuration>
<name>rtthread</name>
<toolchain>
@@ -11,7 +11,7 @@
<name>C-SPY</name>
<archiveVersion>2</archiveVersion>
<data>
- <version>32</version>
+ <version>33</version>
<wantNonLocal>1</wantNonLocal>
<debug>1</debug>
<option>
@@ -36,7 +36,7 @@
</option>
<option>
<name>MacFile</name>
- <state></state>
+ <state>C:\XGW\IARWorkspace\rt-thread-imxrt\bsp\imxrt\imxrt1170-nxp-evk\m7\evkbmimxrt1170_connect_cm7.mac</state>
</option>
<option>
<name>MemOverride</name>
@@ -44,7 +44,7 @@
</option>
<option>
<name>MemFile</name>
- <state>$TOOLKIT_DIR$\CONFIG\debugger\NXP\MIMXRT1176xxxA_M7.ddf</state>
+ <state>$TOOLKIT_DIR$\config\debugger\NXP\MIMXRT1176xxxA_M7.ddf</state>
</option>
<option>
<name>RunToEnable</name>
@@ -84,11 +84,11 @@
</option>
<option>
<name>OCDynDriverList</name>
- <state>JLINK_ID</state>
+ <state>CMSISDAP_ID</state>
</option>
<option>
<name>OCLastSavedByProductVersion</name>
- <state>9.30.1.50052</state>
+ <state>9.40.1.63870</state>
</option>
<option>
<name>UseFlashLoader</name>
@@ -222,6 +222,38 @@
<name>OCTpiuBaseOption</name>
<state>1</state>
</option>
+ <option>
+ <name>OCOverrideSlave</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>OCOverrideSlavePath</name>
+ <state></state>
+ </option>
+ <option>
+ <name>C_32_64Device</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>AuthEnable</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AuthSdmSelection</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>AuthSdmManifest</name>
+ <state></state>
+ </option>
+ <option>
+ <name>AuthSdmExplicitLib</name>
+ <state></state>
+ </option>
+ <option>
+ <name>AuthEnforce</name>
+ <state>0</state>
+ </option>
</data>
</settings>
<settings>
@@ -296,7 +328,7 @@
<option>
<name>CMSISDAPResetList</name>
<version>1</version>
- <state>4</state>
+ <state>1</state>
</option>
<option>
<name>CMSISDAPHWResetDuration</name>
@@ -381,27 +413,27 @@
</option>
<option>
<name>CatchMMERR</name>
- <state>1</state>
+ <state>0</state>
</option>
<option>
<name>CatchNOCPERR</name>
- <state>1</state>
+ <state>0</state>
</option>
<option>
<name>CatchCHKERR</name>
- <state>1</state>
+ <state>0</state>
</option>
<option>
<name>CatchSTATERR</name>
- <state>1</state>
+ <state>0</state>
</option>
<option>
<name>CatchBUSERR</name>
- <state>1</state>
+ <state>0</state>
</option>
<option>
<name>CatchINTERR</name>
- <state>1</state>
+ <state>0</state>
</option>
<option>
<name>CatchSFERR</name>
@@ -409,7 +441,7 @@
</option>
<option>
<name>CatchHARDERR</name>
- <state>1</state>
+ <state>0</state>
</option>
<option>
<name>CatchDummy</name>
@@ -458,6 +490,39 @@
</data>
</settings>
<settings>
+ <name>E2_ID</name>
+ <archiveVersion>2</archiveVersion>
+ <data>
+ <version>0</version>
+ <wantNonLocal>1</wantNonLocal>
+ <debug>1</debug>
+ <option>
+ <name>E2PowerFromProbe</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CE2UsbSerialNo</name>
+ <state></state>
+ </option>
+ <option>
+ <name>CE2IdCodeEditB</name>
+ <state>0xFFFF'FFFF'FFFF'FFFF'FFFF'FFFF'FFFF'FFFF</state>
+ </option>
+ <option>
+ <name>CE2LogFileCheck</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CE2LogFileEditB</name>
+ <state>$PROJ_DIR$\cspycomm.log</state>
+ </option>
+ <option>
+ <name>OCDriverInfo</name>
+ <state>1</state>
+ </option>
+ </data>
+ </settings>
+ <settings>
<name>GDBSERVER_ID</name>
<archiveVersion>2</archiveVersion>
<data>
@@ -1072,7 +1137,7 @@
<name>STLINK_ID</name>
<archiveVersion>2</archiveVersion>
<data>
- <version>7</version>
+ <version>8</version>
<wantNonLocal>1</wantNonLocal>
<debug>1</debug>
<option>
@@ -1187,9 +1252,17 @@
</option>
<option>
<name>CCSTLinkProbeList</name>
- <version>1</version>
+ <version>2</version>
<state>2</state>
</option>
+ <option>
+ <name>CCSTLinkTargetVccEnable</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CCSTLinkTargetVoltage</name>
+ <state>3.3</state>
+ </option>
</data>
</settings>
<settings>
@@ -1417,7 +1490,7 @@
</option>
<option>
<name>CCXds100ResetList</name>
- <version>0</version>
+ <version>1</version>
<state>0</state>
</option>
<option>
diff --git a/bsp/imxrt/imxrt1170-nxp-evk/m7/project.ewp b/bsp/imxrt/imxrt1170-nxp-evk/m7/project.ewp
index dd22c2fcc0..29f4959d18 100644
--- a/bsp/imxrt/imxrt1170-nxp-evk/m7/project.ewp
+++ b/bsp/imxrt/imxrt1170-nxp-evk/m7/project.ewp
@@ -1,5 +1,5 @@
<project>
- <fileVersion>3</fileVersion>
+ <fileVersion>4</fileVersion>
<configuration>
<name>rtthread</name>
<toolchain>
@@ -10,7 +10,7 @@
<name>General</name>
<archiveVersion>3</archiveVersion>
<data>
- <version>35</version>
+ <version>36</version>
<wantNonLocal>1</wantNonLocal>
<debug>1</debug>
<option>
@@ -69,7 +69,7 @@
</option>
<option>
<name>OGLastSavedByProductVersion</name>
- <state>9.30.1.50052</state>
+ <state>9.40.1.63870</state>
</option>
<option>
<name>OGChipSelectEditMenu</name>
@@ -97,7 +97,7 @@
</option>
<option>
<name>GBECoreSlave</name>
- <version>32</version>
+ <version>33</version>
<state>41</state>
</option>
<option>
@@ -114,7 +114,7 @@
</option>
<option>
<name>CoreVariant</name>
- <version>32</version>
+ <version>33</version>
<state>41</state>
</option>
<option>
@@ -137,7 +137,7 @@
</option>
<option>
<name>GFPUCoreSlave2</name>
- <version>32</version>
+ <version>33</version>
<state>41</state>
</option>
<option>
@@ -210,13 +210,18 @@
<name>FPU64</name>
<state>1</state>
</option>
+ <option>
+ <name>OG_32_64DeviceCoreSlave</name>
+ <version>33</version>
+ <state>41</state>
+ </option>
</data>
</settings>
<settings>
<name>ICCARM</name>
<archiveVersion>2</archiveVersion>
<data>
- <version>37</version>
+ <version>38</version>
<wantNonLocal>1</wantNonLocal>
<debug>1</debug>
<option>
@@ -237,7 +242,6 @@
<state>XIP_EXTERNAL_FLASH=1</state>
<state>ARM_MATH_CM7</state>
<state>USE_SDRAM</state>
- <state>SOC_IMXRT1170_SERIES</state>
<state>ENDIANNESS</state>
<state>USE_RTOS</state>
<state>__RTTHREAD__</state>
@@ -367,8 +371,8 @@
<state>$PROJ_DIR$\..\..\libraries\MIMXRT1170\CMSIS\Include</state>
<state>$PROJ_DIR$\..\..\..\..\components\libc\compilers\common\extension\fcntl\octal</state>
<state>$PROJ_DIR$\..\..\..\..\components\drivers\usb\usbhost\include</state>
- <state>$PROJ_DIR$\..\..\..\..\components\libc\posix\io\stdio</state>
<state>$PROJ_DIR$\..\..\..\..\components\libc\posix\io\poll</state>
+ <state>$PROJ_DIR$\..\..\..\..\components\libc\posix\io\epoll</state>
<state>$PROJ_DIR$\..\..\libraries\MIMXRT1170\MIMXRT1176\drivers\cm7</state>
<state>$PROJ_DIR$\..\..\libraries\drivers</state>
<state>$PROJ_DIR$\..\..\..\..\libcpu\arm\cortex-m7</state>
@@ -383,6 +387,7 @@
<state>$PROJ_DIR$\..\..\..\..\components\drivers\usb\usbhost\class</state>
<state>$PROJ_DIR$\board\ports</state>
<state>$PROJ_DIR$\applications</state>
+ <state>$PROJ_DIR$\..\..\..\..\components\libc\posix\io\eventfd</state>
<state>$PROJ_DIR$\..\..\..\..\include</state>
<state>$PROJ_DIR$\..\..\..\..\components\libc\compilers\common\include</state>
<state>$PROJ_DIR$\..\..\..\..\components\libc\posix\ipc</state>
@@ -500,13 +505,21 @@
<name>CCStackProtection</name>
<state>0</state>
</option>
+ <option>
+ <name>CCPointerAutentiction</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCBranchTargetIdentification</name>
+ <state>0</state>
+ </option>
</data>
</settings>
<settings>
<name>AARM</name>
<archiveVersion>2</archiveVersion>
<data>
- <version>11</version>
+ <version>12</version>
<wantNonLocal>1</wantNonLocal>
<debug>1</debug>
<option>
@@ -666,6 +679,10 @@
<name>PreInclude</name>
<state />
</option>
+ <option>
+ <name>A_32_64Device</name>
+ <state>1</state>
+ </option>
</data>
</settings>
<settings>
@@ -704,19 +721,11 @@
<data>
<extensions />
<cmdline />
- <hasPrio>208</hasPrio>
+ <hasPrio>1</hasPrio>
<buildSequence>inputOutputBased</buildSequence>
</data>
</settings>
<settings>
- <name>BUILDACTION</name>
- <archiveVersion>1</archiveVersion>
- <data>
- <prebuild />
- <postbuild />
- </data>
- </settings>
- <settings>
<name>ILINK</name>
<archiveVersion>0</archiveVersion>
<data>
@@ -797,7 +806,7 @@
</option>
<option>
<name>IlinkIcfFile</name>
- <state>$PROJ_DIR$\board\linker_scripts\link.icf</state>
+ <state>$PROJ_DIR$\board\linker_scripts\link_ram.icf</state>
</option>
<option>
<name>IlinkIcfFileSlave</name>
@@ -1111,6 +1120,11 @@
</option>
</data>
</settings>
+ <settings>
+ <name>BUILDACTION</name>
+ <archiveVersion>2</archiveVersion>
+ <data />
+ </settings>
</configuration>
<group>
<name>Applications</name>
@@ -1127,9 +1141,6 @@
<name>$PROJ_DIR$\..\..\..\..\components\libc\compilers\common\cctype.c</name>
</file>
<file>
- <name>$PROJ_DIR$\..\..\..\..\components\libc\compilers\common\cstdio.c</name>
- </file>
- <file>
<name>$PROJ_DIR$\..\..\..\..\components\libc\compilers\common\cstdlib.c</name>
</file>
<file>
@@ -1139,6 +1150,9 @@
<name>$PROJ_DIR$\..\..\..\..\components\libc\compilers\common\ctime.c</name>
</file>
<file>
+ <name>$PROJ_DIR$\..\..\..\..\components\libc\compilers\common\cunistd.c</name>
+ </file>
+ <file>
<name>$PROJ_DIR$\..\..\..\..\components\libc\compilers\common\cwchar.c</name>
</file>
<file>
@@ -1172,6 +1186,9 @@
<group>
<name>CPU</name>
<file>
+ <name>$PROJ_DIR$\..\..\..\..\libcpu\arm\common\atomic_arm.c</name>
+ </file>
+ <file>
<name>$PROJ_DIR$\..\..\..\..\libcpu\arm\common\div0.c</name>
</file>
<file>
@@ -1190,6 +1207,9 @@
<group>
<name>DeviceDrivers</name>
<file>
+ <name>$PROJ_DIR$\..\..\..\..\components\drivers\core\device.c</name>
+ </file>
+ <file>
<name>$PROJ_DIR$\..\..\..\..\components\drivers\ipc\completion.c</name>
</file>
<file>
@@ -1286,9 +1306,6 @@
<name>$PROJ_DIR$\..\..\..\..\src\components.c</name>
</file>
<file>
- <name>$PROJ_DIR$\..\..\..\..\src\device.c</name>
- </file>
- <file>
<name>$PROJ_DIR$\..\..\..\..\src\idle.c</name>
</file>
<file>
@@ -1382,10 +1399,10 @@
<group>
<name>SAL</name>
<file>
- <name>$PROJ_DIR$\..\..\..\..\components\net\netdev\src\netdev_ipaddr.c</name>
+ <name>$PROJ_DIR$\..\..\..\..\components\net\netdev\src\netdev.c</name>
</file>
<file>
- <name>$PROJ_DIR$\..\..\..\..\components\net\netdev\src\netdev.c</name>
+ <name>$PROJ_DIR$\..\..\..\..\components\net\netdev\src\netdev_ipaddr.c</name>
</file>
</group>
<group>
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 @@
<?xml version="1.0" encoding="UTF-8"?>
<project>
- <fileVersion>3</fileVersion>
+ <fileVersion>4</fileVersion>
<configuration>
<name>rtthread</name>
<toolchain>
@@ -11,7 +11,7 @@
<name>C-SPY</name>
<archiveVersion>2</archiveVersion>
<data>
- <version>32</version>
+ <version>33</version>
<wantNonLocal>1</wantNonLocal>
<debug>1</debug>
<option>
@@ -44,7 +44,7 @@
</option>
<option>
<name>MemFile</name>
- <state>$TOOLKIT_DIR$\CONFIG\debugger\NXP\MIMXRT1176xxxA_M7.ddf</state>
+ <state>$TOOLKIT_DIR$\config\debugger\NXP\MIMXRT1176xxxA_M7.ddf</state>
</option>
<option>
<name>RunToEnable</name>
@@ -88,7 +88,7 @@
</option>
<option>
<name>OCLastSavedByProductVersion</name>
- <state>9.30.1.50052</state>
+ <state>9.40.1.63870</state>
</option>
<option>
<name>UseFlashLoader</name>
@@ -222,6 +222,38 @@
<name>OCTpiuBaseOption</name>
<state>1</state>
</option>
+ <option>
+ <name>OCOverrideSlave</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>OCOverrideSlavePath</name>
+ <state></state>
+ </option>
+ <option>
+ <name>C_32_64Device</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>AuthEnable</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AuthSdmSelection</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>AuthSdmManifest</name>
+ <state></state>
+ </option>
+ <option>
+ <name>AuthSdmExplicitLib</name>
+ <state></state>
+ </option>
+ <option>
+ <name>AuthEnforce</name>
+ <state>0</state>
+ </option>
</data>
</settings>
<settings>
@@ -458,6 +490,39 @@
</data>
</settings>
<settings>
+ <name>E2_ID</name>
+ <archiveVersion>2</archiveVersion>
+ <data>
+ <version>0</version>
+ <wantNonLocal>1</wantNonLocal>
+ <debug>1</debug>
+ <option>
+ <name>E2PowerFromProbe</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CE2UsbSerialNo</name>
+ <state></state>
+ </option>
+ <option>
+ <name>CE2IdCodeEditB</name>
+ <state>0xFFFF'FFFF'FFFF'FFFF'FFFF'FFFF'FFFF'FFFF</state>
+ </option>
+ <option>
+ <name>CE2LogFileCheck</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CE2LogFileEditB</name>
+ <state>$PROJ_DIR$\cspycomm.log</state>
+ </option>
+ <option>
+ <name>OCDriverInfo</name>
+ <state>1</state>
+ </option>
+ </data>
+ </settings>
+ <settings>
<name>GDBSERVER_ID</name>
<archiveVersion>2</archiveVersion>
<data>
@@ -1072,7 +1137,7 @@
<name>STLINK_ID</name>
<archiveVersion>2</archiveVersion>
<data>
- <version>7</version>
+ <version>8</version>
<wantNonLocal>1</wantNonLocal>
<debug>1</debug>
<option>
@@ -1187,9 +1252,17 @@
</option>
<option>
<name>CCSTLinkProbeList</name>
- <version>1</version>
+ <version>2</version>
<state>2</state>
</option>
+ <option>
+ <name>CCSTLinkTargetVccEnable</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CCSTLinkTargetVoltage</name>
+ <state>###Uninitialized###</state>
+ </option>
</data>
</settings>
<settings>
@@ -1417,7 +1490,7 @@
</option>
<option>
<name>CCXds100ResetList</name>
- <version>0</version>
+ <version>1</version>
<state>0</state>
</option>
<option>
diff --git a/bsp/imxrt/imxrt1170-nxp-evk/m7/template.ewp b/bsp/imxrt/imxrt1170-nxp-evk/m7/template.ewp
index e2ee9db5dd..500df888bc 100644
--- a/bsp/imxrt/imxrt1170-nxp-evk/m7/template.ewp
+++ b/bsp/imxrt/imxrt1170-nxp-evk/m7/template.ewp
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project>
- <fileVersion>3</fileVersion>
+ <fileVersion>4</fileVersion>
<configuration>
<name>rtthread</name>
<toolchain>
@@ -11,7 +11,7 @@
<name>General</name>
<archiveVersion>3</archiveVersion>
<data>
- <version>35</version>
+ <version>36</version>
<wantNonLocal>1</wantNonLocal>
<debug>1</debug>
<option>
@@ -70,7 +70,7 @@
</option>
<option>
<name>OGLastSavedByProductVersion</name>
- <state>9.30.1.50052</state>
+ <state>9.40.1.63870</state>
</option>
<option>
<name>OGChipSelectEditMenu</name>
@@ -98,7 +98,7 @@
</option>
<option>
<name>GBECoreSlave</name>
- <version>32</version>
+ <version>33</version>
<state>41</state>
</option>
<option>
@@ -115,7 +115,7 @@
</option>
<option>
<name>CoreVariant</name>
- <version>32</version>
+ <version>33</version>
<state>41</state>
</option>
<option>
@@ -138,7 +138,7 @@
</option>
<option>
<name>GFPUCoreSlave2</name>
- <version>32</version>
+ <version>33</version>
<state>41</state>
</option>
<option>
@@ -211,13 +211,18 @@
<name>FPU64</name>
<state>1</state>
</option>
+ <option>
+ <name>OG_32_64DeviceCoreSlave</name>
+ <version>33</version>
+ <state>41</state>
+ </option>
</data>
</settings>
<settings>
<name>ICCARM</name>
<archiveVersion>2</archiveVersion>
<data>
- <version>37</version>
+ <version>38</version>
<wantNonLocal>1</wantNonLocal>
<debug>1</debug>
<option>
@@ -459,13 +464,21 @@
<name>CCStackProtection</name>
<state>0</state>
</option>
+ <option>
+ <name>CCPointerAutentiction</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCBranchTargetIdentification</name>
+ <state>0</state>
+ </option>
</data>
</settings>
<settings>
<name>AARM</name>
<archiveVersion>2</archiveVersion>
<data>
- <version>11</version>
+ <version>12</version>
<wantNonLocal>1</wantNonLocal>
<debug>1</debug>
<option>
@@ -625,6 +638,10 @@
<name>PreInclude</name>
<state></state>
</option>
+ <option>
+ <name>A_32_64Device</name>
+ <state>1</state>
+ </option>
</data>
</settings>
<settings>
@@ -663,19 +680,11 @@
<data>
<extensions></extensions>
<cmdline></cmdline>
- <hasPrio>208</hasPrio>
+ <hasPrio>1</hasPrio>
<buildSequence>inputOutputBased</buildSequence>
</data>
</settings>
<settings>
- <name>BUILDACTION</name>
- <archiveVersion>1</archiveVersion>
- <data>
- <prebuild></prebuild>
- <postbuild></postbuild>
- </data>
- </settings>
- <settings>
<name>ILINK</name>
<archiveVersion>0</archiveVersion>
<data>
@@ -756,7 +765,7 @@
</option>
<option>
<name>IlinkIcfFile</name>
- <state>$PROJ_DIR$\board\linker_scripts\link.icf</state>
+ <state>$PROJ_DIR$\board\linker_scripts\link_ram.icf</state>
</option>
<option>
<name>IlinkIcfFileSlave</name>
@@ -1070,5 +1079,10 @@
</option>
</data>
</settings>
+ <settings>
+ <name>BUILDACTION</name>
+ <archiveVersion>2</archiveVersion>
+ <data />
+ </settings>
</configuration>
</project>
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 <rtthread.h>
+#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 <rtthread.h>
+
+#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<stdlib.h>
+#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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* 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 <stdio.h> // for snprintf
+#include <stdlib.h>
+#include <string.h>
+
+#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; i<num_fields; i++)
+ {
+ if(src_font_fields[i].info.eName == FONT_FAMILY ||
+ src_font_fields[i].info.eName == FONT_WEIGHT ||
+ src_font_fields[i].info.eName == FONT_STRETCH ||
+ src_font_fields[i].info.eName == FONT_STYLE ||
+ src_font_fields[i].info.eName == TEXT_ANCHOR )
+ {
+ switch(src_font_fields[i].info.eName)
+ {
+ case FONT_FAMILY:
+ len = strlen((char *)src_font_fields[i].data);
+ dst_font_fields[eFontNameProperty].eName = FONT_FAMILY;
+ dst_font_fields[eFontNameProperty].value.data =
+ (char *)elm_alloc(1, len+1);
+ strcpy(dst_font_fields[eFontNameProperty].value.data,
+ (char *)src_font_fields[i].data);
+ dst_font_fields[eFontNameProperty].value.data[len] = '\0';
+ break;
+ case FONT_WEIGHT:
+ dst_font_fields[eFontWeightProperty].eName = FONT_WEIGHT;
+ dst_font_fields[eFontWeightProperty].value.i_value =
+ (eFontWeight_t)src_font_fields[i].info.value.i_value;
+ break;
+ case FONT_STRETCH:
+ dst_font_fields[eFontStretchProperty].eName = FONT_STRETCH;
+ dst_font_fields[eFontStretchProperty].value.i_value =
+ (eFontStretch_t)src_font_fields[i].info.value.i_value;
+ break;
+ case FONT_STYLE:
+ dst_font_fields[eFontStyleProperty].eName = FONT_STYLE;
+ dst_font_fields[eFontStyleProperty].value.i_value =
+ (eFontStyle_t)src_font_fields[i].info.value.i_value;
+ break;
+ case TEXT_ANCHOR:
+ dst_font_fields[eTextAlignProperty].eName = TEXT_ANCHOR;
+ dst_font_fields[eTextAlignProperty].value.i_value =
+ (eTextAlign_t)src_font_fields[i].info.value.i_value;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+vg_lite_error_t draw_text(el_Obj_Buffer *buff,
+ el_Obj_EVO *evo, vg_lite_matrix_t *mat)
+{
+ vg_lite_error_t error = VG_LITE_INVALID_ARGUMENT;
+ el_Obj_TEXT *text = (el_Obj_TEXT *)evo;
+ vg_lite_blend_t blend = (vg_lite_blend_t)text->attribute.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; i<num_fields; i++)
+ {
+ fields[i].info.eName = (eFontFields_t)*(uint32_t *)(data + (0 + 3*i) * 4);
+ fields[i].offset = *(uint32_t *)(data + (1 + 3*i)* 4);
+ fields[i].data = NULL;
+ eName = fields[i].info.eName;
+ if(eName == FONT_SIZE ||
+ eName == HORIZ_ORIGIN_X ||
+ eName == HORIZ_ADV_X ||
+ eName == ASCENT ||
+ eName == ALPHABETIC ||
+ eName == CAP_HEIGHT ||
+ eName == DESCENT ||
+ eName == SLOPE ||
+ eName == UNITS_PER_EM ||
+ eName == X_HEIGHT
+ )
+ {
+ fields[i].info.value.f_value = *(float *)(data + (2 + 3*i)* 4);
+ }
+ else
+ {
+ fields[i].info.value.i_value = *(uint32_t *)(data + (2 + 3*i)* 4);
+ }
+
+ if(fields[i].offset != 0)
+ {
+ fields[i].size = *(uint16_t *)(data_start + fields[i].offset);
+ fields[i].data = (uint8_t *)elm_alloc(1, fields[i].size+1);
+ memset(fields[i].data,0, fields[i].size+1);
+ memcpy(fields[i].data, (void *)(data_start + fields[i].offset + 2), fields[i].size);
+ }
+ }
+
+ memset(&g_font_properties[g_total_system_font][0], 0,
+ sizeof(font_fields_t)*eMaxFontProperties);
+ get_property(g_font_properties[g_total_system_font], fields, num_fields);
+ g_total_system_font++;
+
+ return 0;
+}
+
+/* process ttf-type font data */
+static int _process_ttf_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->ttf_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; i<fontblockobj->num_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; i<fontblockobj->num_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; i<fontblockobj->num_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; i<fontblockobj->num_ttf_fonts; i++)
+ {
+ if(fontblockobj->ttf_fonts[i].fields != NULL){
+ for(j=0; j<fontblockobj->ttf_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; i<fontblockobj->num_vector_fonts; i++)
+ {
+ if(fontblockobj->vector_fonts[i].fields != NULL){
+ for(j=0; j<fontblockobj->vector_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; i<fontblockobj->num_text_fonts; i++)
+ {
+ if(fontblockobj->text_fonts[i].fields != NULL){
+ for(j=0; j<fontblockobj->text_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; i<g_total_system_font; i++)
+ {
+ if(g_font_properties[i][eFontNameProperty].value.data != NULL)
+ {
+ elm_free(g_font_properties[i][eFontNameProperty].value.data);
+ g_font_properties[i][eFontNameProperty].value.data = NULL;
+ }
+ }
+
+ return;
+}
+
+void _release_default_text_parameters(void)
+{
+ if(g_default_font_properties[eFontNameProperty].value.data != NULL)
+ {
+ elm_free(g_default_font_properties[eFontNameProperty].value.data);
+ g_default_font_properties[eFontNameProperty].value.data = NULL;
+ }
+ return;
+}
diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_text.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_text.h
new file mode 100644
index 0000000000..f5df74c67b
--- /dev/null
+++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_text.h
@@ -0,0 +1,207 @@
+/****************************************************************************
+*
+* 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 "Elm.h"
+#include "velm.h"
+
+#ifndef _elm_text_h_
+#define _elm_text_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum eElemType {
+ eElemTypeLinearGradient = 0,
+ eElemTypePath = 1,
+ eElemTypeGroup = 2,
+ eElemTypeText = 3,
+ eElemTypeTspan = 4,
+ eElemTypeFont = 5,
+ eElemTypeTtfFont = 6,
+ eElemTypeVectorFont = 7,
+ eElemTypeTextFont = 8,
+} eElemType_t;
+
+typedef enum eFontVariant {
+ eFontVariantNormal = 1,
+ eFontVariantSmallCaps = 2,
+ eFontVariantInherit = 3,
+} eFontVariant_t;
+
+typedef enum eDisplayAlign {
+ eDisplayAlignBefore = 1,
+ eDisplayAlignCenter = 2,
+ eDisplayAlignAfter = 3,
+ eDisplayAlignAuto = 1,
+} eDisplayAlign_t;
+
+typedef enum eFontFields {
+ HORIZ_ADV_X = 0,
+ HORIZ_ORIGIN_X = 1,
+ ASCENT = 2,
+ ALPHABETIC = 3,
+ BBOX = 4,
+ CAP_HEIGHT = 5,
+ DESCENT = 6,
+ FONT_FAMILY = 7,
+ FONT_SIZE = 8,
+ FONT_STRETCH = 9,
+ FONT_STYLE = 10,
+ FONT_TYPE = 11,
+ FONT_VARIANT = 12,
+ FONT_WEIGHT = 13,
+ SLOPE = 14,
+ UNICODE_RANGE = 15,
+ UNITS_PER_EM = 16,
+ X_HEIGHT = 17,
+ TEXT_ANCHOR = 18,
+ MAX_FONT_ATTRIBUTES = 19,
+} eFontFields_t;
+
+typedef struct glyph {
+ uint8_t glyph_name;
+ uint8_t unicode;
+ uint32_t horiz_adv_x;
+ uint32_t path_data_length;
+ void *path_data;
+} glyph_t;
+
+typedef struct glyph_table {
+ uint32_t offset;
+ uint32_t size;
+} glyph_table_t;
+
+typedef union value_type {
+ uint32_t i_value;
+ float f_value;
+ char *data;
+} value_type_t;
+
+typedef struct font_field_info {
+ value_type_t value;
+ eFontFields_t eName;
+} font_field_info_t;
+
+typedef struct font_fields {
+ font_field_info_t info;
+ uint32_t offset;
+ uint32_t size;
+ unsigned char *data;
+} font_fields_t;
+
+typedef struct vector_font {
+ uint32_t id;
+ eElemType_t type;
+ uint32_t num_fields;
+ font_fields_t *fields;
+ glyph_table_t *glyph_table;
+ glyph_t *glyph_offset;
+} vector_font_t;
+
+typedef struct ttf_font {
+ uint32_t id;
+ eElemType_t type;
+ uint32_t num_fields;
+ font_fields_t *fields;
+} ttf_font_t;
+
+typedef struct font_prop {
+ uint32_t num_props;
+ font_fields_t *prop_values;
+} font_prop_t;
+
+typedef struct font_block {
+ uint32_t size;
+ eElemType_t type;
+ 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;
+ font_prop_t *font_prop;
+ unsigned int *sizes_of_ttf_data;
+ unsigned int *offsets_of_ttf_data;
+ ttf_font_t *ttf_fonts;
+ unsigned int *sizes_of_vector_data;
+ unsigned int *offsets_of_vector_data;
+ vector_font_t *vector_fonts;
+ unsigned int *sizes_of_text_font_data;
+ unsigned int *offsets_of_text_font_data;
+ ttf_font_t *text_fonts;
+} font_block_t;
+
+typedef struct {
+ el_Object object;
+ el_Attribute attribute;
+ el_Attribute defaultAttrib;
+ uint32_t tspan_has_dx_dy;
+ uint32_t text_anchor;
+ uint32_t font_size;
+ uint32_t font_id;
+ uint32_t x_pos;
+ uint32_t y_pos;
+ unsigned char *msg;
+} el_Obj_TEXT;
+
+typedef enum eAppProperties {
+ eFontNameProperty,
+ eFontHeightProperty,
+ eFontWeightProperty,
+ eFontStretchProperty,
+ eFontStyleProperty,
+ eTextColorProperty,
+ eTextAlignProperty,
+ eMaxFontProperties,
+} eAppProperties_t;
+
+vg_lite_error_t draw_text(el_Obj_Buffer *buff,
+ el_Obj_EVO *evo, vg_lite_matrix_t *mat);
+
+extern font_block_t *fontblockobj;
+
+int _load_font_data(uint8_t *data);
+
+ElmHandle _load_text_data(uint8_t *data, el_Obj_EVO *evo);
+void _unload_text(el_Obj_EVO *evo);
+void _init_transform(el_Transform *transform);
+void initialize_elm_text(void);
+void destroy_font_data();
+void _release_default_text_parameters(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _elm_text_h_ */
diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fonts.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fonts.h
new file mode 100644
index 0000000000..40ebe2734e
--- /dev/null
+++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fonts.h
@@ -0,0 +1,30 @@
+/****************************************************************************
+*
+* 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.
+*
+*****************************************************************************/
+
+#define ABS_ARY(x) (void *)x, sizeof(x), 0
diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb.h
new file mode 100644
index 0000000000..87265a5f3b
--- /dev/null
+++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_DC_FB_H_
+#define _FSL_DC_FB_H_
+
+#include "fsl_video_common.h"
+
+/*!
+ * @addtogroup dc_fb
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+/*! @brief frame buffer information. */
+typedef struct _dc_fb_info
+{
+ uint16_t startX; /*!< The start position in the panel. */
+ uint16_t startY; /*!< The start position in the panel. */
+ uint16_t width; /*!< How many pixels in one line of the frame buffer.*/
+ uint16_t height; /*!< How many lines in one frame buffer. */
+ uint16_t strideBytes; /*!< Stride of the frame buffer */
+ video_pixel_format_t pixelFormat; /*!< Pixel format of the frame buffer */
+} dc_fb_info_t;
+
+/*! @brief Display controller frame callback. */
+typedef void (*dc_fb_callback_t)(void *param, void *inactiveBuffer);
+
+/*! @brief Display controller. */
+typedef struct _dc_fb dc_fb_t;
+
+/*! @brief Display controller operations. */
+typedef struct _dc_fb_ops
+{
+ status_t (*init)(const dc_fb_t *dc);
+ status_t (*deinit)(const dc_fb_t *dc);
+ status_t (*enableLayer)(const dc_fb_t *dc, uint8_t layer);
+ status_t (*disableLayer)(const dc_fb_t *dc, uint8_t layer);
+ status_t (*setLayerConfig)(const dc_fb_t *dc, uint8_t layer, dc_fb_info_t *fbInfo);
+ status_t (*getLayerDefaultConfig)(const dc_fb_t *dc, uint8_t layer, dc_fb_info_t *fbInfo);
+ status_t (*setFrameBuffer)(const dc_fb_t *dc, uint8_t layer, void *frameBuffer);
+ uint32_t (*getProperty)(const dc_fb_t *dc);
+ void (*setCallback)(const dc_fb_t *dc, uint8_t layer, dc_fb_callback_t callback, void *param);
+} dc_fb_ops_t;
+
+/*! @brief Display controller property. */
+enum _dc_fb_property
+{
+ kDC_FB_ReserveFrameBuffer = (1 << 0), /*< One frame buffer is always used as the DC active buffer. */
+ kDC_FB_TwoDimensionMemoryWrite = (1 << 1), /*< Support writing memory to device in two dimension way. */
+};
+
+/*! @brief Display controller driver handle. */
+struct _dc_fb
+{
+ const dc_fb_ops_t *ops; /* Display controller operations. */
+ void *prvData; /* Private data for the display controller. */
+ const void *config; /* Configuration for the display controller. */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @} */
+
+#endif /* _FSL_DC_FB_H_ */
diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_elcdif.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_elcdif.c
new file mode 100644
index 0000000000..f0720c1684
--- /dev/null
+++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_elcdif.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2019-2020, 2023 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_dc_fb_elcdif.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+const dc_fb_ops_t g_dcFbOpsElcdif = {
+ .init = DC_FB_ELCDIF_Init,
+ .deinit = DC_FB_ELCDIF_Deinit,
+ .enableLayer = DC_FB_ELCDIF_EnableLayer,
+ .disableLayer = DC_FB_ELCDIF_DisableLayer,
+ .setLayerConfig = DC_FB_ELCDIF_SetLayerConfig,
+ .getLayerDefaultConfig = DC_FB_ELCDIF_GetLayerDefaultConfig,
+ .setFrameBuffer = DC_FB_ELCDIF_SetFrameBuffer,
+ .getProperty = DC_FB_ELCDIF_GetProperty,
+ .setCallback = DC_FB_ELCDIF_SetCallback,
+};
+
+typedef struct
+{
+ video_pixel_format_t videoFormat;
+ elcdif_pixel_format_t elcdifFormat;
+} dc_fb_elcdif_pixel_foramt_map_t;
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+static status_t DC_FB_ELCDIF_GetPixelFormat(video_pixel_format_t input, elcdif_pixel_format_t *output);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+static const dc_fb_elcdif_pixel_foramt_map_t s_elcdifPixelFormatMap[] = {
+ {kVIDEO_PixelFormatLUT8, kELCDIF_PixelFormatRAW8},
+ {kVIDEO_PixelFormatRGB565, kELCDIF_PixelFormatRGB565},
+ {
+ kVIDEO_PixelFormatXRGB8888,
+ kELCDIF_PixelFormatXRGB8888,
+ },
+ {
+ kVIDEO_PixelFormatRGB888,
+ kELCDIF_PixelFormatRGB888,
+ }};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static status_t DC_FB_ELCDIF_GetPixelFormat(video_pixel_format_t input, elcdif_pixel_format_t *output)
+{
+ uint8_t i;
+
+ for (i = 0; i < ARRAY_SIZE(s_elcdifPixelFormatMap); i++)
+ {
+ if (s_elcdifPixelFormatMap[i].videoFormat == input)
+ {
+ *output = s_elcdifPixelFormatMap[i].elcdifFormat;
+ return kStatus_Success;
+ }
+ }
+
+ return kStatus_InvalidArgument;
+}
+
+status_t DC_FB_ELCDIF_Init(const dc_fb_t *dc)
+{
+ const dc_fb_elcdif_config_t *dcConfig;
+ elcdif_rgb_mode_config_t elcdifConfig = {0};
+
+ dc_fb_elcdif_handle_t *dcHandle = dc->prvData;
+
+ 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 <stdbool.h>
+
+/* 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 <avr/pgmspace.h>
+#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
+ #include <pgmspace.h>
+#else
+ #include <stdint.h>
+ #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 <stdint.h>
+
+/* 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 <stddef.h>
+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 <stdbool.h>
+
+/* 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 <stdbool.h>
+
+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 <stdbool.h>
+
+#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(&current->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, &current, &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, &current, &text));
+ }
+
+ if (previous.chars)
+ {
+ /* Tune the length and dispatch the previous line. */
+ if (!previous.linebreak && !current.linebreak)
+ tune_lines(&current, &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, &current, &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, &current, &text));
+ }
+
+ if (previous.chars)
+ {
+ /* Tune the length and dispatch the previous line. */
+ if (!previous.linebreak && !current.linebreak)
+ tune_lines(&current, &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 <stdbool.h>
+
+/* 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 <mcufont.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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; i<MAX_SYSTEM_FONTS; i++) {
+ /* Is entry is valid ? */
+ if ( s_device_fonts[i].valid == 0 ) {
+ /* Grab free entry in list for new font */
+ if (free_entry == -1 ) {
+ free_entry = i;
+ }
+ } else if (s_device_fonts[i].valid == 1 ) {
+ /* Does font.name matches */
+ if ( strncmp(s_device_fonts[i].font_params.name,
+ params->name,
+ 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; i<MAX_SYSTEM_FONTS; i++)
+ {
+ vg_lite_free_font_memory(i);
+ }
+
+ return;
+}
diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/velm.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/velm.h
new file mode 100644
index 0000000000..6c0beab8b8
--- /dev/null
+++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/velm.h
@@ -0,0 +1,351 @@
+/****************************************************************************
+*
+* 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 VELM_H_
+#define VELM_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ /*
+ */
+#define VERSION 0x00000001
+#define SLOT_COUNT 256/*16*/
+#define OBJECT_SLOT(id) \
+ elm_tls->gContext.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 <stdio.h>
+#include <stdlib.h>
+#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; i<count; i++) {
+ DBG_TRACE(("DBG: %s[%d]=%f offset=%d\n", \
+ name, \
+ i, \
+ ary[i], offset));
+ offset+= 4;
+ }
+ *disk_offset = offset;
+}
+
+void dbg_int_ary(char *name, uint32_t *ary, int count, int *disk_offset)
+{
+ int i;
+ int offset = *disk_offset;
+ for (i=0; i<count; i++) {
+ DBG_TRACE(("DBG: %s[%d]=%d offset=%d\n", \
+ name, \
+ i, \
+ ary[i], offset));
+ offset+= 4;
+ }
+ *disk_offset = offset;
+}
+
+void dbg_int_param(char *name, uint32_t value, int *disk_offset)
+{
+ int offset = *disk_offset;
+ DBG_TRACE(("DBG: %s=%d offset=%d\n", \
+ name, \
+ value, offset));
+ offset+= 4;
+ *disk_offset = offset;
+}
+
+void dbg_float_ary_no_offset_update(char *name, float *ary,
+ int count, int disk_offset)
+{
+ int i;
+ int offset = disk_offset;
+ for (i=0; i<count; i++) {
+ DBG_TRACE(("DBG: %s[%d]=%f offset=%d\n", \
+ name, \
+ i, \
+ ary[i], offset));
+ offset+= 4;
+ }
+}
+
+void dbg_int_ary_no_offset_update(char *name, uint32_t *ary,
+ int count, int disk_offset)
+{
+ int i;
+ int offset = disk_offset;
+ for (i=0; i<count; i++) {
+ DBG_TRACE(("DBG: %s[%d]=%d offset=%d\n", \
+ name, \
+ i, \
+ ary[i], offset));
+ offset+= 4;
+ }
+}
+
+void dbg_int_param_no_offset_update(char *name, uint32_t value, int disk_offset)
+{
+ int offset = disk_offset;
+ DBG_TRACE(("DBG: %s=%d offset=%d\n", \
+ name, \
+ value, offset));
+ offset+= 4;
+}
+
+#endif
diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_debug.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_debug.h
new file mode 100644
index 0000000000..7710b2a4ab
--- /dev/null
+++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_debug.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+*
+* 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.
+*
+*****************************************************************************/
+
+//#define ENABLE_DEBUG_TRACE
+
+#ifdef ENABLE_DEBUG_TRACE
+/* With debug configuration */
+
+/* Macros */
+#define TRACE_DBG(x) printf x
+#define TRACE_BIN(x) // printf x /* Tracer for binary layout */
+#define TRACE_WRN(x) printf x
+#define TRACE_INFO(x) printf x
+#define TRACE_ERR(x) printf x
+#define DBG_ARY(obj, param, count) \
+ dbg_float_ary(#param, &obj->param[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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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; i<GLYPH_CACHE_SIZE; i++) {
+ if ( g_glyph_cache[i].h_path != NULL ) {
+ /* For non-mapped path this resetting is sufficient */
+ vg_lite_clear_path(g_glyph_cache[i].h_path);
+
+ /* Release path handle */
+ VFT_FREE(g_glyph_cache[i].h_path);
+
+ /* Reset pointer */
+ g_glyph_cache[i].h_path = NULL;
+ }
+ }
+
+ /* Next time font init will be required */
+ g_glyph_cache_init_done = 0;
+}
+
+vg_lite_path_t *vft_cache_lookup(glyph_desc_t *g)
+{
+ int i;
+ int unused_idx = 0;
+
+ /* Not present caching code does not handle multiple font-face */
+ glyph_cache_init();
+
+ /* Check if path object for given glyph exists */
+ for (i=0; i<GLYPH_CACHE_SIZE; i++) {
+ if ( g_glyph_cache[i].g != NULL && g->unicode ==
+ 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; i<GLYPH_CACHE_SIZE; i++) {
+ if ( g_glyph_cache[i].use_count <
+ g_glyph_cache[unused_idx].use_count ) {
+ unused_idx = i;
+ }
+ }
+ /* Re-cycle descriptor */
+ if ( g_glyph_cache[unused_idx].h_path != NULL ) {
+ /* For non-mapped path this resetting is sufficient */
+ vg_lite_clear_path(g_glyph_cache[unused_idx].h_path);
+ } else {
+ /* Allocate new path object */
+ g_glyph_cache[unused_idx].h_path =
+ (vg_lite_path_t *)VFT_ALLOC(sizeof(vg_lite_path_t));
+ }
+ /* Allocate new path */
+ vg_lite_init_path(g_glyph_cache[unused_idx].h_path,
+ VG_LITE_FP32, VG_LITE_HIGH,
+ g->path.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 <stdint.h>
+
+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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <math.h>
+#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 <unistd.h>
+#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 <stddef.h>
+#include <stdint.h>
+
+#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, <code>VG_LITE_SUCCESS</code> 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 <code>vg_lite_buffer_t</code> 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 <code>vg_lite_stroke_conversion_t</code>.*/
+ vg_lite_draw_path_type_t path_type; /*! Refer to the definition by <code>vg_lite_draw_path_type_t</code>. */
+ 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 <code>vg_lite_color_t</code>.*/
+ } 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 <code>vg_lite_linear_gradient_parameter_t</code>.*/
+
+ 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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_buffer_t</code> 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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_buffer_t</code> 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 <code>NULL</code> 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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_buffer_t</code> structure that describes the buffer to be filled.
+
+ @param rectangle
+ Pointer to a rectangle that specifies the area to be filled. If <code>rectangle</code> is <code>NULL</code>, 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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>NULL</code>, 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 <code>color</code> parameter to 0.
+
+ Note that on hardware that doesn't support border scissoring (GC355) the blend mode will be forced to
+ <code>VG_LITE_BLEND_SRC_OVER</code> if rotation or perspective is involved.
+
+ @param target
+ Pointer to a <code>vg_lite_buffer_t</code> structure that describes the target of the blit.
+
+ @param source
+ Pointer to a <code>vg_lite_buffer_t</code> 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
+ <code>NULL</code>, 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
+ <code>VG_LITE_BLEND_NONE</code> (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
+ <code>VG_LITE_FILTER_BI_LINEAR</code> (0x20000).
+
+ @result
+ Returns the status as defined by <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_buffer_t</code> structure that describes the target of the draw.
+
+ @param path
+ Pointer to a <code>vg_lite_path_t</code> 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 <code>matrix</code> is <code>NULL</code>, 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
+ <code>VG_LITE_BLEND_NONE</code> (0).
+
+ @param color
+ The color applied to each pixel drawn by the path.
+
+ @result
+ Returns the status as defined by <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_path_t</code> structure that describes the path.
+
+ @param stroke_cap_style
+ The end cap style defined by <code>vg_lite_cap_style_t</code>.
+
+ @param stroke_join_style
+ The line join style defined by <code>vg_lite_join_style_t</code>.
+
+ @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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_path_t</code> structure that describes the path.
+
+ @result
+ Returns the status as defined by <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_path_t</code> structure that describes the path.
+
+ @param path_type
+ Pointer to a <code>vg_lite_draw_path_type_t</code> structure that describes the path.
+
+ @result
+ Returns the status as defined by <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_path_t</code> 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 <code>vg_lite_buffer_t</code> structure that contains the command buffer and path data after uploading it to GPU
+ memory. <code>NULL</code> 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 <code>vg_lite_path_t</code> 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 <code>matrix</code> is <code>NULL</code>, an
+ identity matrix is assumed which is usually a bad idea since the path can be anything.
+
+ @param source
+ Pointer to a <code>vg_lite_buffer_t</code> 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
+ <code>NULL</code>, 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
+ <code>VG_LITE_BLEND_NONE</code> (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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_linear_gradient_parameter_t</code>.
+
+ @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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_path_t</code> 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 <code>matrix</code> is <code>NULL</code>, 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
+ <code>VG_LITE_BLEND_NONE</code> (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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_path_t</code> 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 <code>matrix</code> is <code>NULL</code>, 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
+ <code>VG_LITE_BLEND_NONE</code> (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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_path_t</code> 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 <code>matrix</code> is <code>NULL</code>, 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
+ <code>VG_LITE_BLEND_NONE</code> (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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_matrix_t</code> 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 <code>vg_lite_matrix_t</code> 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 <code>vg_lite_matrix_t</code> 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 <code>vg_lite_matrix_t</code> 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 <code>vg_lite_error_t</code>.
+ */
+ 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 <code>vg_lite_error_t</code>.*/
+ 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 <code>vg_lite_error_t</code>.*/
+ vg_lite_error_t vg_lite_enable_scissor(void);
+
+ /*!
+ @abstract Disable scissor.
+
+ @result
+ Returns the status as defined by <code>vg_lite_error_t</code>.*/
+ 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 <code>vg_lite_error_t</code>.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 <code>vg_lite_error_t</code>.*/
+ vg_lite_error_t vg_lite_enable_premultiply(void);
+
+ /*!
+ @abstract Disable premultiply.
+
+ @result
+ Returns the status as defined by <code>vg_lite_error_t</code>.*/
+ 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 <code>vg_lite_error_t</code>.
+ */
+ vg_lite_error_t vg_lite_set_dither(int enable);
+
+ /*!
+ @abstract use to set the colorkey.
+
+ @param colorkey
+ Defined by <code>vg_lite_color_key4_t</code>.
+
+ @result
+ Returns the status as defined by <code>vg_lite_error_t</code>.
+ 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 <math.h>
+
+#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, &params, 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, &params, 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(&current_curve, tolerance);
+ for (int j = 0; j < params.num_points; ++j) {
+ quad_bezier_flatten_at(&current_curve, &params, 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. <code>NULL</code> 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 <code>NULL</code> if the logical address is not known.
+
+ @param physical
+ The physical address of the memory region to map if <code>logical</code> is <code>NULL</code>.
+
+ @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. <code>NULL</code> 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 <code>timeout = 0xFFFFFFFF</code>
+ 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 <string.h>
+
+#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 <asm/uaccess.h>
+#include <linux/version.h>
+#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, <code>VG_LITE_SUCCESS</code> 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 <math.h>
+#include <string.h>
+#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 <stdint.h>
+
+#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 <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#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 <stdio.h>
+#include <string.h>
+
+#include <mcufont.h>
+#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 <code>vg_lite_register_font</code> application can register active
+ fonts that <code>vg_lite_draw_text</code> uses to render text.
+
+ for raster fonts mandatory fields of <code>vg_lite_font_params_t</code> are:
+ name,
+ font_weight, font_stretch, font_style, font_height
+ data, data_len
+ for vector fonts mandatory fields of <code>vg_lite_font_params_t</code> are:
+ name,
+ data, data_len
+
+ On successful registeration <code>font</code> poiter will get non-negative
+ application handle.
+
+ @param font
+ Pointer to font handle
+
+ @param params
+ Pointer to font parameters that are used by <code>vg_lite_find_font</code>
+ to select specific font for rendering text
+
+ @result
+ Returns the status as defined by <code>vg_lite_error_t</code>.
+ 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
+ <code>vg_lite_unregister_font</code> unregisters application speciific
+ font form vg_lite driver. This font can not be used lateron by
+ <code>vg_lite_draw_text</code> API.
+
+ @param font
+ Pointer to font handle
+
+ @result
+ Returns the status as defined by <code>vg_lite_error_t</code>.
+ 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
+ <code>vg_lite_is_vector_font</code> 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 <code>vg_lite_error_t</code>.
+ 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 <code>vg_lite_font_attributes_t</code>.
+
+ @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 <code>vg_lite_error_t</code>.
+ 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 <rtthread.h>
+#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']