egl_g3d_api.c revision 4c7001462607e6e99e474d6271dd481d3f8f201c
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.9 4 * 5 * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org> 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 */ 25 26#include "egldriver.h" 27#include "eglcurrent.h" 28#include "egllog.h" 29 30#include "pipe/p_screen.h" 31#include "util/u_memory.h" 32#include "util/u_inlines.h" 33#include "util/u_box.h" 34 35#include "egl_g3d.h" 36#include "egl_g3d_api.h" 37#include "egl_g3d_image.h" 38#include "egl_g3d_sync.h" 39#include "egl_g3d_st.h" 40#include "egl_g3d_loader.h" 41#include "native.h" 42 43/** 44 * Return the state tracker for the given context. 45 */ 46static struct st_api * 47egl_g3d_choose_st(_EGLDriver *drv, _EGLContext *ctx, 48 enum st_profile_type *profile) 49{ 50 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 51 struct st_api *stapi; 52 EGLint api = -1; 53 54 *profile = ST_PROFILE_DEFAULT; 55 56 switch (ctx->ClientAPI) { 57 case EGL_OPENGL_ES_API: 58 switch (ctx->ClientVersion) { 59 case 1: 60 api = ST_API_OPENGL; 61 *profile = ST_PROFILE_OPENGL_ES1; 62 break; 63 case 2: 64 api = ST_API_OPENGL; 65 *profile = ST_PROFILE_OPENGL_ES2; 66 break; 67 default: 68 _eglLog(_EGL_WARNING, "unknown client version %d", 69 ctx->ClientVersion); 70 break; 71 } 72 break; 73 case EGL_OPENVG_API: 74 api = ST_API_OPENVG; 75 break; 76 case EGL_OPENGL_API: 77 api = ST_API_OPENGL; 78 break; 79 default: 80 _eglLog(_EGL_WARNING, "unknown client API 0x%04x", ctx->ClientAPI); 81 break; 82 } 83 84 switch (api) { 85 case ST_API_OPENGL: 86 stapi = gdrv->loader->guess_gl_api(*profile); 87 break; 88 case ST_API_OPENVG: 89 stapi = gdrv->loader->get_st_api(api); 90 break; 91 default: 92 stapi = NULL; 93 break; 94 } 95 if (stapi && !(stapi->profile_mask & (1 << *profile))) 96 stapi = NULL; 97 98 return stapi; 99} 100 101static int 102egl_g3d_compare_config(const _EGLConfig *conf1, const _EGLConfig *conf2, 103 void *priv_data) 104{ 105 const _EGLConfig *criteria = (const _EGLConfig *) priv_data; 106 107 /* EGL_NATIVE_VISUAL_TYPE ignored? */ 108 return _eglCompareConfigs(conf1, conf2, criteria, EGL_TRUE); 109} 110 111static EGLBoolean 112egl_g3d_match_config(const _EGLConfig *conf, const _EGLConfig *criteria) 113{ 114 if (!_eglMatchConfig(conf, criteria)) 115 return EGL_FALSE; 116 117 if (criteria->MatchNativePixmap != EGL_NONE && 118 criteria->MatchNativePixmap != EGL_DONT_CARE) { 119 struct egl_g3d_display *gdpy = egl_g3d_display(conf->Display); 120 struct egl_g3d_config *gconf = egl_g3d_config(conf); 121 EGLNativePixmapType pix = 122 (EGLNativePixmapType) criteria->MatchNativePixmap; 123 124 if (!gdpy->native->is_pixmap_supported(gdpy->native, pix, gconf->native)) 125 return EGL_FALSE; 126 } 127 128 return EGL_TRUE; 129} 130 131static EGLBoolean 132egl_g3d_choose_config(_EGLDriver *drv, _EGLDisplay *dpy, const EGLint *attribs, 133 EGLConfig *configs, EGLint size, EGLint *num_configs) 134{ 135 _EGLConfig **tmp_configs, criteria; 136 EGLint tmp_size, i; 137 138 if (!num_configs) 139 return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs"); 140 141 if (!_eglParseConfigAttribList(&criteria, dpy, attribs)) 142 return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); 143 144 tmp_configs = (_EGLConfig **) _eglFilterArray(dpy->Configs, &tmp_size, 145 (_EGLArrayForEach) egl_g3d_match_config, (void *) &criteria); 146 if (!tmp_configs) 147 return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)"); 148 149 /* perform sorting of configs */ 150 if (tmp_configs && tmp_size) { 151 _eglSortConfigs((const _EGLConfig **) tmp_configs, tmp_size, 152 egl_g3d_compare_config, (void *) &criteria); 153 size = MIN2(tmp_size, size); 154 for (i = 0; i < size; i++) 155 configs[i] = _eglGetConfigHandle(tmp_configs[i]); 156 } 157 158 free(tmp_configs); 159 160 *num_configs = size; 161 162 return EGL_TRUE; 163} 164 165static _EGLContext * 166egl_g3d_create_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, 167 _EGLContext *share, const EGLint *attribs) 168{ 169 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 170 struct egl_g3d_context *gshare = egl_g3d_context(share); 171 struct egl_g3d_config *gconf = egl_g3d_config(conf); 172 struct egl_g3d_context *gctx; 173 struct st_context_attribs stattribs; 174 175 gctx = CALLOC_STRUCT(egl_g3d_context); 176 if (!gctx) { 177 _eglError(EGL_BAD_ALLOC, "eglCreateContext"); 178 return NULL; 179 } 180 181 if (!_eglInitContext(&gctx->base, dpy, conf, attribs)) { 182 FREE(gctx); 183 return NULL; 184 } 185 186 memset(&stattribs, 0, sizeof(stattribs)); 187 if (gconf) 188 stattribs.visual = gconf->stvis; 189 190 gctx->stapi = egl_g3d_choose_st(drv, &gctx->base, &stattribs.profile); 191 if (!gctx->stapi) { 192 FREE(gctx); 193 return NULL; 194 } 195 196 gctx->stctxi = gctx->stapi->create_context(gctx->stapi, gdpy->smapi, 197 &stattribs, (gshare) ? gshare->stctxi : NULL); 198 if (!gctx->stctxi) { 199 FREE(gctx); 200 return NULL; 201 } 202 203 gctx->stctxi->st_manager_private = (void *) &gctx->base; 204 205 return &gctx->base; 206} 207 208/** 209 * Destroy a context. 210 */ 211static void 212destroy_context(_EGLDisplay *dpy, _EGLContext *ctx) 213{ 214 struct egl_g3d_context *gctx = egl_g3d_context(ctx); 215 216 /* FIXME a context might live longer than its display */ 217 if (!dpy->Initialized) 218 _eglLog(_EGL_FATAL, "destroy a context with an unitialized display"); 219 220 gctx->stctxi->destroy(gctx->stctxi); 221 222 FREE(gctx); 223} 224 225static EGLBoolean 226egl_g3d_destroy_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx) 227{ 228 if (_eglPutContext(ctx)) 229 destroy_context(dpy, ctx); 230 return EGL_TRUE; 231} 232 233struct egl_g3d_create_surface_arg { 234 EGLint type; 235 union { 236 EGLNativeWindowType win; 237 EGLNativePixmapType pix; 238 } u; 239}; 240 241static _EGLSurface * 242egl_g3d_create_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, 243 struct egl_g3d_create_surface_arg *arg, 244 const EGLint *attribs) 245{ 246 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 247 struct egl_g3d_config *gconf = egl_g3d_config(conf); 248 struct egl_g3d_surface *gsurf; 249 struct native_surface *nsurf; 250 const char *err; 251 252 switch (arg->type) { 253 case EGL_WINDOW_BIT: 254 err = "eglCreateWindowSurface"; 255 break; 256 case EGL_PIXMAP_BIT: 257 err = "eglCreatePixmapSurface"; 258 break; 259#ifdef EGL_MESA_screen_surface 260 case EGL_SCREEN_BIT_MESA: 261 err = "eglCreateScreenSurface"; 262 break; 263#endif 264 default: 265 err = "eglCreateUnknownSurface"; 266 break; 267 } 268 269 gsurf = CALLOC_STRUCT(egl_g3d_surface); 270 if (!gsurf) { 271 _eglError(EGL_BAD_ALLOC, err); 272 return NULL; 273 } 274 275 if (!_eglInitSurface(&gsurf->base, dpy, arg->type, conf, attribs)) { 276 FREE(gsurf); 277 return NULL; 278 } 279 280 /* create the native surface */ 281 switch (arg->type) { 282 case EGL_WINDOW_BIT: 283 nsurf = gdpy->native->create_window_surface(gdpy->native, 284 arg->u.win, gconf->native); 285 break; 286 case EGL_PIXMAP_BIT: 287 nsurf = gdpy->native->create_pixmap_surface(gdpy->native, 288 arg->u.pix, gconf->native); 289 break; 290#ifdef EGL_MESA_screen_surface 291 case EGL_SCREEN_BIT_MESA: 292 /* prefer back buffer (move to _eglInitSurface?) */ 293 gsurf->base.RenderBuffer = EGL_BACK_BUFFER; 294 nsurf = gdpy->native->modeset->create_scanout_surface(gdpy->native, 295 gconf->native, gsurf->base.Width, gsurf->base.Height); 296 break; 297#endif 298 default: 299 nsurf = NULL; 300 break; 301 } 302 303 if (!nsurf) { 304 FREE(gsurf); 305 return NULL; 306 } 307 /* initialize the geometry */ 308 if (!nsurf->validate(nsurf, 0x0, &gsurf->sequence_number, NULL, 309 &gsurf->base.Width, &gsurf->base.Height)) { 310 nsurf->destroy(nsurf); 311 FREE(gsurf); 312 return NULL; 313 } 314 315 gsurf->stvis = gconf->stvis; 316 if (gsurf->base.RenderBuffer == EGL_SINGLE_BUFFER) 317 gsurf->stvis.render_buffer = ST_ATTACHMENT_FRONT_LEFT; 318 319 gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base); 320 if (!gsurf->stfbi) { 321 nsurf->destroy(nsurf); 322 FREE(gsurf); 323 return NULL; 324 } 325 326 nsurf->user_data = &gsurf->base; 327 gsurf->native = nsurf; 328 329 return &gsurf->base; 330} 331 332static _EGLSurface * 333egl_g3d_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy, 334 _EGLConfig *conf, EGLNativeWindowType win, 335 const EGLint *attribs) 336{ 337 struct egl_g3d_create_surface_arg arg; 338 339 memset(&arg, 0, sizeof(arg)); 340 arg.type = EGL_WINDOW_BIT; 341 arg.u.win = win; 342 343 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs); 344} 345 346static _EGLSurface * 347egl_g3d_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy, 348 _EGLConfig *conf, EGLNativePixmapType pix, 349 const EGLint *attribs) 350{ 351 struct egl_g3d_create_surface_arg arg; 352 353 memset(&arg, 0, sizeof(arg)); 354 arg.type = EGL_PIXMAP_BIT; 355 arg.u.pix = pix; 356 357 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs); 358} 359 360static struct egl_g3d_surface * 361create_pbuffer_surface(_EGLDisplay *dpy, _EGLConfig *conf, 362 const EGLint *attribs, const char *func) 363{ 364 struct egl_g3d_config *gconf = egl_g3d_config(conf); 365 struct egl_g3d_surface *gsurf; 366 367 gsurf = CALLOC_STRUCT(egl_g3d_surface); 368 if (!gsurf) { 369 _eglError(EGL_BAD_ALLOC, func); 370 return NULL; 371 } 372 373 if (!_eglInitSurface(&gsurf->base, dpy, EGL_PBUFFER_BIT, conf, attribs)) { 374 FREE(gsurf); 375 return NULL; 376 } 377 378 gsurf->stvis = gconf->stvis; 379 380 gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base); 381 if (!gsurf->stfbi) { 382 FREE(gsurf); 383 return NULL; 384 } 385 386 return gsurf; 387} 388 389static _EGLSurface * 390egl_g3d_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy, 391 _EGLConfig *conf, const EGLint *attribs) 392{ 393 struct egl_g3d_surface *gsurf; 394 struct pipe_resource *ptex = NULL; 395 396 gsurf = create_pbuffer_surface(dpy, conf, attribs, 397 "eglCreatePbufferSurface"); 398 if (!gsurf) 399 return NULL; 400 401 gsurf->client_buffer_type = EGL_NONE; 402 403 if (!gsurf->stfbi->validate(gsurf->stfbi, 404 &gsurf->stvis.render_buffer, 1, &ptex)) { 405 egl_g3d_destroy_st_framebuffer(gsurf->stfbi); 406 FREE(gsurf); 407 return NULL; 408 } 409 410 return &gsurf->base; 411} 412 413static _EGLSurface * 414egl_g3d_create_pbuffer_from_client_buffer(_EGLDriver *drv, _EGLDisplay *dpy, 415 EGLenum buftype, 416 EGLClientBuffer buffer, 417 _EGLConfig *conf, 418 const EGLint *attribs) 419{ 420 struct egl_g3d_surface *gsurf; 421 struct pipe_resource *ptex = NULL; 422 EGLint pbuffer_attribs[32]; 423 EGLint count, i; 424 425 switch (buftype) { 426 case EGL_OPENVG_IMAGE: 427 break; 428 default: 429 _eglError(EGL_BAD_PARAMETER, "eglCreatePbufferFromClientBuffer"); 430 return NULL; 431 break; 432 } 433 434 /* parse the attributes first */ 435 count = 0; 436 for (i = 0; attribs && attribs[i] != EGL_NONE; i++) { 437 EGLint attr = attribs[i++]; 438 EGLint val = attribs[i]; 439 EGLint err = EGL_SUCCESS; 440 441 switch (attr) { 442 case EGL_TEXTURE_FORMAT: 443 case EGL_TEXTURE_TARGET: 444 case EGL_MIPMAP_TEXTURE: 445 pbuffer_attribs[count++] = attr; 446 pbuffer_attribs[count++] = val; 447 break; 448 default: 449 err = EGL_BAD_ATTRIBUTE; 450 break; 451 } 452 /* bail out */ 453 if (err != EGL_SUCCESS) { 454 _eglError(err, "eglCreatePbufferFromClientBuffer"); 455 return NULL; 456 } 457 } 458 459 pbuffer_attribs[count++] = EGL_NONE; 460 461 gsurf = create_pbuffer_surface(dpy, conf, pbuffer_attribs, 462 "eglCreatePbufferFromClientBuffer"); 463 if (!gsurf) 464 return NULL; 465 466 gsurf->client_buffer_type = buftype; 467 gsurf->client_buffer = buffer; 468 469 if (!gsurf->stfbi->validate(gsurf->stfbi, 470 &gsurf->stvis.render_buffer, 1, &ptex)) { 471 egl_g3d_destroy_st_framebuffer(gsurf->stfbi); 472 FREE(gsurf); 473 return NULL; 474 } 475 476 return &gsurf->base; 477} 478 479/** 480 * Destroy a surface. 481 */ 482static void 483destroy_surface(_EGLDisplay *dpy, _EGLSurface *surf) 484{ 485 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 486 487 /* FIXME a surface might live longer than its display */ 488 if (!dpy->Initialized) 489 _eglLog(_EGL_FATAL, "destroy a surface with an unitialized display"); 490 491 pipe_resource_reference(&gsurf->render_texture, NULL); 492 egl_g3d_destroy_st_framebuffer(gsurf->stfbi); 493 if (gsurf->native) 494 gsurf->native->destroy(gsurf->native); 495 FREE(gsurf); 496} 497 498static EGLBoolean 499egl_g3d_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) 500{ 501 if (_eglPutSurface(surf)) 502 destroy_surface(dpy, surf); 503 return EGL_TRUE; 504} 505 506static EGLBoolean 507egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy, 508 _EGLSurface *draw, _EGLSurface *read, _EGLContext *ctx) 509{ 510 struct egl_g3d_context *gctx = egl_g3d_context(ctx); 511 struct egl_g3d_surface *gdraw = egl_g3d_surface(draw); 512 struct egl_g3d_surface *gread = egl_g3d_surface(read); 513 struct egl_g3d_context *old_gctx; 514 _EGLContext *old_ctx; 515 _EGLSurface *old_draw, *old_read; 516 EGLBoolean ok = EGL_TRUE; 517 518 /* make new bindings */ 519 if (!_eglBindContext(ctx, draw, read, &old_ctx, &old_draw, &old_read)) 520 return EGL_FALSE; 521 522 old_gctx = egl_g3d_context(old_ctx); 523 if (old_gctx) { 524 /* flush old context */ 525 old_gctx->stctxi->flush(old_gctx->stctxi, 526 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); 527 } 528 529 if (gctx) { 530 ok = gctx->stapi->make_current(gctx->stapi, gctx->stctxi, 531 (gdraw) ? gdraw->stfbi : NULL, (gread) ? gread->stfbi : NULL); 532 if (ok) { 533 if (gdraw) { 534 gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, 535 gdraw->stfbi); 536 537 if (gdraw->base.Type == EGL_WINDOW_BIT) { 538 gctx->base.WindowRenderBuffer = 539 (gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ? 540 EGL_SINGLE_BUFFER : EGL_BACK_BUFFER; 541 } 542 } 543 if (gread && gread != gdraw) { 544 gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, 545 gread->stfbi); 546 } 547 } 548 } 549 else if (old_gctx) { 550 ok = old_gctx->stapi->make_current(old_gctx->stapi, NULL, NULL, NULL); 551 if (ok) 552 old_gctx->base.WindowRenderBuffer = EGL_NONE; 553 } 554 555 if (ok) { 556 if (_eglPutContext(old_ctx)) 557 destroy_context(dpy, old_ctx); 558 if (_eglPutSurface(old_draw)) 559 destroy_surface(dpy, old_draw); 560 if (_eglPutSurface(old_read)) 561 destroy_surface(dpy, old_read); 562 } 563 else { 564 /* undo the previous _eglBindContext */ 565 _eglBindContext(old_ctx, old_draw, old_read, &ctx, &draw, &read); 566 assert(&gctx->base == ctx && 567 &gdraw->base == draw && 568 &gread->base == read); 569 570 _eglPutSurface(draw); 571 _eglPutSurface(read); 572 _eglPutContext(ctx); 573 574 _eglPutSurface(old_draw); 575 _eglPutSurface(old_read); 576 _eglPutContext(old_ctx); 577 } 578 579 return ok; 580} 581 582static EGLBoolean 583egl_g3d_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) 584{ 585 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 586 _EGLContext *ctx = _eglGetCurrentContext(); 587 struct egl_g3d_context *gctx = NULL; 588 589 /* no-op for pixmap or pbuffer surface */ 590 if (gsurf->base.Type == EGL_PIXMAP_BIT || 591 gsurf->base.Type == EGL_PBUFFER_BIT) 592 return EGL_TRUE; 593 594 /* or when the surface is single-buffered */ 595 if (gsurf->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) 596 return EGL_TRUE; 597 598 if (ctx && ctx->DrawSurface == surf) 599 gctx = egl_g3d_context(ctx); 600 601 /* flush if the surface is current */ 602 if (gctx) { 603 gctx->stctxi->flush(gctx->stctxi, 604 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); 605 } 606 607 return gsurf->native->present(gsurf->native, 608 NATIVE_ATTACHMENT_BACK_LEFT, 609 gsurf->base.SwapBehavior == EGL_BUFFER_PRESERVED, 610 gsurf->base.SwapInterval); 611} 612 613/** 614 * Get the pipe surface of the given attachment of the native surface. 615 */ 616static struct pipe_resource * 617get_pipe_resource(struct native_display *ndpy, struct native_surface *nsurf, 618 enum native_attachment natt) 619{ 620 struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS]; 621 622 textures[natt] = NULL; 623 nsurf->validate(nsurf, 1 << natt, NULL, textures, NULL, NULL); 624 625 return textures[natt]; 626} 627 628static EGLBoolean 629egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, 630 EGLNativePixmapType target) 631{ 632 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 633 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 634 _EGLContext *ctx = _eglGetCurrentContext(); 635 struct egl_g3d_config *gconf; 636 struct native_surface *nsurf; 637 struct pipe_resource *ptex; 638 639 if (!gsurf->render_texture) 640 return EGL_TRUE; 641 642 gconf = egl_g3d_config(egl_g3d_find_pixmap_config(dpy, target)); 643 if (!gconf) 644 return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCopyBuffers"); 645 646 nsurf = gdpy->native->create_pixmap_surface(gdpy->native, 647 target, gconf->native); 648 if (!nsurf) 649 return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCopyBuffers"); 650 651 /* flush if the surface is current */ 652 if (ctx && ctx->DrawSurface == &gsurf->base) { 653 struct egl_g3d_context *gctx = egl_g3d_context(ctx); 654 gctx->stctxi->flush(gctx->stctxi, 655 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); 656 } 657 658 /* create a pipe context to copy surfaces */ 659 if (!gdpy->pipe) { 660 gdpy->pipe = 661 gdpy->native->screen->context_create(gdpy->native->screen, NULL); 662 if (!gdpy->pipe) 663 return EGL_FALSE; 664 } 665 666 ptex = get_pipe_resource(gdpy->native, nsurf, NATIVE_ATTACHMENT_FRONT_LEFT); 667 if (ptex) { 668 struct pipe_resource *psrc = gsurf->render_texture; 669 struct pipe_box src_box; 670 u_box_origin_2d(ptex->width0, ptex->height0, &src_box); 671 if (psrc) { 672 gdpy->pipe->resource_copy_region(gdpy->pipe, ptex, 0, 0, 0, 0, 673 gsurf->render_texture, 0, &src_box); 674 nsurf->present(nsurf, NATIVE_ATTACHMENT_FRONT_LEFT, FALSE, 0); 675 } 676 677 pipe_resource_reference(&ptex, NULL); 678 } 679 680 nsurf->destroy(nsurf); 681 682 return EGL_TRUE; 683} 684 685static EGLBoolean 686egl_g3d_wait_client(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx) 687{ 688 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 689 struct egl_g3d_context *gctx = egl_g3d_context(ctx); 690 struct pipe_screen *screen = gdpy->native->screen; 691 struct pipe_fence_handle *fence = NULL; 692 693 gctx->stctxi->flush(gctx->stctxi, 694 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, &fence); 695 if (fence) { 696 screen->fence_finish(screen, fence, 0); 697 screen->fence_reference(screen, &fence, NULL); 698 } 699 700 return EGL_TRUE; 701} 702 703static EGLBoolean 704egl_g3d_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine) 705{ 706 _EGLContext *ctx = _eglGetCurrentContext(); 707 708 if (engine != EGL_CORE_NATIVE_ENGINE) 709 return _eglError(EGL_BAD_PARAMETER, "eglWaitNative"); 710 711 if (ctx && ctx->DrawSurface) { 712 struct egl_g3d_surface *gsurf = egl_g3d_surface(ctx->DrawSurface); 713 714 if (gsurf->native) 715 gsurf->native->wait(gsurf->native); 716 } 717 718 return EGL_TRUE; 719} 720 721static EGLBoolean 722egl_g3d_bind_tex_image(_EGLDriver *drv, _EGLDisplay *dpy, 723 _EGLSurface *surf, EGLint buffer) 724{ 725 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 726 _EGLContext *es1 = _eglGetAPIContext(EGL_OPENGL_ES_API); 727 struct egl_g3d_context *gctx; 728 enum pipe_format internal_format; 729 enum st_texture_type target; 730 731 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT) 732 return _eglError(EGL_BAD_SURFACE, "eglBindTexImage"); 733 if (buffer != EGL_BACK_BUFFER) 734 return _eglError(EGL_BAD_PARAMETER, "eglBindTexImage"); 735 if (gsurf->base.BoundToTexture) 736 return _eglError(EGL_BAD_ACCESS, "eglBindTexImage"); 737 738 switch (gsurf->base.TextureFormat) { 739 case EGL_TEXTURE_RGB: 740 internal_format = PIPE_FORMAT_R8G8B8_UNORM; 741 break; 742 case EGL_TEXTURE_RGBA: 743 internal_format = PIPE_FORMAT_B8G8R8A8_UNORM; 744 break; 745 default: 746 return _eglError(EGL_BAD_MATCH, "eglBindTexImage"); 747 } 748 749 switch (gsurf->base.TextureTarget) { 750 case EGL_TEXTURE_2D: 751 target = ST_TEXTURE_2D; 752 break; 753 default: 754 return _eglError(EGL_BAD_MATCH, "eglBindTexImage"); 755 } 756 757 if (!es1) 758 return EGL_TRUE; 759 if (!gsurf->render_texture) 760 return EGL_FALSE; 761 762 /* flush properly if the surface is bound */ 763 if (gsurf->base.CurrentContext) { 764 gctx = egl_g3d_context(gsurf->base.CurrentContext); 765 gctx->stctxi->flush(gctx->stctxi, 766 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); 767 } 768 769 gctx = egl_g3d_context(es1); 770 if (gctx->stctxi->teximage) { 771 if (!gctx->stctxi->teximage(gctx->stctxi, target, 772 gsurf->base.MipmapLevel, internal_format, 773 gsurf->render_texture, gsurf->base.MipmapTexture)) 774 return EGL_FALSE; 775 gsurf->base.BoundToTexture = EGL_TRUE; 776 } 777 778 return EGL_TRUE; 779} 780 781static EGLBoolean 782egl_g3d_release_tex_image(_EGLDriver *drv, _EGLDisplay *dpy, 783 _EGLSurface *surf, EGLint buffer) 784{ 785 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 786 787 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT || 788 !gsurf->base.BoundToTexture) 789 return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage"); 790 if (buffer != EGL_BACK_BUFFER) 791 return _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage"); 792 793 if (gsurf->render_texture) { 794 _EGLContext *ctx = _eglGetAPIContext(EGL_OPENGL_ES_API); 795 struct egl_g3d_context *gctx = egl_g3d_context(ctx); 796 797 /* what if the context the surface binds to is no longer current? */ 798 if (gctx) { 799 gctx->stctxi->teximage(gctx->stctxi, ST_TEXTURE_2D, 800 gsurf->base.MipmapLevel, PIPE_FORMAT_NONE, NULL, FALSE); 801 } 802 } 803 804 gsurf->base.BoundToTexture = EGL_FALSE; 805 806 return EGL_TRUE; 807} 808 809#ifdef EGL_MESA_screen_surface 810 811static _EGLSurface * 812egl_g3d_create_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy, 813 _EGLConfig *conf, const EGLint *attribs) 814{ 815 struct egl_g3d_create_surface_arg arg; 816 817 memset(&arg, 0, sizeof(arg)); 818 arg.type = EGL_SCREEN_BIT_MESA; 819 820 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs); 821} 822 823static EGLBoolean 824egl_g3d_show_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy, 825 _EGLScreen *scr, _EGLSurface *surf, 826 _EGLMode *mode) 827{ 828 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 829 struct egl_g3d_screen *gscr = egl_g3d_screen(scr); 830 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 831 struct native_surface *nsurf; 832 const struct native_mode *nmode; 833 EGLBoolean changed; 834 835 if (gsurf) { 836 EGLint idx; 837 838 if (!mode) 839 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA"); 840 if (gsurf->base.Type != EGL_SCREEN_BIT_MESA) 841 return _eglError(EGL_BAD_SURFACE, "eglShowScreenSurfaceMESA"); 842 if (gsurf->base.Width < mode->Width || gsurf->base.Height < mode->Height) 843 return _eglError(EGL_BAD_MATCH, 844 "eglShowSurfaceMESA(surface smaller than mode size)"); 845 846 /* find the index of the mode */ 847 for (idx = 0; idx < gscr->base.NumModes; idx++) 848 if (mode == &gscr->base.Modes[idx]) 849 break; 850 if (idx >= gscr->base.NumModes) { 851 return _eglError(EGL_BAD_MODE_MESA, 852 "eglShowSurfaceMESA(unknown mode)"); 853 } 854 855 nsurf = gsurf->native; 856 nmode = gscr->native_modes[idx]; 857 } 858 else { 859 if (mode) 860 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA"); 861 862 /* disable the screen */ 863 nsurf = NULL; 864 nmode = NULL; 865 } 866 867 /* TODO surface panning by CRTC choosing */ 868 changed = gdpy->native->modeset->program(gdpy->native, 0, nsurf, 869 gscr->base.OriginX, gscr->base.OriginY, &gscr->native, 1, nmode); 870 if (changed) { 871 gscr->base.CurrentSurface = &gsurf->base; 872 gscr->base.CurrentMode = mode; 873 } 874 875 return changed; 876} 877 878#endif /* EGL_MESA_screen_surface */ 879 880/** 881 * Find a config that supports the pixmap. 882 */ 883_EGLConfig * 884egl_g3d_find_pixmap_config(_EGLDisplay *dpy, EGLNativePixmapType pix) 885{ 886 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 887 struct egl_g3d_config *gconf; 888 EGLint i; 889 890 for (i = 0; i < dpy->Configs->Size; i++) { 891 gconf = egl_g3d_config((_EGLConfig *) dpy->Configs->Elements[i]); 892 if (gdpy->native->is_pixmap_supported(gdpy->native, pix, gconf->native)) 893 break; 894 } 895 896 return (i < dpy->Configs->Size) ? &gconf->base : NULL; 897} 898 899void 900egl_g3d_init_driver_api(_EGLDriver *drv) 901{ 902 _eglInitDriverFallbacks(drv); 903 904 drv->API.ChooseConfig = egl_g3d_choose_config; 905 906 drv->API.CreateContext = egl_g3d_create_context; 907 drv->API.DestroyContext = egl_g3d_destroy_context; 908 drv->API.CreateWindowSurface = egl_g3d_create_window_surface; 909 drv->API.CreatePixmapSurface = egl_g3d_create_pixmap_surface; 910 drv->API.CreatePbufferSurface = egl_g3d_create_pbuffer_surface; 911 drv->API.CreatePbufferFromClientBuffer = egl_g3d_create_pbuffer_from_client_buffer; 912 drv->API.DestroySurface = egl_g3d_destroy_surface; 913 drv->API.MakeCurrent = egl_g3d_make_current; 914 drv->API.SwapBuffers = egl_g3d_swap_buffers; 915 drv->API.CopyBuffers = egl_g3d_copy_buffers; 916 drv->API.WaitClient = egl_g3d_wait_client; 917 drv->API.WaitNative = egl_g3d_wait_native; 918 919 drv->API.BindTexImage = egl_g3d_bind_tex_image; 920 drv->API.ReleaseTexImage = egl_g3d_release_tex_image; 921 922 drv->API.CreateImageKHR = egl_g3d_create_image; 923 drv->API.DestroyImageKHR = egl_g3d_destroy_image; 924#ifdef EGL_MESA_drm_image 925 drv->API.CreateDRMImageMESA = egl_g3d_create_drm_image; 926 drv->API.ExportDRMImageMESA = egl_g3d_export_drm_image; 927#endif 928 929#ifdef EGL_KHR_reusable_sync 930 drv->API.CreateSyncKHR = egl_g3d_create_sync; 931 drv->API.DestroySyncKHR = egl_g3d_destroy_sync; 932 drv->API.ClientWaitSyncKHR = egl_g3d_client_wait_sync; 933 drv->API.SignalSyncKHR = egl_g3d_signal_sync; 934#endif 935 936#ifdef EGL_MESA_screen_surface 937 drv->API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface; 938 drv->API.ShowScreenSurfaceMESA = egl_g3d_show_screen_surface; 939#endif 940} 941