ソースを参照

fix uart1 pin bug, delete and update wrong icf files, add vglite support for rt1170 in IAR environment.

Frogrey 2 年 前
コミット
f941dfcf13
91 ファイル変更32890 行追加236 行削除
  1. 72 26
      bsp/imxrt/imxrt1170-nxp-evk/m7/.config
  2. 36 0
      bsp/imxrt/imxrt1170-nxp-evk/m7/board/Kconfig
  3. 24 20
      bsp/imxrt/imxrt1170-nxp-evk/m7/board/board.c
  4. 0 98
      bsp/imxrt/imxrt1170-nxp-evk/m7/board/linker_scripts/link.icf
  5. 26 14
      bsp/imxrt/imxrt1170-nxp-evk/m7/board/linker_scripts/link_ram.icf
  6. 90 17
      bsp/imxrt/imxrt1170-nxp-evk/m7/project.ewd
  7. 45 28
      bsp/imxrt/imxrt1170-nxp-evk/m7/project.ewp
  8. 29 6
      bsp/imxrt/imxrt1170-nxp-evk/m7/rtconfig.h
  9. 2 2
      bsp/imxrt/imxrt1170-nxp-evk/m7/rtconfig.py
  10. 80 7
      bsp/imxrt/imxrt1170-nxp-evk/m7/template.ewd
  11. 32 18
      bsp/imxrt/imxrt1170-nxp-evk/m7/template.ewp
  12. 681 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/Elm.h
  13. 221 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/buf_reader.c
  14. 63 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/buf_reader.h
  15. 474 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/display_support.c
  16. 189 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/display_support.h
  17. 321 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_buffer.c
  18. 483 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_draw.c
  19. 158 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_headers.h
  20. 160 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_init.c
  21. 2238 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_object.c
  22. 43 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_os.c
  23. 13 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_os.h
  24. 55 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_precom.h
  25. 732 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_text.c
  26. 207 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/elm_text.h
  27. 30 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fonts.h
  28. 81 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb.h
  29. 264 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_elcdif.c
  30. 101 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_elcdif.h
  31. 288 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_lcdifv2.c
  32. 109 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_dc_fb_lcdifv2.h
  33. 140 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_display.h
  34. 243 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_fbdev.c
  35. 227 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_fbdev.h
  36. 187 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_hx8394.c
  37. 57 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_hx8394.h
  38. 351 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_mipi_dsi_cmd.c
  39. 354 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_mipi_dsi_cmd.h
  40. 251 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68191.c
  41. 62 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68191.h
  42. 409 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68200.c
  43. 67 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_rm68200.h
  44. 301 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_video_common.c
  45. 364 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_video_common.h
  46. 14 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mcufont.h
  47. 134 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_bwfont.c
  48. 77 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_bwfont.h
  49. 144 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_config.h
  50. 84 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_encoding.c
  51. 45 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_encoding.h
  52. 122 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_font.c
  53. 137 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_font.h
  54. 332 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_justify.c
  55. 74 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_justify.h
  56. 118 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_kerning.c
  57. 27 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_kerning.h
  58. 286 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_rlefont.c
  59. 82 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_rlefont.h
  60. 83 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_scaledfont.c
  61. 23 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_scaledfont.h
  62. 357 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_wordwrap.c
  63. 35 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/mf_wordwrap.h
  64. 716 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/rle_font_read.c
  65. 351 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/velm.h
  66. 317 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_debug.c
  67. 111 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_debug.h
  68. 463 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_draw.c
  69. 119 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vft_draw.h
  70. 10894 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite.c
  71. 2060 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite.h
  72. 535 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_flat.c
  73. 55 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_flat.h
  74. 499 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hal.c
  75. 272 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hal.h
  76. 64 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_hw.h
  77. 160 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_image.c
  78. 1020 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_kernel.c
  79. 444 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_kernel.h
  80. 113 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_matrix.c
  81. 473 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_os.c
  82. 134 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_os.h
  83. 353 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_path.c
  84. 48 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_platform.h
  85. 359 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_text.c
  86. 372 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vg_lite_text.h
  87. 87 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_support.c
  88. 36 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_support.h
  89. 181 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_window.c
  90. 62 0
      bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/vglite_window.h
  91. 58 0
      bsp/imxrt/libraries/MIMXRT1170/SConscript

