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