graphics.c (45390B)
1 /* 2 Copyright (c) 2012, Broadcom Europe Ltd 3 All rights reserved. 4 5 Redistribution and use in source and binary forms, with or without 6 modification, are permitted provided that the following conditions are met: 7 * Redistributions of source code must retain the above copyright 8 notice, this list of conditions and the following disclaimer. 9 * Redistributions in binary form must reproduce the above copyright 10 notice, this list of conditions and the following disclaimer in the 11 documentation and/or other materials provided with the distribution. 12 * Neither the name of the copyright holder nor the 13 names of its contributors may be used to endorse or promote products 14 derived from this software without specific prior written permission. 15 16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY 20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 // Graphics library for VG 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <assert.h> 34 #include "vgfont.h" 35 #include "graphics_x_private.h" 36 37 /****************************************************************************** 38 Defines. 39 ******************************************************************************/ 40 #define ATEXT_FONT_SIZE 12 /*< Default font size (font size can be set with *_ext functions). */ 41 42 /****************************************************************************** 43 Local data 44 ******************************************************************************/ 45 static GX_DISPLAY_T display; /*< Our one and only EGL display. */ 46 47 /** 48 * We create one eglContext for each of the possible graphics_x resource types 49 * that are supported. 50 ***********************************************************/ 51 static EGLContext gx_contexts[GRAPHICS_RESOURCE_HANDLE_TYPE_MAX]; 52 53 /** Note: we have to share all our contexts, because otherwise it seems 54 * to be not valid to blit from one image to another if the images 55 * have different contexts. 56 * 57 * That means we have to use a single global lock to serialise all accesses 58 * to any contexts. 59 ***********************************************************/ 60 static VCOS_MUTEX_T lock; 61 62 static EGLConfig gx_configs[GRAPHICS_RESOURCE_HANDLE_TYPE_MAX]; 63 64 static int inited; 65 66 /****************************************************************************** 67 Local Functions 68 ******************************************************************************/ 69 70 /** Convert graphics_x colour formats into EGL format. */ 71 static int gx_egl_attrib_colours(EGLint *attribs, GRAPHICS_RESOURCE_TYPE_T res_type) 72 { 73 int i, n; 74 static EGLint rgba[] = {EGL_RED_SIZE, EGL_GREEN_SIZE, EGL_BLUE_SIZE, EGL_ALPHA_SIZE}; 75 static uint8_t rgb565[] = {5,6,5,0}; 76 static uint8_t rgb888[] = {8,8,8,0}; 77 static uint8_t rgb32a[] = {8,8,8,8}; 78 79 uint8_t *sizes = NULL; 80 81 switch (res_type) 82 { 83 case GRAPHICS_RESOURCE_RGB565: 84 sizes = rgb565; 85 break; 86 case GRAPHICS_RESOURCE_RGB888: 87 sizes = rgb888; 88 break; 89 case GRAPHICS_RESOURCE_RGBA32: 90 sizes = rgb32a; 91 break; 92 default: 93 vcos_assert(0); 94 return -1; 95 } 96 for (n=0, i=0; i<countof(rgba); i++) 97 { 98 attribs[n++] = rgba[i]; 99 attribs[n++] = sizes[i]; 100 } 101 return n; 102 } 103 104 /* Create an EGLContext for a given GRAPHICS_RESOURCE_TYPE */ 105 static VCOS_STATUS_T create_context(EGLDisplay disp, 106 GRAPHICS_RESOURCE_TYPE_T image_type, 107 EGLContext *shared_with) 108 { 109 int n; 110 EGLConfig configs[1]; 111 EGLint nconfigs, attribs[32]; 112 n = gx_egl_attrib_colours(attribs, image_type); 113 114 // we want to be able to do OpenVG on this surface... 115 attribs[n++] = EGL_RENDERABLE_TYPE; attribs[n++] = EGL_OPENVG_BIT; 116 attribs[n++] = EGL_SURFACE_TYPE; attribs[n++] = EGL_WINDOW_BIT; 117 118 attribs[n] = EGL_NONE; 119 120 EGLBoolean egl_ret = eglChooseConfig(disp, 121 attribs, configs, 122 countof(configs), &nconfigs); 123 124 if (!egl_ret || !nconfigs) 125 { 126 GX_LOG("%s: no suitable configurations for res type %d", 127 __FUNCTION__, image_type); 128 return VCOS_EINVAL; 129 } 130 131 EGLContext cxt = eglCreateContext(disp, configs[0], *shared_with, 0); 132 if (!cxt) 133 { 134 GX_LOG("Could not create context for image type %d: 0x%x", 135 image_type, eglGetError()); 136 return VCOS_ENOSPC; 137 } 138 139 gx_contexts[image_type] = cxt; 140 gx_configs[image_type] = configs[0]; 141 *shared_with = cxt; 142 143 return VCOS_SUCCESS; 144 } 145 146 /****************************************************************************** 147 Functions private to code inside GraphicsX 148 ******************************************************************************/ 149 150 static VCOS_STATUS_T gx_priv_initialise( void ) 151 { 152 int i; 153 EGLDisplay disp; 154 EGLint egl_maj, egl_min; 155 int32_t ret = VCOS_EINVAL; 156 EGLBoolean result; 157 158 vcos_demand(inited == 0); 159 160 vcos_log_set_level(&gx_log_cat, VCOS_LOG_WARN); 161 vcos_log_register("graphics", &gx_log_cat); 162 163 memset(&display,0,sizeof(display)); 164 165 gx_priv_init(); 166 167 disp = eglGetDisplay(EGL_DEFAULT_DISPLAY); 168 169 if (disp == EGL_NO_DISPLAY) 170 { 171 GX_LOG("Could not open display: 0x%x", eglGetError()); 172 vcos_assert(0); 173 goto fail_disp; 174 } 175 176 result = eglInitialize(disp, &egl_maj, &egl_min); 177 if (!result) 178 { 179 GX_LOG("Could not init display :0x%x", eglGetError()); 180 vcos_assert(0); // really can't continue 181 goto fail_egl_init; 182 } 183 184 result = eglBindAPI(EGL_OPENVG_API); 185 vcos_assert(result); // really should succeed 186 187 display.disp = disp; 188 189 GX_TRACE("Supported client APIS: %s", eglQueryString(disp, EGL_CLIENT_APIS)); 190 191 // create the available contexts 192 EGLContext shared_context = EGL_NO_CONTEXT; 193 ret = create_context(disp,GRAPHICS_RESOURCE_RGB565, &shared_context); 194 ret |= create_context(disp,GRAPHICS_RESOURCE_RGB888, &shared_context); 195 ret |= create_context(disp,GRAPHICS_RESOURCE_RGBA32, &shared_context); 196 197 if (ret != VCOS_SUCCESS) 198 goto fail_cxt; 199 200 eglSwapInterval(disp, 1); 201 202 inited = 1; 203 204 return ret; 205 206 fail_cxt: 207 for (i=0; i<GRAPHICS_RESOURCE_HANDLE_TYPE_MAX; i++) 208 { 209 if (gx_contexts[i]) 210 { 211 eglDestroyContext(display.disp,gx_contexts[i]); 212 vcos_mutex_delete(&lock); 213 } 214 } 215 eglTerminate(display.disp); 216 fail_egl_init: 217 fail_disp: 218 return ret; 219 } 220 221 /*****************************************************************************/ 222 void gx_priv_save(GX_CLIENT_STATE_T *state, GRAPHICS_RESOURCE_HANDLE res) 223 { 224 EGLBoolean egl_result; 225 vcos_assert(res == NULL || (res->magic == RES_MAGIC)); 226 vcos_assert(res == NULL || !res->context_bound); 227 228 state->context = eglGetCurrentContext(); 229 state->api = eglQueryAPI(); 230 state->read_surface = eglGetCurrentSurface(EGL_READ); 231 state->draw_surface = eglGetCurrentSurface(EGL_DRAW); 232 state->res = res; 233 234 vcos_assert(state->api); // should never be anything other than VG or GL 235 236 vcos_mutex_lock(&lock); 237 238 egl_result = eglBindAPI(EGL_OPENVG_API); 239 vcos_assert(egl_result); 240 241 if (res) 242 { 243 GX_TRACE("gx_priv_save: eglMakeCurrent: %s, res %x surface %x, cxt %x", vcos_thread_get_name(vcos_thread_current()), 244 (uint32_t)res, (uint32_t)res->surface, (uint32_t)res->context); 245 246 egl_result = eglMakeCurrent(display.disp, res->surface, 247 res->surface, res->context); 248 vcos_assert(egl_result); 249 250 res->context_bound = 1; 251 } 252 } 253 254 /*****************************************************************************/ 255 void gx_priv_restore(GX_CLIENT_STATE_T *state) 256 { 257 EGLBoolean egl_result; 258 259 GX_TRACE("gx_priv_restore: eglMakeCurrent: %s, res %x draw_surface %x, surface %x, cxt %x", vcos_thread_get_name(vcos_thread_current()), 260 (uint32_t)state->res, (uint32_t)state->draw_surface, (uint32_t)state->read_surface, (uint32_t)state->context); 261 262 // disconnect our thread from this context, so we other threads can use it via 263 // this API 264 egl_result = eglMakeCurrent(display.disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 265 vcos_assert(egl_result); 266 267 // now return to the client's API binding 268 egl_result = eglBindAPI(state->api); 269 vcos_assert(egl_result); 270 271 egl_result = eglMakeCurrent(display.disp, state->draw_surface, state->read_surface, state->context); 272 vcos_assert(egl_result); 273 274 if (state->res) state->res->context_bound = 0; 275 276 vcos_mutex_unlock(&lock); 277 } 278 279 /****************************************************************************** 280 Functions and data exported as part of the public GraphicsX API 281 ******************************************************************************/ 282 283 VCOS_LOG_CAT_T gx_log_cat; /*< Logging category for GraphicsX. */ 284 285 int32_t graphics_initialise( void ) 286 { 287 // dummy initialisation function. This is typically called 288 // early in the day before VLLs are available, and so cannot 289 // do anything useful. 290 return 0; 291 } 292 293 /*****************************************************************************/ 294 int32_t graphics_uninitialise( void ) 295 { 296 int i; 297 vcos_assert(inited); 298 299 gx_priv_font_term(); 300 301 for (i=0; i<GRAPHICS_RESOURCE_HANDLE_TYPE_MAX; i++) 302 if (gx_contexts[i]) 303 eglDestroyContext(display.disp,gx_contexts[i]); 304 305 eglTerminate(display.disp); 306 gx_priv_destroy(); 307 vcos_log_unregister(&gx_log_cat); 308 inited = 0; 309 return 0; 310 } 311 312 /*****************************************************************************/ 313 VCOS_STATUS_T gx_create_window( uint32_t screen_id, 314 uint32_t width, 315 uint32_t height, 316 GRAPHICS_RESOURCE_TYPE_T image_type, 317 GRAPHICS_RESOURCE_HANDLE *resource_handle ) 318 { 319 int rc; 320 VCOS_STATUS_T status = VCOS_SUCCESS; 321 GRAPHICS_RESOURCE_HANDLE h; 322 EGLBoolean egl_result; 323 void *cookie; 324 GX_CLIENT_STATE_T save; 325 326 if (!gx_contexts[image_type]) 327 { 328 GX_LOG("Invalid image type %d", image_type); 329 return VCOS_EINVAL; 330 } 331 332 h = vcos_calloc(1,sizeof(*h), "graphics_x_resource"); 333 if (!h) 334 { 335 GX_LOG("%s: no memory for resource", __FUNCTION__); 336 return VCOS_ENOMEM; 337 } 338 339 // now need to get the native window 340 rc = gx_priv_create_native_window(screen_id, 341 width, height, image_type, 342 &h->u.native_window, 343 &cookie); 344 if (rc < 0) 345 { 346 GX_LOG("%s: could not create native window", __FUNCTION__); 347 status = VCOS_ENOMEM; 348 goto fail_create_native_win; 349 } 350 351 h->magic = RES_MAGIC; 352 h->type = GX_WINDOW; 353 h->alpha = 1.0; 354 355 h->surface = eglCreateWindowSurface(display.disp, gx_configs[image_type], &h->u.native_window.egl_win, NULL); 356 if (!h->surface) 357 { 358 GX_LOG("Could not create window surface: 0x%x", eglGetError()); 359 status = VCOS_ENOMEM; 360 goto fail_win; 361 } 362 363 egl_result = eglSurfaceAttrib(display.disp, h->surface, 364 EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); 365 vcos_assert(egl_result); 366 367 h->context = gx_contexts[image_type]; 368 h->screen_id = screen_id; 369 h->width = width; 370 h->height = height; 371 h->restype = image_type; 372 373 gx_priv_save(&save, h); 374 375 // fill it with black 376 status = gx_priv_resource_fill(h, 0, 0, width, height, GRAPHICS_RGBA32(0,0,0,0xff)); 377 vcos_assert(status == VCOS_SUCCESS); 378 379 gx_priv_finish_native_window(h, cookie); 380 gx_priv_flush(h); 381 382 *resource_handle = h; 383 gx_priv_restore(&save); 384 return status; 385 386 fail_win: 387 gx_priv_destroy_native_window(h); 388 fail_create_native_win: 389 vcos_free(h); 390 return status; 391 } 392 393 /*****************************************************************************/ 394 int32_t graphics_delete_resource( GRAPHICS_RESOURCE_HANDLE res ) 395 { 396 EGLBoolean result; 397 398 if (!res) 399 { 400 // let it slide - mimics old behaviour 401 return 0; 402 } 403 GX_TRACE("delete resource @%p", res); 404 405 vcos_assert(res->magic == RES_MAGIC); 406 407 if (res->type == GX_PBUFFER) 408 { 409 GX_CLIENT_STATE_T save; 410 gx_priv_save(&save, res); 411 vgDestroyImage(res->u.pixmap); 412 vcos_assert(vgGetError() == 0); 413 gx_priv_restore(&save); 414 } 415 416 GX_TRACE("graphics_delete_resource: calling eglDestroySurface..."); 417 result = eglDestroySurface(display.disp, res->surface); 418 vcos_assert(result); 419 420 GX_TRACE("graphics_delete_resource: calling eglWaitClient..."); 421 eglWaitClient(); // wait for EGL to finish sorting out its surfaces 422 423 if (res->type == GX_WINDOW) 424 { 425 GX_TRACE("graphics_delete_resource: calling gx_priv_destroy_native_window..."); 426 gx_priv_destroy_native_window(res); 427 } 428 429 res->magic = ~RES_MAGIC; 430 vcos_free(res); 431 GX_TRACE("graphics_delete_resource: done"); 432 433 return 0; 434 } 435 436 /*****************************************************************************/ 437 int32_t graphics_update_displayed_resource(GRAPHICS_RESOURCE_HANDLE res, 438 const uint32_t x_offset, 439 const uint32_t y_offset, 440 const uint32_t width, 441 const uint32_t height ) 442 { 443 GX_CLIENT_STATE_T save; 444 gx_priv_save(&save, res); 445 446 gx_priv_flush(res); 447 448 gx_priv_restore(&save); 449 450 return 0; 451 } 452 453 /*****************************************************************************/ 454 int32_t graphics_resource_fill(GRAPHICS_RESOURCE_HANDLE res, 455 uint32_t x, 456 uint32_t y, 457 uint32_t width, 458 uint32_t height, 459 uint32_t fill_colour ) 460 { 461 GX_CLIENT_STATE_T save; 462 gx_priv_save(&save, res); 463 464 VCOS_STATUS_T st = gx_priv_resource_fill( 465 res, 466 x, res->height-y-height, 467 width, height, 468 fill_colour); 469 470 gx_priv_restore(&save); 471 472 return st == VCOS_SUCCESS ? 0 : -1; 473 } 474 475 /*****************************************************************************/ 476 int32_t graphics_resource_render_text_ext( GRAPHICS_RESOURCE_HANDLE res, 477 const int32_t x, 478 const int32_t y, 479 const uint32_t width, 480 const uint32_t height, 481 const uint32_t fg_colour, 482 const uint32_t bg_colour, 483 const char *text, 484 const uint32_t text_length, 485 const uint32_t text_size ) 486 { 487 488 /* 489 * FIXME: Not at all optimal - re-renders each time. 490 * FIXME: Not UTF-8 safe 491 * FIXME: much better caching (or any caching) 492 */ 493 VCOS_STATUS_T rc = gx_priv_render_text( 494 &display, res, 495 x, res->height-y-text_size, width, height, fg_colour, bg_colour, 496 text, text_length, text_size); 497 498 return (rc == VCOS_SUCCESS) ? 0 : -1; 499 } 500 501 /*****************************************************************************/ 502 int32_t graphics_resource_render_text( GRAPHICS_RESOURCE_HANDLE res, 503 const int32_t x, 504 const int32_t y, 505 const uint32_t width, /* this can be GRAPHICS_RESOURCE_WIDTH for no clipping */ 506 const uint32_t height, /* this can be GRAPHICS_RESOURCE_HEIGHT for no clipping */ 507 const uint32_t fg_colour, 508 const uint32_t bg_colour, 509 const char *text, 510 const uint32_t text_length) 511 { 512 return graphics_resource_render_text_ext(res, x, y, width, height, 513 fg_colour, bg_colour, 514 text, text_length, 515 ATEXT_FONT_SIZE); 516 } 517 518 /*****************************************************************************/ 519 int32_t graphics_get_resource_size( 520 const GRAPHICS_RESOURCE_HANDLE res, 521 uint32_t *w, 522 uint32_t *h) 523 { 524 if (w) *w = res->width; 525 if (h) *h = res->height; 526 return 0; 527 } 528 529 /*****************************************************************************/ 530 int32_t graphics_get_resource_type(const GRAPHICS_RESOURCE_HANDLE res, GRAPHICS_RESOURCE_TYPE_T *type) 531 { 532 if (type) *type = res->restype; 533 return 0; 534 } 535 536 /*****************************************************************************/ 537 int32_t graphics_bitblt( const GRAPHICS_RESOURCE_HANDLE src, 538 const uint32_t x, // offset within source 539 const uint32_t y, // offset within source 540 const uint32_t width, 541 const uint32_t height, 542 GRAPHICS_RESOURCE_HANDLE dest, 543 const uint32_t x_pos, 544 const uint32_t y_pos ) 545 { 546 int rc = -1; 547 VGfloat old[9]; 548 uint32_t w, h; 549 VGPaint paint = VG_INVALID_HANDLE; 550 GX_CLIENT_STATE_T save; 551 int is_child = 0; 552 VGImage img = VG_INVALID_HANDLE; 553 554 gx_priv_save(&save, dest); 555 556 if (src->type != GX_PBUFFER) 557 { 558 vcos_assert(0); 559 goto finish; 560 } 561 562 // create a child image that contains just the part wanted 563 w = width == GRAPHICS_RESOURCE_WIDTH ? src->width : width; 564 h = height == GRAPHICS_RESOURCE_HEIGHT ? src->height : height; 565 566 if (x==0 && y==0 && 567 w == src->width && 568 h == src->height) 569 { 570 img = src->u.pixmap; 571 } 572 else 573 { 574 is_child = 1; 575 img = vgChildImage(src->u.pixmap, x, y, w, h); 576 if (img == VG_INVALID_HANDLE) 577 { 578 vcos_assert(0); 579 goto finish; 580 } 581 } 582 583 vcos_assert(vgGetError()==0); 584 585 vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); 586 vgGetMatrix(old); 587 vgLoadIdentity(); 588 vgTranslate((VGfloat)x_pos, (VGfloat)(dest->height-y_pos)); 589 vgScale(1.0, -1.0); 590 591 // Do we have a translucency going on? 592 if (src->alpha != 1.0) 593 { 594 VGfloat colour[4] = {1.0,1.0,1.0,src->alpha}; 595 paint = vgCreatePaint(); 596 597 vgSetParameterfv(paint, VG_PAINT_COLOR, 4, colour); 598 vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_MULTIPLY); 599 vgSetPaint(paint, VG_STROKE_PATH | VG_FILL_PATH); 600 } 601 vcos_assert(vgGetError()==0); 602 603 vgDrawImage(img); 604 vcos_assert(vgGetError()==0); 605 vgLoadMatrix(old); 606 607 int err = vgGetError(); 608 609 if (err) 610 { 611 GX_LOG("vg error %x blitting area", err); 612 vcos_assert(0); 613 rc = -1; 614 } 615 else 616 { 617 rc = 0; 618 } 619 finish: 620 if (paint != VG_INVALID_HANDLE) 621 vgDestroyPaint(paint); 622 623 if (is_child) 624 vgDestroyImage(img); 625 626 gx_priv_restore(&save); 627 return rc; 628 } 629 630 void gx_priv_flush(GRAPHICS_RESOURCE_HANDLE res) 631 { 632 EGLBoolean result; 633 result = eglSwapBuffers(display.disp, res->surface); 634 vcos_assert(result); 635 } 636 637 638 /** Map a colour, which the client will have supplied in RGB888. 639 */ 640 641 void gx_priv_colour_to_paint(uint32_t col, VGfloat *rgba) 642 { 643 // with OpenVG we use RGB order. 644 rgba[0] = ((VGfloat)((col & R_888_MASK) >> 16 )) / 0xff; 645 rgba[1] = ((VGfloat)((col & G_888_MASK) >> 8 )) / 0xff; 646 rgba[2] = ((VGfloat)((col & B_888_MASK) >> 0 )) / 0xff; 647 rgba[3] = ((VGfloat)((col & ALPHA_888_MASK) >> 24)) / 0xff; 648 } 649 650 /** Fill an area of a surface with a fixed colour. 651 */ 652 VCOS_STATUS_T gx_priv_resource_fill(GRAPHICS_RESOURCE_HANDLE res, 653 uint32_t x, 654 uint32_t y, 655 uint32_t width, 656 uint32_t height, 657 uint32_t fill_colour ) 658 { 659 VGfloat vg_clear_colour[4]; 660 661 gx_priv_colour_to_paint(fill_colour, vg_clear_colour); 662 vgSeti(VG_SCISSORING, VG_FALSE); 663 664 vgSetfv(VG_CLEAR_COLOR, 4, vg_clear_colour); 665 vgClear(x, y, width, height); 666 667 int err = vgGetError(); 668 if (err) 669 { 670 GX_LOG("vg error %x filling area", err); 671 vcos_assert(0); 672 } 673 674 return VCOS_SUCCESS; 675 } 676 677 VCOS_STATUS_T gx_priv_get_pixels(const GRAPHICS_RESOURCE_HANDLE res, void **p_pixels, GX_RASTER_ORDER_T raster_order) 678 { 679 VCOS_STATUS_T status = VCOS_SUCCESS; 680 void *pixels, *dest; 681 uint32_t width, height; 682 int data_size, pitch; 683 VGImageFormat image_format; 684 685 if (!p_pixels) 686 { 687 status = VCOS_EINVAL; 688 goto finish; 689 } 690 691 GX_TRACE("%s: res %p", __FUNCTION__, res); 692 693 graphics_get_resource_size(res, &width, &height); 694 695 /* FIXME: implement e.g. gx_get_pitch */ 696 switch (res->restype) 697 { 698 case GRAPHICS_RESOURCE_RGB565: 699 pitch = ((width + 31)&(~31)) << 1; 700 break; 701 case GRAPHICS_RESOURCE_RGB888: 702 case GRAPHICS_RESOURCE_RGBA32: 703 pitch = ((width + 31)&(~31)) << 2; 704 break; 705 default: 706 { 707 GX_LOG("Unsupported pixel format"); 708 status = VCOS_EINVAL; 709 goto finish; 710 } 711 } 712 713 data_size = pitch * height; 714 715 /* NB: vgReadPixels requires that the data pointer is aligned, but does not 716 require the stride to be aligned. Most implementations probably will 717 require that as well though... */ 718 pixels = vcos_malloc(data_size, "gx_get_pixels data"); 719 if (!pixels) 720 { 721 GX_LOG("Could not allocate %d bytes for vgReadPixels", data_size); 722 status = VCOS_ENOMEM; 723 goto finish; 724 } 725 /* FIXME: introduce e.g. GX_COLOR_FORMAT and mapping to VGImageFormat... */ 726 727 /* Hand out image data formatted to match OpenGL RGBA format. 728 */ 729 switch (res->restype) 730 { 731 case GRAPHICS_RESOURCE_RGB565: 732 image_format = VG_sBGR_565; 733 break; 734 case GRAPHICS_RESOURCE_RGB888: 735 image_format = VG_sXBGR_8888; 736 break; 737 case GRAPHICS_RESOURCE_RGBA32: 738 image_format = VG_sABGR_8888; 739 break; 740 default: 741 { 742 GX_LOG("Unsupported pixel format"); 743 status = VCOS_EINVAL; 744 goto finish; 745 } 746 } 747 748 /* VG raster order is bottom-to-top */ 749 if (raster_order == GX_TOP_BOTTOM) 750 { 751 dest = ((uint8_t*)pixels)+(pitch*(height-1)); 752 pitch = -pitch; 753 } 754 else 755 { 756 dest = pixels; 757 } 758 759 vgReadPixels(dest, pitch, image_format, 0, 0, width, height); 760 761 vcos_assert(vgGetError() == 0); 762 763 *p_pixels = pixels; 764 765 finish: 766 return status; 767 } 768 769 static VCOS_STATUS_T convert_image_type(GRAPHICS_RESOURCE_TYPE_T image_type, 770 VGImageFormat *vg_image_type, 771 int *pbytes_per_pixel) 772 { 773 int bytes_per_pixel; 774 775 switch (image_type) 776 { 777 case GRAPHICS_RESOURCE_RGB565: 778 *vg_image_type = VG_sRGB_565; 779 bytes_per_pixel = 2; 780 break; 781 case GRAPHICS_RESOURCE_RGB888: 782 *vg_image_type = VG_sRGBX_8888; 783 bytes_per_pixel = 3; // 24 bpp 784 break; 785 case GRAPHICS_RESOURCE_RGBA32: 786 *vg_image_type = VG_sARGB_8888; 787 bytes_per_pixel = 4; 788 break; 789 default: 790 vcos_assert(0); 791 *vg_image_type = 0; 792 return VCOS_EINVAL; 793 } 794 if (pbytes_per_pixel) 795 *pbytes_per_pixel = bytes_per_pixel; 796 797 return VCOS_SUCCESS; 798 } 799 800 801 /*****************************************************************************/ 802 VCOS_STATUS_T gx_create_pbuffer( uint32_t width, 803 uint32_t height, 804 GRAPHICS_RESOURCE_TYPE_T image_type, 805 GRAPHICS_RESOURCE_HANDLE *resource_handle ) 806 { 807 VCOS_STATUS_T status = VCOS_SUCCESS; 808 GRAPHICS_RESOURCE_HANDLE h; 809 VGImage image; 810 VGImageFormat vg_image_type; 811 GX_CLIENT_STATE_T save; 812 813 h = vcos_calloc(1,sizeof(*h), "graphics_x_resource"); 814 if (!h) 815 { 816 GX_LOG("%s: no memory for resource", __FUNCTION__); 817 return VCOS_ENOMEM; 818 } 819 820 status = convert_image_type(image_type, &vg_image_type, NULL); 821 if (status != VCOS_SUCCESS) 822 { 823 vcos_free(h); 824 return status; 825 } 826 827 h->magic = RES_MAGIC; 828 h->context = gx_contexts[image_type]; 829 h->config = gx_configs[image_type]; 830 h->alpha = 1.0; 831 h->type = GX_PBUFFER; 832 h->width = width; 833 h->height = height; 834 h->restype = image_type; 835 836 GX_TRACE("Creating pbuffer surface"); 837 838 EGLint attribs[] = {EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE}; 839 h->surface = eglCreatePbufferSurface(display.disp, h->config, 840 attribs); 841 if (!h->surface) 842 { 843 GX_LOG("Could not create EGL pbuffer surface: 0x%x", eglGetError()); 844 vcos_free(h); 845 return VCOS_EINVAL; 846 } 847 848 gx_priv_save(&save, h); 849 850 image = vgCreateImage(vg_image_type, width, height, VG_IMAGE_QUALITY_BETTER); 851 if (image == VG_INVALID_HANDLE) 852 { 853 GX_LOG("Could not create vg image type %d: vg error 0x%x", 854 vg_image_type, vgGetError()); 855 eglDestroySurface(display.disp, h->surface); 856 vcos_free(h); 857 status = VCOS_ENOMEM; 858 goto finish; 859 } 860 861 h->u.pixmap = image; 862 863 // fill it with black 864 status = gx_priv_resource_fill(h, 0, 0, width, height, GRAPHICS_RGBA32(0,0,0,0xff)); 865 vcos_assert(status == VCOS_SUCCESS); 866 867 *resource_handle = h; 868 finish: 869 gx_priv_restore(&save); 870 return status; 871 } 872 873 /*****************************************************************************/ 874 GX_PAINT_T *gx_create_gradient(GRAPHICS_RESOURCE_HANDLE res, 875 uint32_t start_colour, 876 uint32_t end_colour) 877 { 878 // holds the two colour stops (offset,r,g,b,a). 879 VGfloat fill_stops[10]; 880 GX_CLIENT_STATE_T save; 881 VGPaint paint = VG_INVALID_HANDLE; 882 883 gx_priv_save(&save, res); 884 885 paint = vgCreatePaint(); 886 if (!paint) 887 { 888 gx_priv_restore(&save); 889 vcos_log("Could not create paint: vg %d\n", vgGetError()); 890 vcos_assert(0); 891 goto finish; 892 } 893 894 fill_stops[0] = 0.0; 895 gx_priv_colour_to_paint(start_colour, fill_stops+1); 896 897 fill_stops[5] = 1.0; 898 gx_priv_colour_to_paint(end_colour, fill_stops+6); 899 900 vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT); 901 vgSetParameterfv(paint, VG_PAINT_COLOR_RAMP_STOPS, 5*2, fill_stops); 902 903 finish: 904 gx_priv_restore(&save); 905 return (GX_PAINT_T*)paint; 906 } 907 908 /*****************************************************************************/ 909 void gx_destroy_paint(GRAPHICS_RESOURCE_HANDLE res, GX_PAINT_T *p) 910 { 911 GX_CLIENT_STATE_T save; 912 VGPaint paint = (VGPaint)p; 913 gx_priv_save(&save, res); 914 vgDestroyPaint(paint); 915 gx_priv_restore(&save); 916 } 917 918 /*****************************************************************************/ 919 VCOS_STATUS_T gx_fill_gradient(GRAPHICS_RESOURCE_HANDLE dest, 920 uint32_t x, uint32_t y, 921 uint32_t width, uint32_t height, 922 uint32_t radius, 923 GX_PAINT_T *p) 924 { 925 /* Define start and end points of gradient, see OpenVG specification, 926 section 9.3.3. */ 927 VGfloat gradient[4] = {0.0, 0.0, 0.0, 0.0}; 928 VGPaint paint = (VGPaint)p; 929 VGPath path; 930 GX_CLIENT_STATE_T save; 931 VCOS_STATUS_T status = VCOS_SUCCESS; 932 933 if (!paint) 934 return VCOS_EINVAL; 935 936 gx_priv_save(&save, dest); 937 938 if (width == GRAPHICS_RESOURCE_WIDTH) 939 width = dest->width; 940 941 if (height == GRAPHICS_RESOURCE_HEIGHT) 942 height = dest->height; 943 944 gradient[2] = width; 945 946 vgSetParameterfv(paint, VG_PAINT_LINEAR_GRADIENT, 4, gradient); 947 vgSetPaint(paint, VG_FILL_PATH); 948 949 path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_S_32, 950 1.0, 0.0, 8, 8, VG_PATH_CAPABILITY_ALL); 951 if (!path) 952 { 953 status = VCOS_ENOMEM; 954 goto finish; 955 } 956 957 vguRoundRect(path, (VGfloat)x, (VGfloat)y, (VGfloat)width, (VGfloat)height, 958 (VGfloat)radius, (VGfloat)radius); 959 vgDrawPath(path, VG_FILL_PATH); 960 vgDestroyPath(path); 961 962 vcos_assert(vgGetError() == 0); 963 964 finish: 965 gx_priv_restore(&save); 966 967 return status; 968 } 969 970 /*****************************************************************************/ 971 VCOS_STATUS_T gx_graphics_init(const char *font_dir) 972 { 973 GX_CLIENT_STATE_T save; 974 VCOS_STATUS_T rc; 975 976 gx_priv_save(&save, NULL); 977 978 rc = gx_priv_initialise(); 979 if (rc == VCOS_SUCCESS) 980 rc = gx_priv_font_init(font_dir); 981 982 gx_priv_restore(&save); 983 984 return rc; 985 } 986 987 /*****************************************************************************/ 988 int gx_is_double_buffered(void) 989 { 990 return 1; 991 } 992 993 /*****************************************************************************/ 994 int32_t graphics_userblt(GRAPHICS_RESOURCE_TYPE_T src_type, 995 const void *src_data, 996 const uint32_t src_x, 997 const uint32_t src_y, 998 const uint32_t width, 999 const uint32_t height, 1000 const uint32_t pitch, 1001 GRAPHICS_RESOURCE_HANDLE dest, 1002 const uint32_t x_pos, 1003 const uint32_t y_pos ) 1004 { 1005 VCOS_STATUS_T status; 1006 VGImageFormat vg_src_type; 1007 int bytes_per_pixel; 1008 GX_CLIENT_STATE_T save; 1009 1010 status = convert_image_type(src_type, &vg_src_type, &bytes_per_pixel); 1011 if (status != VCOS_SUCCESS) 1012 return status; 1013 1014 gx_priv_save(&save, dest); 1015 1016 if (dest->type == GX_PBUFFER) 1017 { 1018 vgImageSubData(dest->u.pixmap, 1019 src_data, 1020 pitch, 1021 vg_src_type, 1022 x_pos, y_pos, width, height); 1023 } 1024 else if (dest->type == GX_WINDOW) 1025 { 1026 // need to invert this as VG thinks zero is at the bottom 1027 // while graphics_x thinks it is at the top. 1028 vgWritePixels((uint8_t*)src_data + pitch*(height-1), 1029 -pitch, 1030 vg_src_type, 1031 x_pos, dest->height-y_pos-height, width, height); 1032 } 1033 else 1034 { 1035 vcos_assert(0); 1036 } 1037 1038 if (vgGetError() == 0) 1039 status = VCOS_SUCCESS; 1040 else 1041 { 1042 vcos_assert(0); 1043 status = VCOS_EINVAL; 1044 } 1045 1046 gx_priv_restore(&save); 1047 return status; 1048 } 1049 1050 /*****************************************************************************/ 1051 int32_t graphics_resource_text_dimensions( GRAPHICS_RESOURCE_HANDLE resource_handle, 1052 const char *text, 1053 const uint32_t text_length, 1054 uint32_t *width, 1055 uint32_t *height ) 1056 { 1057 return graphics_resource_text_dimensions_ext(resource_handle, text, text_length, width, height, ATEXT_FONT_SIZE); 1058 } 1059 1060 /*****************************************************************************/ 1061 VCOS_STATUS_T gx_render_arrowhead(GRAPHICS_RESOURCE_HANDLE res, 1062 uint32_t tip_x, uint32_t tip_y, 1063 int32_t w, int32_t h, 1064 GX_PAINT_T *p) 1065 { 1066 VGfloat gradient[4]; 1067 VGPaint paint = (VGPaint)p; 1068 VGPath path; 1069 VCOS_STATUS_T status = VCOS_SUCCESS; 1070 1071 GX_CLIENT_STATE_T save; 1072 gx_priv_save(&save, res); 1073 1074 if (!paint) 1075 { 1076 vcos_assert(0); 1077 status = VCOS_EINVAL; 1078 goto finish; 1079 } 1080 1081 gradient[0] = 0.0; gradient[1] = 0.0; 1082 gradient[2] = w; gradient[2] = 0.0; 1083 1084 vgSetParameterfv(paint, VG_PAINT_LINEAR_GRADIENT, 4, gradient); 1085 vgSetPaint(paint, VG_FILL_PATH); 1086 1087 path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_S_32, 1088 1.0, 0.0, 8, 8, VG_PATH_CAPABILITY_ALL); 1089 if (!path) 1090 { 1091 status = VCOS_ENOMEM; 1092 goto finish; 1093 } 1094 VGfloat points[] = { 1095 (VGfloat)tip_x, (VGfloat)tip_y, 1096 (VGfloat)tip_x + w, (VGfloat)tip_y + h/2, 1097 (VGfloat)tip_x + w, (VGfloat)tip_y - h/2, 1098 }; 1099 1100 vguPolygon(path, points, 3, 1); 1101 1102 vgDrawPath(path, VG_FILL_PATH); 1103 vgDestroyPath(path); 1104 1105 vcos_assert(vgGetError()==0); 1106 1107 finish: 1108 gx_priv_restore(&save); 1109 return status; 1110 } 1111 1112 /*****************************************************************************/ 1113 int32_t gx_apply_alpha( GRAPHICS_RESOURCE_HANDLE resource_handle, 1114 const uint8_t alpha ) 1115 { 1116 vcos_assert(resource_handle); 1117 if (resource_handle->type != GX_PBUFFER) 1118 { 1119 vcos_assert(0); 1120 return -1; 1121 } 1122 resource_handle->alpha = 1.0*alpha/255; 1123 return 0; 1124 } 1125 1126 /*****************************************************************************/ 1127 int32_t graphics_resource_set_alpha_per_colour( GRAPHICS_RESOURCE_HANDLE res, 1128 const uint32_t colour, 1129 const uint8_t alpha ) 1130 { 1131 GX_ERROR("Not implemented yet!"); 1132 return 0; 1133 } 1134 1135 /*****************************************************************************/ 1136 VCOS_STATUS_T gx_get_pixels(const GRAPHICS_RESOURCE_HANDLE res, void **pixels) 1137 { 1138 VCOS_STATUS_T status = VCOS_SUCCESS; 1139 GX_CLIENT_STATE_T save; 1140 gx_priv_save(&save, res); 1141 1142 /* Default to top-top-bottom raster scan order */ 1143 status = gx_priv_get_pixels(res, pixels, GX_TOP_BOTTOM); 1144 1145 gx_priv_restore(&save); 1146 return status; 1147 } 1148 1149 /*****************************************************************************/ 1150 VCOS_STATUS_T gx_get_pixels_in_raster_order(const GRAPHICS_RESOURCE_HANDLE res, 1151 void **pixels, 1152 GX_RASTER_ORDER_T raster_order) 1153 { 1154 VCOS_STATUS_T status = VCOS_SUCCESS; 1155 GX_CLIENT_STATE_T save; 1156 gx_priv_save(&save, res); 1157 1158 status = gx_priv_get_pixels(res, pixels, raster_order); 1159 1160 gx_priv_restore(&save); 1161 return status; 1162 } 1163 1164 /*****************************************************************************/ 1165 void gx_free_pixels(const GRAPHICS_RESOURCE_HANDLE res, void *pixels) 1166 { 1167 vcos_free(pixels); 1168 } 1169 1170 VCOS_STATUS_T gx_bind_vg( GX_CLIENT_STATE_T *save, GRAPHICS_RESOURCE_HANDLE res ) 1171 { 1172 gx_priv_save(save, res); 1173 vcos_assert(vgGetError()==0); 1174 return VCOS_SUCCESS; 1175 } 1176 1177 /** Unbind VG */ 1178 void gx_unbind_vg(GX_CLIENT_STATE_T *restore) 1179 { 1180 gx_priv_restore(restore); 1181 } 1182 1183 1184 GX_CLIENT_STATE_T *gx_alloc_context(void) 1185 { 1186 GX_CLIENT_STATE_T *ret = vcos_calloc(1,sizeof(*ret), "gx_client_state"); 1187 return ret; 1188 } 1189 1190 void gx_free_context(GX_CLIENT_STATE_T *state) 1191 { 1192 vcos_free(state); 1193 } 1194 1195 void gx_convert_colour(uint32_t colour, float *dest) 1196 { 1197 gx_priv_colour_to_paint(colour, dest); 1198 } 1199 1200 1201 #define MAX_DISPLAY_HANDLES 4 1202 1203 #define CHANGE_LAYER (1<<0) 1204 #define CHANGE_OPACITY (1<<1) 1205 #define CHANGE_DEST (1<<2) 1206 #define CHANGE_SRC (1<<3) 1207 #define CHANGE_MASK (1<<4) 1208 #define CHANGE_XFORM (1<<5) 1209 1210 typedef struct 1211 { 1212 /** Keep a display handle going for each connected screen (LCD, HDMI). */ 1213 DISPMANX_DISPLAY_HANDLE_T screens[MAX_DISPLAY_HANDLES]; 1214 int refcounts[MAX_DISPLAY_HANDLES]; 1215 1216 //a flag to count the number of dispman starts that have been invoked 1217 1218 uint32_t dispman_start_count; 1219 // maintain the single global handle to the update in progress 1220 DISPMANX_UPDATE_HANDLE_T current_update; 1221 1222 VCOS_MUTEX_T lock; 1223 } gx_priv_state_t; 1224 1225 static gx_priv_state_t gx; 1226 1227 void gx_priv_init(void) 1228 { 1229 vcos_mutex_create(&gx.lock,NULL); 1230 } 1231 1232 void gx_priv_destroy(void) 1233 { 1234 vcos_mutex_delete(&gx.lock); 1235 } 1236 1237 1238 static 1239 int32_t gx_priv_open_screen(uint32_t index, DISPMANX_DISPLAY_HANDLE_T *pscreen) 1240 { 1241 int ret = -1; 1242 vcos_mutex_lock(&gx.lock); 1243 1244 if (gx.refcounts[index] != 0) 1245 { 1246 *pscreen = gx.screens[index]; 1247 gx.refcounts[index]++; 1248 ret = 0; 1249 } 1250 else 1251 { 1252 DISPMANX_DISPLAY_HANDLE_T h = vc_dispmanx_display_open(index); 1253 if (h == DISPMANX_NO_HANDLE) 1254 { 1255 GX_LOG("Could not open dispmanx display %d", index); 1256 ret = -1; 1257 goto finish; 1258 } 1259 gx.screens[index] = h; 1260 gx.refcounts[index] = 1; 1261 *pscreen = h; 1262 ret = 0; 1263 } 1264 finish: 1265 vcos_mutex_unlock(&gx.lock); 1266 return ret; 1267 } 1268 1269 static 1270 int32_t gx_priv_release_screen(uint32_t index) 1271 { 1272 vcos_mutex_lock(&gx.lock); 1273 gx.refcounts[index]--; 1274 if (gx.refcounts[index] == 0) 1275 { 1276 vc_dispmanx_display_close(gx.screens[index]); 1277 gx.screens[index] = DISPMANX_NO_HANDLE; 1278 } 1279 vcos_mutex_unlock(&gx.lock); 1280 return 0; 1281 } 1282 1283 1284 1285 1286 int gx_priv_create_native_window(uint32_t screen_id, 1287 uint32_t w, uint32_t h, 1288 GRAPHICS_RESOURCE_TYPE_T type, 1289 GX_NATIVE_WINDOW_T *win, 1290 void **cookie) 1291 { 1292 int rc; 1293 DISPMANX_DISPLAY_HANDLE_T dispmanx_display; 1294 VC_RECT_T dst_rect; 1295 VC_RECT_T src_rect; 1296 DISPMANX_UPDATE_HANDLE_T current_update; 1297 *cookie = NULL; 1298 1299 rc = gx_priv_open_screen(screen_id, &dispmanx_display); 1300 if (rc < 0) 1301 { 1302 GX_LOG("Could not open display %d", screen_id); 1303 goto fail_screen; 1304 } 1305 1306 current_update = vc_dispmanx_update_start(0); 1307 if (!current_update) 1308 { 1309 GX_LOG("Could not start update on screen %d", screen_id); 1310 goto fail_update; 1311 } 1312 1313 src_rect.x = src_rect.y = 0; 1314 src_rect.width = w << 16; 1315 src_rect.height = h << 16; 1316 1317 dst_rect.x = dst_rect.y = 0; 1318 dst_rect.width = dst_rect.height = 1; 1319 1320 win->egl_win.width = w; 1321 win->egl_win.height = h; 1322 VC_DISPMANX_ALPHA_T alpha; 1323 memset(&alpha, 0x0, sizeof(VC_DISPMANX_ALPHA_T)); 1324 alpha.flags = DISPMANX_FLAGS_ALPHA_FROM_SOURCE; 1325 1326 DISPMANX_CLAMP_T clamp; 1327 memset(&clamp, 0x0, sizeof(DISPMANX_CLAMP_T)); 1328 1329 win->egl_win.element = vc_dispmanx_element_add(current_update, dispmanx_display, 1330 0 /* layer */, &dst_rect, 1331 0 /* src */, &src_rect, 1332 DISPMANX_PROTECTION_NONE, 1333 &alpha /* alpha */, 1334 &clamp /* clamp */, 1335 0 /* transform */); 1336 1337 if ( !win->egl_win.element ) 1338 { 1339 GX_LOG("Could not add element %dx%d",w,h); 1340 vc_dispmanx_update_submit_sync(current_update); 1341 rc = -1; 1342 } 1343 1344 // have to pass back the update so it can be completed *After* the 1345 // window has been initialised (filled with background colour). 1346 *cookie = (void*)current_update; 1347 1348 return 0; 1349 1350 fail_update: 1351 gx_priv_release_screen(screen_id); 1352 fail_screen: 1353 return rc; 1354 } 1355 1356 void gx_priv_finish_native_window(GRAPHICS_RESOURCE_HANDLE_TABLE_T *res, 1357 void *current_update) 1358 { 1359 vc_dispmanx_update_submit_sync((DISPMANX_UPDATE_HANDLE_T)current_update); 1360 } 1361 1362 void 1363 gx_priv_destroy_native_window(GRAPHICS_RESOURCE_HANDLE_TABLE_T *res) 1364 { 1365 DISPMANX_UPDATE_HANDLE_T current_update; 1366 1367 if((current_update = vc_dispmanx_update_start(0)) != 0) 1368 { 1369 int ret = vc_dispmanx_element_remove(current_update, res->u.native_window.egl_win.element); 1370 vcos_assert(ret == 0); 1371 ret = vc_dispmanx_update_submit_sync(current_update); 1372 vcos_assert(ret == 0); 1373 } 1374 1375 gx_priv_release_screen(res->screen_id); 1376 } 1377 1378 1379 /*********************************************************** 1380 * Name: graphics_get_display_size 1381 * 1382 * Arguments: 1383 * void 1384 * 1385 * Description: Return size of display 1386 * 1387 * Returns: int32_t: 1388 * >=0 if it succeeded 1389 * 1390 ***********************************************************/ 1391 int32_t graphics_get_display_size( const uint16_t display_number, 1392 uint32_t *width, 1393 uint32_t *height) 1394 { 1395 DISPMANX_MODEINFO_T mode_info; 1396 int32_t success = -1; 1397 DISPMANX_DISPLAY_HANDLE_T disp; 1398 vcos_assert(width && height); 1399 *width = *height = 0; 1400 1401 if(vcos_verify(display_number < MAX_DISPLAY_HANDLES)) 1402 { 1403 // TODO Shouldn't this close the display if it wasn't previously open? 1404 if (gx_priv_open_screen(display_number, &disp) < 0) 1405 { 1406 vcos_assert(0); 1407 return -1; 1408 } 1409 success = vc_dispmanx_display_get_info(disp, &mode_info); 1410 1411 if( success >= 0 ) 1412 { 1413 *width = mode_info.width; 1414 *height = mode_info.height; 1415 vcos_assert(*height > 64); 1416 } 1417 else 1418 { 1419 vcos_assert(0); 1420 } 1421 } 1422 1423 return success; 1424 } 1425 1426 static inline uint16_t auto_size(uint16_t arg, uint16_t actual_size) 1427 { 1428 return arg == GRAPHICS_RESOURCE_WIDTH ? actual_size : arg; 1429 } 1430 1431 int32_t graphics_display_resource( GRAPHICS_RESOURCE_HANDLE res, 1432 const uint16_t screen_number, 1433 const int16_t z_order, 1434 const uint16_t offset_x, 1435 const uint16_t offset_y, 1436 const uint16_t dest_width, 1437 const uint16_t dest_height, 1438 const VC_DISPMAN_TRANSFORM_T transform, 1439 const uint8_t display ) 1440 { 1441 DISPMANX_UPDATE_HANDLE_T update; 1442 int32_t rc; 1443 int xform_changed; 1444 1445 if (!res) 1446 { 1447 // mimics old behaviour. 1448 (void)vcos_verify(0); 1449 return 0; 1450 } 1451 vcos_assert(res->magic == RES_MAGIC); 1452 1453 xform_changed = transform != res->transform; 1454 res->transform = transform; 1455 1456 rc = graphics_update_start(); 1457 update = gx.current_update; 1458 vcos_assert(rc == 0); 1459 1460 if (display) 1461 { 1462 VC_RECT_T src_rect, dest_rect; 1463 1464 int32_t src_width = res->width; 1465 int32_t src_height = res->height; 1466 1467 uint32_t change_flags = CHANGE_LAYER; 1468 1469 // has the destination position changed? 1470 uint32_t w = auto_size(dest_width, res->width); 1471 uint32_t h = auto_size(dest_height, res->height); 1472 1473 vcos_assert(screen_number == res->screen_id); 1474 1475 if (gx.screens[screen_number] == 0) 1476 { 1477 vcos_assert(0); 1478 DISPMANX_DISPLAY_HANDLE_T display_handle; 1479 gx_priv_open_screen(screen_number, &display_handle); 1480 } 1481 1482 if ((offset_x != res->dest.x) || 1483 (offset_y != res->dest.y) || 1484 (h != res->dest.height) || 1485 (w != res->dest.width)) 1486 { 1487 change_flags |= CHANGE_DEST; 1488 res->dest.x = offset_x; 1489 res->dest.y = offset_y; 1490 res->dest.height = h; 1491 res->dest.width = w; 1492 } 1493 1494 if (xform_changed) 1495 change_flags |= CHANGE_XFORM; 1496 1497 vc_dispmanx_rect_set( &src_rect, 0, 0, ((uint32_t)src_width)<<16, ((uint32_t)src_height)<<16 ); 1498 vc_dispmanx_rect_set( &dest_rect, offset_x, offset_y, w, h); 1499 1500 rc = vc_dispmanx_element_change_attributes(update, 1501 res->u.native_window.egl_win.element, 1502 change_flags, 1503 z_order, /* layer */ 1504 0xff, /* opacity */ 1505 &dest_rect, 1506 &src_rect, 1507 0, transform); 1508 1509 vcos_assert(rc==0); 1510 gx_priv_flush(res); 1511 1512 } 1513 else 1514 { 1515 vgFinish(); 1516 eglWaitClient(); 1517 rc = vc_dispmanx_element_change_source(update, res->u.native_window.egl_win.element, 0); 1518 vcos_assert(rc==0); 1519 } 1520 1521 rc = graphics_update_end(); 1522 vcos_assert(rc==0); 1523 1524 return rc; 1525 } 1526 1527 /*********************************************************** 1528 * Name: graphics_update_start 1529 * 1530 * Arguments: 1531 * void 1532 * 1533 * Description: Starts an update UNLESS and update is already in progress 1534 * 1535 * Returns: int32_t: 1536 * >=0 if it succeeded 1537 * 1538 ***********************************************************/ 1539 int32_t graphics_update_start(void) 1540 { 1541 int32_t success = 0; 1542 1543 //check we are not already in an update 1544 if ( 0 == gx.dispman_start_count ) 1545 { 1546 gx.current_update = vc_dispmanx_update_start( 10 ); 1547 if( gx.current_update == DISPMANX_NO_HANDLE ) 1548 { 1549 //error 1550 success = -1; 1551 vc_assert( 0 ); 1552 } 1553 } 1554 1555 if( success == 0 ) 1556 { 1557 //inc the counter 1558 gx.dispman_start_count++; 1559 } 1560 1561 return success; 1562 } 1563 1564 1565 /*********************************************************** 1566 * Name: graphics_update_end 1567 * 1568 * Arguments: 1569 * void 1570 * 1571 * Description: Ends an update UNLESS more than one update is in progress 1572 * 1573 * Returns: int32_t: 1574 * >=0 if it succeeded 1575 * 1576 ***********************************************************/ 1577 int32_t graphics_update_end( void ) 1578 { 1579 int32_t success = -1; 1580 1581 // make sure you are checking the return value of graphics_update_start 1582 if(vcos_verify(gx.current_update != DISPMANX_NO_HANDLE)) 1583 { 1584 //check we are in an update 1585 if(vcos_verify(gx.dispman_start_count > 0)) 1586 { 1587 //dec the counter 1588 gx.dispman_start_count--; 1589 1590 success = 0; 1591 1592 //is the counter now 0? 1593 if( 0 == gx.dispman_start_count ) 1594 { 1595 eglWaitClient(); 1596 if( vc_dispmanx_update_submit_sync( gx.current_update ) != 0 ) 1597 { 1598 //error 1599 success = -1; 1600 vc_assert( 0 ); 1601 } 1602 } 1603 } 1604 } 1605 1606 return success; 1607 } 1608