egl_g3d.c revision d1e4117355f1db6ff87c837df6212bf6168e98a0
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 (dpy->Configs) { 459 _eglDestroyArray(dpy->Configs, egl_g3d_free_config); 460 dpy->Configs = NULL; 461 } 462 if (dpy->Screens) { 463 _eglDestroyArray(dpy->Screens, egl_g3d_free_screen); 464 dpy->Screens = NULL; 465 } 466 467 _eglCleanupDisplay(dpy); 468 469 if (gdpy->smapi) 470 egl_g3d_destroy_st_manager(gdpy->smapi); 471 472 if (gdpy->native) 473 gdpy->native->destroy(gdpy->native); 474 475 FREE(gdpy); 476 dpy->DriverData = NULL; 477 478 return EGL_TRUE; 479} 480 481static EGLBoolean 482egl_g3d_initialize(_EGLDriver *drv, _EGLDisplay *dpy) 483{ 484 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 485 struct egl_g3d_display *gdpy; 486 const struct native_platform *nplat; 487 488 nplat = egl_g3d_get_platform(drv, dpy->Platform); 489 if (!nplat) 490 return EGL_FALSE; 491 492 if (dpy->Options.TestOnly) 493 return EGL_TRUE; 494 495 gdpy = CALLOC_STRUCT(egl_g3d_display); 496 if (!gdpy) { 497 _eglError(EGL_BAD_ALLOC, "eglInitialize"); 498 goto fail; 499 } 500 gdpy->loader = gdrv->loader; 501 dpy->DriverData = gdpy; 502 503 _eglLog(_EGL_INFO, "use %s for display %p", nplat->name, dpy->PlatformDisplay); 504 gdpy->native = nplat->create_display(dpy->PlatformDisplay, 505 dpy->Options.UseFallback, (void *) dpy); 506 if (!gdpy->native) { 507 _eglError(EGL_NOT_INITIALIZED, "eglInitialize(no usable display)"); 508 goto fail; 509 } 510 511 if (gdpy->loader->profile_masks[ST_API_OPENGL] & ST_PROFILE_DEFAULT_MASK) 512 dpy->ClientAPIs |= EGL_OPENGL_BIT; 513 if (gdpy->loader->profile_masks[ST_API_OPENGL] & ST_PROFILE_OPENGL_ES1_MASK) 514 dpy->ClientAPIs |= EGL_OPENGL_ES_BIT; 515 if (gdpy->loader->profile_masks[ST_API_OPENGL] & ST_PROFILE_OPENGL_ES2_MASK) 516 dpy->ClientAPIs |= EGL_OPENGL_ES2_BIT; 517 if (gdpy->loader->profile_masks[ST_API_OPENVG] & ST_PROFILE_DEFAULT_MASK) 518 dpy->ClientAPIs |= EGL_OPENVG_BIT; 519 520 gdpy->smapi = egl_g3d_create_st_manager(dpy); 521 if (!gdpy->smapi) { 522 _eglError(EGL_NOT_INITIALIZED, 523 "eglInitialize(failed to create st manager)"); 524 goto fail; 525 } 526 527#ifdef EGL_MESA_screen_surface 528 /* enable MESA_screen_surface before adding (and validating) configs */ 529 if (gdpy->native->modeset) { 530 dpy->Extensions.MESA_screen_surface = EGL_TRUE; 531 egl_g3d_add_screens(drv, dpy); 532 } 533#endif 534 535 dpy->Extensions.KHR_image_base = EGL_TRUE; 536 if (gdpy->native->get_param(gdpy->native, NATIVE_PARAM_USE_NATIVE_BUFFER)) 537 dpy->Extensions.KHR_image_pixmap = EGL_TRUE; 538 539 dpy->Extensions.KHR_reusable_sync = EGL_TRUE; 540 dpy->Extensions.KHR_fence_sync = EGL_TRUE; 541 542 dpy->Extensions.KHR_surfaceless_gles1 = EGL_TRUE; 543 dpy->Extensions.KHR_surfaceless_gles2 = EGL_TRUE; 544 dpy->Extensions.KHR_surfaceless_opengl = EGL_TRUE; 545 546 if (dpy->Platform == _EGL_PLATFORM_DRM) { 547 dpy->Extensions.MESA_drm_display = EGL_TRUE; 548 if (gdpy->native->buffer) 549 dpy->Extensions.MESA_drm_image = EGL_TRUE; 550 } 551 552 if (dpy->Platform == _EGL_PLATFORM_WAYLAND && gdpy->native->buffer) 553 dpy->Extensions.MESA_drm_image = EGL_TRUE; 554 555 if (egl_g3d_add_configs(drv, dpy, 1) == 1) { 556 _eglError(EGL_NOT_INITIALIZED, "eglInitialize(unable to add configs)"); 557 goto fail; 558 } 559 560 dpy->VersionMajor = 1; 561 dpy->VersionMinor = 4; 562 563 return EGL_TRUE; 564 565fail: 566 if (gdpy) 567 egl_g3d_terminate(drv, dpy); 568 return EGL_FALSE; 569} 570 571static _EGLProc 572egl_g3d_get_proc_address(_EGLDriver *drv, const char *procname) 573{ 574 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 575 struct st_api *stapi = NULL; 576 577 if (procname && procname[0] == 'v' && procname[1] == 'g') 578 stapi = gdrv->loader->get_st_api(ST_API_OPENVG); 579 else if (procname && procname[0] == 'g' && procname[1] == 'l') 580 stapi = gdrv->loader->get_st_api(ST_API_OPENGL); 581 582 return (_EGLProc) ((stapi) ? 583 stapi->get_proc_address(stapi, procname) : NULL); 584} 585 586_EGLDriver * 587egl_g3d_create_driver(const struct egl_g3d_loader *loader) 588{ 589 struct egl_g3d_driver *gdrv; 590 591 gdrv = CALLOC_STRUCT(egl_g3d_driver); 592 if (!gdrv) 593 return NULL; 594 595 gdrv->loader = loader; 596 597 egl_g3d_init_driver_api(&gdrv->base); 598 gdrv->base.API.Initialize = egl_g3d_initialize; 599 gdrv->base.API.Terminate = egl_g3d_terminate; 600 gdrv->base.API.GetProcAddress = egl_g3d_get_proc_address; 601 602 /* to be filled by the caller */ 603 gdrv->base.Name = NULL; 604 gdrv->base.Unload = NULL; 605 606 return &gdrv->base; 607} 608 609void 610egl_g3d_destroy_driver(_EGLDriver *drv) 611{ 612 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 613 FREE(gdrv); 614} 615