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