egl_g3d.c revision 655e4598927728a663f4cfcd6babdf7e5ad83f77
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 /* pixmap surfaces should be EGL_SINGLE_BUFFER */ 187 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_FRONT_LEFT)) { 188 if (nconf->pixmap_bit) 189 surface_type |= EGL_PIXMAP_BIT; 190 } 191 /* the others surfaces should be EGL_BACK_BUFFER (or settable) */ 192 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_LEFT)) { 193 if (nconf->window_bit) 194 surface_type |= EGL_WINDOW_BIT; 195#ifdef EGL_MESA_screen_surface 196 if (nconf->scanout_bit) 197 surface_type |= EGL_SCREEN_BIT_MESA; 198#endif 199 surface_type |= EGL_PBUFFER_BIT; 200 } 201 202 conf->Conformant = api_mask; 203 conf->RenderableType = api_mask; 204 205 conf->RedSize = rgba[0]; 206 conf->GreenSize = rgba[1]; 207 conf->BlueSize = rgba[2]; 208 conf->AlphaSize = rgba[3]; 209 conf->BufferSize = buffer_size; 210 211 conf->DepthSize = depth_stencil[0]; 212 conf->StencilSize = depth_stencil[1]; 213 214 conf->SurfaceType = surface_type; 215 216 conf->NativeRenderable = EGL_TRUE; 217 if (surface_type & EGL_WINDOW_BIT) { 218 conf->NativeVisualID = nconf->native_visual_id; 219 conf->NativeVisualType = nconf->native_visual_type; 220 } 221 222 if (surface_type & EGL_PBUFFER_BIT) { 223 conf->BindToTextureRGB = EGL_TRUE; 224 if (rgba[3]) 225 conf->BindToTextureRGBA = EGL_TRUE; 226 227 conf->MaxPbufferWidth = 4096; 228 conf->MaxPbufferHeight = 4096; 229 conf->MaxPbufferPixels = 4096 * 4096; 230 } 231 232 conf->Level = nconf->level; 233 234 if (nconf->transparent_rgb) { 235 conf->TransparentType = EGL_TRANSPARENT_RGB; 236 conf->TransparentRedValue = nconf->transparent_rgb_values[0]; 237 conf->TransparentGreenValue = nconf->transparent_rgb_values[1]; 238 conf->TransparentBlueValue = nconf->transparent_rgb_values[2]; 239 } 240 241 conf->MinSwapInterval = 0; 242 conf->MaxSwapInterval = max_swap_interval; 243 if (preserve_buffer) 244 conf->SurfaceType |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT; 245 246 return _eglValidateConfig(conf, EGL_FALSE); 247} 248 249/** 250 * Initialize an EGL config from the native config. 251 */ 252static EGLBoolean 253egl_g3d_init_config(_EGLDriver *drv, _EGLDisplay *dpy, 254 _EGLConfig *conf, const struct native_config *nconf, 255 enum pipe_format depth_stencil_format, 256 int preserve_buffer, int max_swap_interval) 257{ 258 struct egl_g3d_config *gconf = egl_g3d_config(conf); 259 EGLint buffer_mask; 260 EGLBoolean valid; 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 /* will be overridden per surface */ 279 gconf->stvis.render_buffer = (buffer_mask & ST_ATTACHMENT_BACK_LEFT_MASK) ? 280 ST_ATTACHMENT_BACK_LEFT : ST_ATTACHMENT_FRONT_LEFT; 281 282 valid = init_config_attributes(&gconf->base, 283 nconf, dpy->ClientAPIs, depth_stencil_format, 284 preserve_buffer, max_swap_interval); 285 if (!valid) { 286 _eglLog(_EGL_DEBUG, "skip invalid config 0x%x", nconf->native_visual_id); 287 return EGL_FALSE; 288 } 289 290 gconf->native = nconf; 291 292 return EGL_TRUE; 293} 294 295/** 296 * Get all interested depth/stencil formats of a display. 297 */ 298static EGLint 299egl_g3d_fill_depth_stencil_formats(_EGLDisplay *dpy, 300 enum pipe_format formats[8]) 301{ 302 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 303 struct pipe_screen *screen = gdpy->native->screen; 304 const EGLint candidates[] = { 305 1, PIPE_FORMAT_Z16_UNORM, 306 1, PIPE_FORMAT_Z32_UNORM, 307 2, PIPE_FORMAT_Z24_UNORM_S8_USCALED, PIPE_FORMAT_S8_USCALED_Z24_UNORM, 308 2, PIPE_FORMAT_Z24X8_UNORM, PIPE_FORMAT_X8Z24_UNORM, 309 0 310 }; 311 const EGLint *fmt = candidates; 312 EGLint count; 313 314 count = 0; 315 formats[count++] = PIPE_FORMAT_NONE; 316 317 while (*fmt) { 318 EGLint i, n = *fmt++; 319 320 /* pick the first supported format */ 321 for (i = 0; i < n; i++) { 322 if (screen->is_format_supported(screen, fmt[i], 323 PIPE_TEXTURE_2D, 0, PIPE_BIND_DEPTH_STENCIL, 0)) { 324 formats[count++] = fmt[i]; 325 break; 326 } 327 } 328 329 fmt += n; 330 } 331 332 return count; 333} 334 335/** 336 * Add configs to display and return the next config ID. 337 */ 338static EGLint 339egl_g3d_add_configs(_EGLDriver *drv, _EGLDisplay *dpy, EGLint id) 340{ 341 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 342 const struct native_config **native_configs; 343 enum pipe_format depth_stencil_formats[8]; 344 int num_formats, num_configs, i, j; 345 int preserve_buffer, max_swap_interval; 346 347 native_configs = gdpy->native->get_configs(gdpy->native, &num_configs); 348 if (!num_configs) { 349 if (native_configs) 350 FREE(native_configs); 351 return id; 352 } 353 354 preserve_buffer = 355 gdpy->native->get_param(gdpy->native, NATIVE_PARAM_PRESERVE_BUFFER); 356 max_swap_interval = 357 gdpy->native->get_param(gdpy->native, NATIVE_PARAM_MAX_SWAP_INTERVAL); 358 359 num_formats = egl_g3d_fill_depth_stencil_formats(dpy, 360 depth_stencil_formats); 361 362 for (i = 0; i < num_configs; i++) { 363 for (j = 0; j < num_formats; j++) { 364 struct egl_g3d_config *gconf; 365 366 gconf = CALLOC_STRUCT(egl_g3d_config); 367 if (gconf) { 368 _eglInitConfig(&gconf->base, dpy, id); 369 if (!egl_g3d_init_config(drv, dpy, &gconf->base, 370 native_configs[i], depth_stencil_formats[j], 371 preserve_buffer, max_swap_interval)) { 372 FREE(gconf); 373 break; 374 } 375 376 _eglLinkConfig(&gconf->base); 377 id++; 378 } 379 } 380 } 381 382 FREE(native_configs); 383 return id; 384} 385 386static void 387egl_g3d_invalid_surface(struct native_display *ndpy, 388 struct native_surface *nsurf, 389 unsigned int seq_num) 390{ 391 /* XXX not thread safe? */ 392 struct egl_g3d_surface *gsurf = egl_g3d_surface(nsurf->user_data); 393 struct egl_g3d_context *gctx; 394 395 /* 396 * Some functions such as egl_g3d_copy_buffers create a temporary native 397 * surface. There is no gsurf associated with it. 398 */ 399 gctx = (gsurf) ? egl_g3d_context(gsurf->base.CurrentContext) : NULL; 400 if (gctx) 401 gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, gsurf->stfbi); 402} 403 404static struct pipe_screen * 405egl_g3d_new_drm_screen(struct native_display *ndpy, const char *name, int fd) 406{ 407 _EGLDisplay *dpy = (_EGLDisplay *) ndpy->user_data; 408 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 409 return gdpy->loader->create_drm_screen(name, fd); 410} 411 412static struct pipe_screen * 413egl_g3d_new_sw_screen(struct native_display *ndpy, struct sw_winsys *ws) 414{ 415 _EGLDisplay *dpy = (_EGLDisplay *) ndpy->user_data; 416 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 417 return gdpy->loader->create_sw_screen(ws); 418} 419 420static struct native_event_handler egl_g3d_native_event_handler = { 421 egl_g3d_invalid_surface, 422 egl_g3d_new_drm_screen, 423 egl_g3d_new_sw_screen 424}; 425 426static void 427egl_g3d_free_config(void *conf) 428{ 429 struct egl_g3d_config *gconf = egl_g3d_config((_EGLConfig *) conf); 430 FREE(gconf); 431} 432 433static void 434egl_g3d_free_screen(void *scr) 435{ 436#ifdef EGL_MESA_screen_surface 437 struct egl_g3d_screen *gscr = egl_g3d_screen((_EGLScreen *) scr); 438 FREE(gscr->native_modes); 439 FREE(gscr); 440#endif 441} 442 443static EGLBoolean 444egl_g3d_terminate(_EGLDriver *drv, _EGLDisplay *dpy) 445{ 446 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 447 448 _eglReleaseDisplayResources(drv, dpy); 449 450 if (gdpy->pipe) 451 gdpy->pipe->destroy(gdpy->pipe); 452 453 if (dpy->Configs) { 454 _eglDestroyArray(dpy->Configs, egl_g3d_free_config); 455 dpy->Configs = NULL; 456 } 457 if (dpy->Screens) { 458 _eglDestroyArray(dpy->Screens, egl_g3d_free_screen); 459 dpy->Screens = NULL; 460 } 461 462 _eglCleanupDisplay(dpy); 463 464 if (gdpy->smapi) 465 egl_g3d_destroy_st_manager(gdpy->smapi); 466 467 if (gdpy->native) 468 gdpy->native->destroy(gdpy->native); 469 470 FREE(gdpy); 471 dpy->DriverData = NULL; 472 473 return EGL_TRUE; 474} 475 476static EGLBoolean 477egl_g3d_initialize(_EGLDriver *drv, _EGLDisplay *dpy) 478{ 479 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 480 struct egl_g3d_display *gdpy; 481 const struct native_platform *nplat; 482 483 nplat = egl_g3d_get_platform(drv, dpy->Platform); 484 if (!nplat) 485 return EGL_FALSE; 486 487 if (dpy->Options.TestOnly) 488 return EGL_TRUE; 489 490 gdpy = CALLOC_STRUCT(egl_g3d_display); 491 if (!gdpy) { 492 _eglError(EGL_BAD_ALLOC, "eglInitialize"); 493 goto fail; 494 } 495 gdpy->loader = gdrv->loader; 496 dpy->DriverData = gdpy; 497 498 _eglLog(_EGL_INFO, "use %s for display %p", nplat->name, dpy->PlatformDisplay); 499 gdpy->native = nplat->create_display(dpy->PlatformDisplay, 500 &egl_g3d_native_event_handler, (void *) dpy); 501 if (!gdpy->native) { 502 _eglError(EGL_NOT_INITIALIZED, "eglInitialize(no usable display)"); 503 goto fail; 504 } 505 506 if (gdpy->loader->profile_masks[ST_API_OPENGL] & ST_PROFILE_DEFAULT_MASK) 507 dpy->ClientAPIs |= EGL_OPENGL_BIT; 508 if (gdpy->loader->profile_masks[ST_API_OPENGL] & ST_PROFILE_OPENGL_ES1_MASK) 509 dpy->ClientAPIs |= EGL_OPENGL_ES_BIT; 510 if (gdpy->loader->profile_masks[ST_API_OPENGL] & ST_PROFILE_OPENGL_ES2_MASK) 511 dpy->ClientAPIs |= EGL_OPENGL_ES2_BIT; 512 if (gdpy->loader->profile_masks[ST_API_OPENVG] & ST_PROFILE_DEFAULT_MASK) 513 dpy->ClientAPIs |= EGL_OPENVG_BIT; 514 515 gdpy->smapi = egl_g3d_create_st_manager(dpy); 516 if (!gdpy->smapi) { 517 _eglError(EGL_NOT_INITIALIZED, 518 "eglInitialize(failed to create st manager)"); 519 goto fail; 520 } 521 522#ifdef EGL_MESA_screen_surface 523 /* enable MESA_screen_surface before adding (and validating) configs */ 524 if (gdpy->native->modeset) { 525 dpy->Extensions.MESA_screen_surface = EGL_TRUE; 526 egl_g3d_add_screens(drv, dpy); 527 } 528#endif 529 530 dpy->Extensions.KHR_image_base = EGL_TRUE; 531 if (gdpy->native->get_param(gdpy->native, NATIVE_PARAM_USE_NATIVE_BUFFER)) 532 dpy->Extensions.KHR_image_pixmap = EGL_TRUE; 533 534 dpy->Extensions.KHR_reusable_sync = EGL_TRUE; 535 dpy->Extensions.KHR_fence_sync = EGL_TRUE; 536 537 dpy->Extensions.KHR_surfaceless_gles1 = EGL_TRUE; 538 dpy->Extensions.KHR_surfaceless_gles2 = EGL_TRUE; 539 dpy->Extensions.KHR_surfaceless_opengl = EGL_TRUE; 540 541 if (dpy->Platform == _EGL_PLATFORM_DRM) { 542 dpy->Extensions.MESA_drm_display = EGL_TRUE; 543 if (gdpy->native->buffer) 544 dpy->Extensions.MESA_drm_image = EGL_TRUE; 545 } 546 547 if (egl_g3d_add_configs(drv, dpy, 1) == 1) { 548 _eglError(EGL_NOT_INITIALIZED, "eglInitialize(unable to add configs)"); 549 goto fail; 550 } 551 552 dpy->VersionMajor = 1; 553 dpy->VersionMinor = 4; 554 555 return EGL_TRUE; 556 557fail: 558 if (gdpy) 559 egl_g3d_terminate(drv, dpy); 560 return EGL_FALSE; 561} 562 563static _EGLProc 564egl_g3d_get_proc_address(_EGLDriver *drv, const char *procname) 565{ 566 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 567 struct st_api *stapi = NULL; 568 569 if (procname && procname[0] == 'v' && procname[1] == 'g') 570 stapi = gdrv->loader->get_st_api(ST_API_OPENVG); 571 else if (procname && procname[0] == 'g' && procname[1] == 'l') 572 stapi = gdrv->loader->get_st_api(ST_API_OPENGL); 573 574 return (_EGLProc) ((stapi) ? 575 stapi->get_proc_address(stapi, procname) : NULL); 576} 577 578_EGLDriver * 579egl_g3d_create_driver(const struct egl_g3d_loader *loader) 580{ 581 struct egl_g3d_driver *gdrv; 582 583 gdrv = CALLOC_STRUCT(egl_g3d_driver); 584 if (!gdrv) 585 return NULL; 586 587 gdrv->loader = loader; 588 589 egl_g3d_init_driver_api(&gdrv->base); 590 gdrv->base.API.Initialize = egl_g3d_initialize; 591 gdrv->base.API.Terminate = egl_g3d_terminate; 592 gdrv->base.API.GetProcAddress = egl_g3d_get_proc_address; 593 594 /* to be filled by the caller */ 595 gdrv->base.Name = NULL; 596 gdrv->base.Unload = NULL; 597 598 return &gdrv->base; 599} 600 601void 602egl_g3d_destroy_driver(_EGLDriver *drv) 603{ 604 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 605 FREE(gdrv); 606} 607