+ 72 - 26
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

+ 36 - 0
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"

+ 24 - 20
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
 }
 

+ 0 - 98
bsp/imxrt/imxrt1170-nxp-evk/m7/board/linker_scripts/link.icf

@@ -1,98 +0,0 @@
-/*
-** ###################################################################
-**     Processors:          MIMXRT1052CVJ5B
-**                          MIMXRT1052CVL5B
-**                          MIMXRT1052DVJ6B
-**                          MIMXRT1052DVL6B
-**
-**     Compiler:            IAR ANSI C/C++ Compiler for ARM
-**     Reference manual:    IMXRT1050RM Rev.1, 03/2018
-**     Version:             rev. 1.0, 2018-09-21
-**     Build:               b180921
-**
-**     Abstract:
-**         Linker file for the IAR ANSI C/C++ Compiler for ARM
-**
-**     Copyright 2016 Freescale Semiconductor, Inc.
-**     Copyright 2016-2018 NXP
-**     All rights reserved.
-**
-**     SPDX-License-Identifier: BSD-3-Clause
-**
-**     http:                 www.nxp.com
-**     mail:                 support@nxp.com
-**
-** ###################################################################
-*/
-
-define symbol m_interrupts_start       = 0x30002000;
-define symbol m_interrupts_end         = 0x300023FF;
-
-define symbol m_text_start             = 0x30002400;
-define symbol m_text_end               = 0x30FBFFFF;
-
-define symbol m_data_start             = 0x20000000;
-define symbol m_data_end               = 0x2003FFFF;
-
-define symbol m_data2_start                    = 0x202C0000;
-define symbol m_data2_end                      = 0x2033FFFF;
-
-define exported symbol __NCACHE_REGION_START   = m_data2_start;
-define exported symbol __NCACHE_REGION_SIZE    = 0x0;
-
-define exported symbol m_boot_hdr_conf_start = 0x30000400;
-define symbol m_boot_hdr_ivt_start           = 0x30001000;
-define symbol m_boot_hdr_boot_data_start     = 0x30001020;
-define symbol m_boot_hdr_dcd_data_start      = 0x30001030;
-
-/* Sizes */
-if (isdefinedsymbol(__stack_size__)) {
-  define symbol __size_cstack__        = __stack_size__;
-} else {
-  define symbol __size_cstack__        = 0x0400;
-}
-
-if (isdefinedsymbol(__heap_size__)) {
-  define symbol __size_heap__          = __heap_size__;
-} else {
-  define symbol __size_heap__          = 0x0400;
-}
-
-define exported symbol __VECTOR_TABLE  = m_interrupts_start;
-define exported symbol __VECTOR_RAM    = m_interrupts_start;
-define exported symbol __RAM_VECTOR_TABLE_SIZE = 0x0;
-define exported symbol __RTT_HEAP_END = m_data2_end;
-
-define memory mem with size = 4G;
-define region TEXT_region = mem:[from m_interrupts_start to m_interrupts_end]
-                          | mem:[from m_text_start to m_text_end];
-
-define region DATA_region = mem:[from m_data_start to m_data_end-__size_cstack__];
-define region DATA2_region = mem:[from m_data2_start to m_data2_end];
-define region CSTACK_region = mem:[from m_data_end-__size_cstack__+1 to m_data_end];
-
-define block CSTACK    with alignment = 8, size = __size_cstack__   { };
-define block HEAP      with alignment = 8, size = __size_heap__     { };
-define block RW        { readwrite };
-define block ZI        { zi };
-define block NCACHE_VAR    { section NonCacheable , section NonCacheable.init };
-
-initialize by copy { readwrite, section .textrw };
-do not initialize  { section .noinit };
-
-place at address mem: m_interrupts_start    { readonly section .intvec };
-
-place at address mem:m_boot_hdr_conf_start { section .boot_hdr.conf };
-place at address mem:m_boot_hdr_ivt_start { section .boot_hdr.ivt };
-place at address mem:m_boot_hdr_boot_data_start { readonly section .boot_hdr.boot_data };
-place at address mem:m_boot_hdr_dcd_data_start { readonly section .boot_hdr.dcd_data };
-
-keep{ section .boot_hdr.conf, section .boot_hdr.ivt, section .boot_hdr.boot_data, section .boot_hdr.dcd_data };
-
-place in TEXT_region                        { readonly };
-place in DATA_region                        { block RW };
-place in DATA_region                        { block ZI };
-place in DATA_region                        { last block HEAP };
-place in DATA_region                        { block NCACHE_VAR };
-place in CSTACK_region                      { block CSTACK };
-

