egl_g3d_api.c revision 04ae53ca8a844fbb2764b6ecb942b68a6db850e7
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 34#include "egl_g3d.h" 35#include "egl_g3d_api.h" 36#include "egl_g3d_image.h" 37#include "egl_g3d_sync.h" 38#include "egl_g3d_st.h" 39#include "egl_g3d_loader.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 egl_g3d_driver *gdrv = egl_g3d_driver(drv); 50 struct st_api *stapi; 51 EGLint api = -1; 52 53 *profile = ST_PROFILE_DEFAULT; 54 55 switch (ctx->ClientAPI) { 56 case EGL_OPENGL_ES_API: 57 switch (ctx->ClientVersion) { 58 case 1: 59 api = ST_API_OPENGL; 60 *profile = ST_PROFILE_OPENGL_ES1; 61 break; 62 case 2: 63 api = ST_API_OPENGL; 64 *profile = ST_PROFILE_OPENGL_ES2; 65 break; 66 default: 67 _eglLog(_EGL_WARNING, "unknown client version %d", 68 ctx->ClientVersion); 69 break; 70 } 71 break; 72 case EGL_OPENVG_API: 73 api = ST_API_OPENVG; 74 break; 75 case EGL_OPENGL_API: 76 api = ST_API_OPENGL; 77 break; 78 default: 79 _eglLog(_EGL_WARNING, "unknown client API 0x%04x", ctx->ClientAPI); 80 break; 81 } 82 83 switch (api) { 84 case ST_API_OPENGL: 85 stapi = gdrv->loader->guess_gl_api(*profile); 86 break; 87 case ST_API_OPENVG: 88 stapi = gdrv->loader->get_st_api(api); 89 break; 90 default: 91 stapi = NULL; 92 break; 93 } 94 if (stapi && !(stapi->profile_mask & (1 << *profile))) 95 stapi = NULL; 96 97 return stapi; 98} 99 100static int 101egl_g3d_compare_config(const _EGLConfig *conf1, const _EGLConfig *conf2, 102 void *priv_data) 103{ 104 const _EGLConfig *criteria = (const _EGLConfig *) priv_data; 105 106 /* EGL_NATIVE_VISUAL_TYPE ignored? */ 107 return _eglCompareConfigs(conf1, conf2, criteria, EGL_TRUE); 108} 109 110static EGLBoolean 111egl_g3d_match_config(const _EGLConfig *conf, const _EGLConfig *criteria) 112{ 113 if (!_eglMatchConfig(conf, criteria)) 114 return EGL_FALSE; 115 116 if (criteria->MatchNativePixmap != EGL_NONE && 117 criteria->MatchNativePixmap != EGL_DONT_CARE) { 118 struct egl_g3d_display *gdpy = egl_g3d_display(conf->Display); 119 struct egl_g3d_config *gconf = egl_g3d_config(conf); 120 EGLNativePixmapType pix = 121 (EGLNativePixmapType) criteria->MatchNativePixmap; 122 123 if (!gdpy->native->is_pixmap_supported(gdpy->native, pix, gconf->native)) 124 return EGL_FALSE; 125 } 126 127 return EGL_TRUE; 128} 129 130static EGLBoolean 131egl_g3d_choose_config(_EGLDriver *drv, _EGLDisplay *dpy, const EGLint *attribs, 132 EGLConfig *configs, EGLint size, EGLint *num_configs) 133{ 134 _EGLConfig **tmp_configs, criteria; 135 EGLint tmp_size, i; 136 137 if (!num_configs) 138 return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs"); 139 140 if (!_eglParseConfigAttribList(&criteria, dpy, attribs)) 141 return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); 142 143 tmp_configs = (_EGLConfig **) _eglFilterArray(dpy->Configs, &tmp_size, 144 (_EGLArrayForEach) egl_g3d_match_config, (void *) &criteria); 145 if (!tmp_configs) 146 return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)"); 147 148 /* perform sorting of configs */ 149 if (tmp_configs && tmp_size) { 150 _eglSortConfigs((const _EGLConfig **) tmp_configs, tmp_size, 151 egl_g3d_compare_config, (void *) &criteria); 152 size = MIN2(tmp_size, size); 153 for (i = 0; i < size; i++) 154 configs[i] = _eglGetConfigHandle(tmp_configs[i]); 155 } 156 157 free(tmp_configs); 158 159 *num_configs = 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 gsurf->stvis.render_buffer = ST_ATTACHMENT_FRONT_LEFT; 317 318 gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base); 319 if (!gsurf->stfbi) { 320 nsurf->destroy(nsurf); 321 FREE(gsurf); 322 return NULL; 323 } 324 325 nsurf->user_data = &gsurf->base; 326 gsurf->native = nsurf; 327 328 return &gsurf->base; 329} 330 331static _EGLSurface * 332egl_g3d_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy, 333 _EGLConfig *conf, EGLNativeWindowType win, 334 const EGLint *attribs) 335{ 336 struct egl_g3d_create_surface_arg arg; 337 338 memset(&arg, 0, sizeof(arg)); 339 arg.type = EGL_WINDOW_BIT; 340 arg.u.win = win; 341 342 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs); 343} 344 345static _EGLSurface * 346egl_g3d_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy, 347 _EGLConfig *conf, EGLNativePixmapType pix, 348 const EGLint *attribs) 349{ 350 struct egl_g3d_create_surface_arg arg; 351 352 memset(&arg, 0, sizeof(arg)); 353 arg.type = EGL_PIXMAP_BIT; 354 arg.u.pix = pix; 355 356 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs); 357} 358 359static struct egl_g3d_surface * 360create_pbuffer_surface(_EGLDisplay *dpy, _EGLConfig *conf, 361 const EGLint *attribs, const char *func) 362{ 363 struct egl_g3d_config *gconf = egl_g3d_config(conf); 364 struct egl_g3d_surface *gsurf; 365 366 gsurf = CALLOC_STRUCT(egl_g3d_surface); 367 if (!gsurf) { 368 _eglError(EGL_BAD_ALLOC, func); 369 return NULL; 370 } 371 372 if (!_eglInitSurface(&gsurf->base, dpy, EGL_PBUFFER_BIT, conf, attribs)) { 373 FREE(gsurf); 374 return NULL; 375 } 376 377 gsurf->stvis = gconf->stvis; 378 379 gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base); 380 if (!gsurf->stfbi) { 381 FREE(gsurf); 382 return NULL; 383 } 384 385 return gsurf; 386} 387 388static _EGLSurface * 389egl_g3d_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy, 390 _EGLConfig *conf, const EGLint *attribs) 391{ 392 struct egl_g3d_surface *gsurf; 393 struct pipe_resource *ptex = NULL; 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 if (!gsurf->stfbi->validate(gsurf->stfbi, 403 &gsurf->stvis.render_buffer, 1, &ptex)) { 404 egl_g3d_destroy_st_framebuffer(gsurf->stfbi); 405 FREE(gsurf); 406 return NULL; 407 } 408 409 return &gsurf->base; 410} 411 412static _EGLSurface * 413egl_g3d_create_pbuffer_from_client_buffer(_EGLDriver *drv, _EGLDisplay *dpy, 414 EGLenum buftype, 415 EGLClientBuffer buffer, 416 _EGLConfig *conf, 417 const EGLint *attribs) 418{ 419 struct egl_g3d_surface *gsurf; 420 struct pipe_resource *ptex = NULL; 421 EGLint pbuffer_attribs[32]; 422 EGLint count, i; 423 424 switch (buftype) { 425 case EGL_OPENVG_IMAGE: 426 break; 427 default: 428 _eglError(EGL_BAD_PARAMETER, "eglCreatePbufferFromClientBuffer"); 429 return NULL; 430 break; 431 } 432 433 /* parse the attributes first */ 434 count = 0; 435 for (i = 0; attribs && attribs[i] != EGL_NONE; i++) { 436 EGLint attr = attribs[i++]; 437 EGLint val = attribs[i]; 438 EGLint err = EGL_SUCCESS; 439 440 switch (attr) { 441 case EGL_TEXTURE_FORMAT: 442 case EGL_TEXTURE_TARGET: 443 case EGL_MIPMAP_TEXTURE: 444 pbuffer_attribs[count++] = attr; 445 pbuffer_attribs[count++] = val; 446 break; 447 default: 448 err = EGL_BAD_ATTRIBUTE; 449 break; 450 } 451 /* bail out */ 452 if (err != EGL_SUCCESS) { 453 _eglError(err, "eglCreatePbufferFromClientBuffer"); 454 return NULL; 455 } 456 } 457 458 pbuffer_attribs[count++] = EGL_NONE; 459 460 gsurf = create_pbuffer_surface(dpy, conf, pbuffer_attribs, 461 "eglCreatePbufferFromClientBuffer"); 462 if (!gsurf) 463 return NULL; 464 465 gsurf->client_buffer_type = buftype; 466 gsurf->client_buffer = buffer; 467 468 if (!gsurf->stfbi->validate(gsurf->stfbi, 469 &gsurf->stvis.render_buffer, 1, &ptex)) { 470 egl_g3d_destroy_st_framebuffer(gsurf->stfbi); 471 FREE(gsurf); 472 return NULL; 473 } 474 475 return &gsurf->base; 476} 477 478/** 479 * Destroy a surface. 480 */ 481static void 482destroy_surface(_EGLDisplay *dpy, _EGLSurface *surf) 483{ 484 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 485 486 /* FIXME a surface might live longer than its display */ 487 if (!dpy->Initialized) 488 _eglLog(_EGL_FATAL, "destroy a surface with an unitialized display"); 489 490 pipe_resource_reference(&gsurf->render_texture, NULL); 491 egl_g3d_destroy_st_framebuffer(gsurf->stfbi); 492 if (gsurf->native) 493 gsurf->native->destroy(gsurf->native); 494 FREE(gsurf); 495} 496 497static EGLBoolean 498egl_g3d_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) 499{ 500 if (_eglPutSurface(surf)) 501 destroy_surface(dpy, surf); 502 return EGL_TRUE; 503} 504 505static EGLBoolean 506egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy, 507 _EGLSurface *draw, _EGLSurface *read, _EGLContext *ctx) 508{ 509 struct egl_g3d_context *gctx = egl_g3d_context(ctx); 510 struct egl_g3d_surface *gdraw = egl_g3d_surface(draw); 511 struct egl_g3d_surface *gread = egl_g3d_surface(read); 512 struct egl_g3d_context *old_gctx; 513 _EGLContext *old_ctx; 514 _EGLSurface *old_draw, *old_read; 515 EGLBoolean ok = EGL_TRUE; 516 517 /* make new bindings */ 518 if (!_eglBindContext(ctx, draw, read, &old_ctx, &old_draw, &old_read)) 519 return EGL_FALSE; 520 521 old_gctx = egl_g3d_context(old_ctx); 522 if (old_gctx) { 523 /* flush old context */ 524 old_gctx->stctxi->flush(old_gctx->stctxi, 525 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); 526 } 527 528 if (gctx) { 529 ok = gctx->stapi->make_current(gctx->stapi, gctx->stctxi, 530 (gdraw) ? gdraw->stfbi : NULL, (gread) ? gread->stfbi : NULL); 531 if (ok) { 532 if (gdraw) { 533 gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, 534 gdraw->stfbi); 535 536 if (gdraw->base.Type == EGL_WINDOW_BIT) { 537 gctx->base.WindowRenderBuffer = 538 (gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ? 539 EGL_SINGLE_BUFFER : EGL_BACK_BUFFER; 540 } 541 } 542 if (gread && gread != gdraw) { 543 gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, 544 gread->stfbi); 545 } 546 } 547 } 548 else if (old_gctx) { 549 ok = old_gctx->stapi->make_current(old_gctx->stapi, NULL, NULL, NULL); 550 if (ok) 551 old_gctx->base.WindowRenderBuffer = EGL_NONE; 552 } 553 554 if (ok) { 555 if (_eglPutContext(old_ctx)) 556 destroy_context(dpy, old_ctx); 557 if (_eglPutSurface(old_draw)) 558 destroy_surface(dpy, old_draw); 559 if (_eglPutSurface(old_read)) 560 destroy_surface(dpy, old_read); 561 } 562 else { 563 /* undo the previous _eglBindContext */ 564 _eglBindContext(old_ctx, old_draw, old_read, &ctx, &draw, &read); 565 assert(&gctx->base == ctx && 566 &gdraw->base == draw && 567 &gread->base == read); 568 569 _eglPutSurface(draw); 570 _eglPutSurface(read); 571 _eglPutContext(ctx); 572 573 _eglPutSurface(old_draw); 574 _eglPutSurface(old_read); 575 _eglPutContext(old_ctx); 576 } 577 578 return ok; 579} 580 581static EGLBoolean 582egl_g3d_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) 583{ 584 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 585 _EGLContext *ctx = _eglGetCurrentContext(); 586 struct egl_g3d_context *gctx = NULL; 587 588 /* no-op for pixmap or pbuffer surface */ 589 if (gsurf->base.Type == EGL_PIXMAP_BIT || 590 gsurf->base.Type == EGL_PBUFFER_BIT) 591 return EGL_TRUE; 592 593 /* or when the surface is single-buffered */ 594 if (gsurf->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) 595 return EGL_TRUE; 596 597 if (ctx && ctx->DrawSurface == surf) 598 gctx = egl_g3d_context(ctx); 599 600 /* flush if the surface is current */ 601 if (gctx) { 602 gctx->stctxi->flush(gctx->stctxi, 603 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); 604 } 605 606 return gsurf->native->present(gsurf->native, 607 NATIVE_ATTACHMENT_BACK_LEFT, 608 gsurf->base.SwapBehavior == EGL_BUFFER_PRESERVED, 609 gsurf->base.SwapInterval); 610} 611 612/** 613 * Get the pipe surface of the given attachment of the native surface. 614 */ 615static struct pipe_resource * 616get_pipe_resource(struct native_display *ndpy, struct native_surface *nsurf, 617 enum native_attachment natt) 618{ 619 struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS]; 620 621 textures[natt] = NULL; 622 nsurf->validate(nsurf, 1 << natt, NULL, textures, NULL, NULL); 623 624 return textures[natt]; 625} 626 627static EGLBoolean 628egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, 629 EGLNativePixmapType target) 630{ 631 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 632 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 633 _EGLContext *ctx = _eglGetCurrentContext(); 634 struct egl_g3d_config *gconf; 635 struct native_surface *nsurf; 636 struct pipe_resource *ptex; 637 638 if (!gsurf->render_texture) 639 return EGL_TRUE; 640 641 gconf = egl_g3d_config(egl_g3d_find_pixmap_config(dpy, target)); 642 if (!gconf) 643 return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCopyBuffers"); 644 645 nsurf = gdpy->native->create_pixmap_surface(gdpy->native, 646 target, gconf->native); 647 if (!nsurf) 648 return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCopyBuffers"); 649 650 /* flush if the surface is current */ 651 if (ctx && ctx->DrawSurface == &gsurf->base) { 652 struct egl_g3d_context *gctx = egl_g3d_context(ctx); 653 gctx->stctxi->flush(gctx->stctxi, 654 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); 655 } 656 657 /* create a pipe context to copy surfaces */ 658 if (!gdpy->pipe) { 659 gdpy->pipe = 660 gdpy->native->screen->context_create(gdpy->native->screen, NULL); 661 if (!gdpy->pipe) 662 return EGL_FALSE; 663 } 664 665 ptex = get_pipe_resource(gdpy->native, nsurf, NATIVE_ATTACHMENT_FRONT_LEFT); 666 if (ptex) { 667 struct pipe_resource *psrc = gsurf->render_texture; 668 struct pipe_subresource subsrc, subdst; 669 subsrc.face = 0; 670 subsrc.level = 0; 671 subdst.face = 0; 672 subdst.level = 0; 673 674 if (psrc) { 675 gdpy->pipe->resource_copy_region(gdpy->pipe, ptex, subdst, 0, 0, 0, 676 gsurf->render_texture, subsrc, 0, 0, 0, ptex->width0, ptex->height0); 677 nsurf->present(nsurf, NATIVE_ATTACHMENT_FRONT_LEFT, FALSE, 0); 678 } 679 680 pipe_resource_reference(&ptex, NULL); 681 } 682 683 nsurf->destroy(nsurf); 684 685 return EGL_TRUE; 686} 687 688static EGLBoolean 689egl_g3d_wait_client(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx) 690{ 691 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 692 struct egl_g3d_context *gctx = egl_g3d_context(ctx); 693 struct pipe_screen *screen = gdpy->native->screen; 694 struct pipe_fence_handle *fence = NULL; 695 696 gctx->stctxi->flush(gctx->stctxi, 697 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, &fence); 698 if (fence) { 699 screen->fence_finish(screen, fence, 0); 700 screen->fence_reference(screen, &fence, NULL); 701 } 702 703 return EGL_TRUE; 704} 705 706static EGLBoolean 707egl_g3d_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine) 708{ 709 _EGLContext *ctx = _eglGetCurrentContext(); 710 711 if (engine != EGL_CORE_NATIVE_ENGINE) 712 return _eglError(EGL_BAD_PARAMETER, "eglWaitNative"); 713 714 if (ctx && ctx->DrawSurface) { 715 struct egl_g3d_surface *gsurf = egl_g3d_surface(ctx->DrawSurface); 716 717 if (gsurf->native) 718 gsurf->native->wait(gsurf->native); 719 } 720 721 return EGL_TRUE; 722} 723 724static EGLBoolean 725egl_g3d_bind_tex_image(_EGLDriver *drv, _EGLDisplay *dpy, 726 _EGLSurface *surf, EGLint buffer) 727{ 728 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 729 _EGLContext *es1 = _eglGetAPIContext(EGL_OPENGL_ES_API); 730 struct egl_g3d_context *gctx; 731 enum pipe_format internal_format; 732 enum st_texture_type target; 733 734 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT) 735 return _eglError(EGL_BAD_SURFACE, "eglBindTexImage"); 736 if (buffer != EGL_BACK_BUFFER) 737 return _eglError(EGL_BAD_PARAMETER, "eglBindTexImage"); 738 if (gsurf->base.BoundToTexture) 739 return _eglError(EGL_BAD_ACCESS, "eglBindTexImage"); 740 741 switch (gsurf->base.TextureFormat) { 742 case EGL_TEXTURE_RGB: 743 internal_format = PIPE_FORMAT_R8G8B8_UNORM; 744 break; 745 case EGL_TEXTURE_RGBA: 746 internal_format = PIPE_FORMAT_B8G8R8A8_UNORM; 747 break; 748 default: 749 return _eglError(EGL_BAD_MATCH, "eglBindTexImage"); 750 } 751 752 switch (gsurf->base.TextureTarget) { 753 case EGL_TEXTURE_2D: 754 target = ST_TEXTURE_2D; 755 break; 756 default: 757 return _eglError(EGL_BAD_MATCH, "eglBindTexImage"); 758 } 759 760 if (!es1) 761 return EGL_TRUE; 762 if (!gsurf->render_texture) 763 return EGL_FALSE; 764 765 /* flush properly if the surface is bound */ 766 if (gsurf->base.CurrentContext) { 767 gctx = egl_g3d_context(gsurf->base.CurrentContext); 768 gctx->stctxi->flush(gctx->stctxi, 769 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); 770 } 771 772 gctx = egl_g3d_context(es1); 773 if (gctx->stctxi->teximage) { 774 if (!gctx->stctxi->teximage(gctx->stctxi, target, 775 gsurf->base.MipmapLevel, internal_format, 776 gsurf->render_texture, gsurf->base.MipmapTexture)) 777 return EGL_FALSE; 778 gsurf->base.BoundToTexture = EGL_TRUE; 779 } 780 781 return EGL_TRUE; 782} 783 784static EGLBoolean 785egl_g3d_release_tex_image(_EGLDriver *drv, _EGLDisplay *dpy, 786 _EGLSurface *surf, EGLint buffer) 787{ 788 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 789 790 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT || 791 !gsurf->base.BoundToTexture) 792 return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage"); 793 if (buffer != EGL_BACK_BUFFER) 794 return _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage"); 795 796 if (gsurf->render_texture) { 797 _EGLContext *ctx = _eglGetAPIContext(EGL_OPENGL_ES_API); 798 struct egl_g3d_context *gctx = egl_g3d_context(ctx); 799 800 /* what if the context the surface binds to is no longer current? */ 801 if (gctx) { 802 gctx->stctxi->teximage(gctx->stctxi, ST_TEXTURE_2D, 803 gsurf->base.MipmapLevel, PIPE_FORMAT_NONE, NULL, FALSE); 804 } 805 } 806 807 gsurf->base.BoundToTexture = EGL_FALSE; 808 809 return EGL_TRUE; 810} 811 812#ifdef EGL_MESA_screen_surface 813 814static _EGLSurface * 815egl_g3d_create_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy, 816 _EGLConfig *conf, const EGLint *attribs) 817{ 818 struct egl_g3d_create_surface_arg arg; 819 820 memset(&arg, 0, sizeof(arg)); 821 arg.type = EGL_SCREEN_BIT_MESA; 822 823 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs); 824} 825 826static EGLBoolean 827egl_g3d_show_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy, 828 _EGLScreen *scr, _EGLSurface *surf, 829 _EGLMode *mode) 830{ 831 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 832 struct egl_g3d_screen *gscr = egl_g3d_screen(scr); 833 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 834 struct native_surface *nsurf; 835 const struct native_mode *nmode; 836 EGLBoolean changed; 837 838 if (gsurf) { 839 EGLint idx; 840 841 if (!mode) 842 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA"); 843 if (gsurf->base.Type != EGL_SCREEN_BIT_MESA) 844 return _eglError(EGL_BAD_SURFACE, "eglShowScreenSurfaceMESA"); 845 if (gsurf->base.Width < mode->Width || gsurf->base.Height < mode->Height) 846 return _eglError(EGL_BAD_MATCH, 847 "eglShowSurfaceMESA(surface smaller than mode size)"); 848 849 /* find the index of the mode */ 850 for (idx = 0; idx < gscr->base.NumModes; idx++) 851 if (mode == &gscr->base.Modes[idx]) 852 break; 853 if (idx >= gscr->base.NumModes) { 854 return _eglError(EGL_BAD_MODE_MESA, 855 "eglShowSurfaceMESA(unknown mode)"); 856 } 857 858 nsurf = gsurf->native; 859 nmode = gscr->native_modes[idx]; 860 } 861 else { 862 if (mode) 863 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA"); 864 865 /* disable the screen */ 866 nsurf = NULL; 867 nmode = NULL; 868 } 869 870 /* TODO surface panning by CRTC choosing */ 871 changed = gdpy->native->modeset->program(gdpy->native, 0, nsurf, 872 gscr->base.OriginX, gscr->base.OriginY, &gscr->native, 1, nmode); 873 if (changed) { 874 gscr->base.CurrentSurface = &gsurf->base; 875 gscr->base.CurrentMode = mode; 876 } 877 878 return changed; 879} 880 881#endif /* EGL_MESA_screen_surface */ 882 883/** 884 * Find a config that supports the pixmap. 885 */ 886_EGLConfig * 887egl_g3d_find_pixmap_config(_EGLDisplay *dpy, EGLNativePixmapType pix) 888{ 889 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 890 struct egl_g3d_config *gconf; 891 EGLint i; 892 893 for (i = 0; i < dpy->Configs->Size; i++) { 894 gconf = egl_g3d_config((_EGLConfig *) dpy->Configs->Elements[i]); 895 if (gdpy->native->is_pixmap_supported(gdpy->native, pix, gconf->native)) 896 break; 897 } 898 899 return (i < dpy->Configs->Size) ? &gconf->base : NULL; 900} 901 902void 903egl_g3d_init_driver_api(_EGLDriver *drv) 904{ 905 _eglInitDriverFallbacks(drv); 906 907 drv->API.ChooseConfig = egl_g3d_choose_config; 908 909 drv->API.CreateContext = egl_g3d_create_context; 910 drv->API.DestroyContext = egl_g3d_destroy_context; 911 drv->API.CreateWindowSurface = egl_g3d_create_window_surface; 912 drv->API.CreatePixmapSurface = egl_g3d_create_pixmap_surface; 913 drv->API.CreatePbufferSurface = egl_g3d_create_pbuffer_surface; 914 drv->API.CreatePbufferFromClientBuffer = egl_g3d_create_pbuffer_from_client_buffer; 915 drv->API.DestroySurface = egl_g3d_destroy_surface; 916 drv->API.MakeCurrent = egl_g3d_make_current; 917 drv->API.SwapBuffers = egl_g3d_swap_buffers; 918 drv->API.CopyBuffers = egl_g3d_copy_buffers; 919 drv->API.WaitClient = egl_g3d_wait_client; 920 drv->API.WaitNative = egl_g3d_wait_native; 921 922 drv->API.BindTexImage = egl_g3d_bind_tex_image; 923 drv->API.ReleaseTexImage = egl_g3d_release_tex_image; 924 925 drv->API.CreateImageKHR = egl_g3d_create_image; 926 drv->API.DestroyImageKHR = egl_g3d_destroy_image; 927#ifdef EGL_MESA_drm_image 928 drv->API.CreateDRMImageMESA = egl_g3d_create_drm_image; 929 drv->API.ExportDRMImageMESA = egl_g3d_export_drm_image; 930#endif 931 932#ifdef EGL_KHR_reusable_sync 933 drv->API.CreateSyncKHR = egl_g3d_create_sync; 934 drv->API.DestroySyncKHR = egl_g3d_destroy_sync; 935 drv->API.ClientWaitSyncKHR = egl_g3d_client_wait_sync; 936 drv->API.SignalSyncKHR = egl_g3d_signal_sync; 937#endif 938 939#ifdef EGL_MESA_screen_surface 940 drv->API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface; 941 drv->API.ShowScreenSurfaceMESA = egl_g3d_show_screen_surface; 942#endif 943} 944