diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2016-05-29 10:22:51 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2016-05-29 10:22:51 +0000 |
commit | c9223eed3c16cd3e98a8f56dda953d8f299de0e3 (patch) | |
tree | 53e2a1c3f13bcf6b4ed201d7bc135e7213c94ebe /lib/mesa/src/egl/drivers | |
parent | 6e8f2d062ab9c198239b9283b2b7ed12f4ea17d8 (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.c | 289 | ||||
-rw-r--r-- | lib/mesa/src/egl/drivers/dri2/egl_dri2.h | 25 | ||||
-rw-r--r-- | lib/mesa/src/egl/drivers/dri2/platform_drm.c | 48 | ||||
-rw-r--r-- | lib/mesa/src/egl/drivers/dri2/platform_wayland.c | 51 | ||||
-rw-r--r-- | lib/mesa/src/egl/drivers/dri2/platform_x11_dri3.c | 547 | ||||
-rw-r--r-- | lib/mesa/src/egl/drivers/dri2/platform_x11_dri3.h | 41 |
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 |