1 /*
2 * Copyright (c) 2008-2010, 2015 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8
9 /**
10 * @defgroup graphics Graphics
11 *
12 * @{
13 */
14
15 /**
16 * @file
17 * @brief Graphics drawing library
18 */
19
20 #include <lk/debug.h>
21 #include <lk/trace.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <arch/ops.h>
26 #include <sys/types.h>
27 #include <lib/gfx.h>
28 #include <dev/display.h>
29 #include <lk/console_cmd.h>
30
31 #define LOCAL_TRACE 0
32
33 // Convert a 32bit ARGB image to its respective gamma corrected grayscale value.
ARGB8888_to_Luma(uint32_t in)34 static uint32_t ARGB8888_to_Luma(uint32_t in) {
35 uint8_t out;
36
37 uint32_t blue = (in & 0xFF) * 74;
38 uint32_t green = ((in >> 8) & 0xFF) * 732;
39 uint32_t red = ((in >> 16) & 0xFF) * 218;
40
41 uint32_t intensity = red + blue + green;
42
43 out = (intensity >> 10) & 0xFF;
44
45 return out;
46 }
47
ARGB8888_to_RGB565(uint32_t in)48 static uint32_t ARGB8888_to_RGB565(uint32_t in) {
49 uint16_t out;
50
51 out = (in >> 3) & 0x1f; // b
52 out |= ((in >> 10) & 0x3f) << 5; // g
53 out |= ((in >> 19) & 0x1f) << 11; // r
54
55 return out;
56 }
57
ARGB8888_to_RGB332(uint32_t in)58 static uint32_t ARGB8888_to_RGB332(uint32_t in) {
59 uint8_t out = 0;
60
61 out = (in >> 6) & 0x3; // b
62 out |= ((in >> 13) & 0x7) << 2; // g
63 out |= ((in >> 21) & 0x7) << 5; // r
64
65 return out;
66 }
67
ARGB8888_to_RGB2220(uint32_t in)68 static uint32_t ARGB8888_to_RGB2220(uint32_t in) {
69 uint8_t out = 0;
70
71 out = ((in >> 6) & 0x3) << 2;
72 out |= ((in >> 14) & 0x3) << 4;
73 out |= ((in >> 22) & 0x3) << 6;
74
75 return out;
76 }
77
78 /**
79 * @brief Copy a rectangle of pixels from one part of the display to another.
80 */
gfx_copyrect(gfx_surface * surface,uint x,uint y,uint width,uint height,uint x2,uint y2)81 void gfx_copyrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2) {
82 // trim
83 if (x >= surface->width)
84 return;
85 if (x2 >= surface->width)
86 return;
87 if (y >= surface->height)
88 return;
89 if (y2 >= surface->height)
90 return;
91 if (width == 0 || height == 0)
92 return;
93
94 // clip the width to src or dest
95 if (x + width > surface->width)
96 width = surface->width - x;
97 if (x2 + width > surface->width)
98 width = surface->width - x2;
99
100 // clip the height to src or dest
101 if (y + height > surface->height)
102 height = surface->height - y;
103 if (y2 + height > surface->height)
104 height = surface->height - y2;
105
106 surface->copyrect(surface, x, y, width, height, x2, y2);
107 }
108
109 /**
110 * @brief Fill a rectangle on the screen with a constant color.
111 */
gfx_fillrect(gfx_surface * surface,uint x,uint y,uint width,uint height,uint color)112 void gfx_fillrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color) {
113 LTRACEF("surface %p, x %u y %u w %u h %u c %u\n", surface, x, y, width, height, color);
114 // trim
115 if (unlikely(x >= surface->width))
116 return;
117 if (y >= surface->height)
118 return;
119 if (width == 0 || height == 0)
120 return;
121
122 // clip the width
123 if (x + width > surface->width)
124 width = surface->width - x;
125
126 // clip the height
127 if (y + height > surface->height)
128 height = surface->height - y;
129
130 surface->fillrect(surface, x, y, width, height, color);
131 }
132
133 /**
134 * @brief Write a single pixel to the screen.
135 */
gfx_putpixel(gfx_surface * surface,uint x,uint y,uint color)136 void gfx_putpixel(gfx_surface *surface, uint x, uint y, uint color) {
137 if (unlikely(x >= surface->width))
138 return;
139 if (y >= surface->height)
140 return;
141
142 surface->putpixel(surface, x, y, color);
143 }
144
putpixel16(gfx_surface * surface,uint x,uint y,uint color)145 static void putpixel16(gfx_surface *surface, uint x, uint y, uint color) {
146 uint16_t *dest = &((uint16_t *)surface->ptr)[x + y * surface->stride];
147
148 // colors come in in ARGB 8888 form, flatten them
149 *dest = (uint16_t)(surface->translate_color(color));
150 }
151
putpixel32(gfx_surface * surface,uint x,uint y,uint color)152 static void putpixel32(gfx_surface *surface, uint x, uint y, uint color) {
153 uint32_t *dest = &((uint32_t *)surface->ptr)[x + y * surface->stride];
154
155 *dest = color;
156 }
157
putpixel8(gfx_surface * surface,uint x,uint y,uint color)158 static void putpixel8(gfx_surface *surface, uint x, uint y, uint color) {
159 uint8_t *dest = &((uint8_t *)surface->ptr)[x + y * surface->stride];
160
161 // colors come in in ARGB 8888 form, flatten them
162 *dest = (uint8_t)(surface->translate_color(color));
163 }
164
copyrect8(gfx_surface * surface,uint x,uint y,uint width,uint height,uint x2,uint y2)165 static void copyrect8(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2) {
166 // copy
167 const uint8_t *src = &((const uint8_t *)surface->ptr)[x + y * surface->stride];
168 uint8_t *dest = &((uint8_t *)surface->ptr)[x2 + y2 * surface->stride];
169 uint stride_diff = surface->stride - width;
170
171 if (dest < src) {
172 uint i, j;
173 for (i=0; i < height; i++) {
174 for (j=0; j < width; j++) {
175 *dest = *src;
176 dest++;
177 src++;
178 }
179 dest += stride_diff;
180 src += stride_diff;
181 }
182 } else {
183 // copy backwards
184 src += height * surface->stride + width;
185 dest += height * surface->stride + width;
186
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
fillrect8(gfx_surface * surface,uint x,uint y,uint width,uint height,uint color)200 static void fillrect8(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color) {
201 uint8_t *dest = &((uint8_t *)surface->ptr)[x + y * surface->stride];
202 uint stride_diff = surface->stride - width;
203
204 uint8_t color8 = (uint8_t)(surface->translate_color(color));
205
206 uint i, j;
207 for (i=0; i < height; i++) {
208 for (j=0; j < width; j++) {
209 *dest = color8;
210 dest++;
211 }
212 dest += stride_diff;
213 }
214 }
215
copyrect16(gfx_surface * surface,uint x,uint y,uint width,uint height,uint x2,uint y2)216 static void copyrect16(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2) {
217 // copy
218 const uint16_t *src = &((const uint16_t *)surface->ptr)[x + y * surface->stride];
219 uint16_t *dest = &((uint16_t *)surface->ptr)[x2 + y2 * surface->stride];
220 uint stride_diff = surface->stride - width;
221
222 if (dest < src) {
223 uint i, j;
224 for (i=0; i < height; i++) {
225 for (j=0; j < width; j++) {
226 *dest = *src;
227 dest++;
228 src++;
229 }
230 dest += stride_diff;
231 src += stride_diff;
232 }
233 } else {
234 // copy backwards
235 src += height * surface->stride + width;
236 dest += height * surface->stride + width;
237
238 uint i, j;
239 for (i=0; i < height; i++) {
240 for (j=0; j < width; j++) {
241 *dest = *src;
242 dest--;
243 src--;
244 }
245 dest -= stride_diff;
246 src -= stride_diff;
247 }
248 }
249 }
250
fillrect16(gfx_surface * surface,uint x,uint y,uint width,uint height,uint color)251 static void fillrect16(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color) {
252 uint16_t *dest = &((uint16_t *)surface->ptr)[x + y * surface->stride];
253 uint stride_diff = surface->stride - width;
254
255 uint16_t color16 = (uint16_t)(surface->translate_color(color));
256
257 uint i, j;
258 for (i=0; i < height; i++) {
259 for (j=0; j < width; j++) {
260 *dest = color16;
261 dest++;
262 }
263 dest += stride_diff;
264 }
265 }
266
copyrect32(gfx_surface * surface,uint x,uint y,uint width,uint height,uint x2,uint y2)267 static void copyrect32(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2) {
268 // copy
269 const uint32_t *src = &((const uint32_t *)surface->ptr)[x + y * surface->stride];
270 uint32_t *dest = &((uint32_t *)surface->ptr)[x2 + y2 * surface->stride];
271 uint stride_diff = surface->stride - width;
272
273 if (dest < src) {
274 uint i, j;
275 for (i=0; i < height; i++) {
276 for (j=0; j < width; j++) {
277 *dest = *src;
278 dest++;
279 src++;
280 }
281 dest += stride_diff;
282 src += stride_diff;
283 }
284 } else {
285 // copy backwards
286 src += height * surface->stride + width;
287 dest += height * surface->stride + width;
288
289 uint i, j;
290 for (i=0; i < height; i++) {
291 for (j=0; j < width; j++) {
292 *dest = *src;
293 dest--;
294 src--;
295 }
296 dest -= stride_diff;
297 src -= stride_diff;
298 }
299 }
300 }
301
fillrect32(gfx_surface * surface,uint x,uint y,uint width,uint height,uint color)302 static void fillrect32(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color) {
303 uint32_t *dest = &((uint32_t *)surface->ptr)[x + y * surface->stride];
304 uint stride_diff = surface->stride - width;
305
306 uint i, j;
307 for (i=0; i < height; i++) {
308 for (j=0; j < width; j++) {
309 *dest = color;
310 dest++;
311 }
312 dest += stride_diff;
313 }
314 }
315
gfx_line(gfx_surface * surface,uint x1,uint y1,uint x2,uint y2,uint color)316 void gfx_line(gfx_surface *surface, uint x1, uint y1, uint x2, uint y2, uint color) {
317 if (unlikely(x1 >= surface->width))
318 return;
319 if (unlikely(x2 >= surface->width))
320 return;
321
322 if (y1 >= surface->height)
323 return;
324 if (y2 >= surface->height)
325 return;
326
327 int dx = x2 - x1;
328 int dy = y2 - y1;
329
330 int sdx = (0 < dx) - (dx < 0);
331 int sdy = (0 < dy) - (dy < 0);
332
333 uint dxabs = (dx > 0) ? dx : -dx;
334 uint dyabs = (dy > 0) ? dy : -dy;
335
336 uint x = dyabs >> 1;
337 uint y = dxabs >> 1;
338
339 uint px = x1;
340 uint py = y1;
341
342 if (dxabs >= dyabs) {
343 // mostly horizontal line.
344 for (uint i = 0; i < dxabs; i++) {
345 y += dyabs;
346 if (y >= dxabs) {
347 y -= dxabs;
348 py += sdy;
349 }
350 px += sdx;
351 surface->putpixel(surface, px, py, color);
352 }
353 } else {
354 // mostly vertical line.
355 for (uint i = 0; i < dyabs; i++) {
356 x += dxabs;
357 if (x >= dyabs) {
358 x -= dyabs;
359 px += sdx;
360 }
361 py += sdy;
362 surface->putpixel(surface, px, py, color);
363 }
364 }
365 }
366
alpha32_add_ignore_destalpha(uint32_t dest,uint32_t src)367 static uint32_t alpha32_add_ignore_destalpha(uint32_t dest, uint32_t src) {
368 uint32_t cdest[3];
369 uint32_t csrc[3];
370
371 uint32_t srca;
372 uint32_t srcainv;
373
374 srca = (src >> 24) & 0xff;
375 if (srca == 0) {
376 return dest;
377 } else if (srca == 255) {
378 return src;
379 }
380 srca++;
381 srcainv = (255 - srca);
382
383 cdest[0] = (dest >> 16) & 0xff;
384 cdest[1] = (dest >> 8) & 0xff;
385 cdest[2] = (dest >> 0) & 0xff;
386
387 csrc[0] = (src >> 16) & 0xff;
388 csrc[1] = (src >> 8) & 0xff;
389 csrc[2] = (src >> 0) & 0xff;
390
391 // if (srca > 0)
392 // 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);
393
394 uint32_t cres[3];
395
396 cres[0] = ((csrc[0] * srca) / 256) + ((cdest[0] * srcainv) / 256);
397 cres[1] = ((csrc[1] * srca) / 256) + ((cdest[1] * srcainv) / 256);
398 cres[2] = ((csrc[2] * srca) / 256) + ((cdest[2] * srcainv) / 256);
399
400 return (srca << 24) | (cres[0] << 16) | (cres[1] << 8) | (cres[2]);
401 }
402
403 /**
404 * @brief Copy pixels from source to dest.
405 *
406 * Currently does not support alpha channel.
407 */
gfx_surface_blend(struct gfx_surface * target,struct gfx_surface * source,uint destx,uint desty)408 void gfx_surface_blend(struct gfx_surface *target, struct gfx_surface *source, uint destx, uint desty) {
409 DEBUG_ASSERT(target->format == source->format);
410
411 LTRACEF("target %p, source %p, destx %u, desty %u\n", target, source, destx, desty);
412
413 if (destx >= target->width)
414 return;
415 if (desty >= target->height)
416 return;
417
418 uint width = source->width;
419 if (destx + width > target->width)
420 width = target->width - destx;
421
422 uint height = source->height;
423 if (desty + height > target->height)
424 height = target->height - desty;
425
426 // XXX total hack to deal with various blends
427 if (source->format == GFX_FORMAT_RGB_565 && target->format == GFX_FORMAT_RGB_565) {
428 // 16 bit to 16 bit
429 const uint16_t *src = (const uint16_t *)source->ptr;
430 uint16_t *dest = &((uint16_t *)target->ptr)[destx + desty * target->stride];
431 uint dest_stride_diff = target->stride - width;
432 uint source_stride_diff = source->stride - width;
433
434 LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff);
435
436 uint i, j;
437 for (i=0; i < height; i++) {
438 for (j=0; j < width; j++) {
439 *dest = *src;
440 dest++;
441 src++;
442 }
443 dest += dest_stride_diff;
444 src += source_stride_diff;
445 }
446 } else if (source->format == GFX_FORMAT_ARGB_8888 && target->format == GFX_FORMAT_ARGB_8888) {
447 // both are 32 bit modes, both alpha
448 const uint32_t *src = (const uint32_t *)source->ptr;
449 uint32_t *dest = &((uint32_t *)target->ptr)[destx + desty * target->stride];
450 uint dest_stride_diff = target->stride - width;
451 uint source_stride_diff = source->stride - width;
452
453 LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff);
454
455 uint i, j;
456 for (i=0; i < height; i++) {
457 for (j=0; j < width; j++) {
458 // XXX ignores destination alpha
459 *dest = alpha32_add_ignore_destalpha(*dest, *src);
460 dest++;
461 src++;
462 }
463 dest += dest_stride_diff;
464 src += source_stride_diff;
465 }
466 } else if (source->format == GFX_FORMAT_RGB_x888 && target->format == GFX_FORMAT_RGB_x888) {
467 // both are 32 bit modes, no alpha
468 const uint32_t *src = (const uint32_t *)source->ptr;
469 uint32_t *dest = &((uint32_t *)target->ptr)[destx + desty * target->stride];
470 uint dest_stride_diff = target->stride - width;
471 uint source_stride_diff = source->stride - width;
472
473 LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff);
474
475 uint i, j;
476 for (i=0; i < height; i++) {
477 for (j=0; j < width; j++) {
478 *dest = *src;
479 dest++;
480 src++;
481 }
482 dest += dest_stride_diff;
483 src += source_stride_diff;
484 }
485 } else if (source->format == GFX_FORMAT_MONO && target->format == GFX_FORMAT_MONO) {
486 // both are 8 bit modes, no alpha
487 const uint8_t *src = (const uint8_t *)source->ptr;
488 uint8_t *dest = &((uint8_t *)target->ptr)[destx + desty * target->stride];
489 uint dest_stride_diff = target->stride - width;
490 uint source_stride_diff = source->stride - width;
491
492 LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff);
493
494 uint i, j;
495 for (i=0; i < height; i++) {
496 for (j=0; j < width; j++) {
497 *dest = *src;
498 dest++;
499 src++;
500 }
501 dest += dest_stride_diff;
502 src += source_stride_diff;
503 }
504 } else {
505 panic("gfx_surface_blend: unimplemented colorspace combination (source %d target %d)\n", source->format, target->format);
506 }
507 }
508
509 /**
510 * @brief Ensure all graphics rendering is sent to display
511 */
gfx_flush(gfx_surface * surface)512 void gfx_flush(gfx_surface *surface) {
513 arch_clean_cache_range((addr_t)surface->ptr, surface->len);
514
515 if (surface->flush)
516 surface->flush(0, surface->height-1);
517 }
518
519 /**
520 * @brief Ensure that a sub-region of the display is up to date.
521 */
gfx_flush_rows(struct gfx_surface * surface,uint start,uint end)522 void gfx_flush_rows(struct gfx_surface *surface, uint start, uint end) {
523 if (start > end) {
524 uint temp = start;
525 start = end;
526 end = temp;
527 }
528
529 if (start >= surface->height)
530 return;
531 if (end >= surface->height)
532 end = surface->height - 1;
533
534 uint32_t runlen = surface->stride * surface->pixelsize;
535 arch_clean_cache_range((addr_t)surface->ptr + start * runlen, (end - start + 1) * runlen);
536
537 if (surface->flush)
538 surface->flush(start, end);
539 }
540
541
542 /**
543 * @brief Create a new graphics surface object
544 */
gfx_create_surface(void * ptr,uint width,uint height,uint stride,gfx_format format)545 gfx_surface *gfx_create_surface(void *ptr, uint width, uint height, uint stride, gfx_format format) {
546 DEBUG_ASSERT(width > 0);
547 DEBUG_ASSERT(height > 0);
548 DEBUG_ASSERT(stride >= width);
549 DEBUG_ASSERT(format < GFX_FORMAT_MAX);
550
551 gfx_surface *surface = malloc(sizeof(gfx_surface));
552
553 surface->free_on_destroy = false;
554 surface->format = format;
555 surface->width = width;
556 surface->height = height;
557 surface->stride = stride;
558 surface->alpha = MAX_ALPHA;
559
560 // set up some function pointers
561 switch (format) {
562 case GFX_FORMAT_RGB_565:
563 surface->translate_color = &ARGB8888_to_RGB565;
564 surface->copyrect = ©rect16;
565 surface->fillrect = &fillrect16;
566 surface->putpixel = &putpixel16;
567 surface->pixelsize = 2;
568 surface->len = (surface->height * surface->stride * surface->pixelsize);
569 break;
570 case GFX_FORMAT_RGB_x888:
571 case GFX_FORMAT_ARGB_8888:
572 surface->translate_color = NULL;
573 surface->copyrect = ©rect32;
574 surface->fillrect = &fillrect32;
575 surface->putpixel = &putpixel32;
576 surface->pixelsize = 4;
577 surface->len = (surface->height * surface->stride * surface->pixelsize);
578 break;
579 case GFX_FORMAT_MONO:
580 surface->translate_color = &ARGB8888_to_Luma;
581 surface->copyrect = ©rect8;
582 surface->fillrect = &fillrect8;
583 surface->putpixel = &putpixel8;
584 surface->pixelsize = 1;
585 surface->len = (surface->height * surface->stride * surface->pixelsize);
586 break;
587 case GFX_FORMAT_RGB_332:
588 surface->translate_color = &ARGB8888_to_RGB332;
589 surface->copyrect = ©rect8;
590 surface->fillrect = &fillrect8;
591 surface->putpixel = &putpixel8;
592 surface->pixelsize = 1;
593 surface->len = (surface->height * surface->stride * surface->pixelsize);
594 break;
595 case GFX_FORMAT_RGB_2220:
596 surface->translate_color = &ARGB8888_to_RGB2220;
597 surface->copyrect = ©rect8;
598 surface->fillrect = &fillrect8;
599 surface->putpixel = &putpixel8;
600 surface->pixelsize = 1;
601 surface->len = (surface->height * surface->stride * surface->pixelsize);
602 break;
603 default:
604 dprintf(INFO, "invalid graphics format\n");
605 DEBUG_ASSERT(0);
606 free(surface);
607 return NULL;
608 }
609
610 if (ptr == NULL) {
611 // allocate a buffer
612 ptr = malloc(surface->len);
613 DEBUG_ASSERT(ptr);
614 surface->free_on_destroy = true;
615 }
616 surface->ptr = ptr;
617
618 return surface;
619 }
620
621 /**
622 * @brief Create a new graphics surface object from a display
623 */
gfx_create_surface_from_display(struct display_framebuffer * fb)624 gfx_surface *gfx_create_surface_from_display(struct display_framebuffer *fb) {
625 DEBUG_ASSERT(fb);
626 gfx_surface *surface;
627 gfx_format format;
628 switch (fb->image.format) {
629 case IMAGE_FORMAT_RGB_565:
630 format = GFX_FORMAT_RGB_565;
631 break;
632 case IMAGE_FORMAT_RGB_332:
633 format = GFX_FORMAT_RGB_332;
634 break;
635 case IMAGE_FORMAT_RGB_2220:
636 format = GFX_FORMAT_RGB_2220;
637 break;
638 case IMAGE_FORMAT_ARGB_8888:
639 format = GFX_FORMAT_ARGB_8888;
640 break;
641 case IMAGE_FORMAT_RGB_x888:
642 format = GFX_FORMAT_RGB_x888;
643 break;
644 case IMAGE_FORMAT_MONO_8:
645 format = GFX_FORMAT_MONO;
646 break;
647 default:
648 dprintf(INFO, "invalid graphics format)");
649 DEBUG_ASSERT(0);
650 return NULL;
651 }
652
653 surface = gfx_create_surface(fb->image.pixels, fb->image.width, fb->image.height, fb->image.stride, format);
654
655 surface->flush = fb->flush;
656
657 return surface;
658 }
659
660 /**
661 * @brief Destroy a graphics surface and free all resources allocated to it.
662 *
663 * @param surface Surface to destroy. This pointer is no longer valid after
664 * this call.
665 */
gfx_surface_destroy(struct gfx_surface * surface)666 void gfx_surface_destroy(struct gfx_surface *surface) {
667 if (surface->free_on_destroy)
668 free(surface->ptr);
669 free(surface);
670 }
671
672 /**
673 * @brief Write a test pattern to the default display.
674 */
gfx_draw_pattern(void)675 void gfx_draw_pattern(void) {
676 struct display_framebuffer fb;
677 if (display_get_framebuffer(&fb) < 0)
678 return;
679
680 gfx_surface *surface = gfx_create_surface_from_display(&fb);
681
682 uint x, y;
683 for (y = 0; y < surface->height; y++) {
684 for (x = 0; x < surface->width; x++) {
685 uint scaledx;
686 uint scaledy;
687
688 scaledx = x * 256 / surface->width;
689 scaledy = y * 256 / surface->height;
690
691 gfx_putpixel(surface, x, y, (0xff << 24) | (scaledx * scaledy) << 16 | (scaledx >> 1) << 8 | scaledy >> 1);
692 }
693 }
694
695 gfx_flush(surface);
696
697 gfx_surface_destroy(surface);
698 }
699
700 /**
701 * @brief Fill default display with white
702 */
gfx_draw_pattern_white(void)703 void gfx_draw_pattern_white(void) {
704 struct display_framebuffer fb;
705 if (display_get_framebuffer(&fb) < 0)
706 return;
707
708 gfx_surface *surface = gfx_create_surface_from_display(&fb);
709
710 uint x, y;
711 for (y = 0; y < surface->height; y++) {
712 for (x = 0; x < surface->width; x++) {
713 gfx_putpixel(surface, x, y, 0xFFFFFFFF);
714 }
715 }
716
717 gfx_flush(surface);
718
719 gfx_surface_destroy(surface);
720 }
721
722 #if LK_DEBUGLEVEL > 1
723
724 static int cmd_gfx(int argc, const console_cmd_args *argv);
725
726 STATIC_COMMAND_START
727 STATIC_COMMAND("gfx", "gfx commands", &cmd_gfx)
728 STATIC_COMMAND_END(gfx);
729
gfx_draw_mandelbrot(gfx_surface * surface)730 static int gfx_draw_mandelbrot(gfx_surface *surface) {
731 float a,b, dx, dy, mag, c, ci;
732 uint32_t color,iter,x,y;
733
734 dx= 3.0f/((float)surface->width);
735 dy= 3.0f/((float)surface->height);
736 c = -2.0;
737 ci = -1.5;
738 for (y = 0; y < surface->height; y++) {
739 c = -2.0;
740 for (x = 0; x < surface->width; x++) {
741 a=0;
742 b=0;
743 mag=0;
744 iter = 0;
745 while ((mag < 4.0f) && (iter < 200) ) {
746 float a1;
747 a1 = a*a - b*b + c;
748 b = 2.0f * a * b + ci;
749 a=a1;
750 mag = a*a + b*b;
751 iter++;
752 }
753 c = c + dx;
754 if (iter == 200) {
755 color = 0;
756 } else {
757 color = 0x231AF9 * iter;
758 }
759 gfx_putpixel(surface, x, y, 0xff << 24 | color);
760 }
761 if (y > 0) {
762 gfx_flush_rows(surface, y - 1, y);
763 }
764 ci = ci + dy;
765 }
766
767 return 0;
768 }
769
770
gfx_draw_rgb_bars(gfx_surface * surface)771 static int gfx_draw_rgb_bars(gfx_surface *surface) {
772 uint x, y;
773
774 uint step = surface->height*100 / 256;
775 uint color;
776
777 for (y = 0; y < surface->height; y++) {
778 //R
779 for (x = 0; x < surface->width/3; x++) {
780 color = y*100 / step;
781 gfx_putpixel(surface, x, y, 0xff << 24 | color << 16);
782 }
783 //G
784 for (; x < 2*(surface->width/3); x++) {
785 color = y*100 / step;
786 gfx_putpixel(surface, x, y, 0xff << 24 | color << 8);
787 }
788 //B
789 for (; x < surface->width; x++) {
790 color = y*100 / step;
791 gfx_putpixel(surface, x, y, 0xff << 24 | color);
792 }
793 }
794
795 return 0;
796 }
797
cmd_gfx(int argc,const console_cmd_args * argv)798 static int cmd_gfx(int argc, const console_cmd_args *argv) {
799 if (argc < 2) {
800 printf("not enough arguments:\n");
801 usage:
802 printf("%s display_info : output information bout the current display\n", argv[0].str);
803 printf("%s rgb_bars : Fill frame buffer with rgb bars\n", argv[0].str);
804 printf("%s test_pattern : Fill frame with test pattern\n", argv[0].str);
805 printf("%s fill r g b : Fill frame buffer with RGB888 value and force update\n", argv[0].str);
806 printf("%s mandelbrot : Fill frame buffer with Mandelbrot fractal\n", argv[0].str);
807
808 return -1;
809 }
810
811 struct display_framebuffer fb;
812 if (display_get_framebuffer(&fb) < 0) {
813 printf("no display to draw on!\n");
814 return -1;
815 }
816
817 gfx_surface *surface = gfx_create_surface_from_display(&fb);
818
819 if (!strcmp(argv[1].str, "display_info")) {
820 printf("display:\n");
821 printf("\tframebuffer %p\n", fb.image.pixels);
822 printf("\twidth %u height %u stride %u\n", fb.image.width, fb.image.height, fb.image.stride);
823 printf("\tformat %u\n", fb.image.format);
824 } else if (!strcmp(argv[1].str, "rgb_bars")) {
825 gfx_draw_rgb_bars(surface);
826 } else if (!strcmp(argv[1].str, "test_pattern")) {
827 gfx_draw_pattern();
828 } else if (!strcmp(argv[1].str, "fill")) {
829 uint x, y;
830
831 for (y = 0; y < surface->height; y++) {
832 for (x = 0; x < surface->width; x++) {
833 /* write pixel to frame buffer */
834 gfx_putpixel(surface, x, y, (0xff << 24) | (argv[2].i << 16) | (argv[3].i << 8) | argv[4].i);
835 }
836 }
837 } else if (!strcmp(argv[1].str, "mandelbrot")) {
838 gfx_draw_mandelbrot(surface);
839 } else {
840 printf("unrecognized subcommand\n");
841 gfx_surface_destroy(surface);
842 goto usage;
843 }
844
845 gfx_flush(surface);
846
847 gfx_surface_destroy(surface);
848
849 return 0;
850 }
851
852 #endif
853