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