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