egl_g3d.c revision 15598fbf42068ecedd17c7b39e796965ff385e93
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 "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_format.h" 33#include "util/u_string.h" 34 35#include "egl_g3d.h" 36#include "egl_g3d_api.h" 37#include "egl_g3d_st.h" 38#include "egl_g3d_loader.h" 39#include "native.h" 40 41static void 42egl_g3d_invalid_surface(struct native_display *ndpy, 43 struct native_surface *nsurf, 44 unsigned int seq_num) 45{ 46 /* XXX not thread safe? */ 47 struct egl_g3d_surface *gsurf = egl_g3d_surface(nsurf->user_data); 48 struct egl_g3d_context *gctx; 49 50 /* 51 * Some functions such as egl_g3d_copy_buffers create a temporary native 52 * surface. There is no gsurf associated with it. 53 */ 54 gctx = (gsurf) ? egl_g3d_context(gsurf->base.CurrentContext) : NULL; 55 if (gctx) 56 gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, gsurf->stfbi); 57} 58 59static struct pipe_screen * 60egl_g3d_new_drm_screen(struct native_display *ndpy, const char *name, int fd) 61{ 62 _EGLDisplay *dpy = (_EGLDisplay *) ndpy->user_data; 63 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 64 return gdpy->loader->create_drm_screen(name, fd); 65} 66 67static struct pipe_screen * 68egl_g3d_new_sw_screen(struct native_display *ndpy, struct sw_winsys *ws) 69{ 70 _EGLDisplay *dpy = (_EGLDisplay *) ndpy->user_data; 71 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 72 return gdpy->loader->create_sw_screen(ws); 73} 74 75static struct native_event_handler egl_g3d_native_event_handler = { 76 egl_g3d_invalid_surface, 77 egl_g3d_new_drm_screen, 78 egl_g3d_new_sw_screen 79}; 80 81/** 82 * Get the native platform. 83 */ 84static const struct native_platform * 85egl_g3d_get_platform(_EGLDriver *drv, _EGLPlatformType plat) 86{ 87 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 88 89 if (!gdrv->platforms[plat]) { 90 const char *plat_name = NULL; 91 const struct native_platform *nplat = NULL; 92 93 switch (plat) { 94 case _EGL_PLATFORM_WINDOWS: 95 plat_name = "Windows"; 96#ifdef HAVE_GDI_BACKEND 97 nplat = native_get_gdi_platform(); 98#endif 99 break; 100 case _EGL_PLATFORM_X11: 101 plat_name = "X11"; 102#ifdef HAVE_X11_BACKEND 103 nplat = native_get_x11_platform(); 104#endif 105 break; 106 case _EGL_PLATFORM_WAYLAND: 107 plat_name = "wayland"; 108#ifdef HAVE_WAYLAND_BACKEND 109 nplat = native_get_wayland_platform(); 110#endif 111 break; 112 case _EGL_PLATFORM_DRM: 113 plat_name = "DRM"; 114#ifdef HAVE_DRM_BACKEND 115 nplat = native_get_drm_platform(); 116#endif 117 break; 118 case _EGL_PLATFORM_FBDEV: 119 plat_name = "FBDEV"; 120#ifdef HAVE_FBDEV_BACKEND 121 nplat = native_get_fbdev_platform(); 122#endif 123 break; 124 default: 125 break; 126 } 127 128 if (nplat) 129 nplat->set_event_handler(&egl_g3d_native_event_handler); 130 else 131 _eglLog(_EGL_WARNING, "unsupported platform %s", plat_name); 132 133 gdrv->platforms[plat] = nplat; 134 } 135 136 return gdrv->platforms[plat]; 137} 138 139#ifdef EGL_MESA_screen_surface 140 141static void 142egl_g3d_add_screens(_EGLDriver *drv, _EGLDisplay *dpy) 143{ 144 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 145 const struct native_connector **native_connectors; 146 EGLint num_connectors, i; 147 148 native_connectors = 149 gdpy->native->modeset->get_connectors(gdpy->native, &num_connectors, NULL); 150 if (!num_connectors) { 151 if (native_connectors) 152 FREE(native_connectors); 153 return; 154 } 155 156 for (i = 0; i < num_connectors; i++) { 157 const struct native_connector *nconn = native_connectors[i]; 158 struct egl_g3d_screen *gscr; 159 const struct native_mode **native_modes; 160 EGLint num_modes, j; 161 162 /* TODO support for hotplug */ 163 native_modes = 164 gdpy->native->modeset->get_modes(gdpy->native, nconn, &num_modes); 165 if (!num_modes) { 166 if (native_modes) 167 FREE(native_modes); 168 continue; 169 } 170 171 gscr = CALLOC_STRUCT(egl_g3d_screen); 172 if (!gscr) { 173 FREE(native_modes); 174 continue; 175 } 176 177 _eglInitScreen(&gscr->base, dpy, num_modes); 178 for (j = 0; j < gscr->base.NumModes; j++) { 179 const struct native_mode *nmode = native_modes[j]; 180 _EGLMode *mode = &gscr->base.Modes[j]; 181 182 mode->Width = nmode->width; 183 mode->Height = nmode->height; 184 mode->RefreshRate = nmode->refresh_rate; 185 mode->Optimal = EGL_FALSE; 186 mode->Interlaced = EGL_FALSE; 187 /* no need to strdup() */ 188 mode->Name = nmode->desc; 189 } 190 191 gscr->native = nconn; 192 gscr->native_modes = native_modes; 193 194 _eglLinkScreen(&gscr->base); 195 } 196 197 FREE(native_connectors); 198} 199 200#endif /* EGL_MESA_screen_surface */ 201 202/** 203 * Initialize and validate the EGL config attributes. 204 */ 205static EGLBoolean 206init_config_attributes(_EGLConfig *conf, const struct native_config *nconf, 207 EGLint api_mask, enum pipe_format depth_stencil_format, 208 EGLBoolean preserve_buffer, EGLint max_swap_interval) 209{ 210 uint rgba[4], depth_stencil[2], buffer_size; 211 EGLint surface_type; 212 EGLint i; 213 214 /* get the color and depth/stencil component sizes */ 215 assert(nconf->color_format != PIPE_FORMAT_NONE); 216 buffer_size = 0; 217 for (i = 0; i < 4; i++) { 218 rgba[i] = util_format_get_component_bits(nconf->color_format, 219 UTIL_FORMAT_COLORSPACE_RGB, i); 220 buffer_size += rgba[i]; 221 } 222 for (i = 0; i < 2; i++) { 223 if (depth_stencil_format != PIPE_FORMAT_NONE) { 224 depth_stencil[i] = 225 util_format_get_component_bits(depth_stencil_format, 226 UTIL_FORMAT_COLORSPACE_ZS, i); 227 } 228 else { 229 depth_stencil[i] = 0; 230 } 231 } 232 233 surface_type = 0x0; 234 /* pixmap surfaces should be EGL_SINGLE_BUFFER */ 235 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_FRONT_LEFT)) { 236 if (nconf->pixmap_bit) 237 surface_type |= EGL_PIXMAP_BIT; 238 } 239 /* the others surfaces should be EGL_BACK_BUFFER (or settable) */ 240 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_LEFT)) { 241 if (nconf->window_bit) 242 surface_type |= EGL_WINDOW_BIT; 243#ifdef EGL_MESA_screen_surface 244 if (nconf->scanout_bit) 245 surface_type |= EGL_SCREEN_BIT_MESA; 246#endif 247 surface_type |= EGL_PBUFFER_BIT; 248 } 249 250 conf->Conformant = api_mask; 251 conf->RenderableType = api_mask; 252 253 conf->RedSize = rgba[0]; 254 conf->GreenSize = rgba[1]; 255 conf->BlueSize = rgba[2]; 256 conf->AlphaSize = rgba[3]; 257 conf->BufferSize = buffer_size; 258 259 conf->DepthSize = depth_stencil[0]; 260 conf->StencilSize = depth_stencil[1]; 261 262 conf->SurfaceType = surface_type; 263 264 conf->NativeRenderable = EGL_TRUE; 265 if (surface_type & EGL_WINDOW_BIT) { 266 conf->NativeVisualID = nconf->native_visual_id; 267 conf->NativeVisualType = nconf->native_visual_type; 268 } 269 270 if (surface_type & EGL_PBUFFER_BIT) { 271 conf->BindToTextureRGB = EGL_TRUE; 272 if (rgba[3]) 273 conf->BindToTextureRGBA = EGL_TRUE; 274 275 conf->MaxPbufferWidth = 4096; 276 conf->MaxPbufferHeight = 4096; 277 conf->MaxPbufferPixels = 4096 * 4096; 278 } 279 280 conf->Level = nconf->level; 281 282 if (nconf->transparent_rgb) { 283 conf->TransparentType = EGL_TRANSPARENT_RGB; 284 conf->TransparentRedValue = nconf->transparent_rgb_values[0]; 285 conf->TransparentGreenValue = nconf->transparent_rgb_values[1]; 286 conf->TransparentBlueValue = nconf->transparent_rgb_values[2]; 287 } 288 289 conf->MinSwapInterval = 0; 290 conf->MaxSwapInterval = max_swap_interval; 291 if (preserve_buffer) 292 conf->SurfaceType |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT; 293 294 return _eglValidateConfig(conf, EGL_FALSE); 295} 296 297/** 298 * Initialize an EGL config from the native config. 299 */ 300static EGLBoolean 301egl_g3d_init_config(_EGLDriver *drv, _EGLDisplay *dpy, 302 _EGLConfig *conf, const struct native_config *nconf, 303 enum pipe_format depth_stencil_format, 304 int preserve_buffer, int max_swap_interval) 305{ 306 struct egl_g3d_config *gconf = egl_g3d_config(conf); 307 EGLint buffer_mask; 308 EGLBoolean valid; 309 310 buffer_mask = 0x0; 311 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_FRONT_LEFT)) 312 buffer_mask |= ST_ATTACHMENT_FRONT_LEFT_MASK; 313 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_LEFT)) 314 buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK; 315 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_FRONT_RIGHT)) 316 buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK; 317 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_RIGHT)) 318 buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK; 319 320 gconf->stvis.buffer_mask = buffer_mask; 321 gconf->stvis.color_format = nconf->color_format; 322 gconf->stvis.depth_stencil_format = depth_stencil_format; 323 gconf->stvis.accum_format = PIPE_FORMAT_NONE; 324 gconf->stvis.samples = 0; 325 326 /* will be overridden per surface */ 327 gconf->stvis.render_buffer = (buffer_mask & ST_ATTACHMENT_BACK_LEFT_MASK) ? 328 ST_ATTACHMENT_BACK_LEFT : ST_ATTACHMENT_FRONT_LEFT; 329 330 valid = init_config_attributes(&gconf->base, 331 nconf, dpy->ClientAPIs, depth_stencil_format, 332 preserve_buffer, max_swap_interval); 333 if (!valid) { 334 _eglLog(_EGL_DEBUG, "skip invalid config 0x%x", nconf->native_visual_id); 335 return EGL_FALSE; 336 } 337 338 gconf->native = nconf; 339 340 return EGL_TRUE; 341} 342 343/** 344 * Get all interested depth/stencil formats of a display. 345 */ 346static EGLint 347egl_g3d_fill_depth_stencil_formats(_EGLDisplay *dpy, 348 enum pipe_format formats[8]) 349{ 350 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 351 struct pipe_screen *screen = gdpy->native->screen; 352 const EGLint candidates[] = { 353 1, PIPE_FORMAT_Z16_UNORM, 354 1, PIPE_FORMAT_Z32_UNORM, 355 2, PIPE_FORMAT_Z24_UNORM_S8_USCALED, PIPE_FORMAT_S8_USCALED_Z24_UNORM, 356 2, PIPE_FORMAT_Z24X8_UNORM, PIPE_FORMAT_X8Z24_UNORM, 357 0 358 }; 359 const EGLint *fmt = candidates; 360 EGLint count; 361 362 count = 0; 363 formats[count++] = PIPE_FORMAT_NONE; 364 365 while (*fmt) { 366 EGLint i, n = *fmt++; 367 368 /* pick the first supported format */ 369 for (i = 0; i < n; i++) { 370 if (screen->is_format_supported(screen, fmt[i], 371 PIPE_TEXTURE_2D, 0, PIPE_BIND_DEPTH_STENCIL, 0)) { 372 formats[count++] = fmt[i]; 373 break; 374 } 375 } 376 377 fmt += n; 378 } 379 380 return count; 381} 382 383/** 384 * Add configs to display and return the next config ID. 385 */ 386static EGLint 387egl_g3d_add_configs(_EGLDriver *drv, _EGLDisplay *dpy, EGLint id) 388{ 389 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 390 const struct native_config **native_configs; 391 enum pipe_format depth_stencil_formats[8]; 392 int num_formats, num_configs, i, j; 393 int preserve_buffer, max_swap_interval; 394 395 native_configs = gdpy->native->get_configs(gdpy->native, &num_configs); 396 if (!num_configs) { 397 if (native_configs) 398 FREE(native_configs); 399 return id; 400 } 401 402 preserve_buffer = 403 gdpy->native->get_param(gdpy->native, NATIVE_PARAM_PRESERVE_BUFFER); 404 max_swap_interval = 405 gdpy->native->get_param(gdpy->native, NATIVE_PARAM_MAX_SWAP_INTERVAL); 406 407 num_formats = egl_g3d_fill_depth_stencil_formats(dpy, 408 depth_stencil_formats); 409 410 for (i = 0; i < num_configs; i++) { 411 for (j = 0; j < num_formats; j++) { 412 struct egl_g3d_config *gconf; 413 414 gconf = CALLOC_STRUCT(egl_g3d_config); 415 if (gconf) { 416 _eglInitConfig(&gconf->base, dpy, id); 417 if (!egl_g3d_init_config(drv, dpy, &gconf->base, 418 native_configs[i], depth_stencil_formats[j], 419 preserve_buffer, max_swap_interval)) { 420 FREE(gconf); 421 break; 422 } 423 424 _eglLinkConfig(&gconf->base); 425 id++; 426 } 427 } 428 } 429 430 FREE(native_configs); 431 return id; 432} 433 434static void 435egl_g3d_free_config(void *conf) 436{ 437 struct egl_g3d_config *gconf = egl_g3d_config((_EGLConfig *) conf); 438 FREE(gconf); 439} 440 441static void 442egl_g3d_free_screen(void *scr) 443{ 444#ifdef EGL_MESA_screen_surface 445 struct egl_g3d_screen *gscr = egl_g3d_screen((_EGLScreen *) scr); 446 FREE(gscr->native_modes); 447 FREE(gscr); 448#endif 449} 450 451static EGLBoolean 452egl_g3d_terminate(_EGLDriver *drv, _EGLDisplay *dpy) 453{ 454 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 455 456 _eglReleaseDisplayResources(drv, dpy); 457 458 if (gdpy->pipe) 459 gdpy->pipe->destroy(gdpy->pipe); 460 461 if (dpy->Configs) { 462 _eglDestroyArray(dpy->Configs, egl_g3d_free_config); 463 dpy->Configs = NULL; 464 } 465 if (dpy->Screens) { 466 _eglDestroyArray(dpy->Screens, egl_g3d_free_screen); 467 dpy->Screens = NULL; 468 } 469 470 _eglCleanupDisplay(dpy); 471 472 if (gdpy->smapi) 473 egl_g3d_destroy_st_manager(gdpy->smapi); 474 475 if (gdpy->native) 476 gdpy->native->destroy(gdpy->native); 477 478 FREE(gdpy); 479 dpy->DriverData = NULL; 480 481 return EGL_TRUE; 482} 483 484static EGLBoolean 485egl_g3d_initialize(_EGLDriver *drv, _EGLDisplay *dpy) 486{ 487 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 488 struct egl_g3d_display *gdpy; 489 const struct native_platform *nplat; 490 491 nplat = egl_g3d_get_platform(drv, dpy->Platform); 492 if (!nplat) 493 return EGL_FALSE; 494 495 if (dpy->Options.TestOnly) 496 return EGL_TRUE; 497 498 gdpy = CALLOC_STRUCT(egl_g3d_display); 499 if (!gdpy) { 500 _eglError(EGL_BAD_ALLOC, "eglInitialize"); 501 goto fail; 502 } 503 gdpy->loader = gdrv->loader; 504 dpy->DriverData = gdpy; 505 506 _eglLog(_EGL_INFO, "use %s for display %p", nplat->name, dpy->PlatformDisplay); 507 gdpy->native = nplat->create_display(dpy->PlatformDisplay, 508 dpy->Options.UseFallback, (void *) dpy); 509 if (!gdpy->native) { 510 _eglError(EGL_NOT_INITIALIZED, "eglInitialize(no usable display)"); 511 goto fail; 512 } 513 514 if (gdpy->loader->profile_masks[ST_API_OPENGL] & ST_PROFILE_DEFAULT_MASK) 515 dpy->ClientAPIs |= EGL_OPENGL_BIT; 516 if (gdpy->loader->profile_masks[ST_API_OPENGL] & ST_PROFILE_OPENGL_ES1_MASK) 517 dpy->ClientAPIs |= EGL_OPENGL_ES_BIT; 518 if (gdpy->loader->profile_masks[ST_API_OPENGL] & ST_PROFILE_OPENGL_ES2_MASK) 519 dpy->ClientAPIs |= EGL_OPENGL_ES2_BIT; 520 if (gdpy->loader->profile_masks[ST_API_OPENVG] & ST_PROFILE_DEFAULT_MASK) 521 dpy->ClientAPIs |= EGL_OPENVG_BIT; 522 523 gdpy->smapi = egl_g3d_create_st_manager(dpy); 524 if (!gdpy->smapi) { 525 _eglError(EGL_NOT_INITIALIZED, 526 "eglInitialize(failed to create st manager)"); 527 goto fail; 528 } 529 530#ifdef EGL_MESA_screen_surface 531 /* enable MESA_screen_surface before adding (and validating) configs */ 532 if (gdpy->native->modeset) { 533 dpy->Extensions.MESA_screen_surface = EGL_TRUE; 534 egl_g3d_add_screens(drv, dpy); 535 } 536#endif 537 538 dpy->Extensions.KHR_image_base = EGL_TRUE; 539 if (gdpy->native->get_param(gdpy->native, NATIVE_PARAM_USE_NATIVE_BUFFER)) 540 dpy->Extensions.KHR_image_pixmap = EGL_TRUE; 541 542 dpy->Extensions.KHR_reusable_sync = EGL_TRUE; 543 dpy->Extensions.KHR_fence_sync = EGL_TRUE; 544 545 dpy->Extensions.KHR_surfaceless_gles1 = EGL_TRUE; 546 dpy->Extensions.KHR_surfaceless_gles2 = EGL_TRUE; 547 dpy->Extensions.KHR_surfaceless_opengl = EGL_TRUE; 548 549 if (dpy->Platform == _EGL_PLATFORM_DRM) { 550 dpy->Extensions.MESA_drm_display = EGL_TRUE; 551 if (gdpy->native->buffer) 552 dpy->Extensions.MESA_drm_image = EGL_TRUE; 553 } 554 555 if (dpy->Platform == _EGL_PLATFORM_WAYLAND && gdpy->native->buffer) 556 dpy->Extensions.MESA_drm_image = EGL_TRUE; 557 558 if (egl_g3d_add_configs(drv, dpy, 1) == 1) { 559 _eglError(EGL_NOT_INITIALIZED, "eglInitialize(unable to add configs)"); 560 goto fail; 561 } 562 563 dpy->VersionMajor = 1; 564 dpy->VersionMinor = 4; 565 566 return EGL_TRUE; 567 568fail: 569 if (gdpy) 570 egl_g3d_terminate(drv, dpy); 571 return EGL_FALSE; 572} 573 574static _EGLProc 575egl_g3d_get_proc_address(_EGLDriver *drv, const char *procname) 576{ 577 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 578 struct st_api *stapi = NULL; 579 580 if (procname && procname[0] == 'v' && procname[1] == 'g') 581 stapi = gdrv->loader->get_st_api(ST_API_OPENVG); 582 else if (procname && procname[0] == 'g' && procname[1] == 'l') 583 stapi = gdrv->loader->get_st_api(ST_API_OPENGL); 584 585 return (_EGLProc) ((stapi) ? 586 stapi->get_proc_address(stapi, procname) : NULL); 587} 588 589_EGLDriver * 590egl_g3d_create_driver(const struct egl_g3d_loader *loader) 591{ 592 struct egl_g3d_driver *gdrv; 593 594 gdrv = CALLOC_STRUCT(egl_g3d_driver); 595 if (!gdrv) 596 return NULL; 597 598 gdrv->loader = loader; 599 600 egl_g3d_init_driver_api(&gdrv->base); 601 gdrv->base.API.Initialize = egl_g3d_initialize; 602 gdrv->base.API.Terminate = egl_g3d_terminate; 603 gdrv->base.API.GetProcAddress = egl_g3d_get_proc_address; 604 605 /* to be filled by the caller */ 606 gdrv->base.Name = NULL; 607 gdrv->base.Unload = NULL; 608 609 return &gdrv->base; 610} 611 612void 613egl_g3d_destroy_driver(_EGLDriver *drv) 614{ 615 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 616 FREE(gdrv); 617} 618