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