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