diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2016-12-11 08:53:23 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2016-12-11 08:53:23 +0000 |
commit | 58cad0a2ccb28b1f82763d80861c6085def38b30 (patch) | |
tree | 8f199bc844429c0ca70acb457cd48a354b6ff177 /lib/mesa/src/egl/drivers | |
parent | 21ab4c9f31674b113c24177398ed39f29b7cd8e6 (diff) |
Merge Mesa 13.0.2
Diffstat (limited to 'lib/mesa/src/egl/drivers')
-rw-r--r-- | lib/mesa/src/egl/drivers/dri2/egl_dri2.c | 1096 | ||||
-rw-r--r-- | lib/mesa/src/egl/drivers/dri2/platform_x11.c | 158 |
2 files changed, 833 insertions, 421 deletions
diff --git a/lib/mesa/src/egl/drivers/dri2/egl_dri2.c b/lib/mesa/src/egl/drivers/dri2/egl_dri2.c index 10b434269..f1f473ca6 100644 --- a/lib/mesa/src/egl/drivers/dri2/egl_dri2.c +++ b/lib/mesa/src/egl/drivers/dri2/egl_dri2.c @@ -27,6 +27,7 @@ #define WL_HIDE_DEPRECATED +#include <stdbool.h> #include <stdint.h> #include <stdbool.h> #include <stdlib.h> @@ -37,12 +38,15 @@ #include <fcntl.h> #include <errno.h> #include <unistd.h> +#include <c11/threads.h> +#include <time.h> #ifdef HAVE_LIBDRM #include <xf86drm.h> #include <drm_fourcc.h> #endif #include <GL/gl.h> #include <GL/internal/dri_interface.h> +#include "GL/mesa_glinterop.h" #include <sys/types.h> #include <sys/stat.h> @@ -76,66 +80,64 @@ const __DRIuseInvalidateExtension use_invalidate = { EGLint dri2_to_egl_attribute_map[] = { 0, - EGL_BUFFER_SIZE, /* __DRI_ATTRIB_BUFFER_SIZE */ - EGL_LEVEL, /* __DRI_ATTRIB_LEVEL */ - EGL_RED_SIZE, /* __DRI_ATTRIB_RED_SIZE */ - EGL_GREEN_SIZE, /* __DRI_ATTRIB_GREEN_SIZE */ - EGL_BLUE_SIZE, /* __DRI_ATTRIB_BLUE_SIZE */ - EGL_LUMINANCE_SIZE, /* __DRI_ATTRIB_LUMINANCE_SIZE */ - EGL_ALPHA_SIZE, /* __DRI_ATTRIB_ALPHA_SIZE */ - 0, /* __DRI_ATTRIB_ALPHA_MASK_SIZE */ - EGL_DEPTH_SIZE, /* __DRI_ATTRIB_DEPTH_SIZE */ - EGL_STENCIL_SIZE, /* __DRI_ATTRIB_STENCIL_SIZE */ - 0, /* __DRI_ATTRIB_ACCUM_RED_SIZE */ - 0, /* __DRI_ATTRIB_ACCUM_GREEN_SIZE */ - 0, /* __DRI_ATTRIB_ACCUM_BLUE_SIZE */ - 0, /* __DRI_ATTRIB_ACCUM_ALPHA_SIZE */ - EGL_SAMPLE_BUFFERS, /* __DRI_ATTRIB_SAMPLE_BUFFERS */ - EGL_SAMPLES, /* __DRI_ATTRIB_SAMPLES */ - 0, /* __DRI_ATTRIB_RENDER_TYPE, */ - 0, /* __DRI_ATTRIB_CONFIG_CAVEAT */ - 0, /* __DRI_ATTRIB_CONFORMANT */ - 0, /* __DRI_ATTRIB_DOUBLE_BUFFER */ - 0, /* __DRI_ATTRIB_STEREO */ - 0, /* __DRI_ATTRIB_AUX_BUFFERS */ - 0, /* __DRI_ATTRIB_TRANSPARENT_TYPE */ - 0, /* __DRI_ATTRIB_TRANSPARENT_INDEX_VALUE */ - 0, /* __DRI_ATTRIB_TRANSPARENT_RED_VALUE */ - 0, /* __DRI_ATTRIB_TRANSPARENT_GREEN_VALUE */ - 0, /* __DRI_ATTRIB_TRANSPARENT_BLUE_VALUE */ - 0, /* __DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE */ - 0, /* __DRI_ATTRIB_FLOAT_MODE (deprecated) */ - 0, /* __DRI_ATTRIB_RED_MASK */ - 0, /* __DRI_ATTRIB_GREEN_MASK */ - 0, /* __DRI_ATTRIB_BLUE_MASK */ - 0, /* __DRI_ATTRIB_ALPHA_MASK */ - EGL_MAX_PBUFFER_WIDTH, /* __DRI_ATTRIB_MAX_PBUFFER_WIDTH */ - EGL_MAX_PBUFFER_HEIGHT, /* __DRI_ATTRIB_MAX_PBUFFER_HEIGHT */ - EGL_MAX_PBUFFER_PIXELS, /* __DRI_ATTRIB_MAX_PBUFFER_PIXELS */ - 0, /* __DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH */ - 0, /* __DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT */ - 0, /* __DRI_ATTRIB_VISUAL_SELECT_GROUP */ - 0, /* __DRI_ATTRIB_SWAP_METHOD */ - EGL_MAX_SWAP_INTERVAL, /* __DRI_ATTRIB_MAX_SWAP_INTERVAL */ - EGL_MIN_SWAP_INTERVAL, /* __DRI_ATTRIB_MIN_SWAP_INTERVAL */ - 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_RGB */ - 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA */ - 0, /* __DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE */ - 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS */ - EGL_Y_INVERTED_NOK, /* __DRI_ATTRIB_YINVERTED */ - 0, /* __DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE */ + EGL_BUFFER_SIZE, /* __DRI_ATTRIB_BUFFER_SIZE */ + EGL_LEVEL, /* __DRI_ATTRIB_LEVEL */ + EGL_RED_SIZE, /* __DRI_ATTRIB_RED_SIZE */ + EGL_GREEN_SIZE, /* __DRI_ATTRIB_GREEN_SIZE */ + EGL_BLUE_SIZE, /* __DRI_ATTRIB_BLUE_SIZE */ + EGL_LUMINANCE_SIZE, /* __DRI_ATTRIB_LUMINANCE_SIZE */ + EGL_ALPHA_SIZE, /* __DRI_ATTRIB_ALPHA_SIZE */ + 0, /* __DRI_ATTRIB_ALPHA_MASK_SIZE */ + EGL_DEPTH_SIZE, /* __DRI_ATTRIB_DEPTH_SIZE */ + EGL_STENCIL_SIZE, /* __DRI_ATTRIB_STENCIL_SIZE */ + 0, /* __DRI_ATTRIB_ACCUM_RED_SIZE */ + 0, /* __DRI_ATTRIB_ACCUM_GREEN_SIZE */ + 0, /* __DRI_ATTRIB_ACCUM_BLUE_SIZE */ + 0, /* __DRI_ATTRIB_ACCUM_ALPHA_SIZE */ + EGL_SAMPLE_BUFFERS, /* __DRI_ATTRIB_SAMPLE_BUFFERS */ + EGL_SAMPLES, /* __DRI_ATTRIB_SAMPLES */ + 0, /* __DRI_ATTRIB_RENDER_TYPE, */ + 0, /* __DRI_ATTRIB_CONFIG_CAVEAT */ + 0, /* __DRI_ATTRIB_CONFORMANT */ + 0, /* __DRI_ATTRIB_DOUBLE_BUFFER */ + 0, /* __DRI_ATTRIB_STEREO */ + 0, /* __DRI_ATTRIB_AUX_BUFFERS */ + 0, /* __DRI_ATTRIB_TRANSPARENT_TYPE */ + 0, /* __DRI_ATTRIB_TRANSPARENT_INDEX_VALUE */ + 0, /* __DRI_ATTRIB_TRANSPARENT_RED_VALUE */ + 0, /* __DRI_ATTRIB_TRANSPARENT_GREEN_VALUE */ + 0, /* __DRI_ATTRIB_TRANSPARENT_BLUE_VALUE */ + 0, /* __DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE */ + 0, /* __DRI_ATTRIB_FLOAT_MODE (deprecated) */ + 0, /* __DRI_ATTRIB_RED_MASK */ + 0, /* __DRI_ATTRIB_GREEN_MASK */ + 0, /* __DRI_ATTRIB_BLUE_MASK */ + 0, /* __DRI_ATTRIB_ALPHA_MASK */ + EGL_MAX_PBUFFER_WIDTH, /* __DRI_ATTRIB_MAX_PBUFFER_WIDTH */ + EGL_MAX_PBUFFER_HEIGHT, /* __DRI_ATTRIB_MAX_PBUFFER_HEIGHT */ + EGL_MAX_PBUFFER_PIXELS, /* __DRI_ATTRIB_MAX_PBUFFER_PIXELS */ + 0, /* __DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH */ + 0, /* __DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT */ + 0, /* __DRI_ATTRIB_VISUAL_SELECT_GROUP */ + 0, /* __DRI_ATTRIB_SWAP_METHOD */ + EGL_MAX_SWAP_INTERVAL, /* __DRI_ATTRIB_MAX_SWAP_INTERVAL */ + EGL_MIN_SWAP_INTERVAL, /* __DRI_ATTRIB_MIN_SWAP_INTERVAL */ + 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_RGB */ + 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA */ + 0, /* __DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE */ + 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS */ + EGL_Y_INVERTED_NOK, /* __DRI_ATTRIB_YINVERTED */ + 0, /* __DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE */ }; const __DRIconfig * dri2_get_dri_config(struct dri2_egl_config *conf, EGLint surface_type, EGLenum colorspace) { - if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) - return surface_type == EGL_WINDOW_BIT ? conf->dri_srgb_double_config : - conf->dri_srgb_single_config; - else - return surface_type == EGL_WINDOW_BIT ? conf->dri_double_config : - conf->dri_single_config; + const bool srgb = colorspace == EGL_GL_COLORSPACE_SRGB_KHR; + + return surface_type == EGL_WINDOW_BIT ? conf->dri_double_config[srgb] : + conf->dri_single_config[srgb]; } static EGLBoolean @@ -152,11 +154,11 @@ dri2_match_config(const _EGLConfig *conf, const _EGLConfig *criteria) struct dri2_egl_config * dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, - EGLint surface_type, const EGLint *attr_list, - const unsigned int *rgba_masks) + EGLint surface_type, const EGLint *attr_list, + const unsigned int *rgba_masks) { struct dri2_egl_config *conf; - struct dri2_egl_display *dri2_dpy; + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); _EGLConfig base; unsigned int attrib, value, double_buffer; bool srgb = false; @@ -167,7 +169,6 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, EGLint config_id; int i; - dri2_dpy = disp->DriverData; _eglInitConfig(&base, disp, id); i = 0; @@ -178,36 +179,36 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, while (dri2_dpy->core->indexConfigAttrib(dri_config, i++, &attrib, &value)) { switch (attrib) { case __DRI_ATTRIB_RENDER_TYPE: - if (value & __DRI_ATTRIB_RGBA_BIT) - value = EGL_RGB_BUFFER; - else if (value & __DRI_ATTRIB_LUMINANCE_BIT) - value = EGL_LUMINANCE_BUFFER; - else - return NULL; - _eglSetConfigKey(&base, EGL_COLOR_BUFFER_TYPE, value); - break; + if (value & __DRI_ATTRIB_RGBA_BIT) + value = EGL_RGB_BUFFER; + else if (value & __DRI_ATTRIB_LUMINANCE_BIT) + value = EGL_LUMINANCE_BUFFER; + else + return NULL; + _eglSetConfigKey(&base, EGL_COLOR_BUFFER_TYPE, value); + break; case __DRI_ATTRIB_CONFIG_CAVEAT: if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG) value = EGL_NON_CONFORMANT_CONFIG; else if (value & __DRI_ATTRIB_SLOW_BIT) value = EGL_SLOW_CONFIG; - else - value = EGL_NONE; - _eglSetConfigKey(&base, EGL_CONFIG_CAVEAT, value); + else + value = EGL_NONE; + _eglSetConfigKey(&base, EGL_CONFIG_CAVEAT, value); break; case __DRI_ATTRIB_BIND_TO_TEXTURE_RGB: - bind_to_texture_rgb = value; - break; + bind_to_texture_rgb = value; + break; case __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA: - bind_to_texture_rgba = value; - break; + bind_to_texture_rgba = value; + break; case __DRI_ATTRIB_DOUBLE_BUFFER: - double_buffer = value; - break; + double_buffer = value; + break; case __DRI_ATTRIB_RED_MASK: dri_masks[0] = value; @@ -236,13 +237,24 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, case __DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE: srgb = value != 0; + if (!disp->Extensions.KHR_gl_colorspace && srgb) + return NULL; + break; + + case __DRI_ATTRIB_MAX_PBUFFER_WIDTH: + _eglSetConfigKey(&base, EGL_MAX_PBUFFER_WIDTH, + _EGL_MAX_PBUFFER_WIDTH); + break; + case __DRI_ATTRIB_MAX_PBUFFER_HEIGHT: + _eglSetConfigKey(&base, EGL_MAX_PBUFFER_HEIGHT, + _EGL_MAX_PBUFFER_HEIGHT); break; default: - key = dri2_to_egl_attribute_map[attrib]; - if (key != 0) - _eglSetConfigKey(&base, key, value); - break; + key = dri2_to_egl_attribute_map[attrib]; + if (key != 0) + _eglSetConfigKey(&base, key, value); + break; } } @@ -283,14 +295,10 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, if (num_configs == 1) { conf = (struct dri2_egl_config *) matching_config; - if (double_buffer && srgb && !conf->dri_srgb_double_config) - conf->dri_srgb_double_config = dri_config; - else if (double_buffer && !srgb && !conf->dri_double_config) - conf->dri_double_config = dri_config; - else if (!double_buffer && srgb && !conf->dri_srgb_single_config) - conf->dri_srgb_single_config = dri_config; - else if (!double_buffer && !srgb && !conf->dri_single_config) - conf->dri_single_config = dri_config; + if (double_buffer && !conf->dri_double_config[srgb]) + conf->dri_double_config[srgb] = dri_config; + else if (!double_buffer && !conf->dri_single_config[srgb]) + conf->dri_single_config[srgb] = dri_config; else /* a similar config type is already added (unlikely) => discard */ return NULL; @@ -300,19 +308,12 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, if (conf == NULL) return NULL; - memcpy(&conf->base, &base, sizeof base); - if (double_buffer) { - if (srgb) - conf->dri_srgb_double_config = dri_config; - else - conf->dri_double_config = dri_config; - } else { - if (srgb) - conf->dri_srgb_single_config = dri_config; - else - conf->dri_single_config = dri_config; - } + if (double_buffer) + conf->dri_double_config[srgb] = dri_config; + else + conf->dri_single_config[srgb] = dri_config; + memcpy(&conf->base, &base, sizeof base); conf->base.SurfaceType = 0; conf->base.ConfigID = config_id; @@ -327,6 +328,15 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, surface_type &= ~EGL_PIXMAP_BIT; } + /* No support for pbuffer + MSAA for now. + * + * XXX TODO: pbuffer + MSAA does not work and causes crashes. + * See QT bugreport: https://bugreports.qt.io/browse/QTBUG-47509 + */ + if (base.Samples) { + surface_type &= ~EGL_PBUFFER_BIT; + } + conf->base.SurfaceType |= surface_type; return conf; @@ -364,57 +374,79 @@ struct dri2_extension_match { int offset; }; -static struct dri2_extension_match dri2_driver_extensions[] = { +static const struct dri2_extension_match dri3_driver_extensions[] = { + { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) }, + { __DRI_IMAGE_DRIVER, 1, offsetof(struct dri2_egl_display, image_driver) }, + { NULL, 0, 0 } +}; + +static const struct dri2_extension_match dri2_driver_extensions[] = { { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) }, { __DRI_DRI2, 2, offsetof(struct dri2_egl_display, dri2) }, { NULL, 0, 0 } }; -static struct dri2_extension_match dri2_core_extensions[] = { +static const struct dri2_extension_match dri2_core_extensions[] = { { __DRI2_FLUSH, 1, offsetof(struct dri2_egl_display, flush) }, { __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) }, { __DRI_IMAGE, 1, offsetof(struct dri2_egl_display, image) }, { NULL, 0, 0 } }; -static struct dri2_extension_match swrast_driver_extensions[] = { +static const struct dri2_extension_match swrast_driver_extensions[] = { { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) }, { __DRI_SWRAST, 2, offsetof(struct dri2_egl_display, swrast) }, { NULL, 0, 0 } }; -static struct dri2_extension_match swrast_core_extensions[] = { +static const struct dri2_extension_match swrast_core_extensions[] = { { __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) }, { NULL, 0, 0 } }; +static const struct dri2_extension_match optional_core_extensions[] = { + { __DRI2_ROBUSTNESS, 1, offsetof(struct dri2_egl_display, robustness) }, + { __DRI2_CONFIG_QUERY, 1, offsetof(struct dri2_egl_display, config) }, + { __DRI2_FENCE, 1, offsetof(struct dri2_egl_display, fence) }, + { __DRI2_RENDERER_QUERY, 1, offsetof(struct dri2_egl_display, rendererQuery) }, + { __DRI2_INTEROP, 1, offsetof(struct dri2_egl_display, interop) }, + { NULL, 0, 0 } +}; + static EGLBoolean dri2_bind_extensions(struct dri2_egl_display *dri2_dpy, - struct dri2_extension_match *matches, - const __DRIextension **extensions) + const struct dri2_extension_match *matches, + const __DRIextension **extensions, + bool optional) { int i, j, ret = EGL_TRUE; void *field; for (i = 0; extensions[i]; i++) { - _eglLog(_EGL_DEBUG, "DRI2: found extension `%s'", extensions[i]->name); + _eglLog(_EGL_DEBUG, "found extension `%s'", extensions[i]->name); for (j = 0; matches[j].name; j++) { - if (strcmp(extensions[i]->name, matches[j].name) == 0 && - extensions[i]->version >= matches[j].version) { - field = ((char *) dri2_dpy + matches[j].offset); - *(const __DRIextension **) field = extensions[i]; - _eglLog(_EGL_INFO, "DRI2: found extension %s version %d", - extensions[i]->name, extensions[i]->version); - } + if (strcmp(extensions[i]->name, matches[j].name) == 0 && + extensions[i]->version >= matches[j].version) { + field = ((char *) dri2_dpy + matches[j].offset); + *(const __DRIextension **) field = extensions[i]; + _eglLog(_EGL_INFO, "found extension %s version %d", + extensions[i]->name, extensions[i]->version); + break; + } } } for (j = 0; matches[j].name; j++) { field = ((char *) dri2_dpy + matches[j].offset); if (*(const __DRIextension **) field == NULL) { - _eglLog(_EGL_WARNING, "DRI2: did not find extension %s version %d", - matches[j].name, matches[j].version); - ret = EGL_FALSE; + if (optional) { + _eglLog(_EGL_DEBUG, "did not find optional extension %s version %d", + matches[j].name, matches[j].version); + } else { + _eglLog(_EGL_WARNING, "did not find extension %s version %d", + matches[j].name, matches[j].version); + ret = EGL_FALSE; + } } } @@ -424,7 +456,7 @@ dri2_bind_extensions(struct dri2_egl_display *dri2_dpy, static const __DRIextension ** dri2_open_driver(_EGLDisplay *disp) { - struct dri2_egl_display *dri2_dpy = disp->DriverData; + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); const __DRIextension **extensions = NULL; char path[PATH_MAX], *search_paths, *p, *next, *end; char *get_extensions_name; @@ -449,15 +481,15 @@ dri2_open_driver(_EGLDisplay *disp) len = next - p; #if GLX_USE_TLS snprintf(path, sizeof path, - "%.*s/tls/%s_dri.so", len, p, dri2_dpy->driver_name); + "%.*s/tls/%s_dri.so", len, p, dri2_dpy->driver_name); dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL); #endif if (dri2_dpy->driver == NULL) { - snprintf(path, sizeof path, - "%.*s/%s_dri.so", len, p, dri2_dpy->driver_name); - dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL); - if (dri2_dpy->driver == NULL) - _eglLog(_EGL_DEBUG, "failed to open %s: %s\n", path, dlerror()); + snprintf(path, sizeof path, + "%.*s/%s_dri.so", len, p, dri2_dpy->driver_name); + dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL); + if (dri2_dpy->driver == NULL) + _eglLog(_EGL_DEBUG, "failed to open %s: %s\n", path, dlerror()); } /* not need continue to loop all paths once the driver is found */ if (dri2_dpy->driver != NULL) @@ -475,8 +507,8 @@ dri2_open_driver(_EGLDisplay *disp) if (dri2_dpy->driver == NULL) { _eglLog(_EGL_WARNING, - "DRI2: failed to open %s (search paths %s)", - dri2_dpy->driver_name, search_paths); + "DRI2: failed to open %s (search paths %s)", + dri2_dpy->driver_name, search_paths); return NULL; } @@ -498,7 +530,7 @@ dri2_open_driver(_EGLDisplay *disp) extensions = dlsym(dri2_dpy->driver, __DRI_DRIVER_EXTENSIONS); if (extensions == NULL) { _eglLog(_EGL_WARNING, - "DRI2: driver exports no extensions (%s)", dlerror()); + "DRI2: driver exports no extensions (%s)", dlerror()); dlclose(dri2_dpy->driver); } @@ -506,16 +538,35 @@ dri2_open_driver(_EGLDisplay *disp) } EGLBoolean +dri2_load_driver_dri3(_EGLDisplay *disp) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + const __DRIextension **extensions; + + extensions = dri2_open_driver(disp); + if (!extensions) + return EGL_FALSE; + + if (!dri2_bind_extensions(dri2_dpy, dri3_driver_extensions, extensions, false)) { + dlclose(dri2_dpy->driver); + return EGL_FALSE; + } + dri2_dpy->driver_extensions = extensions; + + return EGL_TRUE; +} + +EGLBoolean dri2_load_driver(_EGLDisplay *disp) { - struct dri2_egl_display *dri2_dpy = disp->DriverData; + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); const __DRIextension **extensions; extensions = dri2_open_driver(disp); if (!extensions) return EGL_FALSE; - if (!dri2_bind_extensions(dri2_dpy, dri2_driver_extensions, extensions)) { + if (!dri2_bind_extensions(dri2_dpy, dri2_driver_extensions, extensions, false)) { dlclose(dri2_dpy->driver); return EGL_FALSE; } @@ -527,14 +578,14 @@ dri2_load_driver(_EGLDisplay *disp) EGLBoolean dri2_load_driver_swrast(_EGLDisplay *disp) { - struct dri2_egl_display *dri2_dpy = disp->DriverData; + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); const __DRIextension **extensions; extensions = dri2_open_driver(disp); if (!extensions) return EGL_FALSE; - if (!dri2_bind_extensions(dri2_dpy, swrast_driver_extensions, extensions)) { + if (!dri2_bind_extensions(dri2_dpy, swrast_driver_extensions, extensions, false)) { dlclose(dri2_dpy->driver); return EGL_FALSE; } @@ -562,7 +613,9 @@ dri2_setup_screen(_EGLDisplay *disp) struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); unsigned int api_mask; - if (dri2_dpy->dri2) { + if (dri2_dpy->image_driver) { + api_mask = dri2_dpy->image_driver->getAPIMask(dri2_dpy->dri_screen); + } else if (dri2_dpy->dri2) { api_mask = dri2_dpy->dri2->getAPIMask(dri2_dpy->dri_screen); } else { assert(dri2_dpy->swrast); @@ -573,24 +626,26 @@ dri2_setup_screen(_EGLDisplay *disp) } disp->ClientAPIs = 0; - if (api_mask & (1 <<__DRI_API_OPENGL)) + if ((api_mask & (1 <<__DRI_API_OPENGL)) && _eglIsApiValid(EGL_OPENGL_API)) disp->ClientAPIs |= EGL_OPENGL_BIT; - if (api_mask & (1 <<__DRI_API_GLES)) + if ((api_mask & (1 << __DRI_API_GLES)) && _eglIsApiValid(EGL_OPENGL_ES_API)) disp->ClientAPIs |= EGL_OPENGL_ES_BIT; - if (api_mask & (1 << __DRI_API_GLES2)) + if ((api_mask & (1 << __DRI_API_GLES2)) && _eglIsApiValid(EGL_OPENGL_ES_API)) disp->ClientAPIs |= EGL_OPENGL_ES2_BIT; - if (api_mask & (1 << __DRI_API_GLES3)) + if ((api_mask & (1 << __DRI_API_GLES3)) && _eglIsApiValid(EGL_OPENGL_ES_API)) disp->ClientAPIs |= EGL_OPENGL_ES3_BIT_KHR; - assert(dri2_dpy->dri2 || dri2_dpy->swrast); + assert(dri2_dpy->image_driver || dri2_dpy->dri2 || dri2_dpy->swrast); + disp->Extensions.KHR_no_config_context = EGL_TRUE; disp->Extensions.KHR_surfaceless_context = EGL_TRUE; - disp->Extensions.MESA_configless_context = EGL_TRUE; if (dri2_renderer_query_integer(dri2_dpy, __DRI2_RENDERER_HAS_FRAMEBUFFER_SRGB)) disp->Extensions.KHR_gl_colorspace = EGL_TRUE; - if (dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) { + if (dri2_dpy->image_driver || + (dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) || + (dri2_dpy->swrast && dri2_dpy->swrast->base.version >= 3)) { disp->Extensions.KHR_create_context = EGL_TRUE; if (dri2_dpy->robustness) @@ -604,6 +659,8 @@ dri2_setup_screen(_EGLDisplay *disp) disp->Extensions.KHR_cl_event2 = EGL_TRUE; } + disp->Extensions.KHR_reusable_sync = EGL_TRUE; + if (dri2_dpy->image) { if (dri2_dpy->image->base.version >= 10 && dri2_dpy->image->getCapabilities != NULL) { @@ -647,34 +704,38 @@ EGLBoolean dri2_create_screen(_EGLDisplay *disp) { const __DRIextension **extensions; - struct dri2_egl_display *dri2_dpy; - unsigned i; - - dri2_dpy = disp->DriverData; + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); - if (dri2_dpy->dri2) { + if (dri2_dpy->image_driver) { + dri2_dpy->dri_screen = + dri2_dpy->image_driver->createNewScreen2(0, dri2_dpy->fd, + dri2_dpy->loader_extensions, + dri2_dpy->driver_extensions, + &dri2_dpy->driver_configs, + disp); + } else if (dri2_dpy->dri2) { if (dri2_dpy->dri2->base.version >= 4) { dri2_dpy->dri_screen = dri2_dpy->dri2->createNewScreen2(0, dri2_dpy->fd, - dri2_dpy->extensions, + dri2_dpy->loader_extensions, dri2_dpy->driver_extensions, &dri2_dpy->driver_configs, disp); } else { dri2_dpy->dri_screen = dri2_dpy->dri2->createNewScreen(0, dri2_dpy->fd, - dri2_dpy->extensions, + dri2_dpy->loader_extensions, &dri2_dpy->driver_configs, disp); } } else { assert(dri2_dpy->swrast); if (dri2_dpy->swrast->base.version >= 4) { dri2_dpy->dri_screen = - dri2_dpy->swrast->createNewScreen2(0, dri2_dpy->extensions, + dri2_dpy->swrast->createNewScreen2(0, dri2_dpy->loader_extensions, dri2_dpy->driver_extensions, &dri2_dpy->driver_configs, disp); } else { dri2_dpy->dri_screen = - dri2_dpy->swrast->createNewScreen(0, dri2_dpy->extensions, + dri2_dpy->swrast->createNewScreen(0, dri2_dpy->loader_extensions, &dri2_dpy->driver_configs, disp); } } @@ -688,30 +749,16 @@ dri2_create_screen(_EGLDisplay *disp) extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen); - if (dri2_dpy->dri2) { - if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions)) + if (dri2_dpy->image_driver || dri2_dpy->dri2) { + if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions, false)) goto cleanup_dri_screen; } else { assert(dri2_dpy->swrast); - if (!dri2_bind_extensions(dri2_dpy, swrast_core_extensions, extensions)) + if (!dri2_bind_extensions(dri2_dpy, swrast_core_extensions, extensions, false)) goto cleanup_dri_screen; } - for (i = 0; extensions[i]; i++) { - if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0) { - dri2_dpy->robustness = (__DRIrobustnessExtension *) extensions[i]; - } - if (strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0) { - dri2_dpy->config = (__DRI2configQueryExtension *) extensions[i]; - } - if (strcmp(extensions[i]->name, __DRI2_FENCE) == 0) { - dri2_dpy->fence = (__DRI2fenceExtension *) extensions[i]; - } - if (strcmp(extensions[i]->name, __DRI2_RENDERER_QUERY) == 0) { - dri2_dpy->rendererQuery = (__DRI2rendererQueryExtension *) extensions[i]; - } - } - + dri2_bind_extensions(dri2_dpy, optional_core_extensions, extensions, true); dri2_setup_screen(disp); return EGL_TRUE; @@ -724,75 +771,119 @@ dri2_create_screen(_EGLDisplay *disp) /** * Called via eglInitialize(), GLX_drv->API.Initialize(). + * + * This must be guaranteed to be called exactly once, even if eglInitialize is + * called many times (without a eglTerminate in between). */ static EGLBoolean dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp) { + EGLBoolean ret = EGL_FALSE; + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + + /* In the case where the application calls eglMakeCurrent(context1), + * eglTerminate, then eglInitialize again (without a call to eglReleaseThread + * or eglMakeCurrent(NULL) before that), dri2_dpy structure is still + * initialized, as we need it to be able to free context1 correctly. + * + * It would probably be safest to forcibly release the display with + * dri2_display_release, to make sure the display is reinitialized correctly. + * However, the EGL spec states that we need to keep a reference to the + * current context (so we cannot call dri2_make_current(NULL)), and therefore + * we would leak context1 as we would be missing the old display connection + * to free it up correctly. + */ + if (dri2_dpy) { + dri2_dpy->ref_count++; + return EGL_TRUE; + } + /* not until swrast_dri is supported */ if (disp->Options.UseFallback) return EGL_FALSE; + /* Nothing to initialize for a test only display */ + if (disp->Options.TestOnly) + return EGL_TRUE; + switch (disp->Platform) { #ifdef HAVE_SURFACELESS_PLATFORM case _EGL_PLATFORM_SURFACELESS: - if (disp->Options.TestOnly) - return EGL_TRUE; - return dri2_initialize_surfaceless(drv, disp); + ret = dri2_initialize_surfaceless(drv, disp); + break; #endif - #ifdef HAVE_X11_PLATFORM case _EGL_PLATFORM_X11: - if (disp->Options.TestOnly) - return EGL_TRUE; - return dri2_initialize_x11(drv, disp); + ret = dri2_initialize_x11(drv, disp); + break; #endif - #ifdef HAVE_DRM_PLATFORM case _EGL_PLATFORM_DRM: - if (disp->Options.TestOnly) - return EGL_TRUE; - return dri2_initialize_drm(drv, disp); + ret = dri2_initialize_drm(drv, disp); + break; #endif #ifdef HAVE_WAYLAND_PLATFORM case _EGL_PLATFORM_WAYLAND: - if (disp->Options.TestOnly) - return EGL_TRUE; - return dri2_initialize_wayland(drv, disp); + ret = dri2_initialize_wayland(drv, disp); + break; #endif #ifdef HAVE_ANDROID_PLATFORM case _EGL_PLATFORM_ANDROID: - if (disp->Options.TestOnly) - return EGL_TRUE; - return dri2_initialize_android(drv, disp); + ret = dri2_initialize_android(drv, disp); + break; #endif - default: _eglLog(_EGL_WARNING, "No EGL platform enabled."); return EGL_FALSE; } + + if (ret) { + dri2_dpy = dri2_egl_display(disp); + + if (!dri2_dpy) { + return EGL_FALSE; + } + + dri2_dpy->ref_count++; + } + + return ret; } /** - * Called via eglTerminate(), drv->API.Terminate(). + * Decrement display reference count, and free up display if necessary. */ -static EGLBoolean -dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp) +static void +dri2_display_release(_EGLDisplay *disp) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_display *dri2_dpy; unsigned i; - _eglReleaseDisplayResources(drv, disp); + if (!disp) + return; + + dri2_dpy = dri2_egl_display(disp); + + assert(dri2_dpy->ref_count > 0); + dri2_dpy->ref_count--; + + if (dri2_dpy->ref_count > 0) + return; + _eglCleanupDisplay(disp); if (dri2_dpy->own_dri_screen) dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); - if (dri2_dpy->fd) + if (dri2_dpy->fd >= 0) close(dri2_dpy->fd); if (dri2_dpy->driver) dlclose(dri2_dpy->driver); - free(dri2_dpy->device_name); free(dri2_dpy->driver_name); +#ifdef HAVE_WAYLAND_PLATFORM + free(dri2_dpy->device_name); +#endif + switch (disp->Platform) { #ifdef HAVE_X11_PLATFORM case _EGL_PLATFORM_X11: @@ -836,6 +927,21 @@ dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp) } free(dri2_dpy); disp->DriverData = NULL; +} + +/** + * Called via eglTerminate(), drv->API.Terminate(). + * + * This must be guaranteed to be called exactly once, even if eglTerminate is + * called many times (without a eglInitialize in between). + */ +static EGLBoolean +dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp) +{ + /* Release all non-current Context/Surfaces. */ + _eglReleaseDisplayResources(drv, disp); + + dri2_display_release(disp); return EGL_TRUE; } @@ -904,12 +1010,61 @@ dri2_create_context_attribs_error(int dri_error) _eglError(egl_error, "dri2_create_context"); } +static bool +dri2_fill_context_attribs(struct dri2_egl_context *dri2_ctx, + struct dri2_egl_display *dri2_dpy, + uint32_t *ctx_attribs, + unsigned *num_attribs) +{ + int pos = 0; + + assert(*num_attribs >= 8); + + ctx_attribs[pos++] = __DRI_CTX_ATTRIB_MAJOR_VERSION; + ctx_attribs[pos++] = dri2_ctx->base.ClientMajorVersion; + ctx_attribs[pos++] = __DRI_CTX_ATTRIB_MINOR_VERSION; + ctx_attribs[pos++] = dri2_ctx->base.ClientMinorVersion; + + if (dri2_ctx->base.Flags != 0) { + /* If the implementation doesn't support the __DRI2_ROBUSTNESS + * extension, don't even try to send it the robust-access flag. + * It may explode. Instead, generate the required EGL error here. + */ + if ((dri2_ctx->base.Flags & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) != 0 + && !dri2_dpy->robustness) { + _eglError(EGL_BAD_MATCH, "eglCreateContext"); + return false; + } + + ctx_attribs[pos++] = __DRI_CTX_ATTRIB_FLAGS; + ctx_attribs[pos++] = dri2_ctx->base.Flags; + } + + if (dri2_ctx->base.ResetNotificationStrategy != EGL_NO_RESET_NOTIFICATION_KHR) { + /* If the implementation doesn't support the __DRI2_ROBUSTNESS + * extension, don't even try to send it a reset strategy. It may + * explode. Instead, generate the required EGL error here. + */ + if (!dri2_dpy->robustness) { + _eglError(EGL_BAD_CONFIG, "eglCreateContext"); + return false; + } + + ctx_attribs[pos++] = __DRI_CTX_ATTRIB_RESET_STRATEGY; + ctx_attribs[pos++] = __DRI_CTX_RESET_LOSE_CONTEXT; + } + + *num_attribs = pos; + + return true; +} + /** * Called via eglCreateContext(), drv->API.CreateContext(). */ static _EGLContext * dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, - _EGLContext *share_list, const EGLint *attrib_list) + _EGLContext *share_list, const EGLint *attrib_list) { struct dri2_egl_context *dri2_ctx; struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); @@ -972,10 +1127,10 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, * doubleBufferMode check in * src/mesa/main/context.c:check_compatible() */ - if (dri2_config->dri_double_config) - dri_config = dri2_config->dri_double_config; + if (dri2_config->dri_double_config[0]) + dri_config = dri2_config->dri_double_config[0]; else - dri_config = dri2_config->dri_single_config; + dri_config = dri2_config->dri_single_config[0]; /* EGL_WINDOW_BIT is set only when there is a dri_double_config. This * makes sure the back buffer will always be used. @@ -986,50 +1141,37 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, else dri_config = NULL; - if (dri2_dpy->dri2) { + if (dri2_dpy->image_driver) { + unsigned error; + unsigned num_attribs = 8; + uint32_t ctx_attribs[8]; + + if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs, + &num_attribs)) + goto cleanup; + + dri2_ctx->dri_context = + dri2_dpy->image_driver->createContextAttribs(dri2_dpy->dri_screen, + api, + dri_config, + shared, + num_attribs / 2, + ctx_attribs, + & error, + dri2_ctx); + dri2_create_context_attribs_error(error); + } else if (dri2_dpy->dri2) { if (dri2_dpy->dri2->base.version >= 3) { unsigned error; - unsigned num_attribs = 0; + unsigned num_attribs = 8; uint32_t ctx_attribs[8]; - ctx_attribs[num_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION; - ctx_attribs[num_attribs++] = dri2_ctx->base.ClientMajorVersion; - ctx_attribs[num_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION; - ctx_attribs[num_attribs++] = dri2_ctx->base.ClientMinorVersion; - - if (dri2_ctx->base.Flags != 0) { - /* If the implementation doesn't support the __DRI2_ROBUSTNESS - * extension, don't even try to send it the robust-access flag. - * It may explode. Instead, generate the required EGL error here. - */ - if ((dri2_ctx->base.Flags & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) != 0 - && !dri2_dpy->robustness) { - _eglError(EGL_BAD_MATCH, "eglCreateContext"); - goto cleanup; - } - - ctx_attribs[num_attribs++] = __DRI_CTX_ATTRIB_FLAGS; - ctx_attribs[num_attribs++] = dri2_ctx->base.Flags; - } - - if (dri2_ctx->base.ResetNotificationStrategy != EGL_NO_RESET_NOTIFICATION_KHR) { - /* If the implementation doesn't support the __DRI2_ROBUSTNESS - * extension, don't even try to send it a reset strategy. It may - * explode. Instead, generate the required EGL error here. - */ - if (!dri2_dpy->robustness) { - _eglError(EGL_BAD_CONFIG, "eglCreateContext"); - goto cleanup; - } - - ctx_attribs[num_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY; - ctx_attribs[num_attribs++] = __DRI_CTX_RESET_LOSE_CONTEXT; - } - - assert(num_attribs <= ARRAY_SIZE(ctx_attribs)); + if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs, + &num_attribs)) + goto cleanup; - dri2_ctx->dri_context = - dri2_dpy->dri2->createContextAttribs(dri2_dpy->dri_screen, + dri2_ctx->dri_context = + dri2_dpy->dri2->createContextAttribs(dri2_dpy->dri_screen, api, dri_config, shared, @@ -1037,23 +1179,44 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, ctx_attribs, & error, dri2_ctx); - dri2_create_context_attribs_error(error); + dri2_create_context_attribs_error(error); } else { - dri2_ctx->dri_context = - dri2_dpy->dri2->createNewContextForAPI(dri2_dpy->dri_screen, - api, - dri_config, + dri2_ctx->dri_context = + dri2_dpy->dri2->createNewContextForAPI(dri2_dpy->dri_screen, + api, + dri_config, shared, - dri2_ctx); + dri2_ctx); } } else { assert(dri2_dpy->swrast); - dri2_ctx->dri_context = - dri2_dpy->swrast->createNewContextForAPI(dri2_dpy->dri_screen, - api, - dri_config, - shared, - dri2_ctx); + if (dri2_dpy->swrast->base.version >= 3) { + unsigned error; + unsigned num_attribs = 8; + uint32_t ctx_attribs[8]; + + if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs, + &num_attribs)) + goto cleanup; + + dri2_ctx->dri_context = + dri2_dpy->swrast->createContextAttribs(dri2_dpy->dri_screen, + api, + dri_config, + shared, + num_attribs / 2, + ctx_attribs, + & error, + dri2_ctx); + dri2_create_context_attribs_error(error); + } else { + dri2_ctx->dri_context = + dri2_dpy->swrast->createNewContextForAPI(dri2_dpy->dri_screen, + api, + dri_config, + shared, + dri2_ctx); + } } if (!dri2_ctx->dri_context) @@ -1083,33 +1246,49 @@ dri2_destroy_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx) return EGL_TRUE; } +static EGLBoolean +dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + + if (!_eglPutSurface(surf)) + return EGL_TRUE; + + return dri2_dpy->vtbl->destroy_surface(drv, dpy, surf); +} + /** * Called via eglMakeCurrent(), drv->API.MakeCurrent(). */ static EGLBoolean dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, - _EGLSurface *rsurf, _EGLContext *ctx) + _EGLSurface *rsurf, _EGLContext *ctx) { struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); - struct dri2_egl_surface *dri2_dsurf = dri2_egl_surface(dsurf); - struct dri2_egl_surface *dri2_rsurf = dri2_egl_surface(rsurf); struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); _EGLContext *old_ctx; _EGLSurface *old_dsurf, *old_rsurf; + _EGLSurface *tmp_dsurf, *tmp_rsurf; __DRIdrawable *ddraw, *rdraw; __DRIcontext *cctx; + EGLBoolean unbind; + + if (!dri2_dpy) + return _eglError(EGL_NOT_INITIALIZED, "eglMakeCurrent"); /* make new bindings */ - if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf)) + if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf)) { + /* _eglBindContext already sets the EGL error (in _eglCheckMakeCurrent) */ return EGL_FALSE; + } /* flush before context switch */ - if (old_ctx && dri2_drv->glFlush) + if (old_ctx) dri2_drv->glFlush(); - ddraw = (dri2_dsurf) ? dri2_dsurf->dri_drawable : NULL; - rdraw = (dri2_rsurf) ? dri2_rsurf->dri_drawable : NULL; + ddraw = (dsurf) ? dri2_dpy->vtbl->get_dri_drawable(dsurf) : NULL; + rdraw = (rsurf) ? dri2_dpy->vtbl->get_dri_drawable(rsurf) : NULL; cctx = (dri2_ctx) ? dri2_ctx->dri_context : NULL; if (old_ctx) { @@ -1117,22 +1296,27 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, dri2_dpy->core->unbindContext(old_cctx); } - if ((cctx == NULL && ddraw == NULL && rdraw == NULL) || - dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) { - if (old_dsurf) - drv->API.DestroySurface(drv, disp, old_dsurf); - if (old_rsurf) - drv->API.DestroySurface(drv, disp, old_rsurf); - if (old_ctx) - drv->API.DestroyContext(drv, disp, old_ctx); + unbind = (cctx == NULL && ddraw == NULL && rdraw == NULL); + + if (unbind || dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) { + dri2_destroy_surface(drv, disp, old_dsurf); + dri2_destroy_surface(drv, disp, old_rsurf); + + if (!unbind) + dri2_dpy->ref_count++; + if (old_ctx) { + EGLDisplay old_disp = _eglGetDisplayHandle(old_ctx->Resource.Display); + dri2_destroy_context(drv, disp, old_ctx); + dri2_display_release(old_disp); + } return EGL_TRUE; } else { /* undo the previous _eglBindContext */ - _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &dsurf, &rsurf); + _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &tmp_dsurf, &tmp_rsurf); assert(&dri2_ctx->base == ctx && - &dri2_dsurf->base == dsurf && - &dri2_rsurf->base == rsurf); + tmp_dsurf == dsurf && + tmp_rsurf == rsurf); _eglPutSurface(dsurf); _eglPutSurface(rsurf); @@ -1142,10 +1326,22 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, _eglPutSurface(old_rsurf); _eglPutContext(old_ctx); - return EGL_FALSE; + /* dri2_dpy->core->bindContext failed. We cannot tell for sure why, but + * setting the error to EGL_BAD_MATCH is surely better than leaving it + * as EGL_SUCCESS. + */ + return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); } } +__DRIdrawable * +dri2_surface_get_dri_drawable(_EGLSurface *surf) +{ + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); + + return dri2_surf->dri_drawable; +} + /* * Called from eglGetProcAddress() via drv->API.GetProcAddress(). */ @@ -1186,13 +1382,6 @@ dri2_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy, } static EGLBoolean -dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) -{ - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); - return dri2_dpy->vtbl->destroy_surface(drv, dpy, surf); -} - -static EGLBoolean dri2_swap_interval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint interval) { @@ -1208,7 +1397,7 @@ void dri2_flush_drawable_for_swapbuffers(_EGLDisplay *disp, _EGLSurface *draw) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); - struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); + __DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(draw); if (dri2_dpy->flush) { if (dri2_dpy->flush->base.version >= 4) { @@ -1226,12 +1415,12 @@ dri2_flush_drawable_for_swapbuffers(_EGLDisplay *disp, _EGLSurface *draw) * after calling eglSwapBuffers." */ dri2_dpy->flush->flush_with_flags(dri2_ctx->dri_context, - dri2_surf->dri_drawable, + dri_drawable, __DRI2_FLUSH_DRAWABLE | __DRI2_FLUSH_INVALIDATE_ANCILLARY, __DRI2_THROTTLE_SWAPBUFFER); } else { - dri2_dpy->flush->flush(dri2_surf->dri_drawable); + dri2_dpy->flush->flush(dri_drawable); } } } @@ -1288,7 +1477,8 @@ static EGLBoolean dri2_wait_client(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); - struct dri2_egl_surface *dri2_surf = dri2_egl_surface(ctx->DrawSurface); + _EGLSurface *surf = ctx->DrawSurface; + __DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(surf); (void) drv; @@ -1296,7 +1486,7 @@ dri2_wait_client(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx) * we need to copy fake to real here.*/ if (dri2_dpy->flush != NULL) - dri2_dpy->flush->flush(dri2_surf->dri_drawable); + dri2_dpy->flush->flush(dri_drawable); return EGL_TRUE; } @@ -1316,13 +1506,13 @@ dri2_wait_native(_EGLDriver *drv, _EGLDisplay *disp, EGLint engine) static EGLBoolean dri2_bind_tex_image(_EGLDriver *drv, - _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer) + _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); - struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); struct dri2_egl_context *dri2_ctx; _EGLContext *ctx; GLint format, target; + __DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(surf); ctx = _eglGetCurrentContext(); dri2_ctx = dri2_egl_context(ctx); @@ -1330,7 +1520,7 @@ dri2_bind_tex_image(_EGLDriver *drv, if (!_eglBindTexImage(drv, disp, surf, buffer)) return EGL_FALSE; - switch (dri2_surf->base.TextureFormat) { + switch (surf->TextureFormat) { case EGL_TEXTURE_RGB: format = __DRI_TEXTURE_FORMAT_RGB; break; @@ -1342,7 +1532,7 @@ dri2_bind_tex_image(_EGLDriver *drv, format = __DRI_TEXTURE_FORMAT_RGBA; } - switch (dri2_surf->base.TextureTarget) { + switch (surf->TextureTarget) { case EGL_TEXTURE_2D: target = GL_TEXTURE_2D; break; @@ -1352,21 +1542,21 @@ dri2_bind_tex_image(_EGLDriver *drv, } (*dri2_dpy->tex_buffer->setTexBuffer2)(dri2_ctx->dri_context, - target, format, - dri2_surf->dri_drawable); + target, format, + dri_drawable); return EGL_TRUE; } static EGLBoolean dri2_release_tex_image(_EGLDriver *drv, - _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer) + _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); - struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); struct dri2_egl_context *dri2_ctx; _EGLContext *ctx; GLint target; + __DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(surf); ctx = _eglGetCurrentContext(); dri2_ctx = dri2_egl_context(ctx); @@ -1374,7 +1564,7 @@ dri2_release_tex_image(_EGLDriver *drv, if (!_eglReleaseTexImage(drv, disp, surf, buffer)) return EGL_FALSE; - switch (dri2_surf->base.TextureTarget) { + switch (surf->TextureTarget) { case EGL_TEXTURE_2D: target = GL_TEXTURE_2D; break; @@ -1386,7 +1576,7 @@ dri2_release_tex_image(_EGLDriver *drv, dri2_dpy->tex_buffer->releaseTexBuffer != NULL) { (*dri2_dpy->tex_buffer->releaseTexBuffer)(dri2_ctx->dri_context, target, - dri2_surf->dri_drawable); + dri_drawable); } return EGL_TRUE; @@ -1430,8 +1620,8 @@ dri2_create_image_from_dri(_EGLDisplay *disp, __DRIimage *dri_image) static _EGLImage * dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx, - EGLClientBuffer buffer, - const EGLint *attr_list) + EGLClientBuffer buffer, + const EGLint *attr_list) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); @@ -1472,8 +1662,8 @@ static const struct wl_drm_components_descriptor { static _EGLImage * dri2_create_image_wayland_wl_buffer(_EGLDisplay *disp, _EGLContext *ctx, - EGLClientBuffer _buffer, - const EGLint *attr_list) + EGLClientBuffer _buffer, + const EGLint *attr_list) { struct wl_drm_buffer *buffer; struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); @@ -1562,9 +1752,9 @@ dri2_create_image_khr_texture_error(int dri_error) static _EGLImage * dri2_create_image_khr_texture(_EGLDisplay *disp, _EGLContext *ctx, - EGLenum target, - EGLClientBuffer buffer, - const EGLint *attr_list) + EGLenum target, + EGLClientBuffer buffer, + const EGLint *attr_list) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); @@ -1641,6 +1831,16 @@ dri2_create_image_khr_texture(_EGLDisplay *disp, _EGLContext *ctx, return &dri2_img->base; } +static EGLBoolean +dri2_query_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, + EGLint attribute, EGLint *value) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + if (!dri2_dpy->vtbl->query_surface) + return _eglQuerySurface(drv, dpy, surf, attribute, value); + return dri2_dpy->vtbl->query_surface(drv, dpy, surf, attribute, value); +} + static struct wl_buffer* dri2_create_wayland_buffer_from_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img) @@ -1652,7 +1852,7 @@ dri2_create_wayland_buffer_from_image(_EGLDriver *drv, _EGLDisplay *dpy, #ifdef HAVE_LIBDRM static _EGLImage * dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx, - EGLClientBuffer buffer, const EGLint *attr_list) + EGLClientBuffer buffer, const EGLint *attr_list) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); EGLint format, name, pitch, err; @@ -1668,7 +1868,7 @@ dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx, if (attrs.Width <= 0 || attrs.Height <= 0 || attrs.DRMBufferStrideMESA <= 0) { _eglError(EGL_BAD_PARAMETER, - "bad width, height or stride"); + "bad width, height or stride"); return NULL; } @@ -1679,18 +1879,18 @@ dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx, break; default: _eglError(EGL_BAD_PARAMETER, - "dri2_create_image_khr: unsupported pixmap depth"); + "dri2_create_image_khr: unsupported pixmap depth"); return NULL; } dri_image = dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen, - attrs.Width, - attrs.Height, - format, - name, - pitch, - NULL); + attrs.Width, + attrs.Height, + format, + name, + pitch, + NULL); return dri2_create_image_from_dri(disp, dri_image); } @@ -1862,9 +2062,9 @@ dri2_check_dma_buf_format(const _EGLImageAttribs *attrs) * * Therefore we must never close or otherwise modify the file descriptors. */ -static _EGLImage * +_EGLImage * dri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx, - EGLClientBuffer buffer, const EGLint *attr_list) + EGLClientBuffer buffer, const EGLint *attr_list) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); _EGLImage *res; @@ -1929,7 +2129,7 @@ dri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx, } static _EGLImage * dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, - const EGLint *attr_list) + const EGLint *attr_list) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_image *dri2_img; @@ -1996,7 +2196,7 @@ dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, dri2_img->dri_image = dri2_dpy->image->createImage(dri2_dpy->dri_screen, - attrs.Width, attrs.Height, + attrs.Width, attrs.Height, format, dri_use, dri2_img); if (dri2_img->dri_image == NULL) { err = EGL_BAD_ALLOC; @@ -2014,7 +2214,7 @@ dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, static EGLBoolean dri2_export_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, - EGLint *name, EGLint *handle, EGLint *stride) + EGLint *name, EGLint *handle, EGLint *stride) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_image *dri2_img = dri2_egl_image(img); @@ -2022,18 +2222,18 @@ dri2_export_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, (void) drv; if (name && !dri2_dpy->image->queryImage(dri2_img->dri_image, - __DRI_IMAGE_ATTRIB_NAME, name)) { + __DRI_IMAGE_ATTRIB_NAME, name)) { _eglError(EGL_BAD_ALLOC, "dri2_export_drm_image_mesa"); return EGL_FALSE; } if (handle) dri2_dpy->image->queryImage(dri2_img->dri_image, - __DRI_IMAGE_ATTRIB_HANDLE, handle); + __DRI_IMAGE_ATTRIB_HANDLE, handle); if (stride) dri2_dpy->image->queryImage(dri2_img->dri_image, - __DRI_IMAGE_ATTRIB_STRIDE, stride); + __DRI_IMAGE_ATTRIB_STRIDE, stride); return EGL_TRUE; } @@ -2052,10 +2252,10 @@ dri2_export_dma_buf_image_query_mesa(_EGLDriver *drv, _EGLDisplay *disp, if (nplanes) dri2_dpy->image->queryImage(dri2_img->dri_image, - __DRI_IMAGE_ATTRIB_NUM_PLANES, nplanes); + __DRI_IMAGE_ATTRIB_NUM_PLANES, nplanes); if (fourcc) dri2_dpy->image->queryImage(dri2_img->dri_image, - __DRI_IMAGE_ATTRIB_FOURCC, fourcc); + __DRI_IMAGE_ATTRIB_FOURCC, fourcc); if (modifiers) *modifiers = 0; @@ -2075,14 +2275,21 @@ dri2_export_dma_buf_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *im /* rework later to provide multiple fds/strides/offsets */ if (fds) dri2_dpy->image->queryImage(dri2_img->dri_image, - __DRI_IMAGE_ATTRIB_FD, fds); + __DRI_IMAGE_ATTRIB_FD, fds); if (strides) dri2_dpy->image->queryImage(dri2_img->dri_image, - __DRI_IMAGE_ATTRIB_STRIDE, strides); - - if (offsets) - offsets[0] = 0; + __DRI_IMAGE_ATTRIB_STRIDE, strides); + + if (offsets) { + int img_offset; + bool ret = dri2_dpy->image->queryImage(dri2_img->dri_image, + __DRI_IMAGE_ATTRIB_OFFSET, &img_offset); + if (ret) + offsets[0] = img_offset; + else + offsets[0] = 0; + } return EGL_TRUE; } @@ -2091,8 +2298,8 @@ dri2_export_dma_buf_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *im _EGLImage * dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, - _EGLContext *ctx, EGLenum target, - EGLClientBuffer buffer, const EGLint *attr_list) + _EGLContext *ctx, EGLenum target, + EGLClientBuffer buffer, const EGLint *attr_list) { (void) drv; @@ -2201,14 +2408,14 @@ dri2_wl_release_buffer(void *user_data, struct wl_drm_buffer *buffer) } static struct wayland_drm_callbacks wl_drm_callbacks = { - .authenticate = NULL, - .reference_buffer = dri2_wl_reference_buffer, - .release_buffer = dri2_wl_release_buffer + .authenticate = NULL, + .reference_buffer = dri2_wl_reference_buffer, + .release_buffer = dri2_wl_release_buffer }; static EGLBoolean dri2_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp, - struct wl_display *wl_dpy) + struct wl_display *wl_dpy) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); int flags = 0; @@ -2217,7 +2424,7 @@ dri2_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp, (void) drv; if (dri2_dpy->wl_server_drm) - return EGL_FALSE; + return EGL_FALSE; wl_drm_callbacks.authenticate = (int(*)(void *, uint32_t)) dri2_dpy->vtbl->authenticate; @@ -2229,11 +2436,11 @@ dri2_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp, flags |= WAYLAND_DRM_PRIME; dri2_dpy->wl_server_drm = - wayland_drm_init(wl_dpy, dri2_dpy->device_name, + wayland_drm_init(wl_dpy, dri2_dpy->device_name, &wl_drm_callbacks, disp, flags); if (!dri2_dpy->wl_server_drm) - return EGL_FALSE; + return EGL_FALSE; #ifdef HAVE_DRM_PLATFORM /* We have to share the wl_drm instance with gbm, so gbm can convert @@ -2247,14 +2454,14 @@ dri2_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp, static EGLBoolean dri2_unbind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp, - struct wl_display *wl_dpy) + struct wl_display *wl_dpy) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); (void) drv; if (!dri2_dpy->wl_server_drm) - return EGL_FALSE; + return EGL_FALSE; wayland_drm_uninit(dri2_dpy->wl_server_drm); dri2_dpy->wl_server_drm = NULL; @@ -2303,20 +2510,26 @@ dri2_egl_unref_sync(struct dri2_egl_display *dri2_dpy, struct dri2_egl_sync *dri2_sync) { if (p_atomic_dec_zero(&dri2_sync->refcount)) { - dri2_dpy->fence->destroy_fence(dri2_dpy->dri_screen, dri2_sync->fence); + if (dri2_sync->base.Type == EGL_SYNC_REUSABLE_KHR) + cnd_destroy(&dri2_sync->cond); + + if (dri2_sync->fence) + dri2_dpy->fence->destroy_fence(dri2_dpy->dri_screen, dri2_sync->fence); + free(dri2_sync); } } static _EGLSync * dri2_create_sync(_EGLDriver *drv, _EGLDisplay *dpy, - EGLenum type, const EGLint *attrib_list, - const EGLAttrib *attrib_list64) + EGLenum type, const EGLAttrib *attrib_list) { _EGLContext *ctx = _eglGetCurrentContext(); struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); struct dri2_egl_sync *dri2_sync; + EGLint ret; + pthread_condattr_t attr; dri2_sync = calloc(1, sizeof(struct dri2_egl_sync)); if (!dri2_sync) { @@ -2324,8 +2537,7 @@ dri2_create_sync(_EGLDriver *drv, _EGLDisplay *dpy, return NULL; } - if (!_eglInitSync(&dri2_sync->base, dpy, type, attrib_list, - attrib_list64)) { + if (!_eglInitSync(&dri2_sync->base, dpy, type, attrib_list)) { free(dri2_sync); return NULL; } @@ -2359,6 +2571,37 @@ dri2_create_sync(_EGLDriver *drv, _EGLDisplay *dpy, dri2_sync->fence, 0, 0)) dri2_sync->base.SyncStatus = EGL_SIGNALED_KHR; break; + + case EGL_SYNC_REUSABLE_KHR: + /* intialize attr */ + ret = pthread_condattr_init(&attr); + + if (ret) { + _eglError(EGL_BAD_ACCESS, "eglCreateSyncKHR"); + free(dri2_sync); + return NULL; + } + + /* change clock attribute to CLOCK_MONOTONIC */ + ret = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + + if (ret) { + _eglError(EGL_BAD_ACCESS, "eglCreateSyncKHR"); + free(dri2_sync); + return NULL; + } + + ret = pthread_cond_init(&dri2_sync->cond, &attr); + + if (ret) { + _eglError(EGL_BAD_ACCESS, "eglCreateSyncKHR"); + free(dri2_sync); + return NULL; + } + + /* initial status of reusable sync must be "unsignaled" */ + dri2_sync->base.SyncStatus = EGL_UNSIGNALED_KHR; + break; } p_atomic_set(&dri2_sync->refcount, 1); @@ -2370,9 +2613,27 @@ dri2_destroy_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync); + EGLint ret = EGL_TRUE; + EGLint err; + + /* if type of sync is EGL_SYNC_REUSABLE_KHR and it is not signaled yet, + * then unlock all threads possibly blocked by the reusable sync before + * destroying it. + */ + if (dri2_sync->base.Type == EGL_SYNC_REUSABLE_KHR && + dri2_sync->base.SyncStatus == EGL_UNSIGNALED_KHR) { + dri2_sync->base.SyncStatus = EGL_SIGNALED_KHR; + /* unblock all threads currently blocked by sync */ + err = cnd_broadcast(&dri2_sync->cond); + if (err) { + _eglError(EGL_BAD_ACCESS, "eglDestroySyncKHR"); + ret = EGL_FALSE; + } + } dri2_egl_unref_sync(dri2_dpy, dri2_sync); - return EGL_TRUE; + + return ret; } static EGLint @@ -2380,10 +2641,16 @@ dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, EGLint flags, EGLTime timeout) { _EGLContext *ctx = _eglGetCurrentContext(); + struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync); unsigned wait_flags = 0; + + /* timespecs for cnd_timedwait */ + struct timespec current; + xtime expire; + EGLint ret = EGL_CONDITION_SATISFIED_KHR; /* The EGL_KHR_fence_sync spec states: @@ -2397,15 +2664,98 @@ dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, /* the sync object should take a reference while waiting */ dri2_egl_ref_sync(dri2_sync); - if (dri2_dpy->fence->client_wait_sync(dri2_ctx ? dri2_ctx->dri_context : NULL, + switch (sync->Type) { + case EGL_SYNC_FENCE_KHR: + case EGL_SYNC_CL_EVENT_KHR: + if (dri2_dpy->fence->client_wait_sync(dri2_ctx ? dri2_ctx->dri_context : NULL, dri2_sync->fence, wait_flags, timeout)) - dri2_sync->base.SyncStatus = EGL_SIGNALED_KHR; - else - ret = EGL_TIMEOUT_EXPIRED_KHR; + dri2_sync->base.SyncStatus = EGL_SIGNALED_KHR; + else + ret = EGL_TIMEOUT_EXPIRED_KHR; + break; - dri2_egl_unref_sync(dri2_dpy, dri2_sync); - return ret; + case EGL_SYNC_REUSABLE_KHR: + if (dri2_ctx && dri2_sync->base.SyncStatus == EGL_UNSIGNALED_KHR && + (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR)) { + /* flush context if EGL_SYNC_FLUSH_COMMANDS_BIT_KHR is set */ + dri2_drv->glFlush(); + } + + /* if timeout is EGL_FOREVER_KHR, it should wait without any timeout.*/ + if (timeout == EGL_FOREVER_KHR) { + mtx_lock(&dri2_sync->mutex); + cnd_wait(&dri2_sync->cond, &dri2_sync->mutex); + mtx_unlock(&dri2_sync->mutex); + } else { + /* if reusable sync has not been yet signaled */ + if (dri2_sync->base.SyncStatus != EGL_SIGNALED_KHR) { + clock_gettime(CLOCK_MONOTONIC, ¤t); + + /* calculating when to expire */ + expire.nsec = timeout % 1000000000L; + expire.sec = timeout / 1000000000L; + + expire.nsec += current.tv_nsec; + expire.sec += current.tv_sec; + + /* expire.nsec now is a number between 0 and 1999999998 */ + if (expire.nsec > 999999999L) { + expire.sec++; + expire.nsec -= 1000000000L; + } + + mtx_lock(&dri2_sync->mutex); + ret = cnd_timedwait(&dri2_sync->cond, &dri2_sync->mutex, &expire); + mtx_unlock(&dri2_sync->mutex); + + if (ret == thrd_busy) { + if (dri2_sync->base.SyncStatus == EGL_UNSIGNALED_KHR) { + ret = EGL_TIMEOUT_EXPIRED_KHR; + } else { + _eglError(EGL_BAD_ACCESS, "eglClientWaitSyncKHR"); + ret = EGL_FALSE; + } + } + } + } + break; + } + dri2_egl_unref_sync(dri2_dpy, dri2_sync); + + return ret; +} + +static EGLBoolean +dri2_signal_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, + EGLenum mode) +{ + struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync); + EGLint ret; + + if (sync->Type != EGL_SYNC_REUSABLE_KHR) { + _eglError(EGL_BAD_MATCH, "eglSignalSyncKHR"); + return EGL_FALSE; + } + + if (mode != EGL_SIGNALED_KHR && mode != EGL_UNSIGNALED_KHR) { + _eglError(EGL_BAD_ATTRIBUTE, "eglSignalSyncKHR"); + return EGL_FALSE; + } + + dri2_sync->base.SyncStatus = mode; + + if (mode == EGL_SIGNALED_KHR) { + ret = cnd_broadcast(&dri2_sync->cond); + + /* fail to broadcast */ + if (ret) { + _eglError(EGL_BAD_ACCESS, "eglSignalSyncKHR"); + return EGL_FALSE; + } + } + + return EGL_TRUE; } static EGLint @@ -2421,13 +2771,39 @@ dri2_server_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync) return EGL_TRUE; } +static int +dri2_interop_query_device_info(_EGLDisplay *dpy, _EGLContext *ctx, + struct mesa_glinterop_device_info *out) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); + + if (!dri2_dpy->interop) + return MESA_GLINTEROP_UNSUPPORTED; + + return dri2_dpy->interop->query_device_info(dri2_ctx->dri_context, out); +} + +static int +dri2_interop_export_object(_EGLDisplay *dpy, _EGLContext *ctx, + struct mesa_glinterop_export_in *in, + struct mesa_glinterop_export_out *out) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); + + if (!dri2_dpy->interop) + return MESA_GLINTEROP_UNSUPPORTED; + + return dri2_dpy->interop->export_object(dri2_ctx->dri_context, in, out); +} + static void dri2_unload(_EGLDriver *drv) { struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); - if (dri2_drv->handle) - dlclose(dri2_drv->handle); + dlclose(dri2_drv->handle); free(dri2_drv); } @@ -2435,10 +2811,12 @@ static EGLBoolean dri2_load(_EGLDriver *drv) { struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); -#ifdef HAVE_ANDROID_PLATFORM +#if defined(HAVE_ANDROID_PLATFORM) || defined(__OpenBSD__) const char *libname = "libglapi.so"; #elif defined(__APPLE__) const char *libname = "libglapi.0.dylib"; +#elif defined(__CYGWIN__) + const char *libname = "cygglapi-0.dll"; #else const char *libname = "libglapi.so.0"; #endif @@ -2446,28 +2824,36 @@ dri2_load(_EGLDriver *drv) /* RTLD_GLOBAL to make sure glapi symbols are visible to DRI drivers */ handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL); - if (handle) { - dri2_drv->get_proc_address = (_EGLProc (*)(const char *)) - dlsym(handle, "_glapi_get_proc_address"); - if (!dri2_drv->get_proc_address || !libname) { - /* no need to keep a reference */ - dlclose(handle); - handle = NULL; - } + if (!handle) { + _eglLog(_EGL_WARNING, "DRI2: failed to open glapi provider"); + goto no_handle; } + dri2_drv->get_proc_address = (_EGLProc (*)(const char *)) + dlsym(handle, "_glapi_get_proc_address"); + /* if glapi is not available, loading DRI drivers will fail */ if (!dri2_drv->get_proc_address) { _eglLog(_EGL_WARNING, "DRI2: failed to find _glapi_get_proc_address"); - return EGL_FALSE; + goto no_symbol; } dri2_drv->glFlush = (void (*)(void)) dri2_drv->get_proc_address("glFlush"); - dri2_drv->handle = handle; + /* if glFlush is not available things are horribly broken */ + if (!dri2_drv->glFlush) { + _eglLog(_EGL_WARNING, "DRI2: failed to find glFlush entry point"); + goto no_symbol; + } + dri2_drv->handle = handle; return EGL_TRUE; + +no_symbol: + dlclose(handle); +no_handle: + return EGL_FALSE; } /** @@ -2515,6 +2901,7 @@ _eglBuiltInDriverDRI2(const char *args) dri2_drv->base.API.CreateImageKHR = dri2_create_image; dri2_drv->base.API.DestroyImageKHR = dri2_destroy_image_khr; dri2_drv->base.API.CreateWaylandBufferFromImageWL = dri2_create_wayland_buffer_from_image; + dri2_drv->base.API.QuerySurface = dri2_query_surface; #ifdef HAVE_LIBDRM dri2_drv->base.API.CreateDRMImageMESA = dri2_create_drm_image_mesa; dri2_drv->base.API.ExportDRMImageMESA = dri2_export_drm_image_mesa; @@ -2529,8 +2916,11 @@ _eglBuiltInDriverDRI2(const char *args) dri2_drv->base.API.GetSyncValuesCHROMIUM = dri2_get_sync_values_chromium; dri2_drv->base.API.CreateSyncKHR = dri2_create_sync; dri2_drv->base.API.ClientWaitSyncKHR = dri2_client_wait_sync; + dri2_drv->base.API.SignalSyncKHR = dri2_signal_sync; dri2_drv->base.API.WaitSyncKHR = dri2_server_wait_sync; dri2_drv->base.API.DestroySyncKHR = dri2_destroy_sync; + dri2_drv->base.API.GLInteropQueryDeviceInfo = dri2_interop_query_device_info; + dri2_drv->base.API.GLInteropExportObject = dri2_interop_export_object; dri2_drv->base.Name = "DRI2"; dri2_drv->base.Unload = dri2_unload; diff --git a/lib/mesa/src/egl/drivers/dri2/platform_x11.c b/lib/mesa/src/egl/drivers/dri2/platform_x11.c index c0a4005d0..cf2ce3f89 100644 --- a/lib/mesa/src/egl/drivers/dri2/platform_x11.c +++ b/lib/mesa/src/egl/drivers/dri2/platform_x11.c @@ -386,9 +386,6 @@ dri2_x11_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) (void) drv; - if (!_eglPutSurface(surf)) - return EGL_TRUE; - (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable); if (dri2_dpy->dri2) { @@ -665,23 +662,16 @@ dri2_x11_connect(struct dri2_egl_display *dri2_dpy) device_name = xcb_dri2_connect_device_name (connect); - dri2_dpy->device_name = - strndup(device_name, - xcb_dri2_connect_device_name_length(connect)); - - dri2_dpy->fd = loader_open_device(dri2_dpy->device_name); + dri2_dpy->fd = loader_open_device(device_name); if (dri2_dpy->fd == -1) { _eglLog(_EGL_WARNING, - "DRI2: could not open %s (%s)", dri2_dpy->device_name, - strerror(errno)); - free(dri2_dpy->device_name); + "DRI2: could not open %s (%s)", device_name, strerror(errno)); free(connect); return EGL_FALSE; } if (!dri2_x11_local_authenticate(dri2_dpy)) { close(dri2_dpy->fd); - free(dri2_dpy->device_name); free(connect); return EGL_FALSE; } @@ -691,7 +681,7 @@ dri2_x11_connect(struct dri2_egl_display *dri2_dpy) /* If Mesa knows about the appropriate driver for this fd, then trust it. * Otherwise, default to the server's value. */ - loader_driver_name = loader_get_driver_for_fd(dri2_dpy->fd, 0); + loader_driver_name = loader_get_driver_for_fd(dri2_dpy->fd); if (loader_driver_name) { dri2_dpy->driver_name = loader_driver_name; } else { @@ -700,13 +690,19 @@ dri2_x11_connect(struct dri2_egl_display *dri2_dpy) xcb_dri2_connect_driver_name_length(connect)); } - if (dri2_dpy->device_name == NULL || dri2_dpy->driver_name == NULL) { + if (dri2_dpy->driver_name == NULL) { close(dri2_dpy->fd); - free(dri2_dpy->device_name); free(dri2_dpy->driver_name); free(connect); return EGL_FALSE; } + +#ifdef HAVE_WAYLAND_PLATFORM + dri2_dpy->device_name = + strndup(device_name, + xcb_dri2_connect_device_name_length(connect)); +#endif + free(connect); return EGL_TRUE; @@ -727,7 +723,7 @@ dri2_x11_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy, xcb_screen_iterator_t s; xcb_depth_iterator_t d; xcb_visualtype_t *visuals; - int i, j, id; + int i, j, count; unsigned int rgba_masks[4]; EGLint surface_type; EGLint config_attrs[] = { @@ -738,7 +734,7 @@ dri2_x11_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy, s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn)); d = xcb_screen_allowed_depths_iterator(get_xcb_screen(s, dri2_dpy->screen)); - id = 1; + count = 0; surface_type = EGL_WINDOW_BIT | @@ -758,6 +754,9 @@ dri2_x11_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy, class_added[visuals[i]._class] = EGL_TRUE; for (j = 0; dri2_dpy->driver_configs[j]; j++) { + struct dri2_egl_config *dri2_conf; + const __DRIconfig *config = dri2_dpy->driver_configs[j]; + config_attrs[1] = visuals[i].visual_id; config_attrs[3] = visuals[i]._class; @@ -765,8 +764,10 @@ dri2_x11_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy, rgba_masks[1] = visuals[i].green_mask; rgba_masks[2] = visuals[i].blue_mask; rgba_masks[3] = 0; - dri2_add_config(disp, dri2_dpy->driver_configs[j], id++, - surface_type, config_attrs, rgba_masks); + dri2_conf = dri2_add_config(disp, config, count + 1, surface_type, + config_attrs, rgba_masks); + if (dri2_conf) + count++; /* Allow a 24-bit RGB visual to match a 32-bit RGBA EGLConfig. * Otherwise it will only match a 32-bit RGBA visual. On a @@ -778,8 +779,10 @@ dri2_x11_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy, if (d.data->depth == 24) { rgba_masks[3] = ~(rgba_masks[0] | rgba_masks[1] | rgba_masks[2]); - dri2_add_config(disp, dri2_dpy->driver_configs[j], id++, - surface_type, config_attrs, rgba_masks); + dri2_conf = dri2_add_config(disp, config, count + 1, surface_type, + config_attrs, rgba_masks); + if (dri2_conf) + count++; } } } @@ -787,7 +790,7 @@ dri2_x11_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy, xcb_depth_next(&d); } - if (!_eglGetArraySize(disp->Configs)) { + if (!count) { _eglLog(_EGL_WARNING, "DRI2: failed to create any config"); return EGL_FALSE; } @@ -1163,6 +1166,19 @@ static struct dri2_egl_display_vtbl dri2_x11_display_vtbl = { .get_dri_drawable = dri2_surface_get_dri_drawable, }; +static const __DRIswrastLoaderExtension swrast_loader_extension = { + .base = { __DRI_SWRAST_LOADER, 1 }, + + .getDrawableInfo = swrastGetDrawableInfo, + .putImage = swrastPutImage, + .getImage = swrastGetImage, +}; + +static const __DRIextension *swrast_loader_extensions[] = { + &swrast_loader_extension.base, + NULL, +}; + static EGLBoolean dri2_initialize_x11_swrast(_EGLDriver *drv, _EGLDisplay *disp) { @@ -1197,15 +1213,7 @@ dri2_initialize_x11_swrast(_EGLDriver *drv, _EGLDisplay *disp) if (!dri2_load_driver_swrast(disp)) goto cleanup_conn; - dri2_dpy->swrast_loader_extension.base.name = __DRI_SWRAST_LOADER; - dri2_dpy->swrast_loader_extension.base.version = 2; - dri2_dpy->swrast_loader_extension.getDrawableInfo = swrastGetDrawableInfo; - dri2_dpy->swrast_loader_extension.putImage = swrastPutImage; - dri2_dpy->swrast_loader_extension.getImage = swrastGetImage; - - dri2_dpy->extensions[0] = &dri2_dpy->swrast_loader_extension.base; - dri2_dpy->extensions[1] = NULL; - dri2_dpy->extensions[2] = NULL; + dri2_dpy->loader_extensions = swrast_loader_extensions; if (!dri2_create_screen(disp)) goto cleanup_driver; @@ -1231,6 +1239,7 @@ dri2_initialize_x11_swrast(_EGLDriver *drv, _EGLDisplay *disp) xcb_disconnect(dri2_dpy->conn); cleanup_dpy: free(dri2_dpy); + disp->DriverData = NULL; return EGL_FALSE; } @@ -1282,6 +1291,14 @@ dri2_x11_setup_swap_interval(struct dri2_egl_display *dri2_dpy) } #ifdef HAVE_DRI3 + +static const __DRIextension *dri3_image_loader_extensions[] = { + &dri3_image_loader_extension.base, + &image_lookup_extension.base, + &use_invalidate.base, + NULL, +}; + static EGLBoolean dri2_initialize_x11_dri3(_EGLDriver *drv, _EGLDisplay *disp) { @@ -1302,23 +1319,18 @@ dri2_initialize_x11_dri3(_EGLDriver *drv, _EGLDisplay *disp) dri2_dpy->screen = DefaultScreen(dpy); } - if (xcb_connection_has_error(dri2_dpy->conn)) { + if (!dri2_dpy->conn || xcb_connection_has_error(dri2_dpy->conn)) { _eglLog(_EGL_WARNING, "DRI3: xcb_connect failed"); goto cleanup_dpy; } - if (dri2_dpy->conn) { - if (!dri3_x11_connect(dri2_dpy)) - goto cleanup_conn; - } + if (!dri3_x11_connect(dri2_dpy)) + goto cleanup_conn; if (!dri2_load_driver_dri3(disp)) goto cleanup_conn; - dri2_dpy->extensions[0] = &dri3_image_loader_extension.base; - dri2_dpy->extensions[1] = &use_invalidate.base; - dri2_dpy->extensions[2] = &image_lookup_extension.base; - dri2_dpy->extensions[3] = NULL; + dri2_dpy->loader_extensions = dri3_image_loader_extensions; dri2_dpy->swap_available = true; dri2_dpy->invalidate_available = true; @@ -1334,14 +1346,10 @@ dri2_initialize_x11_dri3(_EGLDriver *drv, _EGLDisplay *disp) disp->Extensions.CHROMIUM_sync_control = EGL_TRUE; disp->Extensions.EXT_buffer_age = EGL_TRUE; -#ifdef HAVE_WAYLAND_PLATFORM - disp->Extensions.WL_bind_wayland_display = EGL_TRUE; -#endif + dri2_set_WL_bind_wayland_display(drv, disp); - if (dri2_dpy->conn) { - if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, false)) - goto cleanup_configs; - } + if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, false)) + goto cleanup_configs; dri2_dpy->loader_dri3_ext.core = dri2_dpy->core; dri2_dpy->loader_dri3_ext.image_driver = dri2_dpy->image_driver; @@ -1370,11 +1378,40 @@ dri2_initialize_x11_dri3(_EGLDriver *drv, _EGLDisplay *disp) xcb_disconnect(dri2_dpy->conn); cleanup_dpy: free(dri2_dpy); + disp->DriverData = NULL; return EGL_FALSE; } #endif +static const __DRIdri2LoaderExtension dri2_loader_extension_old = { + .base = { __DRI_DRI2_LOADER, 2 }, + + .getBuffers = dri2_x11_get_buffers, + .flushFrontBuffer = dri2_x11_flush_front_buffer, + .getBuffersWithFormat = NULL, +}; + +static const __DRIdri2LoaderExtension dri2_loader_extension = { + .base = { __DRI_DRI2_LOADER, 3 }, + + .getBuffers = dri2_x11_get_buffers, + .flushFrontBuffer = dri2_x11_flush_front_buffer, + .getBuffersWithFormat = dri2_x11_get_buffers_with_format, +}; + +static const __DRIextension *dri2_loader_extensions_old[] = { + &dri2_loader_extension_old.base, + &image_lookup_extension.base, + NULL, +}; + +static const __DRIextension *dri2_loader_extensions[] = { + &dri2_loader_extension.base, + &image_lookup_extension.base, + NULL, +}; + static EGLBoolean dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp) { @@ -1406,24 +1443,10 @@ dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp) if (!dri2_load_driver(disp)) goto cleanup_fd; - if (dri2_dpy->dri2_minor >= 1) { - dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER; - dri2_dpy->dri2_loader_extension.base.version = 3; - dri2_dpy->dri2_loader_extension.getBuffers = dri2_x11_get_buffers; - dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_x11_flush_front_buffer; - dri2_dpy->dri2_loader_extension.getBuffersWithFormat = - dri2_x11_get_buffers_with_format; - } else { - dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER; - dri2_dpy->dri2_loader_extension.base.version = 2; - dri2_dpy->dri2_loader_extension.getBuffers = dri2_x11_get_buffers; - dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_x11_flush_front_buffer; - dri2_dpy->dri2_loader_extension.getBuffersWithFormat = NULL; - } - - dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base; - dri2_dpy->extensions[1] = &image_lookup_extension.base; - dri2_dpy->extensions[2] = NULL; + if (dri2_dpy->dri2_minor >= 1) + dri2_dpy->loader_extensions = dri2_loader_extensions; + else + dri2_dpy->loader_extensions = dri2_loader_extensions_old; dri2_dpy->swap_available = (dri2_dpy->dri2_minor >= 2); dri2_dpy->invalidate_available = (dri2_dpy->dri2_minor >= 3); @@ -1439,9 +1462,7 @@ dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp) disp->Extensions.NV_post_sub_buffer = EGL_TRUE; disp->Extensions.CHROMIUM_sync_control = EGL_TRUE; -#ifdef HAVE_WAYLAND_PLATFORM - disp->Extensions.WL_bind_wayland_display = EGL_TRUE; -#endif + dri2_set_WL_bind_wayland_display(drv, disp); if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, true)) goto cleanup_configs; @@ -1467,6 +1488,7 @@ dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp) xcb_disconnect(dri2_dpy->conn); cleanup_dpy: free(dri2_dpy); + disp->DriverData = NULL; return EGL_FALSE; } |