egl_g3d.c revision 2a15553e431f04d13b757a3a76e4eb7d794f1219
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 "native.h" 39 40/** 41 * Initialize the state trackers. 42 */ 43static void 44egl_g3d_init_st(_EGLDriver *drv) 45{ 46 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 47 EGLint i; 48 49 /* already initialized */ 50 if (gdrv->api_mask) 51 return; 52 53 for (i = 0; i < ST_API_COUNT; i++) { 54 gdrv->stapis[i] = egl_g3d_create_st_api(i); 55 if (gdrv->stapis[i]) 56 gdrv->api_mask |= egl_g3d_st_api_bit(i); 57 } 58 59 if (gdrv->api_mask) 60 _eglLog(_EGL_DEBUG, "Driver API mask: 0x%x", gdrv->api_mask); 61 else 62 _eglLog(_EGL_WARNING, "No supported client API"); 63} 64 65/** 66 * Get the probe object of the display. 67 * 68 * Note that this function may be called before the display is initialized. 69 */ 70static struct native_probe * 71egl_g3d_get_probe(_EGLDriver *drv, _EGLDisplay *dpy) 72{ 73 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 74 struct native_probe *nprobe; 75 76 nprobe = (struct native_probe *) _eglGetProbeCache(gdrv->probe_key); 77 if (!nprobe || nprobe->display != dpy->NativeDisplay) { 78 if (nprobe) 79 nprobe->destroy(nprobe); 80 nprobe = native_create_probe(dpy->NativeDisplay); 81 _eglSetProbeCache(gdrv->probe_key, (void *) nprobe); 82 } 83 84 return nprobe; 85} 86 87/** 88 * Destroy the probe object of the display. The display may be NULL. 89 * 90 * Note that this function may be called before the display is initialized. 91 */ 92static void 93egl_g3d_destroy_probe(_EGLDriver *drv, _EGLDisplay *dpy) 94{ 95 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 96 struct native_probe *nprobe; 97 98 nprobe = (struct native_probe *) _eglGetProbeCache(gdrv->probe_key); 99 if (nprobe && (!dpy || nprobe->display == dpy->NativeDisplay)) { 100 nprobe->destroy(nprobe); 101 _eglSetProbeCache(gdrv->probe_key, NULL); 102 } 103} 104 105#ifdef EGL_MESA_screen_surface 106 107static void 108egl_g3d_add_screens(_EGLDriver *drv, _EGLDisplay *dpy) 109{ 110 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 111 const struct native_connector **native_connectors; 112 EGLint num_connectors, i; 113 114 native_connectors = 115 gdpy->native->modeset->get_connectors(gdpy->native, &num_connectors, NULL); 116 if (!num_connectors) { 117 if (native_connectors) 118 FREE(native_connectors); 119 return; 120 } 121 122 for (i = 0; i < num_connectors; i++) { 123 const struct native_connector *nconn = native_connectors[i]; 124 struct egl_g3d_screen *gscr; 125 const struct native_mode **native_modes; 126 EGLint num_modes, j; 127 128 /* TODO support for hotplug */ 129 native_modes = 130 gdpy->native->modeset->get_modes(gdpy->native, nconn, &num_modes); 131 if (!num_modes) { 132 if (native_modes) 133 FREE(native_modes); 134 continue; 135 } 136 137 gscr = CALLOC_STRUCT(egl_g3d_screen); 138 if (!gscr) { 139 FREE(native_modes); 140 continue; 141 } 142 143 _eglInitScreen(&gscr->base); 144 145 for (j = 0; j < num_modes; j++) { 146 const struct native_mode *nmode = native_modes[j]; 147 _EGLMode *mode; 148 149 mode = _eglAddNewMode(&gscr->base, nmode->width, nmode->height, 150 nmode->refresh_rate, nmode->desc); 151 if (!mode) 152 break; 153 /* gscr->native_modes and gscr->base.Modes should be consistent */ 154 assert(mode == &gscr->base.Modes[j]); 155 } 156 157 gscr->native = nconn; 158 gscr->native_modes = native_modes; 159 160 _eglAddScreen(dpy, &gscr->base); 161 } 162 163 FREE(native_connectors); 164} 165 166#endif /* EGL_MESA_screen_surface */ 167 168/** 169 * Initialize and validate the EGL config attributes. 170 */ 171static EGLBoolean 172init_config_attributes(_EGLConfig *conf, const struct native_config *nconf, 173 EGLint api_mask, enum pipe_format depth_stencil_format) 174{ 175 uint rgba[4], depth_stencil[2], buffer_size; 176 EGLint surface_type; 177 EGLint i; 178 179 /* get the color and depth/stencil component sizes */ 180 assert(nconf->color_format != PIPE_FORMAT_NONE); 181 buffer_size = 0; 182 for (i = 0; i < 4; i++) { 183 rgba[i] = util_format_get_component_bits(nconf->color_format, 184 UTIL_FORMAT_COLORSPACE_RGB, i); 185 buffer_size += rgba[i]; 186 } 187 for (i = 0; i < 2; i++) { 188 if (depth_stencil_format != PIPE_FORMAT_NONE) { 189 depth_stencil[i] = 190 util_format_get_component_bits(depth_stencil_format, 191 UTIL_FORMAT_COLORSPACE_ZS, i); 192 } 193 else { 194 depth_stencil[i] = 0; 195 } 196 } 197 198 surface_type = 0x0; 199 if (nconf->window_bit) 200 surface_type |= EGL_WINDOW_BIT; 201 if (nconf->pixmap_bit) 202 surface_type |= EGL_PIXMAP_BIT; 203#ifdef EGL_MESA_screen_surface 204 if (nconf->scanout_bit) 205 surface_type |= EGL_SCREEN_BIT_MESA; 206#endif 207 208 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_LEFT)) 209 surface_type |= EGL_PBUFFER_BIT; 210 211 SET_CONFIG_ATTRIB(conf, EGL_CONFORMANT, api_mask); 212 SET_CONFIG_ATTRIB(conf, EGL_RENDERABLE_TYPE, api_mask); 213 214 SET_CONFIG_ATTRIB(conf, EGL_RED_SIZE, rgba[0]); 215 SET_CONFIG_ATTRIB(conf, EGL_GREEN_SIZE, rgba[1]); 216 SET_CONFIG_ATTRIB(conf, EGL_BLUE_SIZE, rgba[2]); 217 SET_CONFIG_ATTRIB(conf, EGL_ALPHA_SIZE, rgba[3]); 218 SET_CONFIG_ATTRIB(conf, EGL_BUFFER_SIZE, buffer_size); 219 220 SET_CONFIG_ATTRIB(conf, EGL_DEPTH_SIZE, depth_stencil[0]); 221 SET_CONFIG_ATTRIB(conf, EGL_STENCIL_SIZE, depth_stencil[1]); 222 223 SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE, surface_type); 224 225 SET_CONFIG_ATTRIB(conf, EGL_NATIVE_RENDERABLE, EGL_TRUE); 226 if (surface_type & EGL_WINDOW_BIT) { 227 SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID, nconf->native_visual_id); 228 SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, 229 nconf->native_visual_type); 230 } 231 232 if (surface_type & EGL_PBUFFER_BIT) { 233 SET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE); 234 if (rgba[3]) 235 SET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE); 236 237 SET_CONFIG_ATTRIB(conf, EGL_MAX_PBUFFER_WIDTH, 4096); 238 SET_CONFIG_ATTRIB(conf, EGL_MAX_PBUFFER_HEIGHT, 4096); 239 SET_CONFIG_ATTRIB(conf, EGL_MAX_PBUFFER_PIXELS, 4096 * 4096); 240 } 241 242 SET_CONFIG_ATTRIB(conf, EGL_LEVEL, nconf->level); 243 SET_CONFIG_ATTRIB(conf, EGL_SAMPLES, nconf->samples); 244 SET_CONFIG_ATTRIB(conf, EGL_SAMPLE_BUFFERS, 1); 245 246 if (nconf->slow_config) 247 SET_CONFIG_ATTRIB(conf, EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG); 248 249 if (nconf->transparent_rgb) { 250 rgba[0] = nconf->transparent_rgb_values[0]; 251 rgba[1] = nconf->transparent_rgb_values[1]; 252 rgba[2] = nconf->transparent_rgb_values[2]; 253 254 SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_TYPE, EGL_TRANSPARENT_RGB); 255 SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_RED_VALUE, rgba[0]); 256 SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_GREEN_VALUE, rgba[1]); 257 SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_BLUE_VALUE, rgba[2]); 258 } 259 260 return _eglValidateConfig(conf, EGL_FALSE); 261} 262 263/** 264 * Initialize an EGL config from the native config. 265 */ 266static EGLBoolean 267egl_g3d_init_config(_EGLDriver *drv, _EGLDisplay *dpy, 268 _EGLConfig *conf, const struct native_config *nconf, 269 enum pipe_format depth_stencil_format) 270{ 271 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 272 struct egl_g3d_config *gconf = egl_g3d_config(conf); 273 EGLint buffer_mask, api_mask; 274 EGLBoolean valid; 275 EGLint i; 276 277 buffer_mask = 0x0; 278 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_FRONT_LEFT)) 279 buffer_mask |= ST_ATTACHMENT_FRONT_LEFT_MASK; 280 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_LEFT)) 281 buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK; 282 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_FRONT_RIGHT)) 283 buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK; 284 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_RIGHT)) 285 buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK; 286 287 gconf->stvis.buffer_mask = buffer_mask; 288 gconf->stvis.color_format = nconf->color_format; 289 gconf->stvis.depth_stencil_format = depth_stencil_format; 290 gconf->stvis.accum_format = PIPE_FORMAT_NONE; 291 gconf->stvis.samples = nconf->samples; 292 293 gconf->stvis.render_buffer = (buffer_mask & ST_ATTACHMENT_BACK_LEFT_MASK) ? 294 ST_ATTACHMENT_BACK_LEFT : ST_ATTACHMENT_FRONT_LEFT; 295 296 api_mask = 0; 297 for (i = 0; i < ST_API_COUNT; i++) { 298 struct st_api *stapi = gdrv->stapis[i]; 299 if (stapi) { 300 if (stapi->is_visual_supported(stapi, &gconf->stvis)) 301 api_mask |= egl_g3d_st_api_bit(i); 302 } 303 } 304 /* this is required by EGL, not by OpenGL ES */ 305 if (nconf->window_bit && 306 gconf->stvis.render_buffer != ST_ATTACHMENT_BACK_LEFT) 307 api_mask &= ~(EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT); 308 309 if (!api_mask) { 310 _eglLog(_EGL_DEBUG, "no state tracker supports config 0x%x", 311 nconf->native_visual_id); 312 } 313 314 valid = init_config_attributes(&gconf->base, 315 nconf, api_mask, depth_stencil_format); 316 if (!valid) { 317 _eglLog(_EGL_DEBUG, "skip invalid config 0x%x", nconf->native_visual_id); 318 return EGL_FALSE; 319 } 320 321 gconf->native = nconf; 322 323 return EGL_TRUE; 324} 325 326/** 327 * Get all interested depth/stencil formats of a display. 328 */ 329static EGLint 330egl_g3d_fill_depth_stencil_formats(_EGLDisplay *dpy, 331 enum pipe_format formats[8]) 332{ 333 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 334 struct pipe_screen *screen = gdpy->native->screen; 335 const EGLint candidates[] = { 336 1, PIPE_FORMAT_Z16_UNORM, 337 1, PIPE_FORMAT_Z32_UNORM, 338 2, PIPE_FORMAT_Z24_UNORM_S8_USCALED, PIPE_FORMAT_S8_USCALED_Z24_UNORM, 339 2, PIPE_FORMAT_Z24X8_UNORM, PIPE_FORMAT_X8Z24_UNORM, 340 0 341 }; 342 const EGLint *fmt = candidates; 343 EGLint count; 344 345 count = 0; 346 formats[count++] = PIPE_FORMAT_NONE; 347 348 while (*fmt) { 349 EGLint i, n = *fmt++; 350 351 /* pick the first supported format */ 352 for (i = 0; i < n; i++) { 353 if (screen->is_format_supported(screen, fmt[i], 354 PIPE_TEXTURE_2D, 0, PIPE_BIND_DEPTH_STENCIL, 0)) { 355 formats[count++] = fmt[i]; 356 break; 357 } 358 } 359 360 fmt += n; 361 } 362 363 return count; 364} 365 366/** 367 * Add configs to display and return the next config ID. 368 */ 369static EGLint 370egl_g3d_add_configs(_EGLDriver *drv, _EGLDisplay *dpy, EGLint id) 371{ 372 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 373 const struct native_config **native_configs; 374 enum pipe_format depth_stencil_formats[8]; 375 int num_formats, num_configs, i, j; 376 377 native_configs = gdpy->native->get_configs(gdpy->native, &num_configs); 378 if (!num_configs) { 379 if (native_configs) 380 FREE(native_configs); 381 return id; 382 } 383 384 num_formats = egl_g3d_fill_depth_stencil_formats(dpy, 385 depth_stencil_formats); 386 387 for (i = 0; i < num_configs; i++) { 388 for (j = 0; j < num_formats; j++) { 389 struct egl_g3d_config *gconf; 390 391 gconf = CALLOC_STRUCT(egl_g3d_config); 392 if (gconf) { 393 _eglInitConfig(&gconf->base, dpy, id); 394 if (!egl_g3d_init_config(drv, dpy, &gconf->base, 395 native_configs[i], depth_stencil_formats[j])) { 396 FREE(gconf); 397 break; 398 } 399 400 _eglAddConfig(dpy, &gconf->base); 401 id++; 402 } 403 } 404 } 405 406 FREE(native_configs); 407 return id; 408} 409 410static void 411egl_g3d_invalid_surface(struct native_display *ndpy, 412 struct native_surface *nsurf, 413 unsigned int seq_num) 414{ 415 /* XXX not thread safe? */ 416 struct egl_g3d_surface *gsurf = egl_g3d_surface(nsurf->user_data); 417 struct egl_g3d_context *gctx; 418 419 /* 420 * Some functions such as egl_g3d_copy_buffers create a temporary native 421 * surface. There is no gsurf associated with it. 422 */ 423 gctx = (gsurf) ? egl_g3d_context(gsurf->base.CurrentContext) : NULL; 424 if (gctx) 425 gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, gsurf->stfbi); 426} 427 428static struct native_event_handler egl_g3d_native_event_handler = { 429 .invalid_surface = egl_g3d_invalid_surface 430}; 431 432static EGLBoolean 433egl_g3d_terminate(_EGLDriver *drv, _EGLDisplay *dpy) 434{ 435 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 436 EGLint i; 437 438 _eglReleaseDisplayResources(drv, dpy); 439 _eglCleanupDisplay(dpy); 440 441 if (gdpy->pipe) 442 gdpy->pipe->destroy(gdpy->pipe); 443 444 if (dpy->Screens) { 445 for (i = 0; i < dpy->NumScreens; i++) { 446 struct egl_g3d_screen *gscr = egl_g3d_screen(dpy->Screens[i]); 447 FREE(gscr->native_modes); 448 FREE(gscr); 449 } 450 FREE(dpy->Screens); 451 } 452 453 if (gdpy->smapi) 454 egl_g3d_destroy_st_manager(gdpy->smapi); 455 456 if (gdpy->native) 457 gdpy->native->destroy(gdpy->native); 458 459 FREE(gdpy); 460 dpy->DriverData = NULL; 461 462 return EGL_TRUE; 463} 464 465static EGLBoolean 466egl_g3d_initialize(_EGLDriver *drv, _EGLDisplay *dpy, 467 EGLint *major, EGLint *minor) 468{ 469 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 470 struct egl_g3d_display *gdpy; 471 472 /* the probe object is unlikely to be needed again */ 473 egl_g3d_destroy_probe(drv, dpy); 474 475 gdpy = CALLOC_STRUCT(egl_g3d_display); 476 if (!gdpy) { 477 _eglError(EGL_BAD_ALLOC, "eglInitialize"); 478 goto fail; 479 } 480 dpy->DriverData = gdpy; 481 482 gdpy->native = native_create_display(dpy->NativeDisplay, 483 &egl_g3d_native_event_handler); 484 if (!gdpy->native) { 485 _eglError(EGL_NOT_INITIALIZED, "eglInitialize(no usable display)"); 486 goto fail; 487 } 488 489 gdpy->native->user_data = (void *) dpy; 490 491 egl_g3d_init_st(&gdrv->base); 492 dpy->ClientAPIsMask = gdrv->api_mask; 493 494 gdpy->smapi = egl_g3d_create_st_manager(dpy); 495 if (!gdpy->smapi) { 496 _eglError(EGL_NOT_INITIALIZED, 497 "eglInitialize(failed to create st manager)"); 498 goto fail; 499 } 500 501#ifdef EGL_MESA_screen_surface 502 /* enable MESA_screen_surface before adding (and validating) configs */ 503 if (gdpy->native->modeset) { 504 dpy->Extensions.MESA_screen_surface = EGL_TRUE; 505 egl_g3d_add_screens(drv, dpy); 506 } 507#endif 508 509 dpy->Extensions.KHR_image_base = EGL_TRUE; 510 if (gdpy->native->get_param(gdpy->native, NATIVE_PARAM_USE_NATIVE_BUFFER)) 511 dpy->Extensions.KHR_image_pixmap = EGL_TRUE; 512 513 if (egl_g3d_add_configs(drv, dpy, 1) == 1) { 514 _eglError(EGL_NOT_INITIALIZED, "eglInitialize(unable to add configs)"); 515 goto fail; 516 } 517 518 *major = 1; 519 *minor = 4; 520 521 return EGL_TRUE; 522 523fail: 524 if (gdpy) 525 egl_g3d_terminate(drv, dpy); 526 return EGL_FALSE; 527} 528 529static _EGLProc 530egl_g3d_get_proc_address(_EGLDriver *drv, const char *procname) 531{ 532 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 533 _EGLProc proc; 534 EGLint i; 535 536 /* in case this is called before a display is initialized */ 537 egl_g3d_init_st(&gdrv->base); 538 539 for (i = 0; i < ST_API_COUNT; i++) { 540 struct st_api *stapi = gdrv->stapis[i]; 541 if (stapi) { 542 proc = (_EGLProc) stapi->get_proc_address(stapi, procname); 543 if (proc) 544 return proc; 545 } 546 } 547 548 return (_EGLProc) NULL; 549} 550 551static EGLint 552egl_g3d_probe(_EGLDriver *drv, _EGLDisplay *dpy) 553{ 554 struct native_probe *nprobe; 555 enum native_probe_result res; 556 EGLint score; 557 558 nprobe = egl_g3d_get_probe(drv, dpy); 559 res = native_get_probe_result(nprobe); 560 561 switch (res) { 562 case NATIVE_PROBE_UNKNOWN: 563 default: 564 score = 0; 565 break; 566 case NATIVE_PROBE_FALLBACK: 567 score = 40; 568 break; 569 case NATIVE_PROBE_SUPPORTED: 570 score = 50; 571 break; 572 case NATIVE_PROBE_EXACT: 573 score = 100; 574 break; 575 } 576 577 return score; 578} 579 580static void 581egl_g3d_unload(_EGLDriver *drv) 582{ 583 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 584 EGLint i; 585 586 for (i = 0; i < ST_API_COUNT; i++) { 587 if (gdrv->stapis[i]) 588 gdrv->stapis[i]->destroy(gdrv->stapis[i]); 589 } 590 591 egl_g3d_destroy_probe(drv, NULL); 592 FREE(gdrv); 593} 594 595_EGLDriver * 596_eglMain(const char *args) 597{ 598 static char driver_name[64]; 599 struct egl_g3d_driver *gdrv; 600 601 util_snprintf(driver_name, sizeof(driver_name), 602 "Gallium/%s", native_get_name()); 603 604 gdrv = CALLOC_STRUCT(egl_g3d_driver); 605 if (!gdrv) 606 return NULL; 607 608 egl_g3d_init_driver_api(&gdrv->base); 609 gdrv->base.API.Initialize = egl_g3d_initialize; 610 gdrv->base.API.Terminate = egl_g3d_terminate; 611 gdrv->base.API.GetProcAddress = egl_g3d_get_proc_address; 612 613 gdrv->base.Name = driver_name; 614 gdrv->base.Probe = egl_g3d_probe; 615 gdrv->base.Unload = egl_g3d_unload; 616 617 /* the key is " EGL G3D" */ 618 gdrv->probe_key = 0x0E61063D; 619 620 return &gdrv->base; 621} 622