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 #include +#include +#include #include @@ -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; }; -struct xwl_pixmap { - struct wl_buffer *buffer; - struct xwl_screen *xwl_screen; +enum xwl_pixmap_type { + XWL_PIXMAP_EGLSTREAM, /* Pixmaps created by glamor. */ + XWL_PIXMAP_DMA_BUF, /* Pixmaps allocated through DRI3. */ +}; +struct xwl_pixmap { + 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); diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c index 1b1d517da..12d820e44 100644 --- a/hw/xwayland/xwayland-glamor-gbm.c +++ b/hw/xwayland/xwayland-glamor-gbm.c @@ -969,7 +969,6 @@ xwl_glamor_init_gbm(struct xwl_screen *xwl_screen) xwl_screen->gbm_backend.get_wl_buffer_for_pixmap = xwl_glamor_gbm_get_wl_buffer_for_pixmap; xwl_screen->gbm_backend.check_flip = NULL; xwl_screen->gbm_backend.is_available = TRUE; - xwl_screen->gbm_backend.backend_flags = XWL_EGL_BACKEND_HAS_PRESENT_FLIP | - XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH | + xwl_screen->gbm_backend.backend_flags = XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH | XWL_EGL_BACKEND_NEEDS_N_BUFFERING; } diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c index 060471f01..9e44d5106 100644 --- a/hw/xwayland/xwayland-glamor.c +++ b/hw/xwayland/xwayland-glamor.c @@ -362,16 +362,6 @@ glamor_egl_fd_name_from_pixmap(ScreenPtr screen, return 0; } -Bool -xwl_glamor_has_present_flip(struct xwl_screen *xwl_screen) -{ - if (!xwl_screen->glamor || !xwl_screen->egl_backend) - return FALSE; - - return (xwl_screen->egl_backend->backend_flags & - XWL_EGL_BACKEND_HAS_PRESENT_FLIP); -} - Bool xwl_glamor_needs_buffer_flush(struct xwl_screen *xwl_screen) { @@ -430,8 +420,6 @@ xwl_glamor_select_eglstream_backend(struct xwl_screen *xwl_screen) #ifdef XWL_HAS_EGLSTREAM if (xwl_screen->eglstream_backend.is_available && xwl_glamor_has_wl_interfaces(xwl_screen, &xwl_screen->eglstream_backend)) { - ErrorF("glamor: Using nvidia's EGLStream interface, direct rendering impossible.\n"); - ErrorF("glamor: Performance may be affected. Ask your vendor to support GBM!\n"); xwl_screen->egl_backend = &xwl_screen->eglstream_backend; return TRUE; } diff --git a/hw/xwayland/xwayland-glamor.h b/hw/xwayland/xwayland-glamor.h index a86b30b40..26ab78f04 100644 --- a/hw/xwayland/xwayland-glamor.h +++ b/hw/xwayland/xwayland-glamor.h @@ -34,9 +34,8 @@ typedef enum _xwl_egl_backend_flags { XWL_EGL_BACKEND_NO_FLAG = 0, - XWL_EGL_BACKEND_HAS_PRESENT_FLIP = (1 << 0), - XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH = (1 << 1), - XWL_EGL_BACKEND_NEEDS_N_BUFFERING = (1 << 2), + XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH = (1 << 0), + XWL_EGL_BACKEND_NEEDS_N_BUFFERING = (1 << 1), } xwl_egl_backend_flags; struct xwl_egl_backend { @@ -122,7 +121,6 @@ void xwl_glamor_post_damage(struct xwl_window *xwl_window, PixmapPtr pixmap, RegionPtr region); Bool xwl_glamor_allow_commits(struct xwl_window *xwl_window); void xwl_glamor_egl_make_current(struct xwl_screen *xwl_screen); -Bool xwl_glamor_has_present_flip(struct xwl_screen *xwl_screen); Bool xwl_glamor_needs_buffer_flush(struct xwl_screen *xwl_screen); Bool xwl_glamor_needs_n_buffering(struct xwl_screen *xwl_screen); Bool xwl_glamor_is_modifier_supported(struct xwl_screen *xwl_screen, diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c index 666ea15e7..7ba7efc11 100644 --- a/hw/xwayland/xwayland-present.c +++ b/hw/xwayland/xwayland-present.c @@ -404,6 +404,9 @@ xwl_present_check_flip2(RRCrtcPtr crtc, if (!xwl_window) return FALSE; + if (!xwl_glamor_check_flip(pixmap)) + return FALSE; + /* Can't flip if the window pixmap doesn't match the xwl_window parent * window's, e.g. because a client redirected this window or one of its * parents. @@ -540,7 +543,7 @@ xwl_present_init(ScreenPtr screen) { struct xwl_screen *xwl_screen = xwl_screen_get(screen); - if (!xwl_glamor_has_present_flip(xwl_screen)) + if (!xwl_screen->glamor || !xwl_screen->egl_backend) return FALSE; if (!dixRegisterPrivateKey(&xwl_present_window_private_key, PRIVATE_WINDOW, 0))