summaryrefslogtreecommitdiff
path: root/hw/xwayland/xwayland-glamor-eglstream.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/xwayland/xwayland-glamor-eglstream.c')
-rw-r--r--hw/xwayland/xwayland-glamor-eglstream.c202
1 files changed, 197 insertions, 5 deletions
diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c
index ccaa59cbe..2d8380e1f 100644
--- a/hw/xwayland/xwayland-glamor-eglstream.c
+++ b/hw/xwayland/xwayland-glamor-eglstream.c
@@ -37,6 +37,8 @@
#include <glamor_transfer.h>
#include <xf86drm.h>
+#include <dri3.h>
+#include <drm_fourcc.h>
#include <epoxy/egl.h>
@@ -47,6 +49,7 @@
#include "wayland-eglstream-client-protocol.h"
#include "wayland-eglstream-controller-client-protocol.h"
+#include "linux-dmabuf-unstable-v1-client-protocol.h"
struct xwl_eglstream_pending_stream {
PixmapPtr pixmap;
@@ -80,12 +83,23 @@ struct xwl_eglstream_private {
GLuint blit_is_rgba_pos;
};
+enum xwl_pixmap_type {
+ XWL_PIXMAP_EGLSTREAM, /* Pixmaps created by glamor. */
+ XWL_PIXMAP_DMA_BUF, /* Pixmaps allocated through DRI3. */
+};
+
struct xwl_pixmap {
- struct wl_buffer *buffer;
+ enum xwl_pixmap_type type;
+ /* add any new <= 4-byte member here to avoid holes on 64-bit */
struct xwl_screen *xwl_screen;
+ struct wl_buffer *buffer;
+ /* XWL_PIXMAP_EGLSTREAM. */
EGLStreamKHR stream;
EGLSurface surface;
+
+ /* XWL_PIXMAP_DMA_BUF. */
+ EGLImage image;
};
static DevPrivateKeyRec xwl_eglstream_private_key;
@@ -289,12 +303,18 @@ xwl_eglstream_unref_pixmap_stream(struct xwl_pixmap *xwl_pixmap)
xwl_screen->egl_context);
}
- if (xwl_pixmap->surface)
+ if (xwl_pixmap->surface != EGL_NO_SURFACE)
eglDestroySurface(xwl_screen->egl_display, xwl_pixmap->surface);
- eglDestroyStreamKHR(xwl_screen->egl_display, xwl_pixmap->stream);
+ if (xwl_pixmap->stream != EGL_NO_STREAM_KHR)
+ eglDestroyStreamKHR(xwl_screen->egl_display, xwl_pixmap->stream);
+
+ if (xwl_pixmap->buffer)
+ wl_buffer_destroy(xwl_pixmap->buffer);
+
+ if (xwl_pixmap->image != EGL_NO_IMAGE_KHR)
+ eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image);
- wl_buffer_destroy(xwl_pixmap->buffer);
free(xwl_pixmap);
}
@@ -509,9 +529,13 @@ xwl_eglstream_create_pending_stream(struct xwl_screen *xwl_screen,
FatalError("Not enough memory to create pixmap\n");
xwl_pixmap_set_private(pixmap, xwl_pixmap);
+ xwl_pixmap->type = XWL_PIXMAP_EGLSTREAM;
+ xwl_pixmap->image = EGL_NO_IMAGE;
+
xwl_glamor_egl_make_current(xwl_screen);
xwl_pixmap->xwl_screen = xwl_screen;
+ xwl_pixmap->surface = EGL_NO_SURFACE;
xwl_pixmap->stream = eglCreateStreamKHR(xwl_screen->egl_display, NULL);
stream_fd = eglGetStreamFileDescriptorKHR(xwl_screen->egl_display,
xwl_pixmap->stream);
@@ -552,6 +576,7 @@ xwl_glamor_eglstream_allow_commits(struct xwl_window *xwl_window)
struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
if (xwl_pixmap) {
+ assert(xwl_pixmap->type == XWL_PIXMAP_EGLSTREAM);
if (pending) {
/* Wait for the compositor to finish connecting the consumer for
* this eglstream */
@@ -590,6 +615,8 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window,
};
GLint saved_vao;
+ assert(xwl_pixmap->type == XWL_PIXMAP_EGLSTREAM);
+
/* Unbind the framebuffer BEFORE binding the EGLSurface, otherwise we
* won't actually draw to it
*/
@@ -636,7 +663,7 @@ xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window,
static Bool
xwl_glamor_eglstream_check_flip(PixmapPtr pixmap)
{
- return FALSE;
+ return xwl_pixmap_get(pixmap)->type == XWL_PIXMAP_DMA_BUF;
}
static void
@@ -681,6 +708,9 @@ xwl_glamor_eglstream_init_wl_registry(struct xwl_screen *xwl_screen,
xwl_eglstream->controller = wl_registry_bind(
wl_registry, id, &wl_eglstream_controller_interface, version);
return TRUE;
+ } else if (strcmp(name, "zwp_linux_dmabuf_v1") == 0) {
+ xwl_screen_set_dmabuf_interface(xwl_screen, id, version);
+ return TRUE;
}
/* no match */
@@ -779,6 +809,163 @@ xwl_eglstream_init_shaders(struct xwl_screen *xwl_screen)
glGetUniformLocation(xwl_eglstream->blit_prog, "is_rgba");
}
+static int
+xwl_dri3_open_client(ClientPtr client,
+ ScreenPtr screen,
+ RRProviderPtr provider,
+ int *pfd)
+{
+ /* Not supported with this backend. */
+ return BadImplementation;
+}
+
+static PixmapPtr
+xwl_dri3_pixmap_from_fds(ScreenPtr screen,
+ CARD8 num_fds, const int *fds,
+ CARD16 width, CARD16 height,
+ const CARD32 *strides, const CARD32 *offsets,
+ CARD8 depth, CARD8 bpp,
+ uint64_t modifier)
+{
+ PixmapPtr pixmap;
+ struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+ struct xwl_pixmap *xwl_pixmap;
+ unsigned int texture;
+ EGLint image_attribs[48];
+ uint32_t mod_hi = modifier >> 32, mod_lo = modifier & 0xffffffff, format;
+ int attrib = 0, i;
+ struct zwp_linux_buffer_params_v1 *params;
+
+ format = wl_drm_format_for_depth(depth);
+ if (!xwl_glamor_is_modifier_supported(xwl_screen, format, modifier)) {
+ ErrorF("glamor: unsupported format modifier\n");
+ return NULL;
+ }
+
+ xwl_pixmap = calloc(1, sizeof (*xwl_pixmap));
+ if (!xwl_pixmap)
+ return NULL;
+ xwl_pixmap->type = XWL_PIXMAP_DMA_BUF;
+ xwl_pixmap->xwl_screen = xwl_screen;
+
+ xwl_pixmap->buffer = NULL;
+ xwl_pixmap->stream = EGL_NO_STREAM_KHR;
+ xwl_pixmap->surface = EGL_NO_SURFACE;
+
+ params = zwp_linux_dmabuf_v1_create_params(xwl_screen->dmabuf);
+ for (i = 0; i < num_fds; i++) {
+ zwp_linux_buffer_params_v1_add(params, fds[i], i,
+ offsets[i], strides[i],
+ mod_hi, mod_lo);
+ }
+ xwl_pixmap->buffer =
+ zwp_linux_buffer_params_v1_create_immed(params, width, height,
+ format, 0);
+ zwp_linux_buffer_params_v1_destroy(params);
+
+
+ image_attribs[attrib++] = EGL_WIDTH;
+ image_attribs[attrib++] = width;
+ image_attribs[attrib++] = EGL_HEIGHT;
+ image_attribs[attrib++] = height;
+ image_attribs[attrib++] = EGL_LINUX_DRM_FOURCC_EXT;
+ image_attribs[attrib++] = drm_format_for_depth(depth, bpp);
+
+ if (num_fds > 0) {
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE0_FD_EXT;
+ image_attribs[attrib++] = fds[0];
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
+ image_attribs[attrib++] = offsets[0];
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
+ image_attribs[attrib++] = strides[0];
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
+ image_attribs[attrib++] = mod_hi;
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
+ image_attribs[attrib++] = mod_lo;
+ }
+ if (num_fds > 1) {
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE1_FD_EXT;
+ image_attribs[attrib++] = fds[1];
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
+ image_attribs[attrib++] = offsets[1];
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
+ image_attribs[attrib++] = strides[1];
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT;
+ image_attribs[attrib++] = mod_hi;
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT;
+ image_attribs[attrib++] = mod_lo;
+ }
+ if (num_fds > 2) {
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE2_FD_EXT;
+ image_attribs[attrib++] = fds[2];
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
+ image_attribs[attrib++] = offsets[2];
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
+ image_attribs[attrib++] = strides[2];
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT;
+ image_attribs[attrib++] = mod_hi;
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT;
+ image_attribs[attrib++] = mod_lo;
+ }
+ if (num_fds > 3) {
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE3_FD_EXT;
+ image_attribs[attrib++] = fds[3];
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT;
+ image_attribs[attrib++] = offsets[3];
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE3_PITCH_EXT;
+ image_attribs[attrib++] = strides[3];
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT;
+ image_attribs[attrib++] = mod_hi;
+ image_attribs[attrib++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT;
+ image_attribs[attrib++] = mod_lo;
+ }
+ image_attribs[attrib++] = EGL_NONE;
+
+ xwl_glamor_egl_make_current(xwl_screen);
+
+ /* eglCreateImageKHR will close fds */
+ xwl_pixmap->image = eglCreateImageKHR(xwl_screen->egl_display,
+ EGL_NO_CONTEXT,
+ EGL_LINUX_DMA_BUF_EXT,
+ NULL, image_attribs);
+ if (xwl_pixmap->image == EGL_NO_IMAGE_KHR) {
+ ErrorF("eglCreateImageKHR failed!\n");
+ if (xwl_pixmap->buffer)
+ wl_buffer_destroy(xwl_pixmap->buffer);
+ free(xwl_pixmap);
+ return NULL;
+ }
+
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, xwl_pixmap->image);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ pixmap = glamor_create_pixmap(screen, width, height, depth,
+ GLAMOR_CREATE_PIXMAP_NO_TEXTURE);
+ glamor_set_pixmap_texture(pixmap, texture);
+ glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
+ wl_buffer_add_listener(xwl_pixmap->buffer,
+ &xwl_eglstream_buffer_release_listener,
+ pixmap);
+ xwl_pixmap_set_private(pixmap, xwl_pixmap);
+
+ return pixmap;
+}
+
+static const dri3_screen_info_rec xwl_dri3_info = {
+ .version = 2,
+ .open = NULL,
+ .pixmap_from_fds = xwl_dri3_pixmap_from_fds,
+ .fds_from_pixmap = NULL,
+ .open_client = xwl_dri3_open_client,
+ .get_formats = xwl_glamor_get_formats,
+ .get_modifiers = xwl_glamor_get_modifiers,
+ .get_drawable_modifiers = glamor_get_drawable_modifiers,
+};
+
static Bool
xwl_glamor_eglstream_init_egl(struct xwl_screen *xwl_screen)
{
@@ -858,6 +1045,11 @@ xwl_glamor_eglstream_init_egl(struct xwl_screen *xwl_screen)
xwl_eglstream_init_shaders(xwl_screen);
+ if (epoxy_has_gl_extension("GL_OES_EGL_image") &&
+ !dri3_screen_init(xwl_screen->screen, &xwl_dri3_info)) {
+ ErrorF("DRI3 initialization failed. Performance will be affected.\n");
+ }
+
return TRUE;
error:
xwl_eglstream_cleanup(xwl_screen);