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