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 33const struct gfx_font font_9x16 = { 34 .data = FONT9X16, 35 .width = FONT9X16_WIDTH, 36 .height = FONT9X16_HEIGHT, 37}; 38 39const 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. 48static 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 62static 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 72static 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 82static 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 */ 95void 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 */ 126void 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 */ 150void 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 159template <typename T> 160static 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 171template <typename T> 172static 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 207template <typename T> 208static 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 229void 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 280static 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 */ 321void 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 422template <typename T> 423static 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 439void 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 */ 460void 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 */ 471void 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 */ 495gfx_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 506int 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 */ 587gfx_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 598int 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 */ 627void 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 */ 636void 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 */ 664static 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 686static int cmd_gfx(int argc, const cmd_args* argv, uint32_t flags); 687 688STATIC_COMMAND_START 689STATIC_COMMAND("gfx", "gfx commands", &cmd_gfx) 690STATIC_COMMAND_END(gfx); 691 692static 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 719static 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