29dbbefbf481c74f866c9ad64a1bc017cf965317
[mesa.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 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 */
84 static const struct native_platform *
85 egl_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
141 static void
142 egl_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 */
205 static EGLBoolean
206 init_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 /* st/vega will allocate the mask on demand */
263 if (api_mask & EGL_OPENVG_BIT)
264 conf->AlphaMaskSize = 8;
265
266 conf->SurfaceType = surface_type;
267
268 conf->NativeRenderable = EGL_TRUE;
269 if (surface_type & EGL_WINDOW_BIT) {
270 conf->NativeVisualID = nconf->native_visual_id;
271 conf->NativeVisualType = nconf->native_visual_type;
272 }
273
274 if (surface_type & EGL_PBUFFER_BIT) {
275 conf->BindToTextureRGB = EGL_TRUE;
276 if (rgba[3])
277 conf->BindToTextureRGBA = EGL_TRUE;
278
279 conf->MaxPbufferWidth = 4096;
280 conf->MaxPbufferHeight = 4096;
281 conf->MaxPbufferPixels = 4096 * 4096;
282 }
283
284 conf->Level = nconf->level;
285
286 if (nconf->transparent_rgb) {
287 conf->TransparentType = EGL_TRANSPARENT_RGB;
288 conf->TransparentRedValue = nconf->transparent_rgb_values[0];
289 conf->TransparentGreenValue = nconf->transparent_rgb_values[1];
290 conf->TransparentBlueValue = nconf->transparent_rgb_values[2];
291 }
292
293 conf->MinSwapInterval = 0;
294 conf->MaxSwapInterval = max_swap_interval;
295 if (preserve_buffer)
296 conf->SurfaceType |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
297
298 return _eglValidateConfig(conf, EGL_FALSE);
299 }
300
301 /**
302 * Initialize an EGL config from the native config.
303 */
304 static EGLBoolean
305 egl_g3d_init_config(_EGLDriver *drv, _EGLDisplay *dpy,
306 _EGLConfig *conf, const struct native_config *nconf,
307 enum pipe_format depth_stencil_format,
308 int preserve_buffer, int max_swap_interval)
309 {
310 struct egl_g3d_config *gconf = egl_g3d_config(conf);
311 EGLint buffer_mask;
312 EGLBoolean valid;
313
314 buffer_mask = 0x0;
315 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_FRONT_LEFT))
316 buffer_mask |= ST_ATTACHMENT_FRONT_LEFT_MASK;
317 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_LEFT))
318 buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK;
319 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_FRONT_RIGHT))
320 buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK;
321 if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_RIGHT))
322 buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK;
323
324 gconf->stvis.buffer_mask = buffer_mask;
325 gconf->stvis.color_format = nconf->color_format;
326 gconf->stvis.depth_stencil_format = depth_stencil_format;
327 gconf->stvis.accum_format = PIPE_FORMAT_NONE;
328 gconf->stvis.samples = 0;
329
330 /* will be overridden per surface */
331 gconf->stvis.render_buffer = (buffer_mask & ST_ATTACHMENT_BACK_LEFT_MASK) ?
332 ST_ATTACHMENT_BACK_LEFT : ST_ATTACHMENT_FRONT_LEFT;
333
334 valid = init_config_attributes(&gconf->base,
335 nconf, dpy->ClientAPIs, depth_stencil_format,
336 preserve_buffer, max_swap_interval);
337 if (!valid) {
338 _eglLog(_EGL_DEBUG, "skip invalid config 0x%x", nconf->native_visual_id);
339 return EGL_FALSE;
340 }
341
342 gconf->native = nconf;
343
344 return EGL_TRUE;
345 }
346
347 /**
348 * Get all interested depth/stencil formats of a display.
349 */
350 static EGLint
351 egl_g3d_fill_depth_stencil_formats(_EGLDisplay *dpy,
352 enum pipe_format formats[8])
353 {
354 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
355 struct pipe_screen *screen = gdpy->native->screen;
356 const EGLint candidates[] = {
357 1, PIPE_FORMAT_Z16_UNORM,
358 1, PIPE_FORMAT_Z32_UNORM,
359 2, PIPE_FORMAT_Z24_UNORM_S8_USCALED, PIPE_FORMAT_S8_USCALED_Z24_UNORM,
360 2, PIPE_FORMAT_Z24X8_UNORM, PIPE_FORMAT_X8Z24_UNORM,
361 0
362 };
363 const EGLint *fmt = candidates;
364 EGLint count;
365
366 count = 0;
367 formats[count++] = PIPE_FORMAT_NONE;
368
369 while (*fmt) {
370 EGLint i, n = *fmt++;
371
372 /* pick the first supported format */
373 for (i = 0; i < n; i++) {
374 if (screen->is_format_supported(screen, fmt[i],
375 PIPE_TEXTURE_2D, 0, PIPE_BIND_DEPTH_STENCIL)) {
376 formats[count++] = fmt[i];
377 break;
378 }
379 }
380
381 fmt += n;
382 }
383
384 return count;
385 }
386
387 /**
388 * Add configs to display and return the next config ID.
389 */
390 static EGLint
391 egl_g3d_add_configs(_EGLDriver *drv, _EGLDisplay *dpy, EGLint id)
392 {
393 struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
394 const struct native_config **native_configs;
395 enum pipe_format depth_stencil_formats[8];
396 int num_formats, num_configs, i, j;
397 int preserve_buffer, max_swap_interval;
398
399 native_configs = gdpy->native->get_configs(gdpy->native, &num_configs);
400 if (!num_configs) {
401 if (native_configs)
402 FREE(native_configs);
403 return id;
404 }
405
406 preserve_buffer =
407 gdpy->native->get_param(gdpy->native, NATIVE_PARAM_PRESERVE_BUFFER);
408 max_swap_interval =
409 gdpy->native->get_param(gdpy->native, NATIVE_PARAM_MAX_SWAP_INTERVAL);
410
411 num_formats = egl_g3d_fill_depth_stencil_formats(dpy,
412 depth_stencil_formats);
413
414 for (i = 0; i < num_configs; i++) {
415 for (j = 0; j < num_formats; j++) {
416 struct egl_g3d_config *gconf;
417
418 gconf = CALLOC_STRUCT(egl_g3d_config);
419 if (gconf) {
420 _eglInitConfig(&gconf->base, dpy, id);
421 if (!egl_g3d_init_config(drv, dpy, &gconf->base,
422 native_configs[i], depth_stencil_formats[j],
423 preserve_buffer, max_swap_interval)) {
424 FREE(gconf);
425 break;
426 }
427
428 _eglLinkConfig(&gconf->base);
429 id++;
430 }
431 }
432 }
433
434 FREE(native_configs);
435 return id;
436 }
437
438 static void
439 egl_g3d_free_config(void *conf)
440 {
441 struct egl_g3d_config *gconf = egl_g3d_config((_EGLConfig *) conf);
442 FREE(gconf);
443 }
444
445 static void
446 egl_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
455 static EGLBoolean
456 egl_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 (dpy->Configs) {
463 _eglDestroyArray(dpy->Configs, egl_g3d_free_config);
464 dpy->Configs = NULL;
465 }
466 if (dpy->Screens) {
467 _eglDestroyArray(dpy->Screens, egl_g3d_free_screen);
468 dpy->Screens = NULL;
469 }
470
471 _eglCleanupDisplay(dpy);
472
473 if (gdpy->smapi)
474 egl_g3d_destroy_st_manager(gdpy->smapi);
475
476 if (gdpy->native)
477 gdpy->native->destroy(gdpy->native);
478
479 FREE(gdpy);
480 dpy->DriverData = NULL;
481
482 return EGL_TRUE;
483 }
484
485 static EGLBoolean
486 egl_g3d_initialize(_EGLDriver *drv, _EGLDisplay *dpy)
487 {
488 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
489 struct egl_g3d_display *gdpy;
490 const struct native_platform *nplat;
491
492 nplat = egl_g3d_get_platform(drv, dpy->Platform);
493 if (!nplat)
494 return EGL_FALSE;
495
496 if (dpy->Options.TestOnly)
497 return EGL_TRUE;
498
499 gdpy = CALLOC_STRUCT(egl_g3d_display);
500 if (!gdpy) {
501 _eglError(EGL_BAD_ALLOC, "eglInitialize");
502 goto fail;
503 }
504 gdpy->loader = gdrv->loader;
505 dpy->DriverData = gdpy;
506
507 _eglLog(_EGL_INFO, "use %s for display %p", nplat->name, dpy->PlatformDisplay);
508 gdpy->native = nplat->create_display(dpy->PlatformDisplay,
509 dpy->Options.UseFallback, (void *) dpy);
510 if (!gdpy->native) {
511 _eglError(EGL_NOT_INITIALIZED, "eglInitialize(no usable display)");
512 goto fail;
513 }
514
515 if (gdpy->loader->profile_masks[ST_API_OPENGL] & ST_PROFILE_DEFAULT_MASK)
516 dpy->ClientAPIs |= EGL_OPENGL_BIT;
517 if (gdpy->loader->profile_masks[ST_API_OPENGL] & ST_PROFILE_OPENGL_ES1_MASK)
518 dpy->ClientAPIs |= EGL_OPENGL_ES_BIT;
519 if (gdpy->loader->profile_masks[ST_API_OPENGL] & ST_PROFILE_OPENGL_ES2_MASK)
520 dpy->ClientAPIs |= EGL_OPENGL_ES2_BIT;
521 if (gdpy->loader->profile_masks[ST_API_OPENVG] & ST_PROFILE_DEFAULT_MASK)
522 dpy->ClientAPIs |= EGL_OPENVG_BIT;
523
524 gdpy->smapi = egl_g3d_create_st_manager(dpy);
525 if (!gdpy->smapi) {
526 _eglError(EGL_NOT_INITIALIZED,
527 "eglInitialize(failed to create st manager)");
528 goto fail;
529 }
530
531 #ifdef EGL_MESA_screen_surface
532 /* enable MESA_screen_surface before adding (and validating) configs */
533 if (gdpy->native->modeset) {
534 dpy->Extensions.MESA_screen_surface = EGL_TRUE;
535 egl_g3d_add_screens(drv, dpy);
536 }
537 #endif
538
539 dpy->Extensions.KHR_image_base = EGL_TRUE;
540 if (gdpy->native->get_param(gdpy->native, NATIVE_PARAM_USE_NATIVE_BUFFER))
541 dpy->Extensions.KHR_image_pixmap = EGL_TRUE;
542
543 dpy->Extensions.KHR_reusable_sync = EGL_TRUE;
544 dpy->Extensions.KHR_fence_sync = EGL_TRUE;
545
546 dpy->Extensions.KHR_surfaceless_gles1 = EGL_TRUE;
547 dpy->Extensions.KHR_surfaceless_gles2 = EGL_TRUE;
548 dpy->Extensions.KHR_surfaceless_opengl = EGL_TRUE;
549
550 if (dpy->Platform == _EGL_PLATFORM_DRM) {
551 dpy->Extensions.MESA_drm_display = EGL_TRUE;
552 if (gdpy->native->buffer)
553 dpy->Extensions.MESA_drm_image = EGL_TRUE;
554 }
555
556 if (dpy->Platform == _EGL_PLATFORM_WAYLAND && gdpy->native->buffer)
557 dpy->Extensions.MESA_drm_image = EGL_TRUE;
558
559 #ifdef EGL_WL_bind_wayland_display
560 if (gdpy->native->wayland_bufmgr)
561 dpy->Extensions.WL_bind_wayland_display = EGL_TRUE;
562 #endif
563
564 if (egl_g3d_add_configs(drv, dpy, 1) == 1) {
565 _eglError(EGL_NOT_INITIALIZED, "eglInitialize(unable to add configs)");
566 goto fail;
567 }
568
569 dpy->VersionMajor = 1;
570 dpy->VersionMinor = 4;
571
572 return EGL_TRUE;
573
574 fail:
575 if (gdpy)
576 egl_g3d_terminate(drv, dpy);
577 return EGL_FALSE;
578 }
579
580 static _EGLProc
581 egl_g3d_get_proc_address(_EGLDriver *drv, const char *procname)
582 {
583 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
584 struct st_api *stapi = NULL;
585
586 if (procname && procname[0] == 'v' && procname[1] == 'g')
587 stapi = gdrv->loader->get_st_api(ST_API_OPENVG);
588 else if (procname && procname[0] == 'g' && procname[1] == 'l')
589 stapi = gdrv->loader->get_st_api(ST_API_OPENGL);
590
591 return (_EGLProc) ((stapi) ?
592 stapi->get_proc_address(stapi, procname) : NULL);
593 }
594
595 _EGLDriver *
596 egl_g3d_create_driver(const struct egl_g3d_loader *loader)
597 {
598 struct egl_g3d_driver *gdrv;
599
600 gdrv = CALLOC_STRUCT(egl_g3d_driver);
601 if (!gdrv)
602 return NULL;
603
604 gdrv->loader = loader;
605
606 egl_g3d_init_driver_api(&gdrv->base);
607 gdrv->base.API.Initialize = egl_g3d_initialize;
608 gdrv->base.API.Terminate = egl_g3d_terminate;
609 gdrv->base.API.GetProcAddress = egl_g3d_get_proc_address;
610
611 /* to be filled by the caller */
612 gdrv->base.Name = NULL;
613 gdrv->base.Unload = NULL;
614
615 return &gdrv->base;
616 }
617
618 void
619 egl_g3d_destroy_driver(_EGLDriver *drv)
620 {
621 struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
622 FREE(gdrv);
623 }