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