egl_g3d.c revision 3a93c348280767949c80ff6dde1645b77cab143d
1762bb9d0ad20320b9f97a841dce57ba5e8e48b07Richard Smith/* 23e4c6c4c79a03f5cb0c4671d7c282d623c6dc35eRichard Smith * Mesa 3-D graphics library 33e4c6c4c79a03f5cb0c4671d7c282d623c6dc35eRichard Smith * Version: 7.8 4898574e7496ba8fd76290079d3a9d06954992734Douglas Gregor * 5898574e7496ba8fd76290079d3a9d06954992734Douglas Gregor * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org> 6898574e7496ba8fd76290079d3a9d06954992734Douglas Gregor * 7898574e7496ba8fd76290079d3a9d06954992734Douglas Gregor * Permission is hereby granted, free of charge, to any person obtaining a 8898574e7496ba8fd76290079d3a9d06954992734Douglas Gregor * copy of this software and associated documentation files (the "Software"), 96e8247556807ecaaac470852222762db998a05b2Sebastian Redl * to deal in the Software without restriction, including without limitation 10898574e7496ba8fd76290079d3a9d06954992734Douglas Gregor * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11898574e7496ba8fd76290079d3a9d06954992734Douglas Gregor * and/or sell copies of the Software, and to permit persons to whom the 123e4c6c4c79a03f5cb0c4671d7c282d623c6dc35eRichard Smith * Software is furnished to do so, subject to the following conditions: 13898574e7496ba8fd76290079d3a9d06954992734Douglas Gregor * 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 conf->Samples = nconf->samples; 230 conf->SampleBuffers = 0; 231 232 if (nconf->transparent_rgb) { 233 conf->TransparentType = EGL_TRANSPARENT_RGB; 234 conf->TransparentRedValue = nconf->transparent_rgb_values[0]; 235 conf->TransparentGreenValue = nconf->transparent_rgb_values[1]; 236 conf->TransparentBlueValue = nconf->transparent_rgb_values[2]; 237 } 238 239 conf->MinSwapInterval = 0; 240 conf->MaxSwapInterval = max_swap_interval; 241 if (preserve_buffer) 242 conf->SurfaceType |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT; 243 244 return _eglValidateConfig(conf, EGL_FALSE); 245} 246 247/** 248 * Initialize an EGL config from the native config. 249 */ 250static EGLBoolean 251egl_g3d_init_config(_EGLDriver *drv, _EGLDisplay *dpy, 252 _EGLConfig *conf, const struct native_config *nconf, 253 enum pipe_format depth_stencil_format, 254 int preserve_buffer, int max_swap_interval) 255{ 256 struct egl_g3d_config *gconf = egl_g3d_config(conf); 257 EGLint buffer_mask, api_mask; 258 EGLBoolean valid; 259 260 /* skip single-buffered configs */ 261 if (!(nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_LEFT))) 262 return EGL_FALSE; 263 264 buffer_mask = 0x0; 265 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_FRONT_LEFT)) 266 buffer_mask |= ST_ATTACHMENT_FRONT_LEFT_MASK; 267 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_LEFT)) 268 buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK; 269 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_FRONT_RIGHT)) 270 buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK; 271 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_RIGHT)) 272 buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK; 273 274 gconf->stvis.buffer_mask = buffer_mask; 275 gconf->stvis.color_format = nconf->color_format; 276 gconf->stvis.depth_stencil_format = depth_stencil_format; 277 gconf->stvis.accum_format = PIPE_FORMAT_NONE; 278 gconf->stvis.samples = nconf->samples; 279 280 gconf->stvis.render_buffer = (buffer_mask & ST_ATTACHMENT_BACK_LEFT_MASK) ? 281 ST_ATTACHMENT_BACK_LEFT : ST_ATTACHMENT_FRONT_LEFT; 282 283 api_mask = dpy->ClientAPIsMask; 284 /* this is required by EGL, not by OpenGL ES */ 285 if (nconf->window_bit && 286 gconf->stvis.render_buffer != ST_ATTACHMENT_BACK_LEFT) 287 api_mask &= ~(EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT); 288 289 if (!api_mask) { 290 _eglLog(_EGL_DEBUG, "no state tracker supports config 0x%x", 291 nconf->native_visual_id); 292 } 293 294 valid = init_config_attributes(&gconf->base, 295 nconf, api_mask, depth_stencil_format, 296 preserve_buffer, max_swap_interval); 297 if (!valid) { 298 _eglLog(_EGL_DEBUG, "skip invalid config 0x%x", nconf->native_visual_id); 299 return EGL_FALSE; 300 } 301 302 gconf->native = nconf; 303 304 return EGL_TRUE; 305} 306 307/** 308 * Get all interested depth/stencil formats of a display. 309 */ 310static EGLint 311egl_g3d_fill_depth_stencil_formats(_EGLDisplay *dpy, 312 enum pipe_format formats[8]) 313{ 314 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 315 struct pipe_screen *screen = gdpy->native->screen; 316 const EGLint candidates[] = { 317 1, PIPE_FORMAT_Z16_UNORM, 318 1, PIPE_FORMAT_Z32_UNORM, 319 2, PIPE_FORMAT_Z24_UNORM_S8_USCALED, PIPE_FORMAT_S8_USCALED_Z24_UNORM, 320 2, PIPE_FORMAT_Z24X8_UNORM, PIPE_FORMAT_X8Z24_UNORM, 321 0 322 }; 323 const EGLint *fmt = candidates; 324 EGLint count; 325 326 count = 0; 327 formats[count++] = PIPE_FORMAT_NONE; 328 329 while (*fmt) { 330 EGLint i, n = *fmt++; 331 332 /* pick the first supported format */ 333 for (i = 0; i < n; i++) { 334 if (screen->is_format_supported(screen, fmt[i], 335 PIPE_TEXTURE_2D, 0, PIPE_BIND_DEPTH_STENCIL, 0)) { 336 formats[count++] = fmt[i]; 337 break; 338 } 339 } 340 341 fmt += n; 342 } 343 344 return count; 345} 346 347/** 348 * Add configs to display and return the next config ID. 349 */ 350static EGLint 351egl_g3d_add_configs(_EGLDriver *drv, _EGLDisplay *dpy, EGLint id) 352{ 353 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 354 const struct native_config **native_configs; 355 enum pipe_format depth_stencil_formats[8]; 356 int num_formats, num_configs, i, j; 357 int preserve_buffer, max_swap_interval; 358 359 native_configs = gdpy->native->get_configs(gdpy->native, &num_configs); 360 if (!num_configs) { 361 if (native_configs) 362 FREE(native_configs); 363 return id; 364 } 365 366 preserve_buffer = 367 gdpy->native->get_param(gdpy->native, NATIVE_PARAM_PRESERVE_BUFFER); 368 max_swap_interval = 369 gdpy->native->get_param(gdpy->native, NATIVE_PARAM_MAX_SWAP_INTERVAL); 370 371 num_formats = egl_g3d_fill_depth_stencil_formats(dpy, 372 depth_stencil_formats); 373 374 for (i = 0; i < num_configs; i++) { 375 for (j = 0; j < num_formats; j++) { 376 struct egl_g3d_config *gconf; 377 378 gconf = CALLOC_STRUCT(egl_g3d_config); 379 if (gconf) { 380 _eglInitConfig(&gconf->base, dpy, id); 381 if (!egl_g3d_init_config(drv, dpy, &gconf->base, 382 native_configs[i], depth_stencil_formats[j], 383 preserve_buffer, max_swap_interval)) { 384 FREE(gconf); 385 break; 386 } 387 388 _eglLinkConfig(&gconf->base); 389 id++; 390 } 391 } 392 } 393 394 FREE(native_configs); 395 return id; 396} 397 398static void 399egl_g3d_invalid_surface(struct native_display *ndpy, 400 struct native_surface *nsurf, 401 unsigned int seq_num) 402{ 403 /* XXX not thread safe? */ 404 struct egl_g3d_surface *gsurf = egl_g3d_surface(nsurf->user_data); 405 struct egl_g3d_context *gctx; 406 407 /* 408 * Some functions such as egl_g3d_copy_buffers create a temporary native 409 * surface. There is no gsurf associated with it. 410 */ 411 gctx = (gsurf) ? egl_g3d_context(gsurf->base.CurrentContext) : NULL; 412 if (gctx) 413 gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, gsurf->stfbi); 414} 415 416static struct pipe_screen * 417egl_g3d_new_drm_screen(struct native_display *ndpy, const char *name, int fd) 418{ 419 _EGLDisplay *dpy = (_EGLDisplay *) ndpy->user_data; 420 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 421 return gdpy->loader->create_drm_screen(name, fd); 422} 423 424static struct pipe_screen * 425egl_g3d_new_sw_screen(struct native_display *ndpy, struct sw_winsys *ws) 426{ 427 _EGLDisplay *dpy = (_EGLDisplay *) ndpy->user_data; 428 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 429 return gdpy->loader->create_sw_screen(ws); 430} 431 432static struct native_event_handler egl_g3d_native_event_handler = { 433 egl_g3d_invalid_surface, 434 egl_g3d_new_drm_screen, 435 egl_g3d_new_sw_screen 436}; 437 438static void 439egl_g3d_free_config(void *conf) 440{ 441 struct egl_g3d_config *gconf = egl_g3d_config((_EGLConfig *) conf); 442 FREE(gconf); 443} 444 445static void 446egl_g3d_free_screen(void *scr) 447{ 448#ifdef EGL_MESA_screen_surface 449 struct egl_g3d_screen *gscr = egl_g3d_screen((_EGLScreen *) scr); 450 FREE(gscr->native_modes); 451 FREE(gscr); 452#endif 453} 454 455static EGLBoolean 456egl_g3d_terminate(_EGLDriver *drv, _EGLDisplay *dpy) 457{ 458 struct egl_g3d_display *gdpy = egl_g3d_display(dpy); 459 460 _eglReleaseDisplayResources(drv, dpy); 461 462 if (gdpy->pipe) 463 gdpy->pipe->destroy(gdpy->pipe); 464 465 if (dpy->Configs) { 466 _eglDestroyArray(dpy->Configs, egl_g3d_free_config); 467 dpy->Configs = NULL; 468 } 469 if (dpy->Screens) { 470 _eglDestroyArray(dpy->Screens, egl_g3d_free_screen); 471 dpy->Screens = NULL; 472 } 473 474 _eglCleanupDisplay(dpy); 475 476 if (gdpy->smapi) 477 egl_g3d_destroy_st_manager(gdpy->smapi); 478 479 if (gdpy->native) 480 gdpy->native->destroy(gdpy->native); 481 482 FREE(gdpy); 483 dpy->DriverData = NULL; 484 485 return EGL_TRUE; 486} 487 488static EGLBoolean 489egl_g3d_initialize(_EGLDriver *drv, _EGLDisplay *dpy, 490 EGLint *major, EGLint *minor) 491{ 492 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 493 struct egl_g3d_display *gdpy; 494 const struct native_platform *nplat; 495 496 nplat = egl_g3d_get_platform(drv, dpy->Platform); 497 if (!nplat) 498 return EGL_FALSE; 499 500 gdpy = CALLOC_STRUCT(egl_g3d_display); 501 if (!gdpy) { 502 _eglError(EGL_BAD_ALLOC, "eglInitialize"); 503 goto fail; 504 } 505 gdpy->loader = gdrv->loader; 506 dpy->DriverData = gdpy; 507 508 _eglLog(_EGL_INFO, "use %s for display %p", nplat->name, dpy->PlatformDisplay); 509 gdpy->native = nplat->create_display(dpy->PlatformDisplay, 510 &egl_g3d_native_event_handler, (void *) dpy); 511 if (!gdpy->native) { 512 _eglError(EGL_NOT_INITIALIZED, "eglInitialize(no usable display)"); 513 goto fail; 514 } 515 516 if (gdpy->loader->profile_masks[ST_API_OPENGL] & ST_PROFILE_DEFAULT_MASK) 517 dpy->ClientAPIsMask |= EGL_OPENGL_BIT; 518 if (gdpy->loader->profile_masks[ST_API_OPENGL] & ST_PROFILE_OPENGL_ES1_MASK) 519 dpy->ClientAPIsMask |= EGL_OPENGL_ES_BIT; 520 if (gdpy->loader->profile_masks[ST_API_OPENGL] & ST_PROFILE_OPENGL_ES2_MASK) 521 dpy->ClientAPIsMask |= EGL_OPENGL_ES2_BIT; 522 if (gdpy->loader->profile_masks[ST_API_OPENVG] & ST_PROFILE_DEFAULT_MASK) 523 dpy->ClientAPIsMask |= EGL_OPENVG_BIT; 524 525 gdpy->smapi = egl_g3d_create_st_manager(dpy); 526 if (!gdpy->smapi) { 527 _eglError(EGL_NOT_INITIALIZED, 528 "eglInitialize(failed to create st manager)"); 529 goto fail; 530 } 531 532#ifdef EGL_MESA_screen_surface 533 /* enable MESA_screen_surface before adding (and validating) configs */ 534 if (gdpy->native->modeset) { 535 dpy->Extensions.MESA_screen_surface = EGL_TRUE; 536 egl_g3d_add_screens(drv, dpy); 537 } 538#endif 539 540 dpy->Extensions.KHR_image_base = EGL_TRUE; 541 if (gdpy->native->get_param(gdpy->native, NATIVE_PARAM_USE_NATIVE_BUFFER)) 542 dpy->Extensions.KHR_image_pixmap = EGL_TRUE; 543 544 dpy->Extensions.KHR_reusable_sync = EGL_TRUE; 545 dpy->Extensions.KHR_fence_sync = EGL_TRUE; 546 547 dpy->Extensions.KHR_surfaceless_gles1 = EGL_TRUE; 548 dpy->Extensions.KHR_surfaceless_gles2 = EGL_TRUE; 549 dpy->Extensions.KHR_surfaceless_opengl = EGL_TRUE; 550 551 if (dpy->Platform == _EGL_PLATFORM_DRM) { 552 dpy->Extensions.MESA_drm_display = EGL_TRUE; 553 if (gdpy->native->buffer) 554 dpy->Extensions.MESA_drm_image = EGL_TRUE; 555 } 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 *major = 1; 563 *minor = 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 588static EGLint 589egl_g3d_probe(_EGLDriver *drv, _EGLDisplay *dpy) 590{ 591 return (egl_g3d_get_platform(drv, dpy->Platform)) ? 90 : 0; 592} 593 594_EGLDriver * 595egl_g3d_create_driver(const struct egl_g3d_loader *loader) 596{ 597 struct egl_g3d_driver *gdrv; 598 599 gdrv = CALLOC_STRUCT(egl_g3d_driver); 600 if (!gdrv) 601 return NULL; 602 603 gdrv->loader = loader; 604 605 egl_g3d_init_driver_api(&gdrv->base); 606 gdrv->base.API.Initialize = egl_g3d_initialize; 607 gdrv->base.API.Terminate = egl_g3d_terminate; 608 gdrv->base.API.GetProcAddress = egl_g3d_get_proc_address; 609 610 gdrv->base.Probe = egl_g3d_probe; 611 612 /* to be filled by the caller */ 613 gdrv->base.Name = NULL; 614 gdrv->base.Unload = NULL; 615 616 return &gdrv->base; 617} 618 619void 620egl_g3d_destroy_driver(_EGLDriver *drv) 621{ 622 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); 623 FREE(gdrv); 624} 625