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