#include <xcb/present.h>
#include <xf86drm.h>
+#include "util/macros.h"
#include "egl_dri2.h"
-#include "egl_dri2_fallbacks.h"
#include "platform_x11_dri3.h"
#include "loader.h"
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;
+ dri3_surf->surf.base.Width = width;
+ dri3_surf->surf.base.Height = height;
}
static bool
struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
_EGLContext *ctx = _eglGetCurrentContext();
- return ctx->Resource.Display == dri3_surf->base.Resource.Display;
+ return ctx->Resource.Display == dri3_surf->surf.base.Resource.Display;
}
static __DRIcontext *
}
static __DRIscreen *
-egl_dri3_get_dri_screen(struct loader_dri3_drawable *draw)
+egl_dri3_get_dri_screen(void)
{
_EGLContext *ctx = _eglGetCurrentContext();
struct dri2_egl_context *dri2_ctx;
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;
+ _EGLDisplay *disp = dri3_surf->surf.base.Resource.Display;
- dri2_flush_drawable_for_swapbuffers(disp, &dri3_surf->base);
+ dri2_flush_drawable_for_swapbuffers(disp, &dri3_surf->surf.base);
}
static const 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,
};
static EGLBoolean
-dri3_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
+dri3_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
-
- (void) drv;
+ xcb_drawable_t drawable = dri3_surf->loader_drawable.drawable;
loader_dri3_drawable_fini(&dri3_surf->loader_drawable);
+ if (surf->Type == EGL_PBUFFER_BIT)
+ xcb_free_pixmap (dri2_dpy->conn, drawable);
+
+ dri2_fini_surface(surf);
free(surf);
return EGL_TRUE;
}
static EGLBoolean
-dri3_set_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
- EGLint interval)
+dri3_set_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval)
{
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
+ dri3_surf->surf.base.SwapInterval = interval;
loader_dri3_set_swap_interval(&dri3_surf->loader_drawable, interval);
return EGL_TRUE;
}
static _EGLSurface *
-dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
- _EGLConfig *conf, void *native_surface,
- const EGLint *attrib_list)
+dri3_create_surface(_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);
const __DRIconfig *dri_config;
xcb_drawable_t drawable;
- 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))
+ if (!dri2_init_surface(&dri3_surf->surf.base, disp, type, conf,
+ attrib_list, false, native_surface))
goto cleanup_surf;
if (type == EGL_PBUFFER_BIT) {
drawable = xcb_generate_id(dri2_dpy->conn);
xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
drawable, dri2_dpy->screen->root,
- dri3_surf->base.Width, dri3_surf->base.Height);
+ dri3_surf->surf.base.Width, dri3_surf->surf.base.Height);
+ } else {
+ STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));
+ drawable = (uintptr_t) native_surface;
}
dri_config = dri2_get_dri_config(dri2_conf, type,
- dri3_surf->base.GLColorspace);
+ dri3_surf->surf.base.GLColorspace);
+
+ if (!dri_config) {
+ _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");
+ goto cleanup_pixmap;
+ }
if (loader_dri3_drawable_init(dri2_dpy->conn, drawable,
dri2_dpy->dri_screen,
- dri2_dpy->is_different_gpu, dri_config,
+ dri2_dpy->is_different_gpu,
+ dri2_dpy->multibuffers_available,
+ dri_config,
&dri2_dpy->loader_dri3_ext,
&egl_dri3_vtable,
&dri3_surf->loader_drawable)) {
goto cleanup_pixmap;
}
- return &dri3_surf->base;
+ return &dri3_surf->surf.base;
cleanup_pixmap:
if (type == EGL_PBUFFER_BIT)
}
/**
- * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
+ * Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
*/
static _EGLSurface *
-dri3_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
- _EGLConfig *conf, void *native_window,
- const EGLint *attrib_list)
+dri3_create_window_surface(_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,
+ surf = dri3_create_surface(disp, EGL_WINDOW_BIT, conf,
native_window, attrib_list);
if (surf != NULL)
- dri3_set_swap_interval(drv, disp, surf, dri2_dpy->default_swap_interval);
+ dri3_set_swap_interval(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)
+dri3_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
+ void *native_pixmap, const EGLint *attrib_list)
{
- return dri3_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
+ return dri3_create_surface(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)
+dri3_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
+ const EGLint *attrib_list)
{
- return dri3_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,
- XCB_WINDOW_NONE, attrib_list);
+ return dri3_create_surface(disp, EGL_PBUFFER_BIT, conf,
+ NULL, attrib_list);
}
static EGLBoolean
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:
+ format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);
+ if (format == __DRI_IMAGE_FORMAT_NONE) {
_eglError(EGL_BAD_PARAMETER,
"dri3_create_image_khr: unsupported pixmap depth");
free(bp_reply);
dri2_img = malloc(sizeof *dri2_img);
if (!dri2_img) {
_eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
+ free(bp_reply);
return EGL_NO_IMAGE_KHR;
}
- if (!_eglInitImage(&dri2_img->base, disp)) {
- free(dri2_img);
- return EGL_NO_IMAGE_KHR;
- }
+ _eglInitImage(&dri2_img->base, disp);
dri2_img->dri_image = loader_dri3_create_image(dri2_dpy->conn,
bp_reply,
return &dri2_img->base;
}
+#ifdef HAVE_DRI3_MODIFIERS
+static _EGLImage *
+dri3_create_image_khr_pixmap_from_buffers(_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_dri3_buffers_from_pixmap_cookie_t bp_cookie;
+ xcb_dri3_buffers_from_pixmap_reply_t *bp_reply;
+ xcb_drawable_t drawable;
+ unsigned int format;
+
+ drawable = (xcb_drawable_t) (uintptr_t) buffer;
+ bp_cookie = xcb_dri3_buffers_from_pixmap(dri2_dpy->conn, drawable);
+ bp_reply = xcb_dri3_buffers_from_pixmap_reply(dri2_dpy->conn,
+ bp_cookie, NULL);
+
+ if (!bp_reply) {
+ _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);
+ if (format == __DRI_IMAGE_FORMAT_NONE) {
+ _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");
+ free(bp_reply);
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ _eglInitImage(&dri2_img->base, disp);
+
+ dri2_img->dri_image = loader_dri3_create_image_from_buffers(dri2_dpy->conn,
+ bp_reply,
+ format,
+ dri2_dpy->dri_screen,
+ dri2_dpy->image,
+ dri2_img);
+ free(bp_reply);
+
+ if (!dri2_img->dri_image) {
+ _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
+ free(dri2_img);
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ return &dri2_img->base;
+}
+#endif
+
static _EGLImage *
-dri3_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
- _EGLContext *ctx, EGLenum target,
+dri3_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,
EGLClientBuffer buffer, const EGLint *attr_list)
{
- (void) drv;
+#ifdef HAVE_DRI3_MODIFIERS
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+#endif
switch (target) {
case EGL_NATIVE_PIXMAP_KHR:
+#ifdef HAVE_DRI3_MODIFIERS
+ if (dri2_dpy->multibuffers_available)
+ return dri3_create_image_khr_pixmap_from_buffers(disp, ctx, buffer,
+ attr_list);
+#endif
return dri3_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
default:
- return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
+ return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);
}
}
static void
dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
{
+ struct loader_dri3_drawable *draw = loaderPrivate;
+ (void) driDrawable;
+
/* 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;
+ if (!draw->is_pixmap)
+ _eglLog(_EGL_WARNING, "FIXME: egl/x11 doesn't support front buffer rendering.");
}
const __DRIimageLoaderExtension dri3_image_loader_extension = {
};
static EGLBoolean
-dri3_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
+dri3_swap_buffers(_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 EGL_FALSE;
-
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)
+dri3_copy_buffers(_EGLDisplay *disp, _EGLSurface *surf, void *native_pixmap_target)
{
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
xcb_pixmap_t target;
}
static int
-dri3_query_buffer_age(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
+dri3_query_buffer_age(const _EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
{
struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
return loader_dri3_query_buffer_age(&dri3_surf->loader_drawable);
}
+static EGLBoolean
+dri3_query_surface(_EGLDisplay *disp, _EGLSurface *surf,
+ EGLint attribute, EGLint *value)
+{
+ struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
+
+ switch (attribute) {
+ case EGL_WIDTH:
+ case EGL_HEIGHT:
+ loader_dri3_update_drawable_geometry(&dri3_surf->loader_drawable);
+ break;
+ default:
+ break;
+ }
+
+ return _eglQuerySurface(disp, surf, attribute, value);
+}
+
static __DRIdrawable *
dri3_get_dri_drawable(_EGLSurface *surf)
{
return dri3_surf->loader_drawable.dri_drawable;
}
+static void
+dri3_close_screen_notify(_EGLDisplay *disp)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+
+ loader_dri3_close_screen(dri2_dpy->dri_screen);
+}
+
struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
.authenticate = dri3_authenticate,
.create_window_surface = dri3_create_window_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,
+ .query_surface = dri3_query_surface,
.get_sync_values = dri3_get_sync_values,
.get_dri_drawable = dri3_get_dri_drawable,
+ .close_screen_notify = dri3_close_screen_notify,
};
+/* Only request versions of these protocols which we actually support. */
+#define DRI3_SUPPORTED_MAJOR 1
+#define PRESENT_SUPPORTED_MAJOR 1
+
+#ifdef HAVE_DRI3_MODIFIERS
+#define DRI3_SUPPORTED_MINOR 2
+#define PRESENT_SUPPORTED_MINOR 2
+#else
+#define PRESENT_SUPPORTED_MINOR 0
+#define DRI3_SUPPORTED_MINOR 0
+#endif
+
EGLBoolean
dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
{
return EGL_FALSE;
dri3_query_cookie = xcb_dri3_query_version(dri2_dpy->conn,
- XCB_DRI3_MAJOR_VERSION,
- XCB_DRI3_MINOR_VERSION);
+ DRI3_SUPPORTED_MAJOR,
+ DRI3_SUPPORTED_MINOR);
present_query_cookie = xcb_present_query_version(dri2_dpy->conn,
- XCB_PRESENT_MAJOR_VERSION,
- XCB_PRESENT_MINOR_VERSION);
+ PRESENT_SUPPORTED_MAJOR,
+ PRESENT_SUPPORTED_MINOR);
dri3_query =
xcb_dri3_query_version_reply(dri2_dpy->conn, dri3_query_cookie, &error);
free(error);
return EGL_FALSE;
}
+
+ dri2_dpy->dri3_major_version = dri3_query->major_version;
+ dri2_dpy->dri3_minor_version = dri3_query->minor_version;
free(dri3_query);
present_query =
free(error);
return EGL_FALSE;
}
+
+ dri2_dpy->present_major_version = present_query->major_version;
+ dri2_dpy->present_minor_version = present_query->minor_version;
free(present_query);
dri2_dpy->fd = loader_dri3_open(dri2_dpy->conn, dri2_dpy->screen->root, 0);