egl_g3d.c revision ba81b0743efd978509b1931d7b4b93f37e8aeb5e
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.8 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 <assert.h> 27#include <stdio.h> 28#include <string.h> 29#include "pipe/p_screen.h" 30#include "util/u_memory.h" 31#include "util/u_rect.h" 32#include "util/u_inlines.h" 33#include "egldriver.h" 34#include "eglcurrent.h" 35#include "eglconfigutil.h" 36#include "egllog.h" 37 38#include "native.h" 39#include "egl_g3d.h" 40#include "egl_g3d_st.h" 41#include "egl_g3d_image.h" 42 43/** 44 * Return the state tracker for the given context. 45 */ 46static struct st_api * 47egl_g3d_choose_st(_EGLDriver *drv, _EGLContext *ctx) 48{ 49 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 50 struct st_api *stapi; 51 EGLint idx = -1; 52 53 switch (ctx->ClientAPI) { 54 case EGL_OPENGL_ES_API: 55 switch (ctx->ClientVersion) { 56 case 1: 57 idx = ST_API_OPENGL_ES1; 58 break; 59 case 2: 60 idx = ST_API_OPENGL_ES2; 61 break; 62 default: 63 _eglLog(_EGL_WARNING, "unknown client version %d", 64 ctx->ClientVersion); 65 break; 66 } 67 break; 68 case EGL_OPENVG_API: 69 idx = ST_API_OPENVG; 70 break; 71 case EGL_OPENGL_API: 72 idx = ST_API_OPENGL; 73 break; 74 default: 75 _eglLog(_EGL_WARNING, "unknown client API 0x%04x", ctx->ClientAPI); 76 break; 77 } 78 79 stapi = (idx >= 0) ? gdrv->stapis[idx] : NULL; 80 return stapi; 81} 82 83/** 84 * Initialize the state trackers. 85 */ 86static void 87egl_g3d_init_st(_EGLDriver *drv) 88{ 89 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 90 EGLint i; 91 92 /* already initialized */ 93 if (gdrv->api_mask) 94 return; 95 96 for (i = 0; i < ST_API_COUNT; i++) { 97 gdrv->stapis[i] = egl_g3d_create_st_api(i); 98 if (gdrv->stapis[i]) 99 gdrv->api_mask |= egl_g3d_st_api_bit(i); 100 } 101 102 if (gdrv->api_mask) 103 _eglLog(_EGL_DEBUG, "Driver API mask: 0x%x", gdrv->api_mask); 104 else 105 _eglLog(_EGL_WARNING, "No supported client API"); 106} 107 108/** 109 * Get the probe object of the display. 110 * 111 * Note that this function may be called before the display is initialized. 112 */ 113static struct native_probe * 114egl_g3d_get_probe(_EGLDriver *drv, _EGLDisplay *dpy) 115{ 116 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 117 struct native_probe *nprobe; 118 119 nprobe = (struct native_probe *) _eglGetProbeCache(gdrv->probe_key); 120 if (!nprobe || nprobe->display != dpy->NativeDisplay) { 121 if (nprobe) 122 nprobe->destroy(nprobe); 123 nprobe = native_create_probe(dpy->NativeDisplay); 124 _eglSetProbeCache(gdrv->probe_key, (void *) nprobe); 125 } 126 127 return nprobe; 128} 129 130/** 131 * Destroy the probe object of the display. The display may be NULL. 132 * 133 * Note that this function may be called before the display is initialized. 134 */ 135static void 136egl_g3d_destroy_probe(_EGLDriver *drv, _EGLDisplay *dpy) 137{ 138 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 139 struct native_probe *nprobe; 140 141 nprobe = (struct native_probe *) _eglGetProbeCache(gdrv->probe_key); 142 if (nprobe && (!dpy || nprobe->display == dpy->NativeDisplay)) { 143 nprobe->destroy(nprobe); 144 _eglSetProbeCache(gdrv->probe_key, NULL); 145 } 146} 147 148#ifdef EGL_MESA_screen_surface 149 150static void 151egl_g3d_add_screens(_EGLDriver *drv, _EGLDisplay *dpy) 152{ 153 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 154 const struct native_connector **native_connectors; 155 EGLint num_connectors, i; 156 157 native_connectors = 158 gdpy->native->modeset->get_connectors(gdpy->native, &num_connectors, NULL); 159 if (!num_connectors) { 160 if (native_connectors) 161 free(native_connectors); 162 return; 163 } 164 165 for (i = 0; i < num_connectors; i++) { 166 const struct native_connector *nconn = native_connectors[i]; 167 struct egl_g3d_screen *gscr; 168 const struct native_mode **native_modes; 169 EGLint num_modes, j; 170 171 /* TODO support for hotplug */ 172 native_modes = 173 gdpy->native->modeset->get_modes(gdpy->native, nconn, &num_modes); 174 if (!num_modes) { 175 if (native_modes) 176 free(native_modes); 177 continue; 178 } 179 180 gscr = CALLOC_STRUCT(egl_g3d_screen); 181 if (!gscr) { 182 free(native_modes); 183 continue; 184 } 185 186 _eglInitScreen(&gscr->base); 187 188 for (j = 0; j < num_modes; j++) { 189 const struct native_mode *nmode = native_modes[j]; 190 _EGLMode *mode; 191 192 mode = _eglAddNewMode(&gscr->base, nmode->width, nmode->height, 193 nmode->refresh_rate, nmode->desc); 194 if (!mode) 195 break; 196 /* gscr->native_modes and gscr->base.Modes should be consistent */ 197 assert(mode == &gscr->base.Modes[j]); 198 } 199 200 gscr->native = nconn; 201 gscr->native_modes = native_modes; 202 203 _eglAddScreen(dpy, &gscr->base); 204 } 205 206 free(native_connectors); 207} 208 209#endif /* EGL_MESA_screen_surface */ 210 211/** 212 * Initialize an EGL config from the native config. 213 */ 214static EGLBoolean 215egl_g3d_init_config(_EGLDriver *drv, _EGLDisplay *dpy, 216 _EGLConfig *conf, const struct native_config *nconf) 217{ 218 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 219 struct egl_g3d_config *gconf = egl_g3d_config(conf); 220 const __GLcontextModes *mode = &nconf->mode; 221 EGLint buffer_mask, api_mask; 222 EGLBoolean valid; 223 EGLint i; 224 225 buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK; 226 if (mode->doubleBufferMode) 227 buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK; 228 if (mode->stereoMode) { 229 buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK; 230 if (mode->doubleBufferMode) 231 buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK; 232 } 233 234 gconf->stvis.buffer_mask = buffer_mask; 235 gconf->stvis.color_format = nconf->color_format; 236 gconf->stvis.depth_stencil_format = nconf->depth_format; 237 gconf->stvis.accum_format = PIPE_FORMAT_NONE; 238 gconf->stvis.samples = 0; 239 240 gconf->stvis.render_buffer = (buffer_mask & ST_ATTACHMENT_BACK_LEFT_MASK) ? 241 ST_ATTACHMENT_BACK_LEFT : ST_ATTACHMENT_FRONT_LEFT; 242 243 api_mask = 0; 244 for (i = 0; i < ST_API_COUNT; i++) { 245 struct st_api *stapi = gdrv->stapis[i]; 246 if (stapi) { 247 if (stapi->is_visual_supported(stapi, &gconf->stvis)) 248 api_mask |= egl_g3d_st_api_bit(i); 249 } 250 } 251 /* this is required by EGL, not by OpenGL ES */ 252 if ((mode->drawableType & GLX_WINDOW_BIT) && !mode->doubleBufferMode) 253 api_mask &= ~(EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT); 254 255 if (!api_mask) { 256 _eglLog(_EGL_DEBUG, "no state tracker supports config 0x%x", 257 mode->visualID); 258 } 259 260 valid = _eglConfigFromContextModesRec(&gconf->base, 261 mode, api_mask, api_mask); 262 if (valid) { 263#ifdef EGL_MESA_screen_surface 264 /* check if scanout surface bit is set */ 265 if (nconf->scanout_bit) { 266 EGLint val = GET_CONFIG_ATTRIB(&gconf->base, EGL_SURFACE_TYPE); 267 val |= EGL_SCREEN_BIT_MESA; 268 SET_CONFIG_ATTRIB(&gconf->base, EGL_SURFACE_TYPE, val); 269 } 270#endif 271 valid = _eglValidateConfig(&gconf->base, EGL_FALSE); 272 } 273 if (!valid) { 274 _eglLog(_EGL_DEBUG, "skip invalid config 0x%x", mode->visualID); 275 return EGL_FALSE; 276 } 277 278 gconf->native = nconf; 279 280 return EGL_TRUE; 281} 282 283/** 284 * Add configs to display and return the next config ID. 285 */ 286static EGLint 287egl_g3d_add_configs(_EGLDriver *drv, _EGLDisplay *dpy, EGLint id) 288{ 289 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 290 const struct native_config **native_configs; 291 int num_configs, i; 292 293 native_configs = gdpy->native->get_configs(gdpy->native, &num_configs); 294 if (!num_configs) { 295 if (native_configs) 296 free(native_configs); 297 return id; 298 } 299 300 for (i = 0; i < num_configs; i++) { 301 struct egl_g3d_config *gconf; 302 303 gconf = CALLOC_STRUCT(egl_g3d_config); 304 if (gconf) { 305 _eglInitConfig(&gconf->base, dpy, id); 306 if (!egl_g3d_init_config(drv, dpy, &gconf->base, native_configs[i])) { 307 free(gconf); 308 continue; 309 } 310 311 _eglAddConfig(dpy, &gconf->base); 312 id++; 313 } 314 } 315 316 free(native_configs); 317 return id; 318} 319 320static void 321egl_g3d_invalid_surface(struct native_display *ndpy, 322 struct native_surface *nsurf, 323 unsigned int seq_num) 324{ 325 /* XXX not thread safe? */ 326 struct egl_g3d_surface *gsurf = egl_g3d_surface(nsurf->user_data); 327 struct egl_g3d_context *gctx; 328 329 /* 330 * Some functions such as egl_g3d_copy_buffers create a temporary native 331 * surface. There is no gsurf associated with it. 332 */ 333 gctx = (gsurf) ? egl_g3d_context(gsurf->base.CurrentContext) : NULL; 334 if (gctx) 335 gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, gsurf->stfbi); 336} 337 338static struct native_event_handler egl_g3d_native_event_handler = { 339 .invalid_surface = egl_g3d_invalid_surface 340}; 341 342static EGLBoolean 343egl_g3d_terminate(_EGLDriver *drv, _EGLDisplay *dpy) 344{ 345 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 346 EGLint i; 347 348 _eglReleaseDisplayResources(drv, dpy); 349 _eglCleanupDisplay(dpy); 350 351 if (gdpy->pipe) 352 gdpy->pipe->destroy(gdpy->pipe); 353 354 if (dpy->Screens) { 355 for (i = 0; i < dpy->NumScreens; i++) { 356 struct egl_g3d_screen *gscr = egl_g3d_screen(dpy->Screens[i]); 357 free(gscr->native_modes); 358 free(gscr); 359 } 360 free(dpy->Screens); 361 } 362 363 if (gdpy->smapi) 364 egl_g3d_destroy_st_manager(gdpy->smapi); 365 366 if (gdpy->native) 367 gdpy->native->destroy(gdpy->native); 368 369 free(gdpy); 370 dpy->DriverData = NULL; 371 372 return EGL_TRUE; 373} 374 375static EGLBoolean 376egl_g3d_initialize(_EGLDriver *drv, _EGLDisplay *dpy, 377 EGLint *major, EGLint *minor) 378{ 379 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 380 struct egl_g3d_display *gdpy; 381 382 /* the probe object is unlikely to be needed again */ 383 egl_g3d_destroy_probe(drv, dpy); 384 385 gdpy = CALLOC_STRUCT(egl_g3d_display); 386 if (!gdpy) { 387 _eglError(EGL_BAD_ALLOC, "eglInitialize"); 388 goto fail; 389 } 390 dpy->DriverData = gdpy; 391 392 gdpy->native = native_create_display(dpy->NativeDisplay, 393 &egl_g3d_native_event_handler); 394 if (!gdpy->native) { 395 _eglError(EGL_NOT_INITIALIZED, "eglInitialize(no usable display)"); 396 goto fail; 397 } 398 399 gdpy->native->user_data = (void *) dpy; 400 401 egl_g3d_init_st(&gdrv->base); 402 dpy->ClientAPIsMask = gdrv->api_mask; 403 404 gdpy->smapi = egl_g3d_create_st_manager(dpy); 405 if (!gdpy->smapi) { 406 _eglError(EGL_NOT_INITIALIZED, 407 "eglInitialize(failed to create st manager)"); 408 goto fail; 409 } 410 411#ifdef EGL_MESA_screen_surface 412 /* enable MESA_screen_surface before adding (and validating) configs */ 413 if (gdpy->native->modeset) { 414 dpy->Extensions.MESA_screen_surface = EGL_TRUE; 415 egl_g3d_add_screens(drv, dpy); 416 } 417#endif 418 419 dpy->Extensions.KHR_image_base = EGL_TRUE; 420 if (gdpy->native->get_param(gdpy->native, NATIVE_PARAM_USE_NATIVE_BUFFER)) 421 dpy->Extensions.KHR_image_pixmap = EGL_TRUE; 422 423 if (egl_g3d_add_configs(drv, dpy, 1) == 1) { 424 _eglError(EGL_NOT_INITIALIZED, "eglInitialize(unable to add configs)"); 425 goto fail; 426 } 427 428 *major = 1; 429 *minor = 4; 430 431 return EGL_TRUE; 432 433fail: 434 if (gdpy) 435 egl_g3d_terminate(drv, dpy); 436 return EGL_FALSE; 437} 438 439static _EGLContext * 440egl_g3d_create_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, 441 _EGLContext *share, const EGLint *attribs) 442{ 443 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 444 struct egl_g3d_context *gshare = egl_g3d_context(share); 445 struct egl_g3d_config *gconf = egl_g3d_config(conf); 446 struct egl_g3d_context *gctx; 447 448 gctx = CALLOC_STRUCT(egl_g3d_context); 449 if (!gctx) { 450 _eglError(EGL_BAD_ALLOC, "eglCreateContext"); 451 return NULL; 452 } 453 454 if (!_eglInitContext(&gctx->base, dpy, conf, attribs)) { 455 free(gctx); 456 return NULL; 457 } 458 459 gctx->stapi = egl_g3d_choose_st(drv, &gctx->base); 460 if (!gctx->stapi) { 461 free(gctx); 462 return NULL; 463 } 464 465 gctx->stctxi = gctx->stapi->create_context(gctx->stapi, gdpy->smapi, 466 &gconf->stvis, (gshare) ? gshare->stctxi : NULL); 467 if (!gctx->stctxi) { 468 free(gctx); 469 return NULL; 470 } 471 472 gctx->stctxi->st_manager_private = (void *) &gctx->base; 473 474 return &gctx->base; 475} 476 477/** 478 * Destroy a context. 479 */ 480static void 481destroy_context(_EGLDisplay *dpy, _EGLContext *ctx) 482{ 483 struct egl_g3d_context *gctx = egl_g3d_context(ctx); 484 485 /* FIXME a context might live longer than its display */ 486 if (!dpy->Initialized) 487 _eglLog(_EGL_FATAL, "destroy a context with an unitialized display"); 488 489 gctx->stctxi->destroy(gctx->stctxi); 490 491 free(gctx); 492} 493 494static EGLBoolean 495egl_g3d_destroy_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx) 496{ 497 if (!_eglIsContextBound(ctx)) 498 destroy_context(dpy, ctx); 499 return EGL_TRUE; 500} 501 502struct egl_g3d_create_surface_arg { 503 EGLint type; 504 union { 505 EGLNativeWindowType win; 506 EGLNativePixmapType pix; 507 } u; 508}; 509 510static _EGLSurface * 511egl_g3d_create_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, 512 struct egl_g3d_create_surface_arg *arg, 513 const EGLint *attribs) 514{ 515 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 516 struct egl_g3d_config *gconf = egl_g3d_config(conf); 517 struct egl_g3d_surface *gsurf; 518 struct native_surface *nsurf; 519 const char *err; 520 521 switch (arg->type) { 522 case EGL_WINDOW_BIT: 523 err = "eglCreateWindowSurface"; 524 break; 525 case EGL_PIXMAP_BIT: 526 err = "eglCreatePixmapSurface"; 527 break; 528#ifdef EGL_MESA_screen_surface 529 case EGL_SCREEN_BIT_MESA: 530 err = "eglCreateScreenSurface"; 531 break; 532#endif 533 default: 534 err = "eglCreateUnknownSurface"; 535 break; 536 } 537 538 gsurf = CALLOC_STRUCT(egl_g3d_surface); 539 if (!gsurf) { 540 _eglError(EGL_BAD_ALLOC, err); 541 return NULL; 542 } 543 544 if (!_eglInitSurface(&gsurf->base, dpy, arg->type, conf, attribs)) { 545 free(gsurf); 546 return NULL; 547 } 548 549 /* create the native surface */ 550 switch (arg->type) { 551 case EGL_WINDOW_BIT: 552 nsurf = gdpy->native->create_window_surface(gdpy->native, 553 arg->u.win, gconf->native); 554 break; 555 case EGL_PIXMAP_BIT: 556 nsurf = gdpy->native->create_pixmap_surface(gdpy->native, 557 arg->u.pix, gconf->native); 558 break; 559#ifdef EGL_MESA_screen_surface 560 case EGL_SCREEN_BIT_MESA: 561 /* prefer back buffer (move to _eglInitSurface?) */ 562 gsurf->base.RenderBuffer = EGL_BACK_BUFFER; 563 nsurf = gdpy->native->modeset->create_scanout_surface(gdpy->native, 564 gconf->native, gsurf->base.Width, gsurf->base.Height); 565 break; 566#endif 567 default: 568 nsurf = NULL; 569 break; 570 } 571 572 if (!nsurf) { 573 free(gsurf); 574 return NULL; 575 } 576 /* initialize the geometry */ 577 if (!nsurf->validate(nsurf, 0x0, &gsurf->sequence_number, NULL, 578 &gsurf->base.Width, &gsurf->base.Height)) { 579 nsurf->destroy(nsurf); 580 free(gsurf); 581 return NULL; 582 } 583 584 gsurf->stvis = gconf->stvis; 585 if (gsurf->base.RenderBuffer == EGL_SINGLE_BUFFER) 586 gsurf->stvis.render_buffer = ST_ATTACHMENT_FRONT_LEFT; 587 588 gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base); 589 if (!gsurf->stfbi) { 590 nsurf->destroy(nsurf); 591 free(gsurf); 592 return NULL; 593 } 594 595 nsurf->user_data = &gsurf->base; 596 gsurf->native = nsurf; 597 598 return &gsurf->base; 599} 600 601static _EGLSurface * 602egl_g3d_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy, 603 _EGLConfig *conf, EGLNativeWindowType win, 604 const EGLint *attribs) 605{ 606 struct egl_g3d_create_surface_arg arg; 607 608 memset(&arg, 0, sizeof(arg)); 609 arg.type = EGL_WINDOW_BIT; 610 arg.u.win = win; 611 612 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs); 613} 614 615static _EGLSurface * 616egl_g3d_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy, 617 _EGLConfig *conf, EGLNativePixmapType pix, 618 const EGLint *attribs) 619{ 620 struct egl_g3d_create_surface_arg arg; 621 622 memset(&arg, 0, sizeof(arg)); 623 arg.type = EGL_PIXMAP_BIT; 624 arg.u.pix = pix; 625 626 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs); 627} 628 629static _EGLSurface * 630egl_g3d_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy, 631 _EGLConfig *conf, const EGLint *attribs) 632{ 633 struct egl_g3d_config *gconf = egl_g3d_config(conf); 634 struct egl_g3d_surface *gsurf; 635 636 gsurf = CALLOC_STRUCT(egl_g3d_surface); 637 if (!gsurf) { 638 _eglError(EGL_BAD_ALLOC, "eglCreatePbufferSurface"); 639 return NULL; 640 } 641 642 if (!_eglInitSurface(&gsurf->base, dpy, EGL_PBUFFER_BIT, conf, attribs)) { 643 free(gsurf); 644 return NULL; 645 } 646 647 gsurf->stvis = gconf->stvis; 648 649 gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base); 650 if (!gsurf->stfbi) { 651 free(gsurf); 652 return NULL; 653 } 654 655 return &gsurf->base; 656} 657 658/** 659 * Destroy a surface. 660 */ 661static void 662destroy_surface(_EGLDisplay *dpy, _EGLSurface *surf) 663{ 664 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 665 666 /* FIXME a surface might live longer than its display */ 667 if (!dpy->Initialized) 668 _eglLog(_EGL_FATAL, "destroy a surface with an unitialized display"); 669 670 pipe_texture_reference(&gsurf->render_texture, NULL); 671 egl_g3d_destroy_st_framebuffer(gsurf->stfbi); 672 if (gsurf->native) 673 gsurf->native->destroy(gsurf->native); 674 free(gsurf); 675} 676 677static EGLBoolean 678egl_g3d_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) 679{ 680 if (!_eglIsSurfaceBound(surf)) 681 destroy_surface(dpy, surf); 682 return EGL_TRUE; 683} 684 685static EGLBoolean 686egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy, 687 _EGLSurface *draw, _EGLSurface *read, _EGLContext *ctx) 688{ 689 struct egl_g3d_context *gctx = egl_g3d_context(ctx); 690 struct egl_g3d_surface *gdraw = egl_g3d_surface(draw); 691 struct egl_g3d_surface *gread = egl_g3d_surface(read); 692 struct egl_g3d_context *old_gctx; 693 EGLBoolean ok = EGL_TRUE; 694 695 /* bind the new context and return the "orphaned" one */ 696 if (!_eglBindContext(&ctx, &draw, &read)) 697 return EGL_FALSE; 698 old_gctx = egl_g3d_context(ctx); 699 700 if (old_gctx) { 701 /* flush old context */ 702 old_gctx->stctxi->flush(old_gctx->stctxi, 703 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); 704 } 705 706 if (gctx) { 707 ok = gctx->stapi->make_current(gctx->stapi, gctx->stctxi, 708 (gdraw) ? gdraw->stfbi : NULL, (gread) ? gread->stfbi : NULL); 709 if (ok) { 710 gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, gdraw->stfbi); 711 if (gread != gdraw) { 712 gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, 713 gread->stfbi); 714 } 715 716 if (gdraw->base.Type == EGL_WINDOW_BIT) { 717 gctx->base.WindowRenderBuffer = 718 (gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ? 719 EGL_SINGLE_BUFFER : EGL_BACK_BUFFER; 720 } 721 } 722 } 723 else if (old_gctx) { 724 ok = old_gctx->stapi->make_current(old_gctx->stapi, NULL, NULL, NULL); 725 old_gctx->base.WindowRenderBuffer = EGL_NONE; 726 } 727 728 if (ctx && !_eglIsContextLinked(ctx)) 729 destroy_context(dpy, ctx); 730 if (draw && !_eglIsSurfaceLinked(draw)) 731 destroy_surface(dpy, draw); 732 if (read && read != draw && !_eglIsSurfaceLinked(read)) 733 destroy_surface(dpy, read); 734 735 return ok; 736} 737 738static EGLBoolean 739egl_g3d_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) 740{ 741 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 742 _EGLContext *ctx = _eglGetCurrentContext(); 743 struct egl_g3d_context *gctx = NULL; 744 745 /* no-op for pixmap or pbuffer surface */ 746 if (gsurf->base.Type == EGL_PIXMAP_BIT || 747 gsurf->base.Type == EGL_PBUFFER_BIT) 748 return EGL_TRUE; 749 750 /* or when the surface is single-buffered */ 751 if (gsurf->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) 752 return EGL_TRUE; 753 754 if (ctx && ctx->DrawSurface == surf) 755 gctx = egl_g3d_context(ctx); 756 757 /* flush if the surface is current */ 758 if (gctx) { 759 gctx->stctxi->flush(gctx->stctxi, 760 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); 761 } 762 763 return gsurf->native->swap_buffers(gsurf->native); 764} 765 766/** 767 * Find a config that supports the pixmap. 768 */ 769_EGLConfig * 770egl_g3d_find_pixmap_config(_EGLDisplay *dpy, EGLNativePixmapType pix) 771{ 772 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 773 struct egl_g3d_config *gconf; 774 EGLint i; 775 776 for (i = 0; i < dpy->NumConfigs; i++) { 777 gconf = egl_g3d_config(dpy->Configs[i]); 778 if (gdpy->native->is_pixmap_supported(gdpy->native, pix, gconf->native)) 779 break; 780 } 781 782 return (i < dpy->NumConfigs) ? &gconf->base : NULL; 783} 784 785/** 786 * Get the pipe surface of the given attachment of the native surface. 787 */ 788static struct pipe_surface * 789get_pipe_surface(struct native_display *ndpy, struct native_surface *nsurf, 790 enum native_attachment natt) 791{ 792 struct pipe_texture *textures[NUM_NATIVE_ATTACHMENTS]; 793 struct pipe_surface *psurf; 794 795 textures[natt] = NULL; 796 nsurf->validate(nsurf, 1 << natt, NULL, textures, NULL, NULL); 797 if (!textures[natt]) 798 return NULL; 799 800 psurf = ndpy->screen->get_tex_surface(ndpy->screen, textures[natt], 801 0, 0, 0, PIPE_BUFFER_USAGE_GPU_WRITE); 802 pipe_texture_reference(&textures[natt], NULL); 803 804 return psurf; 805} 806 807static EGLBoolean 808egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, 809 EGLNativePixmapType target) 810{ 811 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 812 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 813 _EGLContext *ctx = _eglGetCurrentContext(); 814 struct egl_g3d_config *gconf; 815 struct native_surface *nsurf; 816 struct pipe_screen *screen = gdpy->native->screen; 817 struct pipe_surface *psurf; 818 819 if (!gsurf->render_texture) 820 return EGL_TRUE; 821 822 gconf = egl_g3d_config(egl_g3d_find_pixmap_config(dpy, target)); 823 if (!gconf) 824 return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCopyBuffers"); 825 826 nsurf = gdpy->native->create_pixmap_surface(gdpy->native, 827 target, gconf->native); 828 if (!nsurf) 829 return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCopyBuffers"); 830 831 /* flush if the surface is current */ 832 if (ctx && ctx->DrawSurface == &gsurf->base) { 833 struct egl_g3d_context *gctx = egl_g3d_context(ctx); 834 gctx->stctxi->flush(gctx->stctxi, 835 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); 836 } 837 838 /* create a pipe context to copy surfaces */ 839 if (!gdpy->pipe) { 840 gdpy->pipe = 841 gdpy->native->screen->context_create(gdpy->native->screen, NULL); 842 if (!gdpy->pipe) 843 return EGL_FALSE; 844 } 845 846 psurf = get_pipe_surface(gdpy->native, nsurf, NATIVE_ATTACHMENT_FRONT_LEFT); 847 if (psurf) { 848 struct pipe_surface *psrc; 849 850 psrc = screen->get_tex_surface(screen, gsurf->render_texture, 851 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ); 852 if (psrc) { 853 gdpy->pipe->surface_copy(gdpy->pipe, psurf, 0, 0, 854 psrc, 0, 0, psurf->width, psurf->height); 855 pipe_surface_reference(&psrc, NULL); 856 857 nsurf->flush_frontbuffer(nsurf); 858 } 859 860 pipe_surface_reference(&psurf, NULL); 861 } 862 863 nsurf->destroy(nsurf); 864 865 return EGL_TRUE; 866} 867 868static EGLBoolean 869egl_g3d_wait_client(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx) 870{ 871 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 872 struct egl_g3d_context *gctx = egl_g3d_context(ctx); 873 struct pipe_screen *screen = gdpy->native->screen; 874 struct pipe_fence_handle *fence = NULL; 875 876 gctx->stctxi->flush(gctx->stctxi, 877 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, &fence); 878 screen->fence_finish(screen, fence, 0); 879 screen->fence_reference(screen, &fence, NULL); 880 881 return EGL_TRUE; 882} 883 884static EGLBoolean 885egl_g3d_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine) 886{ 887 _EGLContext *ctx = _eglGetCurrentContext(); 888 889 if (engine != EGL_CORE_NATIVE_ENGINE) 890 return _eglError(EGL_BAD_PARAMETER, "eglWaitNative"); 891 892 if (ctx && ctx->DrawSurface) { 893 struct egl_g3d_surface *gsurf = egl_g3d_surface(ctx->DrawSurface); 894 895 if (gsurf->native) 896 gsurf->native->wait(gsurf->native); 897 } 898 899 return EGL_TRUE; 900} 901 902static _EGLProc 903egl_g3d_get_proc_address(_EGLDriver *drv, const char *procname) 904{ 905 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 906 _EGLProc proc; 907 EGLint i; 908 909 /* in case this is called before a display is initialized */ 910 egl_g3d_init_st(&gdrv->base); 911 912 for (i = 0; i < ST_API_COUNT; i++) { 913 struct st_api *stapi = gdrv->stapis[i]; 914 if (stapi) { 915 proc = (_EGLProc) stapi->get_proc_address(stapi, procname); 916 if (proc) 917 return proc; 918 } 919 } 920 921 return (_EGLProc) NULL; 922} 923 924static EGLBoolean 925egl_g3d_bind_tex_image(_EGLDriver *drv, _EGLDisplay *dpy, 926 _EGLSurface *surf, EGLint buffer) 927{ 928 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 929 _EGLContext *es1 = _eglGetAPIContext(EGL_OPENGL_ES_API); 930 struct egl_g3d_context *gctx; 931 enum pipe_format internal_format; 932 enum st_texture_type target; 933 934 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT) 935 return _eglError(EGL_BAD_SURFACE, "eglBindTexImage"); 936 if (buffer != EGL_BACK_BUFFER) 937 return _eglError(EGL_BAD_PARAMETER, "eglBindTexImage"); 938 if (gsurf->base.BoundToTexture) 939 return _eglError(EGL_BAD_ACCESS, "eglBindTexImage"); 940 941 switch (gsurf->base.TextureFormat) { 942 case EGL_TEXTURE_RGB: 943 internal_format = PIPE_FORMAT_R8G8B8_UNORM; 944 break; 945 case EGL_TEXTURE_RGBA: 946 internal_format = PIPE_FORMAT_B8G8R8A8_UNORM; 947 break; 948 default: 949 return _eglError(EGL_BAD_MATCH, "eglBindTexImage"); 950 } 951 952 switch (gsurf->base.TextureTarget) { 953 case EGL_TEXTURE_2D: 954 target = ST_TEXTURE_2D; 955 break; 956 default: 957 return _eglError(EGL_BAD_MATCH, "eglBindTexImage"); 958 } 959 960 if (!es1) 961 return EGL_TRUE; 962 if (!gsurf->render_texture) 963 return EGL_FALSE; 964 965 /* flush properly if the surface is bound */ 966 if (gsurf->base.CurrentContext) { 967 gctx = egl_g3d_context(gsurf->base.CurrentContext); 968 gctx->stctxi->flush(gctx->stctxi, 969 PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); 970 } 971 972 gctx = egl_g3d_context(es1); 973 if (gctx->stctxi->teximage) { 974 if (!gctx->stctxi->teximage(gctx->stctxi, target, 975 gsurf->base.MipmapLevel, internal_format, 976 gsurf->render_texture, gsurf->base.MipmapTexture)) 977 return EGL_FALSE; 978 gsurf->base.BoundToTexture = EGL_TRUE; 979 } 980 981 return EGL_TRUE; 982} 983 984static EGLBoolean 985egl_g3d_release_tex_image(_EGLDriver *drv, _EGLDisplay *dpy, 986 _EGLSurface *surf, EGLint buffer) 987{ 988 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 989 990 if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT || 991 !gsurf->base.BoundToTexture) 992 return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage"); 993 if (buffer != EGL_BACK_BUFFER) 994 return _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage"); 995 996 if (gsurf->render_texture) { 997 _EGLContext *ctx = _eglGetAPIContext(EGL_OPENGL_ES_API); 998 struct egl_g3d_context *gctx = egl_g3d_context(ctx); 999 1000 /* what if the context the surface binds to is no longer current? */ 1001 if (gctx) { 1002 gctx->stctxi->teximage(gctx->stctxi, ST_TEXTURE_2D, 1003 gsurf->base.MipmapLevel, PIPE_FORMAT_NONE, NULL, FALSE); 1004 } 1005 } 1006 1007 gsurf->base.BoundToTexture = EGL_FALSE; 1008 1009 return EGL_TRUE; 1010} 1011 1012#ifdef EGL_MESA_screen_surface 1013 1014static _EGLSurface * 1015egl_g3d_create_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy, 1016 _EGLConfig *conf, const EGLint *attribs) 1017{ 1018 struct egl_g3d_create_surface_arg arg; 1019 1020 memset(&arg, 0, sizeof(arg)); 1021 arg.type = EGL_SCREEN_BIT_MESA; 1022 1023 return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs); 1024} 1025 1026static EGLBoolean 1027egl_g3d_show_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy, 1028 _EGLScreen *scr, _EGLSurface *surf, 1029 _EGLMode *mode) 1030{ 1031 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 1032 struct egl_g3d_screen *gscr = egl_g3d_screen(scr); 1033 struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); 1034 struct native_surface *nsurf; 1035 const struct native_mode *nmode; 1036 EGLBoolean changed; 1037 1038 if (gsurf) { 1039 EGLint idx; 1040 1041 if (!mode) 1042 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA"); 1043 if (gsurf->base.Type != EGL_SCREEN_BIT_MESA) 1044 return _eglError(EGL_BAD_SURFACE, "eglShowScreenSurfaceMESA"); 1045 if (gsurf->base.Width < mode->Width || gsurf->base.Height < mode->Height) 1046 return _eglError(EGL_BAD_MATCH, 1047 "eglShowSurfaceMESA(surface smaller than mode size)"); 1048 1049 /* find the index of the mode */ 1050 for (idx = 0; idx < gscr->base.NumModes; idx++) 1051 if (mode == &gscr->base.Modes[idx]) 1052 break; 1053 if (idx >= gscr->base.NumModes) { 1054 return _eglError(EGL_BAD_MODE_MESA, 1055 "eglShowSurfaceMESA(unknown mode)"); 1056 } 1057 1058 nsurf = gsurf->native; 1059 nmode = gscr->native_modes[idx]; 1060 } 1061 else { 1062 if (mode) 1063 return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA"); 1064 1065 /* disable the screen */ 1066 nsurf = NULL; 1067 nmode = NULL; 1068 } 1069 1070 /* TODO surface panning by CRTC choosing */ 1071 changed = gdpy->native->modeset->program(gdpy->native, 0, nsurf, 1072 gscr->base.OriginX, gscr->base.OriginY, &gscr->native, 1, nmode); 1073 if (changed) { 1074 gscr->base.CurrentSurface = &gsurf->base; 1075 gscr->base.CurrentMode = mode; 1076 } 1077 1078 return changed; 1079} 1080 1081#endif /* EGL_MESA_screen_surface */ 1082 1083static EGLint 1084egl_g3d_probe(_EGLDriver *drv, _EGLDisplay *dpy) 1085{ 1086 struct native_probe *nprobe; 1087 enum native_probe_result res; 1088 EGLint score; 1089 1090 nprobe = egl_g3d_get_probe(drv, dpy); 1091 res = native_get_probe_result(nprobe); 1092 1093 switch (res) { 1094 case NATIVE_PROBE_UNKNOWN: 1095 default: 1096 score = 0; 1097 break; 1098 case NATIVE_PROBE_FALLBACK: 1099 score = 40; 1100 break; 1101 case NATIVE_PROBE_SUPPORTED: 1102 score = 50; 1103 break; 1104 case NATIVE_PROBE_EXACT: 1105 score = 100; 1106 break; 1107 } 1108 1109 return score; 1110} 1111 1112static void 1113egl_g3d_unload(_EGLDriver *drv) 1114{ 1115 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 1116 EGLint i; 1117 1118 for (i = 0; i < ST_API_COUNT; i++) { 1119 if (gdrv->stapis[i]) 1120 gdrv->stapis[i]->destroy(gdrv->stapis[i]); 1121 } 1122 1123 egl_g3d_destroy_probe(drv, NULL); 1124 free(gdrv); 1125} 1126 1127_EGLDriver * 1128_eglMain(const char *args) 1129{ 1130 static char driver_name[64]; 1131 struct egl_g3d_driver *gdrv; 1132 1133 snprintf(driver_name, sizeof(driver_name), 1134 "Gallium/%s", native_get_name()); 1135 1136 gdrv = CALLOC_STRUCT(egl_g3d_driver); 1137 if (!gdrv) 1138 return NULL; 1139 1140 _eglInitDriverFallbacks(&gdrv->base); 1141 1142 gdrv->base.API.Initialize = egl_g3d_initialize; 1143 gdrv->base.API.Terminate = egl_g3d_terminate; 1144 gdrv->base.API.CreateContext = egl_g3d_create_context; 1145 gdrv->base.API.DestroyContext = egl_g3d_destroy_context; 1146 gdrv->base.API.CreateWindowSurface = egl_g3d_create_window_surface; 1147 gdrv->base.API.CreatePixmapSurface = egl_g3d_create_pixmap_surface; 1148 gdrv->base.API.CreatePbufferSurface = egl_g3d_create_pbuffer_surface; 1149 gdrv->base.API.DestroySurface = egl_g3d_destroy_surface; 1150 gdrv->base.API.MakeCurrent = egl_g3d_make_current; 1151 gdrv->base.API.SwapBuffers = egl_g3d_swap_buffers; 1152 gdrv->base.API.CopyBuffers = egl_g3d_copy_buffers; 1153 gdrv->base.API.WaitClient = egl_g3d_wait_client; 1154 gdrv->base.API.WaitNative = egl_g3d_wait_native; 1155 gdrv->base.API.GetProcAddress = egl_g3d_get_proc_address; 1156 1157 gdrv->base.API.BindTexImage = egl_g3d_bind_tex_image; 1158 gdrv->base.API.ReleaseTexImage = egl_g3d_release_tex_image; 1159 1160 gdrv->base.API.CreateImageKHR = egl_g3d_create_image; 1161 gdrv->base.API.DestroyImageKHR = egl_g3d_destroy_image; 1162 1163#ifdef EGL_MESA_screen_surface 1164 gdrv->base.API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface; 1165 gdrv->base.API.ShowScreenSurfaceMESA = egl_g3d_show_screen_surface; 1166#endif 1167 1168 gdrv->base.Name = driver_name; 1169 gdrv->base.Probe = egl_g3d_probe; 1170 gdrv->base.Unload = egl_g3d_unload; 1171 1172 /* the key is " EGL G3D" */ 1173 gdrv->probe_key = 0x0E61063D; 1174 1175 return &gdrv->base; 1176} 1177