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