sw_draw.h 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /*
  2. * Copyright (c) 2020 Actions Technology Co., Ltd
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /**
  7. * @file
  8. * @brief Utilities of sw draw API
  9. */
  10. #ifndef ZEPHYR_FRAMEWORK_INCLUDE_DISPLAY_SW_DRAW_H_
  11. #define ZEPHYR_FRAMEWORK_INCLUDE_DISPLAY_SW_DRAW_H_
  12. #include <stddef.h>
  13. #include <stdint.h>
  14. /**
  15. * @defgroup display-util Display Utilities
  16. * @ingroup display_libraries
  17. * @{
  18. */
  19. #ifndef ALWAYS_INLINE
  20. #define ALWAYS_INLINE inline __attribute__((always_inline))
  21. #endif
  22. #ifdef __cplusplus
  23. extern "C" {
  24. #endif
  25. /*******************************************************************************
  26. * pixel blending
  27. ******************************************************************************/
  28. /*
  29. * @brief blend argb8888 over argb8888
  30. *
  31. * @param dest_color dest argb8888 value
  32. * @param src_color src argb8888 value
  33. */
  34. static ALWAYS_INLINE uint32_t mix_argb8888_over_argb8888(uint32_t dest_color, uint32_t src_color)
  35. {
  36. uint32_t a = src_color >> 24;
  37. uint32_t ra = 255 - a;
  38. uint32_t result_1 = (src_color & 0x00FF00FF) * a + (dest_color & 0x00FF00FF) * ra;
  39. uint32_t result_2 = ((src_color & 0xFF00FF00) >> 8) * a + ((dest_color & 0xFF00FF00) >> 8) * ra;
  40. return ((result_1 & 0xFF00FF00) >> 8) | (result_2 & 0xFF00FF00);
  41. }
  42. /*
  43. * @brief blend argb8888 over rgb565
  44. *
  45. * @param dest_color dest rgb565 value
  46. * @param src_color src argb8888 value
  47. */
  48. static ALWAYS_INLINE uint16_t mix_argb8888_over_rgb565(uint16_t dest_color, uint32_t src_color)
  49. {
  50. uint32_t a = src_color >> 24;
  51. uint32_t ra = 255 - a;
  52. #if 0
  53. uint32_t dest32_rb = ((dest_color & 0xf800) << 5) | (dest_color & 0x1f);
  54. dest32_rb = (dest32_rb << 3) | (dest32_rb & 0x00070007);
  55. dest32_rb = (src_color & 0x00FF00FF) * a + dest32_rb * ra;
  56. uint32_t dest32_g = ((dest_color & 0x07e0) << 5) | ((dest_color & 0x0060) << 3);
  57. dest32_g = (src_color & 0x0000FF00) * a + dest32_g * ra;
  58. return ((dest32_rb >> 16) & 0xf800) | ((dest32_rb >> 11) & 0x1f) |
  59. ((dest32_g >> 13) & 0x07e0);
  60. #else
  61. uint32_t dest32_rb = ((dest_color & 0xf800) << 8) | ((dest_color & 0x1f) << 3);
  62. dest32_rb = (src_color & 0x00FF00FF) * a + dest32_rb * ra;
  63. uint32_t dest32_g = (dest_color & 0x07e0) << 5;
  64. dest32_g = (src_color & 0x0000FF00) * a + dest32_g * ra;
  65. return ((dest32_rb >> 16) & 0xf800) | ((dest32_rb >> 11) & 0x1f) |
  66. ((dest32_g >> 13) & 0x07e0);
  67. #endif
  68. }
  69. /*
  70. * @brief blend rgb565 over rgb565
  71. *
  72. * @param dest_color dest rgb565 value
  73. * @param src_color src rgb565 value
  74. */
  75. static ALWAYS_INLINE uint16_t mix_rgb565_over_rgb565(uint16_t dest_color, uint16_t src_color, uint8_t src_a)
  76. {
  77. uint16_t dest_r = (dest_color >> 11) * (255 - src_a) + (src_color >> 11) * src_a;
  78. uint16_t dest_b = (dest_color & 0x001f) * (255 - src_a) + (src_color & 0x001f) * src_a;
  79. uint32_t dest_g = (dest_color & 0x07e0) * (255 - src_a) + (src_color & 0x07e0) * (uint32_t)src_a;
  80. return ((dest_r >> 8) << 11) | ((dest_g >> 8) & 0x07e0) | (dest_b >> 8);
  81. }
  82. /*
  83. * @brief blend rgb565 over rgb565
  84. *
  85. * @param dest_color dest rgb565 value
  86. * @param src_color src rgb565 value
  87. */
  88. static ALWAYS_INLINE uint16_t blend_rgb565_over_rgb565(uint16_t dest_color, uint16_t src_color, uint8_t src_a)
  89. {
  90. if (src_a <= 0) {
  91. return dest_color;
  92. } else if (src_a >= 255) {
  93. return src_color;
  94. } else {
  95. return mix_rgb565_over_rgb565(dest_color, src_color, src_a);
  96. }
  97. }
  98. /*
  99. * @brief blend rgb565 over rgb565
  100. *
  101. * @param dest_color dest rgb565 value
  102. * @param src_color src rgb565 value
  103. */
  104. static ALWAYS_INLINE uint16_t blend_argb6666_over_rgb565(uint16_t dest_color, const uint8_t src_color[3])
  105. {
  106. uint8_t src_a = src_color[2] >> 2;
  107. if (src_a <= 0) {
  108. return dest_color;
  109. } else {
  110. uint8_t src_b = (src_color[0] & 0x3f);
  111. uint8_t src_g = ((src_color[1] & 0x0f) << 2) | (src_color[0] >> 6);
  112. uint8_t src_r = ((src_color[2] & 0x03) << 4) | (src_color[1] >> 4);
  113. if (src_a >= 63) {
  114. return ((src_r & 0x3e) << 10) | ((uint16_t)src_g << 5) | (src_b >> 1);
  115. } else {
  116. uint16_t dest_b = ((dest_color & 0x001f) << 1) | (dest_color & 0x1);
  117. dest_b = dest_b * (63 - src_a) + (uint16_t)src_b * src_a;
  118. uint16_t dest_g = (dest_color & 0x07e0) >> 5;
  119. dest_g = dest_g * (63 - src_a) + (uint16_t)src_g * src_a;
  120. uint16_t dest_r = ((dest_color & 0xf800) >> 10) | ((dest_color & 0x0800) >> 11);
  121. dest_r = dest_r * (63 - src_a) + (uint16_t)src_r * src_a;
  122. return ((dest_r & 0x0f80) << 4) | ((dest_g & 0x0fc0) >> 1) | (dest_b >> 7);
  123. }
  124. }
  125. }
  126. /*
  127. * @brief blend argb8888 over rgb565
  128. *
  129. * @param dest_color dest rgb565 value
  130. * @param src_color src argb8888 value
  131. */
  132. static ALWAYS_INLINE uint16_t blend_argb8888_over_rgb565(uint16_t dest_color, uint32_t src_color)
  133. {
  134. uint8_t src_a = src_color >> 24;
  135. if (src_a <= 0) {
  136. return dest_color;
  137. } else if (src_a >= 255) {
  138. return ((src_color & 0xf80000) >> 8) | ((src_color & 0x00fc00) >> 5) |
  139. ((src_color & 0x0000f8) >> 3);
  140. } else {
  141. return mix_argb8888_over_rgb565(dest_color, src_color);
  142. }
  143. }
  144. /*
  145. * @brief blend argb8888 over argb8888
  146. *
  147. * @param dest_color dest argb8888 value
  148. * @param src_color src argb8888 value
  149. */
  150. static ALWAYS_INLINE uint32_t blend_argb8888_over_argb8888(uint32_t dest_color, uint32_t src_color)
  151. {
  152. uint8_t src_a = src_color >> 24;
  153. if (src_a <= 0) {
  154. return dest_color;
  155. } else if (src_a >= 255) {
  156. return src_color;
  157. } else {
  158. return mix_argb8888_over_argb8888(dest_color, src_color);
  159. }
  160. }
  161. /*******************************************************************************
  162. * pixel filtering
  163. ******************************************************************************/
  164. /*
  165. * @brief rgb565 bilinear filtering with lossy precition distance grid
  166. *
  167. * @param c00 color value at (0, 0)
  168. * @param c10 color value at (1, 0)
  169. * @param c01 color value at (0, 1)
  170. * @param c11 color value at (1, 1)
  171. * @param x_tap filter tap coefficient in x direction
  172. * @param y_tap filter tap coefficient in y direction
  173. * @param tap_bits bits of filter tap coefficient, must not greater than 6
  174. */
  175. static ALWAYS_INLINE uint16_t bilinear_rgb565_fast_m6(
  176. uint16_t c00, uint16_t c10, uint16_t c01, uint16_t c11,
  177. int16_t x_tap, int16_t y_tap, int16_t tap_bits)
  178. {
  179. uint32_t pm11 = (x_tap * y_tap) >> tap_bits;
  180. uint32_t pm10 = x_tap - pm11;
  181. uint32_t pm01 = y_tap - pm11;
  182. uint32_t pm00 = (1 << tap_bits) - pm01 - pm10 - pm11;
  183. uint32_t rb = (c00 & 0xf81f) * pm00;
  184. uint32_t g = (c00 & 0x07e0) * pm00;
  185. rb += (c10 & 0xf81f) * pm10;
  186. g += (c10 & 0x07e0) * pm10;
  187. rb += (c01 & 0xf81f) * pm01;
  188. g += (c01 & 0x07e0) * pm01;
  189. rb += (c11 & 0xf81f) * pm11;
  190. g += (c11 & 0x07e0) * pm11;
  191. return ((rb >> tap_bits) & 0xf81f) | ((g >> tap_bits) & 0x07e0);
  192. }
  193. /*
  194. * @brief argb8888 bilinear filtering with lossy precition distance grid
  195. *
  196. * @param c00 color value at (0, 0)
  197. * @param c10 color value at (1, 0)
  198. * @param c01 color value at (0, 1)
  199. * @param c11 color value at (1, 1)
  200. * @param x_tap filter tap coefficient in x direction
  201. * @param y_tap filter tap coefficient in y direction
  202. * @param tap_bits bits of filter tap coefficient, must not greater than 8
  203. */
  204. static ALWAYS_INLINE uint32_t bilinear_argb8888_fast_m8(
  205. uint32_t c00, uint32_t c10, uint32_t c01, uint32_t c11,
  206. int16_t x_tap, int16_t y_tap, int16_t tap_bits)
  207. {
  208. uint32_t pm11 = ((uint32_t)x_tap * y_tap) >> tap_bits;
  209. uint32_t pm10 = x_tap - pm11;
  210. uint32_t pm01 = y_tap - pm11;
  211. uint32_t pm00 = (1 << tap_bits) - pm01 - pm10 - pm11;
  212. uint32_t rb = (c00 & 0x00FF00FF) * pm00;
  213. uint32_t ag = ((c00 & 0xFF00FF00) >> tap_bits) * pm00;
  214. rb += (c10 & 0x00FF00FF) * pm10;
  215. ag += ((c10 & 0xFF00FF00) >> tap_bits) * pm10;
  216. rb += (c01 & 0x00FF00FF) * pm01;
  217. ag += ((c01 & 0xFF00FF00) >> tap_bits) * pm01;
  218. rb += (c11 & 0x00FF00FF) * pm11;
  219. ag += ((c11 & 0xFF00FF00) >> tap_bits) * pm11;
  220. return ((rb >> tap_bits) & 0x00FF00FF) | (ag & 0xFF00FF00);
  221. }
  222. /*
  223. * @brief blend an argb8565 image over rgb565 image
  224. *
  225. * @param dst address of dst image
  226. * @param src address of src image
  227. * @param dst_stride stride in pixels of dst image
  228. * @param src_stride stride in pixels of src image
  229. * @param w width in pixels of blend area
  230. * @param h height in pixels of blend area
  231. *
  232. * @retval N/A
  233. */
  234. void sw_blend_argb8565_over_rgb565(void *dst, const void *src,
  235. uint16_t dst_stride, uint16_t src_stride, uint16_t w, uint16_t h);
  236. /*
  237. * @brief blend an argb6666 image over rgb565 image
  238. *
  239. * @param dst address of dst image
  240. * @param src address of src image
  241. * @param dst_stride stride in pixels of dst image
  242. * @param src_stride stride in pixels of src image
  243. * @param w width in pixels of blend area
  244. * @param h height in pixels of blend area
  245. *
  246. * @retval N/A
  247. */
  248. void sw_blend_argb6666_over_rgb565(void *dst, const void *src,
  249. uint16_t dst_stride, uint16_t src_stride, uint16_t w, uint16_t h);
  250. /*
  251. * @brief blend an argb8888 image over rgb565 image
  252. *
  253. * @param dst address of dst image
  254. * @param src address of src image
  255. * @param dst_stride stride in pixels of dst image
  256. * @param src_stride stride in pixels of src image
  257. * @param w width in pixels of blend area
  258. * @param h height in pixels of blend area
  259. *
  260. * @retval N/A
  261. */
  262. void sw_blend_argb8888_over_rgb565(void *dst, const void *src,
  263. uint16_t dst_stride, uint16_t src_stride, uint16_t w, uint16_t h);
  264. /*
  265. * @brief blend an argb8888 image over argb8888 image
  266. *
  267. * @param dst address of dst image
  268. * @param src address of src image
  269. * @param dst_stride stride in pixels of dst image
  270. * @param src_stride stride in pixels of src image
  271. * @param w width in pixels of blend area
  272. * @param h height in pixels of blend area
  273. *
  274. * @retval N/A
  275. */
  276. void sw_blend_argb8888_over_argb8888(void *dst, const void *src,
  277. uint16_t dst_stride, uint16_t src_stride, uint16_t w, uint16_t h);
  278. #ifdef __cplusplus
  279. }
  280. #endif
  281. /**
  282. * @}
  283. */
  284. #endif /* ZEPHYR_FRAMEWORK_INCLUDE_DISPLAY_SW_DRAW_H_ */