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