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