render.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-02-25 GuEe-GUI the first version
  9. */
  10. #include <rtthread.h>
  11. #include <rtdevice.h>
  12. #include "psf.h"
  13. #include "render.h"
  14. struct render
  15. {
  16. struct rt_device *fbdev;
  17. struct rt_device_graphic_info info;
  18. struct fb_var_screeninfo var;
  19. struct fb_fix_screeninfo fix;
  20. struct psf_font psf;
  21. rt_uint32_t xlate;
  22. rt_uint32_t font_line_length;
  23. rt_uint32_t buffer_idx;
  24. rt_size_t buffer_size;
  25. rt_size_t line_size;
  26. rt_size_t screen_size;
  27. rt_size_t font_size;
  28. rt_uint8_t color_size;
  29. rt_uint8_t *cursor, *cursor_backend;
  30. struct render_point position, start_point, end_point;
  31. rt_uint32_t foreground, background;
  32. rt_uint32_t raw_foreground, raw_background;
  33. rt_uint32_t red_off, green_off, blue_off, alpha_off;
  34. rt_uint32_t red_mask, green_mask, blue_mask, alpha_mask;
  35. void *hook_ptr;
  36. void (*set_pixel)(void *fb, rt_uint32_t color);
  37. rt_uint32_t (*get_pixel)(void *fb);
  38. void *(*last_buffer)(void);
  39. void *(*next_buffer)(void);
  40. void (*move_buffer)(void *dst, void *src, rt_size_t size);
  41. void (*pan_display)(void);
  42. };
  43. static struct render _render = {};
  44. rt_err_t render_load_fbdev(struct rt_device *fbdev)
  45. {
  46. rt_err_t err = RT_EOK;
  47. struct render *rd = &_render;
  48. if ((err = rt_device_open(fbdev, 0)))
  49. {
  50. return err;
  51. }
  52. rd->fbdev = fbdev;
  53. err |= rt_device_control(fbdev, FBIOGET_VSCREENINFO, &rd->var);
  54. err |= rt_device_control(fbdev, FBIOGET_FSCREENINFO, &rd->fix);
  55. err |= rt_device_control(fbdev, RTGRAPHIC_CTRL_GET_INFO, &rd->info);
  56. rt_device_close(fbdev);
  57. return err;
  58. }
  59. static rt_uint32_t parse_color(struct render_color *color)
  60. {
  61. rt_uint32_t color_value;
  62. struct render *rd = &_render;
  63. color_value = ((color->red & rd->red_mask) << rd->red_off) |
  64. ((color->green & rd->green_mask) << rd->green_off) |
  65. ((color->blue & rd->blue_mask) << rd->blue_off);
  66. if (rd->var.transp.length)
  67. {
  68. color_value |= (color->alpha & rd->alpha_mask) << rd->alpha_off;
  69. }
  70. return color_value;
  71. }
  72. static void set_pixel16(void *fb, rt_uint32_t color)
  73. {
  74. rt_memcpy(fb, &color, 2);
  75. }
  76. static rt_uint32_t get_pixel16(void *fb)
  77. {
  78. rt_uint16_t color;
  79. rt_memcpy(&color, fb, 2);
  80. return color;
  81. }
  82. static void set_pixel24(void *fb, rt_uint32_t color)
  83. {
  84. rt_memcpy(fb, &color, 3);
  85. }
  86. static rt_uint32_t get_pixel24(void *fb)
  87. {
  88. rt_uint32_t color;
  89. rt_memcpy(&color, fb, 3);
  90. return color;
  91. }
  92. static void set_pixel32(void *fb, rt_uint32_t color)
  93. {
  94. *(rt_uint32_t *)fb = color;
  95. }
  96. static rt_uint32_t get_pixel32(void *fb)
  97. {
  98. return *(rt_uint32_t *)fb;
  99. }
  100. static void *last_buffer_single(void)
  101. {
  102. struct render *rd = &_render;
  103. return (void *)rd->info.framebuffer;
  104. }
  105. static void *fb_next_buffer_dummy(void)
  106. {
  107. return last_buffer_single();
  108. }
  109. static void fb_move_buffer_single(void *dst, void *src, rt_size_t size)
  110. {
  111. rt_memmove(dst, src, size);
  112. }
  113. static void fb_pan_display_dummy(void)
  114. {
  115. }
  116. static void *last_buffer_multi(void)
  117. {
  118. struct render *rd = &_render;
  119. return (void *)rd->info.framebuffer + rd->buffer_idx * rd->line_size;
  120. }
  121. static void *fb_next_buffer(void)
  122. {
  123. struct render *rd = &_render;
  124. if (rd->buffer_idx < rd->buffer_size)
  125. {
  126. ++rd->buffer_idx;
  127. }
  128. else
  129. {
  130. rd->buffer_idx = 0;
  131. }
  132. return last_buffer_multi();
  133. }
  134. static void fb_move_buffer_multi(void *dst, void *src, rt_size_t size)
  135. {
  136. struct render *rd = &_render;
  137. if (rd->buffer_idx == 0)
  138. {
  139. fb_move_buffer_single(dst, src, size);
  140. }
  141. }
  142. static void fb_pan_display(void)
  143. {
  144. struct render *rd = &_render;
  145. rd->var.yoffset = rd->buffer_idx * rd->psf.height;
  146. rt_device_control(rd->fbdev, FBIOPAN_DISPLAY, &rd->var);
  147. }
  148. static void color_hook_dummy(void *, rt_uint32_t *);
  149. rt_err_t render_load_font(const char *psf_data, rt_size_t size,
  150. struct render_color *foreground, struct render_color *background,
  151. struct render_point *out_start_point, struct render_point *out_end_point)
  152. {
  153. rt_err_t err;
  154. rt_uint8_t *font_data, *cursor, *cursor_backend;
  155. rt_uint32_t foreground_color, background_color;
  156. struct psf_font new_psf;
  157. struct render *rd = &_render;
  158. if ((err = psf_initialize(psf_data, &new_psf)))
  159. {
  160. return err;
  161. }
  162. if (!new_psf.count)
  163. {
  164. return -RT_EEMPTY;
  165. }
  166. /* Font + Cursor + Cursor backend */
  167. rd->color_size = rd->var.bits_per_pixel / 8;
  168. font_data = rt_malloc_align(rd->color_size * new_psf.glyph * (new_psf.count + 2), sizeof(rt_ubase_t));
  169. if (!font_data)
  170. {
  171. return -RT_ENOMEM;
  172. }
  173. cursor = font_data + rd->color_size * new_psf.glyph * new_psf.count;
  174. cursor_backend = cursor + rd->color_size * new_psf.glyph * new_psf.count;
  175. rd->red_off = rd->var.red.offset;
  176. rd->red_mask = RT_GENMASK(rd->var.red.length, 0);
  177. rd->green_off = rd->var.green.offset;
  178. rd->green_mask = RT_GENMASK(rd->var.green.length, 0);
  179. rd->blue_off = rd->var.blue.offset;
  180. rd->blue_mask = RT_GENMASK(rd->var.blue.length, 0);
  181. rd->alpha_off = rd->var.transp.offset;
  182. rd->alpha_mask = RT_GENMASK(rd->var.transp.length, 0);
  183. foreground_color = parse_color(foreground);
  184. background_color = parse_color(background);
  185. if ((err = psf_parse(&new_psf, font_data, cursor_backend,
  186. rd->color_size, foreground_color, background_color)))
  187. {
  188. rt_free(font_data);
  189. return err;
  190. }
  191. if (rd->psf.font_data)
  192. {
  193. rt_free((void *)rd->psf.font_data);
  194. }
  195. rd->foreground = rd->raw_foreground = foreground_color;
  196. rd->background = rd->raw_background = background_color;
  197. rd->hook_ptr = &color_hook_dummy;
  198. rt_memcpy(&rd->psf, &new_psf, sizeof(rd->psf));
  199. rd->font_line_length = rd->psf.width * rd->color_size;
  200. rd->xlate = rd->fix.line_length - rd->font_line_length;
  201. rd->line_size = rd->psf.height * rd->fix.line_length;
  202. rd->screen_size = rd->var.xres * rd->var.yres * rd->color_size;
  203. rd->font_size = rd->psf.glyph * rd->color_size;
  204. rd->buffer_idx = 0;
  205. rd->buffer_size = (rd->fix.smem_len - rd->screen_size) / rd->line_size;
  206. if (rd->buffer_size)
  207. {
  208. rd->var.yres_virtual = (rd->fix.smem_len / rd->screen_size) * rd->var.yres;
  209. if (rt_device_control(rd->fbdev, FBIOPUT_VSCREENINFO, &rd->var))
  210. {
  211. /* Enable double buffer fail */
  212. rd->buffer_size = 0;
  213. }
  214. }
  215. if (rd->buffer_size)
  216. {
  217. rd->last_buffer = last_buffer_multi;
  218. rd->next_buffer = fb_next_buffer;
  219. rd->move_buffer = fb_move_buffer_single;
  220. rd->pan_display = fb_pan_display;
  221. }
  222. else
  223. {
  224. rd->last_buffer = last_buffer_single;
  225. rd->next_buffer = fb_next_buffer_dummy;
  226. rd->move_buffer = fb_move_buffer_multi;
  227. rd->pan_display = fb_pan_display_dummy;
  228. }
  229. rd->cursor = cursor;
  230. rd->cursor_backend = cursor_backend;
  231. rd->start_point.row = rd->var.yoffset / rd->psf.height;
  232. rd->start_point.col = rd->var.xoffset / rd->psf.width;
  233. rd->end_point.row = rd->var.yres / rd->psf.height - 1;
  234. rd->end_point.col = rd->var.xres / rd->psf.width - 1;
  235. if (out_start_point)
  236. {
  237. rt_memcpy(out_start_point, &rd->start_point, sizeof(*out_start_point));
  238. }
  239. if (out_end_point)
  240. {
  241. rt_memcpy(out_end_point, &rd->end_point, sizeof(*out_end_point));
  242. }
  243. switch (rd->var.bits_per_pixel)
  244. {
  245. case 32:
  246. rd->set_pixel = set_pixel32;
  247. rd->get_pixel = get_pixel32;
  248. break;
  249. case 24:
  250. rd->set_pixel = set_pixel24;
  251. rd->get_pixel = get_pixel24;
  252. break;
  253. case 16:
  254. rd->set_pixel = set_pixel16;
  255. rd->get_pixel = get_pixel16;
  256. break;
  257. default: break;
  258. }
  259. return RT_EOK;
  260. }
  261. void render_clear_display(void)
  262. {
  263. void *fb, *fb_end;
  264. rt_uint32_t color;
  265. rt_size_t color_size;
  266. struct render *rd = &_render;
  267. typeof(rd->set_pixel) set_pixel_handler = rd->set_pixel;
  268. fb = rd->next_buffer();
  269. fb_end = fb + rd->screen_size;
  270. color = rd->background;
  271. color_size = rd->color_size;
  272. while (fb < fb_end)
  273. {
  274. set_pixel_handler(fb, color);
  275. fb += color_size;
  276. }
  277. rd->pan_display();
  278. render_move_cursor(RT_NULL);
  279. }
  280. static void roll_display(void)
  281. {
  282. rt_uint32_t color;
  283. rt_size_t screen_size, flush_size, color_size;
  284. void *old_fb, *fb, *fb_end;
  285. struct render *rd = &_render;
  286. typeof(rd->set_pixel) set_pixel_handler = rd->set_pixel;
  287. color = rd->background;
  288. color_size = rd->color_size;
  289. screen_size = rd->screen_size;
  290. flush_size = screen_size - rd->line_size;
  291. old_fb = rd->last_buffer();
  292. fb = rd->next_buffer();
  293. fb_end = fb + screen_size;
  294. rd->move_buffer(fb, old_fb + rd->line_size, flush_size);
  295. /* The last line */
  296. fb += flush_size;
  297. while (fb < fb_end)
  298. {
  299. set_pixel_handler(fb, color);
  300. fb += color_size;
  301. }
  302. rd->pan_display();
  303. rt_device_control(rd->fbdev, FBIO_WAITFORVSYNC, RT_NULL);
  304. }
  305. static void color_hook_dummy(void *fb, rt_uint32_t *out_color)
  306. {
  307. }
  308. static void color_hook_transform(void *fb, rt_uint32_t *out_color)
  309. {
  310. rt_uint32_t color;
  311. struct render *rd = &_render;
  312. rt_memcpy(&color, out_color, rd->color_size);
  313. if (color == rd->raw_foreground)
  314. {
  315. *out_color = rd->foreground;
  316. }
  317. else if (color == rd->raw_background)
  318. {
  319. *out_color = rd->background;
  320. }
  321. }
  322. void render_set_foreground(struct render_color *foreground)
  323. {
  324. struct render *rd = &_render;
  325. rd->foreground = parse_color(foreground);
  326. if (rd->foreground != rd->raw_foreground)
  327. {
  328. rd->hook_ptr = color_hook_transform;
  329. }
  330. else
  331. {
  332. rd->hook_ptr = color_hook_dummy;
  333. }
  334. }
  335. void render_set_background(struct render_color *background)
  336. {
  337. struct render *rd = &_render;
  338. rd->background = parse_color(background);
  339. if (rd->foreground != rd->raw_foreground)
  340. {
  341. rd->hook_ptr = color_hook_transform;
  342. }
  343. else
  344. {
  345. rd->hook_ptr = color_hook_dummy;
  346. }
  347. }
  348. static void color_hook_invert(void *fb, rt_uint32_t *out_color)
  349. {
  350. struct render *rd = &_render;
  351. *out_color ^= rd->get_pixel(fb) & ~(rd->alpha_mask << rd->alpha_off);
  352. }
  353. static void draw_block(void *block, void (*color_hook)(void *fb, rt_uint32_t *out_color))
  354. {
  355. void *fb;
  356. rt_size_t color_size;
  357. int font_width, font_height, xlate;
  358. struct render *rd = &_render;
  359. typeof(rd->set_pixel) set_pixel_handler = rd->set_pixel;
  360. color_size = rd->color_size;
  361. font_width = rd->psf.width;
  362. font_height = rd->psf.height;
  363. xlate = rd->xlate;
  364. fb = rd->last_buffer();
  365. fb += rd->position.col * rd->font_line_length + rd->position.row * rd->line_size;
  366. for (int y = 0; y < font_height; ++y)
  367. {
  368. for (int x = 0; x < font_width; ++x)
  369. {
  370. rt_uint32_t color = *(rt_uint32_t *)block;
  371. color_hook(fb, &color);
  372. set_pixel_handler(fb, color);
  373. fb += color_size;
  374. block += color_size;
  375. }
  376. fb += xlate;
  377. }
  378. }
  379. static void cursor_leave(void)
  380. {
  381. struct render *rd = &_render;
  382. draw_block(rd->cursor, &color_hook_invert);
  383. }
  384. static void cursor_update(void)
  385. {
  386. struct render *rd = &_render;
  387. draw_block(rd->cursor, &color_hook_invert);
  388. rt_device_control(rd->fbdev, FBIO_WAITFORVSYNC, RT_NULL);
  389. }
  390. void render_select_cursor(enum cursor shape)
  391. {
  392. void *cursor;
  393. rt_size_t color_size;
  394. int font_width, font_height;
  395. rt_uint32_t foreground, background;
  396. struct render *rd = &_render;
  397. typeof(rd->set_pixel) set_pixel_handler = rd->set_pixel;
  398. cursor = rd->cursor;
  399. font_width = rd->psf.width;
  400. font_height = rd->psf.height;
  401. foreground = rd->foreground;
  402. background = rd->background;
  403. color_size = rd->color_size;
  404. switch (shape)
  405. {
  406. case CURSOR_HLINE:
  407. for (int y = 0; y < font_height; ++y)
  408. {
  409. for (int x = 0; x < font_width; ++x)
  410. {
  411. if (y + 1 < font_height)
  412. {
  413. set_pixel_handler(cursor, background);
  414. }
  415. else
  416. {
  417. set_pixel_handler(cursor, foreground);
  418. }
  419. cursor += color_size;
  420. }
  421. }
  422. break;
  423. case CURSOR_VLINE:
  424. for (int i = 0; i < font_height; ++i)
  425. {
  426. set_pixel_handler(cursor, foreground);
  427. cursor += color_size;
  428. for (int x = 1; x < font_width; ++x)
  429. {
  430. set_pixel_handler(cursor, background);
  431. cursor += color_size;
  432. }
  433. }
  434. break;
  435. case CURSOR_BLOCK:
  436. for (int y = 0; y < font_height; ++y)
  437. {
  438. for (int x = 0; x < font_width; ++x)
  439. {
  440. set_pixel_handler(cursor, foreground);
  441. cursor += color_size;
  442. }
  443. }
  444. break;
  445. default:
  446. return;
  447. }
  448. cursor_update();
  449. }
  450. void render_move_cursor(struct render_point *position)
  451. {
  452. struct render *rd = &_render;
  453. if (position)
  454. {
  455. cursor_leave();
  456. if (position->row > rd->end_point.row || position->col > rd->end_point.col)
  457. {
  458. return;
  459. }
  460. rt_memcpy(&rd->position, position, sizeof(rd->position));
  461. }
  462. else
  463. {
  464. rt_memset(&rd->position, 0, sizeof(rd->position));
  465. }
  466. cursor_update();
  467. }
  468. void render_reset_cursor(struct render_point *out_position)
  469. {
  470. struct render *rd = &_render;
  471. cursor_leave();
  472. rd->position.col = rd->start_point.col;
  473. cursor_update();
  474. render_current_cursor(out_position);
  475. }
  476. void render_return_cursor(struct render_point *out_position)
  477. {
  478. struct render *rd = &_render;
  479. cursor_leave();
  480. rd->position.col = rd->start_point.col;
  481. if (rd->position.row >= rd->end_point.row)
  482. {
  483. roll_display();
  484. }
  485. else
  486. {
  487. ++rd->position.row;
  488. }
  489. cursor_update();
  490. render_current_cursor(out_position);
  491. }
  492. void render_current_cursor(struct render_point *out_position)
  493. {
  494. struct render *rd = &_render;
  495. if (out_position)
  496. {
  497. rt_memcpy(out_position, &rd->position, sizeof(rd->position));
  498. }
  499. }
  500. void render_put_char(char ch)
  501. {
  502. struct render *rd = &_render;
  503. draw_block((void *)rd->psf.font_data + ch * rd->font_size, rd->hook_ptr);
  504. ++rd->position.col;
  505. if (rd->position.col > rd->end_point.col)
  506. {
  507. rd->position.col = rd->start_point.col;
  508. if (rd->position.row >= rd->end_point.row)
  509. {
  510. roll_display();
  511. }
  512. else
  513. {
  514. ++rd->position.row;
  515. }
  516. }
  517. cursor_update();
  518. }