gfx.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. /*
  2. * Copyright (c) 2008-2010 Travis Geiselbrecht
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining
  5. * a copy of this software and associated documentation files
  6. * (the "Software"), to deal in the Software without restriction,
  7. * including without limitation the rights to use, copy, modify, merge,
  8. * publish, distribute, sublicense, and/or sell copies of the Software,
  9. * and to permit persons to whom the Software is furnished to do so,
  10. * subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be
  13. * included in all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  18. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  19. * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  20. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  21. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. */
  23. /**
  24. * @defgroup graphics Graphics
  25. *
  26. * @{
  27. */
  28. /**
  29. * @file
  30. * @brief Graphics drawing library
  31. */
  32. #include <debug.h>
  33. #include <string.h>
  34. #include <stdlib.h>
  35. #include <arch/ops.h>
  36. #include <sys/types.h>
  37. #include <lib/gfx.h>
  38. #include <dev/display.h>
  39. #define LOCAL_TRACE 0
  40. static uint16_t ARGB8888_to_RGB565(uint32_t in)
  41. {
  42. uint16_t out;
  43. out = (in >> 3) & 0x1f; // b
  44. out |= ((in >> 10) & 0x3f) << 5; // g
  45. out |= ((in >> 19) & 0x1f) << 11; // r
  46. return out;
  47. }
  48. /**
  49. * @brief Copy a rectangle of pixels from one part of the display to another.
  50. */
  51. void gfx_copyrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2)
  52. {
  53. // trim
  54. if (x >= surface->width)
  55. return;
  56. if (x2 >= surface->width)
  57. return;
  58. if (y >= surface->height)
  59. return;
  60. if (y2 >= surface->height)
  61. return;
  62. if (width == 0 || height == 0)
  63. return;
  64. // clip the width to src or dest
  65. if (x + width > surface->width)
  66. width = surface->width - x;
  67. if (x2 + width > surface->width)
  68. width = surface->width - x2;
  69. // clip the height to src or dest
  70. if (y + height > surface->height)
  71. height = surface->height - y;
  72. if (y2 + height > surface->height)
  73. height = surface->height - y2;
  74. surface->copyrect(surface, x, y, width, height, x2, y2);
  75. }
  76. /**
  77. * @brief Fill a rectangle on the screen with a constant color.
  78. */
  79. void gfx_fillrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color)
  80. {
  81. LTRACEF("surface %p, x %u y %u w %u h %u c %u\n", surface, x, y, width, height, color);
  82. // trim
  83. if (unlikely(x >= surface->width))
  84. return;
  85. if (y >= surface->height)
  86. return;
  87. if (width == 0 || height == 0)
  88. return;
  89. // clip the width
  90. if (x + width > surface->width)
  91. width = surface->width - x;
  92. // clip the height
  93. if (y + height > surface->height)
  94. height = surface->height - y;
  95. surface->fillrect(surface, x, y, width, height, color);
  96. }
  97. /**
  98. * @brief Write a single pixel to the screen.
  99. */
  100. void gfx_putpixel(gfx_surface *surface, uint x, uint y, uint color)
  101. {
  102. if (unlikely(x >= surface->width))
  103. return;
  104. if (y >= surface->height)
  105. return;
  106. surface->putpixel(surface, x, y, color);
  107. }
  108. static void putpixel16(gfx_surface *surface, uint x, uint y, uint color)
  109. {
  110. uint16_t *dest = &((uint16_t *)surface->ptr)[x + y * surface->stride];
  111. // colors come in in ARGB 8888 form, flatten them
  112. *dest = ARGB8888_to_RGB565(color);
  113. }
  114. static void putpixel32(gfx_surface *surface, uint x, uint y, uint color)
  115. {
  116. uint32_t *dest = &((uint32_t *)surface->ptr)[x + y * surface->stride];
  117. *dest = color;
  118. }
  119. static void copyrect16(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2)
  120. {
  121. // copy
  122. const uint16_t *src = &((const uint16_t *)surface->ptr)[x + y * surface->stride];
  123. uint16_t *dest = &((uint16_t *)surface->ptr)[x2 + y2 * surface->stride];
  124. uint stride_diff = surface->stride - width;
  125. if (dest < src) {
  126. uint i, j;
  127. for (i=0; i < height; i++) {
  128. for (j=0; j < width; j++) {
  129. *dest = *src;
  130. dest++;
  131. src++;
  132. }
  133. dest += stride_diff;
  134. src += stride_diff;
  135. }
  136. } else {
  137. // copy backwards
  138. src += height * surface->stride + width;
  139. dest += height * surface->stride + width;
  140. uint i, j;
  141. for (i=0; i < height; i++) {
  142. for (j=0; j < width; j++) {
  143. *dest = *src;
  144. dest--;
  145. src--;
  146. }
  147. dest -= stride_diff;
  148. src -= stride_diff;
  149. }
  150. }
  151. }
  152. static void fillrect16(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color)
  153. {
  154. uint16_t *dest = &((uint16_t *)surface->ptr)[x + y * surface->stride];
  155. uint stride_diff = surface->stride - width;
  156. uint16_t color16 = ARGB8888_to_RGB565(color);
  157. uint i, j;
  158. for (i=0; i < height; i++) {
  159. for (j=0; j < width; j++) {
  160. *dest = color16;
  161. dest++;
  162. }
  163. dest += stride_diff;
  164. }
  165. }
  166. static void copyrect32(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2)
  167. {
  168. // copy
  169. const uint32_t *src = &((const uint32_t *)surface->ptr)[x + y * surface->stride];
  170. uint32_t *dest = &((uint32_t *)surface->ptr)[x2 + y2 * surface->stride];
  171. uint stride_diff = surface->stride - width;
  172. if (dest < src) {
  173. uint i, j;
  174. for (i=0; i < height; i++) {
  175. for (j=0; j < width; j++) {
  176. *dest = *src;
  177. dest++;
  178. src++;
  179. }
  180. dest += stride_diff;
  181. src += stride_diff;
  182. }
  183. } else {
  184. // copy backwards
  185. src += height * surface->stride + width;
  186. dest += height * surface->stride + width;
  187. uint i, j;
  188. for (i=0; i < height; i++) {
  189. for (j=0; j < width; j++) {
  190. *dest = *src;
  191. dest--;
  192. src--;
  193. }
  194. dest -= stride_diff;
  195. src -= stride_diff;
  196. }
  197. }
  198. }
  199. static void fillrect32(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color)
  200. {
  201. uint32_t *dest = &((uint32_t *)surface->ptr)[x + y * surface->stride];
  202. uint stride_diff = surface->stride - width;
  203. uint i, j;
  204. for (i=0; i < height; i++) {
  205. for (j=0; j < width; j++) {
  206. *dest = color;
  207. dest++;
  208. }
  209. dest += stride_diff;
  210. }
  211. }
  212. uint32_t alpha32_add_ignore_destalpha(uint32_t dest, uint32_t src)
  213. {
  214. uint32_t cdest[3];
  215. uint32_t csrc[3];
  216. uint32_t srca;
  217. uint32_t srcainv;
  218. srca = (src >> 24) & 0xff;
  219. if (srca == 0) {
  220. return dest;
  221. } else if (srca == 255) {
  222. return src;
  223. }
  224. srca++;
  225. srcainv = (255 - srca);
  226. cdest[0] = (dest >> 16) & 0xff;
  227. cdest[1] = (dest >> 8) & 0xff;
  228. cdest[2] = (dest >> 0) & 0xff;
  229. csrc[0] = (src >> 16) & 0xff;
  230. csrc[1] = (src >> 8) & 0xff;
  231. csrc[2] = (src >> 0) & 0xff;
  232. // if (srca > 0)
  233. // printf("s %d %d %d d %d %d %d a %d ai %d\n", csrc[0], csrc[1], csrc[2], cdest[0], cdest[1], cdest[2], srca, srcainv);
  234. uint32_t cres[3];
  235. cres[0] = ((csrc[0] * srca) / 256) + ((cdest[0] * srcainv) / 256);
  236. cres[1] = ((csrc[1] * srca) / 256) + ((cdest[1] * srcainv) / 256);
  237. cres[2] = ((csrc[2] * srca) / 256) + ((cdest[2] * srcainv) / 256);
  238. return (srca << 24) | (cres[0] << 16) | (cres[1] << 8) | (cres[2]);
  239. }
  240. /**
  241. * @brief Copy pixels from source to dest.
  242. *
  243. * Currently does not support alpha channel.
  244. */
  245. void gfx_surface_blend(struct gfx_surface *target, struct gfx_surface *source, uint destx, uint desty)
  246. {
  247. DEBUG_ASSERT(target->format == source->format);
  248. LTRACEF("target %p, source %p, destx %u, desty %u\n", target, source, destx, desty);
  249. if (destx >= target->width)
  250. return;
  251. if (desty >= target->height)
  252. return;
  253. uint width = source->width;
  254. if (destx + width > target->width)
  255. width = target->width - destx;
  256. uint height = source->height;
  257. if (desty + height > target->height)
  258. height = target->height - desty;
  259. // XXX total hack to deal with various blends
  260. if (source->format == GFX_FORMAT_RGB_565 && target->format == GFX_FORMAT_RGB_565) {
  261. // 16 bit to 16 bit
  262. const uint16_t *src = (const uint16_t *)source->ptr;
  263. uint16_t *dest = &((uint16_t *)target->ptr)[destx + desty * target->stride];
  264. uint dest_stride_diff = target->stride - width;
  265. uint source_stride_diff = source->stride - width;
  266. LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff);
  267. uint i, j;
  268. for (i=0; i < height; i++) {
  269. for (j=0; j < width; j++) {
  270. *dest = *src;
  271. dest++;
  272. src++;
  273. }
  274. dest += dest_stride_diff;
  275. src += source_stride_diff;
  276. }
  277. } else if (source->format == GFX_FORMAT_ARGB_8888 && target->format == GFX_FORMAT_ARGB_8888) {
  278. // both are 32 bit modes, both alpha
  279. const uint32_t *src = (const uint32_t *)source->ptr;
  280. uint32_t *dest = &((uint32_t *)target->ptr)[destx + desty * target->stride];
  281. uint dest_stride_diff = target->stride - width;
  282. uint source_stride_diff = source->stride - width;
  283. LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff);
  284. uint i, j;
  285. for (i=0; i < height; i++) {
  286. for (j=0; j < width; j++) {
  287. // XXX ignores destination alpha
  288. *dest = alpha32_add_ignore_destalpha(*dest, *src);
  289. dest++;
  290. src++;
  291. }
  292. dest += dest_stride_diff;
  293. src += source_stride_diff;
  294. }
  295. } else if (source->format == GFX_FORMAT_RGB_x888 && target->format == GFX_FORMAT_RGB_x888) {
  296. // both are 32 bit modes, no alpha
  297. const uint32_t *src = (const uint32_t *)source->ptr;
  298. uint32_t *dest = &((uint32_t *)target->ptr)[destx + desty * target->stride];
  299. uint dest_stride_diff = target->stride - width;
  300. uint source_stride_diff = source->stride - width;
  301. LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff);
  302. uint i, j;
  303. for (i=0; i < height; i++) {
  304. for (j=0; j < width; j++) {
  305. *dest = *src;
  306. dest++;
  307. src++;
  308. }
  309. dest += dest_stride_diff;
  310. src += source_stride_diff;
  311. }
  312. } else {
  313. panic("gfx_surface_blend: unimplemented colorspace combination (source %d target %d)\n", source->format, target->format);
  314. }
  315. }
  316. /**
  317. * @brief Ensure all graphics rendering is sent to display
  318. */
  319. void gfx_flush(gfx_surface *surface)
  320. {
  321. arch_clean_cache_range((addr_t)surface->ptr, surface->len);
  322. if (surface->flush)
  323. surface->flush(0, surface->height-1);
  324. }
  325. /**
  326. * @brief Ensure that a sub-region of the display is up to date.
  327. */
  328. void gfx_flush_rows(struct gfx_surface *surface, uint start, uint end)
  329. {
  330. if (start > end) {
  331. uint temp = start;
  332. start = end;
  333. end = temp;
  334. }
  335. if (start >= surface->height)
  336. return;
  337. if (end >= surface->height)
  338. end = surface->height - 1;
  339. arch_clean_cache_range((addr_t)surface->ptr + start * surface->stride * surface->pixelsize, (end - start + 1) * surface->stride * surface->pixelsize);
  340. if (surface->flush)
  341. surface->flush(start, end);
  342. }
  343. /**
  344. * @brief Create a new graphics surface object
  345. */
  346. gfx_surface *gfx_create_surface(void *ptr, uint width, uint height, uint stride, gfx_format format)
  347. {
  348. DEBUG_ASSERT(width > 0);
  349. DEBUG_ASSERT(height > 0);
  350. DEBUG_ASSERT(stride >= width);
  351. DEBUG_ASSERT(format < GFX_FORMAT_MAX);
  352. gfx_surface *surface = malloc(sizeof(gfx_surface));
  353. surface->free_on_destroy = false;
  354. surface->format = format;
  355. surface->width = width;
  356. surface->height = height;
  357. surface->stride = stride;
  358. surface->alpha = MAX_ALPHA;
  359. // set up some function pointers
  360. switch (format) {
  361. case GFX_FORMAT_RGB_565:
  362. surface->copyrect = &copyrect16;
  363. surface->fillrect = &fillrect16;
  364. surface->putpixel = &putpixel16;
  365. surface->pixelsize = 2;
  366. surface->len = surface->height * surface->stride * surface->pixelsize;
  367. break;
  368. case GFX_FORMAT_RGB_x888:
  369. case GFX_FORMAT_ARGB_8888:
  370. surface->copyrect = &copyrect32;
  371. surface->fillrect = &fillrect32;
  372. surface->putpixel = &putpixel32;
  373. surface->pixelsize = 4;
  374. surface->len = surface->height * surface->stride * surface->pixelsize;
  375. break;
  376. default:
  377. dprintf(INFO, "invalid graphics format\n");
  378. DEBUG_ASSERT(0);
  379. free(surface);
  380. return NULL;
  381. }
  382. if (ptr == NULL) {
  383. // allocate a buffer
  384. ptr = malloc(surface->len);
  385. DEBUG_ASSERT(ptr);
  386. surface->free_on_destroy = true;
  387. }
  388. surface->ptr = ptr;
  389. return surface;
  390. }
  391. /**
  392. * @brief Create a new graphics surface object from a display
  393. */
  394. gfx_surface *gfx_create_surface_from_display(struct display_info *info)
  395. {
  396. gfx_surface* surface;
  397. surface = gfx_create_surface(info->framebuffer, info->width, info->height, info->stride, info->format);
  398. surface->flush = info->flush;
  399. return surface;
  400. }
  401. /**
  402. * @brief Destroy a graphics surface and free all resources allocated to it.
  403. *
  404. * @param surface Surface to destroy. This pointer is no longer valid after
  405. * this call.
  406. */
  407. void gfx_surface_destroy(struct gfx_surface *surface)
  408. {
  409. if (surface->free_on_destroy)
  410. free(surface->ptr);
  411. free(surface);
  412. }
  413. /**
  414. * @brief Write a test pattern to the default display.
  415. */
  416. void gfx_draw_pattern(void)
  417. {
  418. struct display_info info;
  419. display_get_info(&info);
  420. gfx_surface *surface = gfx_create_surface_from_display(&info);
  421. uint x, y;
  422. for (y = 0; y < surface->height; y++) {
  423. for (x = 0; x < surface->width; x++) {
  424. uint scaledx;
  425. uint scaledy;
  426. scaledx = x * 256 / surface->width;
  427. scaledy = y * 256 / surface->height;
  428. gfx_putpixel(surface, x, y, (scaledx * scaledy) << 16 | (scaledx >> 1) << 8 | scaledy >> 1);
  429. }
  430. }
  431. if (surface->flush)
  432. surface->flush(0, surface->height-1);
  433. gfx_surface_destroy(surface);
  434. }
  435. /**
  436. * @brief Fill default display with white
  437. */
  438. void gfx_draw_pattern_white(void)
  439. {
  440. struct display_info info;
  441. display_get_info(&info);
  442. gfx_surface *surface = gfx_create_surface_from_display(&info);
  443. uint x, y;
  444. for (y = 0; y < surface->height; y++) {
  445. for (x = 0; x < surface->width; x++) {
  446. gfx_putpixel(surface, x, y, 0xFFFFFF);
  447. }
  448. }
  449. if (surface->flush)
  450. surface->flush(0, surface->height-1);
  451. gfx_surface_destroy(surface);
  452. }
  453. #if defined(WITH_LIB_CONSOLE)
  454. #if DEBUGLEVEL > 1
  455. #include <lib/console.h>
  456. static int cmd_gfx(int argc, const cmd_args *argv);
  457. STATIC_COMMAND_START
  458. STATIC_COMMAND("gfx", "gfx commands", &cmd_gfx)
  459. STATIC_COMMAND_END(gfx);
  460. static int gfx_draw_rgb_bars(gfx_surface *surface)
  461. {
  462. uint x, y;
  463. int step32 = surface->height*100 / 32;
  464. int step64 = surface->height*100 / 64;
  465. int color;
  466. for (y = 0; y < surface->height; y++) {
  467. //R
  468. for (x = 0; x < surface->width/3; x++) {
  469. color = y*100 / step32;
  470. gfx_putpixel(surface, x, y, color << 16);
  471. }
  472. //G
  473. for (;x < 2*(surface->width/3); x++) {
  474. color = y*100 / step64;
  475. gfx_putpixel(surface, x, y, color << 8);
  476. }
  477. //B
  478. for (;x < surface->width; x++) {
  479. color = y*100 / step32;
  480. gfx_putpixel(surface, x, y, color);
  481. }
  482. }
  483. return 0;
  484. }
  485. static int cmd_gfx(int argc, const cmd_args *argv)
  486. {
  487. if (argc < 2) {
  488. printf("not enough arguments:\n");
  489. usage:
  490. printf("%s rgb_bars : Fill frame buffer with rgb bars\n", argv[0].str);
  491. printf("%s fill r g b : Fill frame buffer with RGB565 value and force update\n", argv[0].str);
  492. return -1;
  493. }
  494. struct display_info info;
  495. display_get_info(&info);
  496. gfx_surface *surface = gfx_create_surface_from_display(&info);
  497. if (!strcmp(argv[1].str, "rgb_bars"))
  498. {
  499. gfx_draw_rgb_bars(surface);
  500. }
  501. else if (!strcmp(argv[1].str, "fill"))
  502. {
  503. uint x, y;
  504. for (y = 0; y < surface->height; y++)
  505. {
  506. for (x = 0; x < surface->width; x++)
  507. {
  508. /* write pixel to frame buffer */
  509. gfx_putpixel(surface, x, y, (argv[2].i << 16) | (argv[3].i << 8) | argv[4].i);
  510. }
  511. }
  512. }
  513. if (surface->flush)
  514. surface->flush(0, surface->height-1);
  515. gfx_surface_destroy(surface);
  516. return 0;
  517. }
  518. #endif
  519. #endif