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 = &copyrect16;
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 = &copyrect32;
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 = &copyrect8;
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 = &copyrect8;
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 = &copyrect8;
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