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