summaryrefslogtreecommitdiff
path: root/lib/mesa/src/egl/drivers
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2016-05-29 10:22:51 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2016-05-29 10:22:51 +0000
commitc9223eed3c16cd3e98a8f56dda953d8f299de0e3 (patch)
tree53e2a1c3f13bcf6b4ed201d7bc135e7213c94ebe /lib/mesa/src/egl/drivers
parent6e8f2d062ab9c198239b9283b2b7ed12f4ea17d8 (diff)
Import Mesa 11.2.2
Diffstat (limited to 'lib/mesa/src/egl/drivers')
-rw-r--r--lib/mesa/src/egl/drivers/dri2/egl_dri2.c289
-rw-r--r--lib/mesa/src/egl/drivers/dri2/egl_dri2.h25
-rw-r--r--lib/mesa/src/egl/drivers/dri2/platform_drm.c48
-rw-r--r--lib/mesa/src/egl/drivers/dri2/platform_wayland.c51
-rw-r--r--lib/mesa/src/egl/drivers/dri2/platform_x11_dri3.c547
-rw-r--r--lib/mesa/src/egl/drivers/dri2/platform_x11_dri3.h41
6 files changed, 866 insertions, 135 deletions
diff --git a/lib/mesa/src/egl/drivers/dri2/egl_dri2.c b/lib/mesa/src/egl/drivers/dri2/egl_dri2.c
index 26aea6e22..8f50f0ce5 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>
@@ -130,12 +131,10 @@ 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
@@ -285,14 +284,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;
@@ -302,19 +297,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;
@@ -366,6 +354,12 @@ struct dri2_extension_match {
int offset;
};
+static 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 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) },
@@ -399,13 +393,13 @@ dri2_bind_extensions(struct dri2_egl_display *dri2_dpy,
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",
+ _eglLog(_EGL_INFO, "found extension %s version %d",
extensions[i]->name, extensions[i]->version);
}
}
@@ -414,7 +408,7 @@ dri2_bind_extensions(struct dri2_egl_display *dri2_dpy,
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",
+ _eglLog(_EGL_WARNING, "did not find extension %s version %d",
matches[j].name, matches[j].version);
ret = EGL_FALSE;
}
@@ -508,6 +502,25 @@ dri2_open_driver(_EGLDisplay *disp)
}
EGLBoolean
+dri2_load_driver_dri3(_EGLDisplay *disp)
+{
+ struct dri2_egl_display *dri2_dpy = disp->DriverData;
+ const __DRIextension **extensions;
+
+ extensions = dri2_open_driver(disp);
+ if (!extensions)
+ return EGL_FALSE;
+
+ if (!dri2_bind_extensions(dri2_dpy, dri3_driver_extensions, extensions)) {
+ 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;
@@ -564,7 +577,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);
@@ -584,7 +599,7 @@ dri2_setup_screen(_EGLDisplay *disp)
if (api_mask & (1 << __DRI_API_GLES3))
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_surfaceless_context = EGL_TRUE;
disp->Extensions.MESA_configless_context = EGL_TRUE;
@@ -592,7 +607,9 @@ dri2_setup_screen(_EGLDisplay *disp)
__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)
@@ -654,7 +671,14 @@ dri2_create_screen(_EGLDisplay *disp)
dri2_dpy = disp->DriverData;
- if (dri2_dpy->dri2) {
+ if (dri2_dpy->image_driver) {
+ dri2_dpy->dri_screen =
+ dri2_dpy->image_driver->createNewScreen2(0, dri2_dpy->fd,
+ dri2_dpy->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,
@@ -690,7 +714,7 @@ dri2_create_screen(_EGLDisplay *disp)
extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);
- if (dri2_dpy->dri2) {
+ if (dri2_dpy->image_driver || dri2_dpy->dri2) {
if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions))
goto cleanup_dri_screen;
} else {
@@ -788,7 +812,7 @@ dri2_terminate(_EGLDriver *drv, _EGLDisplay *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);
@@ -906,6 +930,55 @@ 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().
*/
@@ -974,10 +1047,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.
@@ -988,47 +1061,34 @@ 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,
@@ -1050,12 +1110,33 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
}
} 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)
@@ -1094,11 +1175,10 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
{
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;
@@ -1110,8 +1190,8 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
if (old_ctx && dri2_drv->glFlush)
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) {
@@ -1131,10 +1211,10 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
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);
@@ -1148,6 +1228,14 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
}
}
+__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().
*/
@@ -1210,7 +1298,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) {
@@ -1228,12 +1316,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);
}
}
}
@@ -1290,7 +1378,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;
@@ -1298,7 +1387,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;
}
@@ -1321,10 +1410,10 @@ dri2_bind_tex_image(_EGLDriver *drv,
_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);
@@ -1332,7 +1421,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;
@@ -1344,7 +1433,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;
@@ -1355,7 +1444,7 @@ dri2_bind_tex_image(_EGLDriver *drv,
(*dri2_dpy->tex_buffer->setTexBuffer2)(dri2_ctx->dri_context,
target, format,
- dri2_surf->dri_drawable);
+ dri_drawable);
return EGL_TRUE;
}
@@ -1365,10 +1454,10 @@ dri2_release_tex_image(_EGLDriver *drv,
_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);
@@ -1376,7 +1465,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;
@@ -1388,7 +1477,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;
diff --git a/lib/mesa/src/egl/drivers/dri2/egl_dri2.h b/lib/mesa/src/egl/drivers/dri2/egl_dri2.h
index 9aa2a8c10..52ad92b18 100644
--- a/lib/mesa/src/egl/drivers/dri2/egl_dri2.h
+++ b/lib/mesa/src/egl/drivers/dri2/egl_dri2.h
@@ -35,6 +35,10 @@
#include <xcb/dri2.h>
#include <xcb/xfixes.h>
#include <X11/Xlib-xcb.h>
+
+#ifdef HAVE_DRI3
+#include "loader_dri3_helper.h"
+#endif
#endif
#ifdef HAVE_WAYLAND_PLATFORM
@@ -145,6 +149,8 @@ struct dri2_egl_display_vtbl {
EGLBoolean (*get_sync_values)(_EGLDisplay *display, _EGLSurface *surface,
EGLuint64KHR *ust, EGLuint64KHR *msc,
EGLuint64KHR *sbc);
+
+ __DRIdrawable *(*get_dri_drawable)(_EGLSurface *surf);
};
struct dri2_egl_display
@@ -158,6 +164,7 @@ struct dri2_egl_display
const __DRIconfig **driver_configs;
void *driver;
const __DRIcoreExtension *core;
+ const __DRIimageDriverExtension *image_driver;
const __DRIdri2Extension *dri2;
const __DRIswrastExtension *swrast;
const __DRI2flushExtension *flush;
@@ -190,6 +197,9 @@ struct dri2_egl_display
#ifdef HAVE_X11_PLATFORM
xcb_connection_t *conn;
int screen;
+#ifdef HAVE_DRI3
+ struct loader_dri3_extensions loader_dri3_ext;
+#endif
#endif
#ifdef HAVE_WAYLAND_PLATFORM
@@ -203,8 +213,9 @@ struct dri2_egl_display
int formats;
uint32_t capabilities;
int is_render_node;
- int is_different_gpu;
#endif
+
+ int is_different_gpu;
};
struct dri2_egl_context
@@ -284,10 +295,8 @@ struct dri2_egl_surface
struct dri2_egl_config
{
_EGLConfig base;
- const __DRIconfig *dri_single_config;
- const __DRIconfig *dri_double_config;
- const __DRIconfig *dri_srgb_single_config;
- const __DRIconfig *dri_srgb_double_config;
+ const __DRIconfig *dri_single_config[2];
+ const __DRIconfig *dri_double_config[2];
};
struct dri2_egl_image
@@ -327,8 +336,14 @@ EGLBoolean
dri2_load_driver_swrast(_EGLDisplay *disp);
EGLBoolean
+dri2_load_driver_dri3(_EGLDisplay *disp);
+
+EGLBoolean
dri2_create_screen(_EGLDisplay *disp);
+__DRIdrawable *
+dri2_surface_get_dri_drawable(_EGLSurface *surf);
+
__DRIimage *
dri2_lookup_egl_image(__DRIscreen *screen, void *image, void *data);
diff --git a/lib/mesa/src/egl/drivers/dri2/platform_drm.c b/lib/mesa/src/egl/drivers/dri2/platform_drm.c
index eda50875e..3f4f7e781 100644
--- a/lib/mesa/src/egl/drivers/dri2/platform_drm.c
+++ b/lib/mesa/src/egl/drivers/dri2/platform_drm.c
@@ -101,6 +101,7 @@ dri2_drm_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
struct dri2_egl_surface *dri2_surf;
struct gbm_surface *window = native_window;
struct gbm_dri_surface *surf;
+ const __DRIconfig *config;
(void) drv;
@@ -130,21 +131,20 @@ dri2_drm_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
goto cleanup_surf;
}
- if (dri2_dpy->dri2) {
- const __DRIconfig *config =
- dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
- dri2_surf->base.GLColorspace);
+ config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
+ dri2_surf->base.GLColorspace);
+ if (dri2_dpy->dri2) {
dri2_surf->dri_drawable =
(*dri2_dpy->dri2->createNewDrawable)(dri2_dpy->dri_screen, config,
dri2_surf->gbm_surf);
} else {
assert(dri2_dpy->swrast != NULL);
+
dri2_surf->dri_drawable =
- (*dri2_dpy->swrast->createNewDrawable) (dri2_dpy->dri_screen,
- dri2_conf->dri_double_config,
- dri2_surf->gbm_surf);
+ (*dri2_dpy->swrast->createNewDrawable)(dri2_dpy->dri_screen, config,
+ dri2_surf->gbm_surf);
}
if (dri2_surf->dri_drawable == NULL) {
@@ -594,6 +594,7 @@ static struct dri2_egl_display_vtbl dri2_drm_display_vtbl = {
.query_buffer_age = dri2_drm_query_buffer_age,
.create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
.get_sync_values = dri2_fallback_get_sync_values,
+ .get_dri_drawable = dri2_surface_get_dri_drawable,
};
EGLBoolean
@@ -623,27 +624,19 @@ dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp)
dri2_dpy->own_device = 1;
gbm = gbm_create_device(fd);
if (gbm == NULL)
- return EGL_FALSE;
+ goto cleanup;
+ } else {
+ fd = fcntl(gbm_device_get_fd(gbm), F_DUPFD_CLOEXEC, 3);
+ if (fd < 0)
+ goto cleanup;
}
- if (strcmp(gbm_device_get_backend_name(gbm), "drm") != 0) {
- free(dri2_dpy);
- return EGL_FALSE;
- }
+ if (strcmp(gbm_device_get_backend_name(gbm), "drm") != 0)
+ goto cleanup;
dri2_dpy->gbm_dri = gbm_dri_device(gbm);
- if (dri2_dpy->gbm_dri->base.type != GBM_DRM_DRIVER_TYPE_DRI) {
- free(dri2_dpy);
- return EGL_FALSE;
- }
-
- if (fd < 0) {
- fd = fcntl(gbm_device_get_fd(gbm), F_DUPFD_CLOEXEC, 3);
- if (fd < 0) {
- free(dri2_dpy);
- return EGL_FALSE;
- }
- }
+ if (dri2_dpy->gbm_dri->base.type != GBM_DRM_DRIVER_TYPE_DRI)
+ goto cleanup;
dri2_dpy->fd = fd;
dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);
@@ -727,4 +720,11 @@ dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp)
dri2_dpy->vtbl = &dri2_drm_display_vtbl;
return EGL_TRUE;
+
+cleanup:
+ if (fd >= 0)
+ close(fd);
+
+ free(dri2_dpy);
+ return EGL_FALSE;
}
diff --git a/lib/mesa/src/egl/drivers/dri2/platform_wayland.c b/lib/mesa/src/egl/drivers/dri2/platform_wayland.c
index 27fa93522..341acb7ed 100644
--- a/lib/mesa/src/egl/drivers/dri2/platform_wayland.c
+++ b/lib/mesa/src/egl/drivers/dri2/platform_wayland.c
@@ -653,6 +653,37 @@ create_wl_buffer(struct dri2_egl_surface *dri2_surf)
&wl_buffer_listener, dri2_surf);
}
+static EGLBoolean
+try_damage_buffer(struct dri2_egl_surface *dri2_surf,
+ const EGLint *rects,
+ EGLint n_rects)
+{
+/* The WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION macro and
+ * wl_proxy_get_version() were both introduced in wayland 1.10.
+ * Instead of bumping our wayland dependency we just make this
+ * function conditional on the required 1.10 features, falling
+ * back to old (correct but suboptimal) behaviour for older
+ * wayland.
+ */
+#ifdef WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION
+ int i;
+
+ if (wl_proxy_get_version((struct wl_proxy *) dri2_surf->wl_win->surface)
+ < WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
+ return EGL_FALSE;
+
+ for (i = 0; i < n_rects; i++) {
+ const int *rect = &rects[i * 4];
+
+ wl_surface_damage_buffer(dri2_surf->wl_win->surface,
+ rect[0],
+ dri2_surf->base.Height - rect[1] - rect[3],
+ rect[2], rect[3]);
+ }
+ return EGL_TRUE;
+#endif
+ return EGL_FALSE;
+}
/**
* Called via eglSwapBuffers(), drv->API.SwapBuffers().
*/
@@ -703,10 +734,12 @@ dri2_wl_swap_buffers_with_damage(_EGLDriver *drv,
dri2_surf->dx = 0;
dri2_surf->dy = 0;
- /* We deliberately ignore the damage region and post maximum damage, due to
+ /* If the compositor doesn't support damage_buffer, we deliberately
+ * ignore the damage region and post maximum damage, due to
* https://bugs.freedesktop.org/78190 */
- wl_surface_damage(dri2_surf->wl_win->surface,
- 0, 0, INT32_MAX, INT32_MAX);
+ if (!n_rects || !try_damage_buffer(dri2_surf, rects, n_rects))
+ wl_surface_damage(dri2_surf->wl_win->surface,
+ 0, 0, INT32_MAX, INT32_MAX);
if (dri2_dpy->is_different_gpu) {
_EGLContext *ctx = _eglGetCurrentContext();
@@ -1025,6 +1058,7 @@ static struct dri2_egl_display_vtbl dri2_wl_display_vtbl = {
.query_buffer_age = dri2_wl_query_buffer_age,
.create_wayland_buffer_from_image = dri2_wl_create_wayland_buffer_from_image,
.get_sync_values = dri2_fallback_get_sync_values,
+ .get_dri_drawable = dri2_surface_get_dri_drawable,
};
static EGLBoolean
@@ -1637,6 +1671,7 @@ dri2_wl_swrast_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
struct wl_egl_window *window = native_window;
struct dri2_egl_surface *dri2_surf;
+ const __DRIconfig *config;
(void) drv;
@@ -1661,10 +1696,12 @@ dri2_wl_swrast_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
dri2_surf->base.Width = -1;
dri2_surf->base.Height = -1;
+ config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
+ dri2_surf->base.GLColorspace);
+
dri2_surf->dri_drawable =
- (*dri2_dpy->swrast->createNewDrawable) (dri2_dpy->dri_screen,
- dri2_conf->dri_double_config,
- dri2_surf);
+ (*dri2_dpy->swrast->createNewDrawable)(dri2_dpy->dri_screen,
+ config, dri2_surf);
if (dri2_surf->dri_drawable == NULL) {
_eglError(EGL_BAD_ALLOC, "swrast->createNewDrawable");
goto cleanup_dri_drawable;
@@ -1749,6 +1786,7 @@ static struct dri2_egl_display_vtbl dri2_wl_swrast_display_vtbl = {
.query_buffer_age = dri2_fallback_query_buffer_age,
.create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
.get_sync_values = dri2_fallback_get_sync_values,
+ .get_dri_drawable = dri2_surface_get_dri_drawable,
};
static EGLBoolean
@@ -1796,6 +1834,7 @@ dri2_initialize_wayland_swrast(_EGLDriver *drv, _EGLDisplay *disp)
if (roundtrip(dri2_dpy) < 0 || dri2_dpy->formats == 0)
goto cleanup_shm;
+ dri2_dpy->fd = -1;
dri2_dpy->driver_name = strdup("swrast");
if (!dri2_load_driver_swrast(disp))
goto cleanup_shm;
diff --git a/lib/mesa/src/egl/drivers/dri2/platform_x11_dri3.c b/lib/mesa/src/egl/drivers/dri2/platform_x11_dri3.c
new file mode 100644
index 000000000..8e4a131b1
--- /dev/null
+++ b/lib/mesa/src/egl/drivers/dri2/platform_x11_dri3.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright © 2015 Boyan Ding
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <xcb/xcb.h>
+#include <xcb/dri3.h>
+#include <xcb/present.h>
+
+#include <xf86drm.h>
+
+#include "egl_dri2.h"
+#include "egl_dri2_fallbacks.h"
+#include "platform_x11_dri3.h"
+
+#include "loader.h"
+#include "loader_dri3_helper.h"
+
+static struct dri3_egl_surface *
+loader_drawable_to_egl_surface(struct loader_dri3_drawable *draw) {
+ size_t offset = offsetof(struct dri3_egl_surface, loader_drawable);
+ return (struct dri3_egl_surface *)(((void*) draw) - offset);
+}
+
+static int
+egl_dri3_get_swap_interval(struct loader_dri3_drawable *draw)
+{
+ struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
+
+ return dri3_surf->base.SwapInterval;
+}
+
+static int
+egl_dri3_clamp_swap_interval(struct loader_dri3_drawable *draw, int interval)
+{
+ struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
+
+ if (interval > dri3_surf->base.Config->MaxSwapInterval)
+ interval = dri3_surf->base.Config->MaxSwapInterval;
+ else if (interval < dri3_surf->base.Config->MinSwapInterval)
+ interval = dri3_surf->base.Config->MinSwapInterval;
+
+ return interval;
+}
+
+static void
+egl_dri3_set_swap_interval(struct loader_dri3_drawable *draw, int interval)
+{
+ struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
+
+ dri3_surf->base.SwapInterval = interval;
+}
+
+static void
+egl_dri3_set_drawable_size(struct loader_dri3_drawable *draw,
+ int width, int height)
+{
+ struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
+
+ dri3_surf->base.Width = width;
+ dri3_surf->base.Height = height;
+}
+
+static bool
+egl_dri3_in_current_context(struct loader_dri3_drawable *draw)
+{
+ struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
+ _EGLContext *ctx = _eglGetCurrentContext();
+
+ return ctx->Resource.Display == dri3_surf->base.Resource.Display;
+}
+
+static __DRIcontext *
+egl_dri3_get_dri_context(struct loader_dri3_drawable *draw)
+{
+ _EGLContext *ctx = _eglGetCurrentContext();
+ struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
+
+ return dri2_ctx->dri_context;
+}
+
+static void
+egl_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags)
+{
+ struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
+ _EGLDisplay *disp = dri3_surf->base.Resource.Display;
+
+ dri2_flush_drawable_for_swapbuffers(disp, &dri3_surf->base);
+}
+
+static struct loader_dri3_vtable egl_dri3_vtable = {
+ .get_swap_interval = egl_dri3_get_swap_interval,
+ .clamp_swap_interval = egl_dri3_clamp_swap_interval,
+ .set_swap_interval = egl_dri3_set_swap_interval,
+ .set_drawable_size = egl_dri3_set_drawable_size,
+ .in_current_context = egl_dri3_in_current_context,
+ .get_dri_context = egl_dri3_get_dri_context,
+ .flush_drawable = egl_dri3_flush_drawable,
+ .show_fps = NULL,
+};
+
+static EGLBoolean
+dri3_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
+{
+ struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
+
+ (void) drv;
+
+ if (!_eglPutSurface(surf))
+ return EGL_TRUE;
+
+ loader_dri3_drawable_fini(&dri3_surf->loader_drawable);
+
+ free(surf);
+
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+dri3_set_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
+ EGLint interval)
+{
+ struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
+
+ loader_dri3_set_swap_interval(&dri3_surf->loader_drawable, interval);
+
+ return EGL_TRUE;
+}
+
+static xcb_screen_t *
+get_xcb_screen(xcb_screen_iterator_t iter, int screen)
+{
+ for (; iter.rem; --screen, xcb_screen_next(&iter))
+ if (screen == 0)
+ return iter.data;
+
+ return NULL;
+}
+
+static _EGLSurface *
+dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
+ _EGLConfig *conf, void *native_surface,
+ const EGLint *attrib_list)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
+ struct dri3_egl_surface *dri3_surf;
+ const __DRIconfig *dri_config;
+ xcb_drawable_t drawable;
+ xcb_screen_iterator_t s;
+ xcb_screen_t *screen;
+
+ STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));
+ drawable = (uintptr_t) native_surface;
+
+ (void) drv;
+
+ dri3_surf = calloc(1, sizeof *dri3_surf);
+ if (!dri3_surf) {
+ _eglError(EGL_BAD_ALLOC, "dri3_create_surface");
+ return NULL;
+ }
+
+ if (!_eglInitSurface(&dri3_surf->base, disp, type, conf, attrib_list))
+ goto cleanup_surf;
+
+ if (type == EGL_PBUFFER_BIT) {
+ s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
+ screen = get_xcb_screen(s, dri2_dpy->screen);
+ if (!screen) {
+ _eglError(EGL_BAD_NATIVE_WINDOW, "dri3_create_surface");
+ goto cleanup_surf;
+ }
+
+ drawable = xcb_generate_id(dri2_dpy->conn);
+ xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
+ drawable, screen->root,
+ dri3_surf->base.Width, dri3_surf->base.Height);
+ }
+
+ dri_config = dri2_get_dri_config(dri2_conf, type,
+ dri3_surf->base.GLColorspace);
+
+ if (loader_dri3_drawable_init(dri2_dpy->conn, drawable,
+ dri2_dpy->dri_screen,
+ dri2_dpy->is_different_gpu, dri_config,
+ &dri2_dpy->loader_dri3_ext,
+ &egl_dri3_vtable,
+ &dri3_surf->loader_drawable)) {
+ _eglError(EGL_BAD_ALLOC, "dri3_surface_create");
+ goto cleanup_pixmap;
+ }
+
+ return &dri3_surf->base;
+
+ cleanup_pixmap:
+ if (type == EGL_PBUFFER_BIT)
+ xcb_free_pixmap(dri2_dpy->conn, drawable);
+ cleanup_surf:
+ free(dri3_surf);
+
+ return NULL;
+}
+
+/**
+ * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
+ */
+static _EGLSurface *
+dri3_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
+ _EGLConfig *conf, void *native_window,
+ const EGLint *attrib_list)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ _EGLSurface *surf;
+
+ surf = dri3_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
+ native_window, attrib_list);
+ if (surf != NULL)
+ dri3_set_swap_interval(drv, disp, surf, dri2_dpy->default_swap_interval);
+
+ return surf;
+}
+
+static _EGLSurface *
+dri3_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
+ _EGLConfig *conf, void *native_pixmap,
+ const EGLint *attrib_list)
+{
+ return dri3_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
+ native_pixmap, attrib_list);
+}
+
+static _EGLSurface *
+dri3_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,
+ _EGLConfig *conf, const EGLint *attrib_list)
+{
+ return dri3_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,
+ XCB_WINDOW_NONE, attrib_list);
+}
+
+static EGLBoolean
+dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
+ EGLuint64KHR *ust, EGLuint64KHR *msc,
+ EGLuint64KHR *sbc)
+{
+ struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surface);
+
+ return loader_dri3_wait_for_msc(&dri3_surf->loader_drawable, 0, 0, 0,
+ (int64_t *) ust, (int64_t *) msc,
+ (int64_t *) sbc) ? EGL_TRUE : EGL_FALSE;
+}
+
+static _EGLImage *
+dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
+ EGLClientBuffer buffer, const EGLint *attr_list)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct dri2_egl_image *dri2_img;
+ xcb_drawable_t drawable;
+ xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
+ xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
+ unsigned int format;
+
+ drawable = (xcb_drawable_t) (uintptr_t) buffer;
+ bp_cookie = xcb_dri3_buffer_from_pixmap(dri2_dpy->conn, drawable);
+ bp_reply = xcb_dri3_buffer_from_pixmap_reply(dri2_dpy->conn,
+ bp_cookie, NULL);
+ if (!bp_reply) {
+ _eglError(EGL_BAD_ALLOC, "xcb_dri3_buffer_from_pixmap");
+ return NULL;
+ }
+
+ switch (bp_reply->depth) {
+ case 16:
+ format = __DRI_IMAGE_FORMAT_RGB565;
+ break;
+ case 24:
+ format = __DRI_IMAGE_FORMAT_XRGB8888;
+ break;
+ case 32:
+ format = __DRI_IMAGE_FORMAT_ARGB8888;
+ break;
+ default:
+ _eglError(EGL_BAD_PARAMETER,
+ "dri3_create_image_khr: unsupported pixmap depth");
+ free(bp_reply);
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ dri2_img = malloc(sizeof *dri2_img);
+ if (!dri2_img) {
+ _eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ if (!_eglInitImage(&dri2_img->base, disp)) {
+ free(dri2_img);
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ dri2_img->dri_image = loader_dri3_create_image(dri2_dpy->conn,
+ bp_reply,
+ format,
+ dri2_dpy->dri_screen,
+ dri2_dpy->image,
+ dri2_img);
+
+ free(bp_reply);
+
+ return &dri2_img->base;
+}
+
+static _EGLImage *
+dri3_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
+ _EGLContext *ctx, EGLenum target,
+ EGLClientBuffer buffer, const EGLint *attr_list)
+{
+ (void) drv;
+
+ switch (target) {
+ case EGL_NATIVE_PIXMAP_KHR:
+ return dri3_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
+ default:
+ return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
+ }
+}
+
+/**
+ * Called by the driver when it needs to update the real front buffer with the
+ * contents of its fake front buffer.
+ */
+static void
+dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
+{
+ /* There does not seem to be any kind of consensus on whether we should
+ * support front-buffer rendering or not:
+ * http://lists.freedesktop.org/archives/mesa-dev/2013-June/040129.html
+ */
+ _eglLog(_EGL_WARNING, "FIXME: egl/x11 doesn't support front buffer rendering.");
+ (void) driDrawable;
+ (void) loaderPrivate;
+}
+
+const __DRIimageLoaderExtension dri3_image_loader_extension = {
+ .base = { __DRI_IMAGE_LOADER, 1 },
+
+ .getBuffers = loader_dri3_get_buffers,
+ .flushFrontBuffer = dri3_flush_front_buffer,
+};
+
+static EGLBoolean
+dri3_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
+{
+ struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw);
+
+ /* No-op for a pixmap or pbuffer surface */
+ if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
+ return 0;
+
+ return loader_dri3_swap_buffers_msc(&dri3_surf->loader_drawable,
+ 0, 0, 0, 0,
+ draw->SwapBehavior == EGL_BUFFER_PRESERVED) != -1;
+}
+
+static EGLBoolean
+dri3_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
+ void *native_pixmap_target)
+{
+ struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
+ xcb_pixmap_t target;
+
+ STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));
+ target = (uintptr_t) native_pixmap_target;
+
+ loader_dri3_copy_drawable(&dri3_surf->loader_drawable, target,
+ dri3_surf->loader_drawable.drawable);
+
+ return EGL_TRUE;
+}
+
+static int
+dri3_query_buffer_age(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
+{
+ struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
+
+ return loader_dri3_query_buffer_age(&dri3_surf->loader_drawable);
+}
+
+static __DRIdrawable *
+dri3_get_dri_drawable(_EGLSurface *surf)
+{
+ struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
+
+ return dri3_surf->loader_drawable.dri_drawable;
+}
+
+struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
+ .authenticate = NULL,
+ .create_window_surface = dri3_create_window_surface,
+ .create_pixmap_surface = dri3_create_pixmap_surface,
+ .create_pbuffer_surface = dri3_create_pbuffer_surface,
+ .destroy_surface = dri3_destroy_surface,
+ .create_image = dri3_create_image_khr,
+ .swap_interval = dri3_set_swap_interval,
+ .swap_buffers = dri3_swap_buffers,
+ .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
+ .swap_buffers_region = dri2_fallback_swap_buffers_region,
+ .post_sub_buffer = dri2_fallback_post_sub_buffer,
+ .copy_buffers = dri3_copy_buffers,
+ .query_buffer_age = dri3_query_buffer_age,
+ .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
+ .get_sync_values = dri3_get_sync_values,
+ .get_dri_drawable = dri3_get_dri_drawable,
+};
+
+static char *
+dri3_get_device_name(int fd)
+{
+ char *ret = NULL;
+
+ ret = drmGetRenderDeviceNameFromFd(fd);
+ if (ret)
+ return ret;
+
+ /* For dri3, render node support is required for WL_bind_wayland_display.
+ * In order not to regress on older systems without kernel or libdrm
+ * support, fall back to dri2. User can override it with environment
+ * variable if they don't need to use that extension.
+ */
+ if (getenv("EGL_FORCE_DRI3") == NULL) {
+ _eglLog(_EGL_WARNING, "Render node support not available, falling back to dri2");
+ _eglLog(_EGL_WARNING, "If you want to force dri3, set EGL_FORCE_DRI3 environment variable");
+ } else
+ ret = loader_get_device_name_for_fd(fd);
+
+ return ret;
+}
+
+EGLBoolean
+dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
+{
+ xcb_dri3_query_version_reply_t *dri3_query;
+ xcb_dri3_query_version_cookie_t dri3_query_cookie;
+ xcb_present_query_version_reply_t *present_query;
+ xcb_present_query_version_cookie_t present_query_cookie;
+ xcb_generic_error_t *error;
+ xcb_screen_iterator_t s;
+ xcb_screen_t *screen;
+ const xcb_query_extension_reply_t *extension;
+
+ xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri3_id);
+ xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_present_id);
+
+ extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri3_id);
+ if (!(extension && extension->present))
+ return EGL_FALSE;
+
+ extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_present_id);
+ if (!(extension && extension->present))
+ return EGL_FALSE;
+
+ dri3_query_cookie = xcb_dri3_query_version(dri2_dpy->conn,
+ XCB_DRI3_MAJOR_VERSION,
+ XCB_DRI3_MINOR_VERSION);
+
+ present_query_cookie = xcb_present_query_version(dri2_dpy->conn,
+ XCB_PRESENT_MAJOR_VERSION,
+ XCB_PRESENT_MINOR_VERSION);
+
+ dri3_query =
+ xcb_dri3_query_version_reply(dri2_dpy->conn, dri3_query_cookie, &error);
+ if (dri3_query == NULL || error != NULL) {
+ _eglLog(_EGL_WARNING, "DRI3: failed to query the version");
+ free(dri3_query);
+ free(error);
+ return EGL_FALSE;
+ }
+ free(dri3_query);
+
+ present_query =
+ xcb_present_query_version_reply(dri2_dpy->conn,
+ present_query_cookie, &error);
+ if (present_query == NULL || error != NULL) {
+ _eglLog(_EGL_WARNING, "DRI3: failed to query Present version");
+ free(present_query);
+ free(error);
+ return EGL_FALSE;
+ }
+ free(present_query);
+
+ s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
+ screen = get_xcb_screen(s, dri2_dpy->screen);
+ if (!screen) {
+ _eglError(EGL_BAD_NATIVE_WINDOW, "dri3_x11_connect");
+ return EGL_FALSE;
+ }
+
+ dri2_dpy->fd = loader_dri3_open(dri2_dpy->conn, screen->root, 0);
+ if (dri2_dpy->fd < 0) {
+ int conn_error = xcb_connection_has_error(dri2_dpy->conn);
+ _eglLog(_EGL_WARNING, "DRI3: Screen seems not DRI3 capable");
+
+ if (conn_error)
+ _eglLog(_EGL_WARNING, "DRI3: Failed to initialize");
+
+ return EGL_FALSE;
+ }
+
+ dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu);
+
+ dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd, 0);
+ if (!dri2_dpy->driver_name) {
+ _eglLog(_EGL_WARNING, "DRI3: No driver found");
+ close(dri2_dpy->fd);
+ return EGL_FALSE;
+ }
+
+ dri2_dpy->device_name = dri3_get_device_name(dri2_dpy->fd);
+ if (!dri2_dpy->device_name) {
+ close(dri2_dpy->fd);
+ return EGL_FALSE;
+ }
+
+ return EGL_TRUE;
+}
diff --git a/lib/mesa/src/egl/drivers/dri2/platform_x11_dri3.h b/lib/mesa/src/egl/drivers/dri2/platform_x11_dri3.h
new file mode 100644
index 000000000..13d857242
--- /dev/null
+++ b/lib/mesa/src/egl/drivers/dri2/platform_x11_dri3.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2015 Boyan Ding
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef EGL_X11_DRI3_INCLUDED
+#define EGL_X11_DRI3_INCLUDED
+
+#include "egl_dri2.h"
+
+_EGL_DRIVER_TYPECAST(dri3_egl_surface, _EGLSurface, obj)
+
+struct dri3_egl_surface {
+ _EGLSurface base;
+ struct loader_dri3_drawable loader_drawable;
+};
+
+extern const __DRIimageLoaderExtension dri3_image_loader_extension;
+extern struct dri2_egl_display_vtbl dri3_x11_display_vtbl;
+
+EGLBoolean
+dri3_x11_connect(struct dri2_egl_display *dri2_dpy);
+
+#endif