+ 26 - 14
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 };

+ 90 - 17
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>
@@ -457,6 +489,39 @@
                 </option>
             </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>
@@ -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>

+ 45 - 28
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,18 +721,10 @@
       <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>
@@ -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>
@@ -1126,9 +1140,6 @@
     <file>
       <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>
@@ -1138,6 +1149,9 @@
     <file>
       <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>
@@ -1171,6 +1185,9 @@
   </group>
   <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>
@@ -1189,6 +1206,9 @@
   </group>
   <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>
@@ -1285,9 +1305,6 @@
     <file>
       <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>
@@ -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>

+ 29 - 6
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

+ 2 - 2
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'

+ 80 - 7
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>
@@ -457,6 +489,39 @@
                 </option>
             </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>
@@ -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>

+ 32 - 18
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,18 +680,10 @@
             <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>
@@ -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>

+ 681 - 0
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_ */

+ 221 - 0
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;
+
+}

+ 63 - 0
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_

+ 474 - 0
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;
+}

+ 189 - 0
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_ */

+ 321 - 0
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;
+}

+ 483 - 0
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;
+}

+ 158 - 0
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__ */

+ 160 - 0
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();
+}

+ 2238 - 0
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;
+    }
+}

+ 43 - 0
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;
+}

+ 13 - 0
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

+ 55 - 0
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 */

+ 732 - 0
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;
+}

+ 207 - 0
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_ */

+ 30 - 0
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

+ 81 - 0
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_ */

+ 264 - 0
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);
+        }
+    }
+}

+ 101 - 0
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_ */

+ 288 - 0
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);
+        }
+    }
+}

+ 109 - 0
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_ */

+ 140 - 0
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_ */

+ 243 - 0
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);
+}

+ 227 - 0
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_ */

+ 187 - 0
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);
+}

+ 57 - 0
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_ */

+ 351 - 0
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);
+    }
+}

+ 354 - 0
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_ */

+ 251 - 0
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);
+}

+ 62 - 0
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_ */

+ 409 - 0
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);
+}

+ 67 - 0
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_ */

+ 301 - 0
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;
+}

+ 364 - 0
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_ */

+ 14 - 0
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

+ 134 - 0
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);
+}

+ 77 - 0
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

+ 144 - 0
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
+

+ 84 - 0
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

+ 45 - 0
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

+ 122 - 0
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;
+}
+

+ 137 - 0
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

+ 332 - 0
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
+

+ 74 - 0
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

+ 118 - 0
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

+ 27 - 0
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

+ 286 - 0
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);
+}

+ 82 - 0
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

+ 83 - 0
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;
+}
+

+ 23 - 0
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

+ 357 - 0
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

+ 35 - 0
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

+ 716 - 0
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;
+}

+ 351 - 0
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_ */

+ 317 - 0
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

+ 111 - 0
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;
+

+ 463 - 0
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);
+}

+ 119 - 0
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

+ 10894 - 0
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;
+}

+ 2060 - 0
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_ */

+ 535 - 0
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;
+}

+ 55 - 0
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_ */

+ 499 - 0
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;
+}

+ 272 - 0
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_ */

+ 64 - 0
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) */

+ 160 - 0
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;
+}

+ 1020 - 0
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;
+}

+ 444 - 0
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_ */

+ 113 - 0
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);
+}

+ 473 - 0
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) */

+ 134 - 0
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

+ 353 - 0
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;
+}

+ 48 - 0
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

+ 359 - 0
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;
+}

+ 372 - 0
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_ */

+ 87 - 0
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;
+}

+ 36 - 0
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_ */

+ 181 - 0
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);
+}

+ 62 - 0
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_ */

+ 58 - 0
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']