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