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