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