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