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 = ©rect<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 = ©rect<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 = ©rect<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 = ©rect<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 = ©rect<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