38e875904b
Provides an implementation for the pixmap_from_buffers DRI3 function for xwayland's eglstream backend. This will be used by the NVIDIA GLX driver to pass buffers from client applications to the server. These can then be presented using the PRESENT extension. To hopefully make this less error-prone, we also introduce a "type" field for this struct to distinguish between xwl_pixmaps for the new DRI3-created pixmaps and those for the existing glamor-created pixmaps. Additionally, the patch enables wnmd present mode with the eglstream backend. This involves creating a wl_buffer for the provided dma-buf before importing it into EGL and passing this to the compositor so it can be scanned out directly if possible. Since both backends now support this present mode, the HAS_PRESENT_FLIP flag is no longer needed, so it can be removed. Reviewed-by: Michel Dänzer <mdaenzer@redhat.com> Acked-by: Olivier Fourdan <ofourdan@redhat.com> Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
487 lines
14 KiB
C
487 lines
14 KiB
C
/*
|
|
* Copyright © 2011-2014 Intel Corporation
|
|
*
|
|
* 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 <xwayland-config.h>
|
|
|
|
#define MESA_EGL_NO_X11_HEADERS
|
|
#define EGL_NO_X11
|
|
#include <glamor_egl.h>
|
|
|
|
#include <glamor.h>
|
|
#include <glamor_context.h>
|
|
#ifdef GLXEXT
|
|
#include "glx_extinit.h"
|
|
#endif
|
|
|
|
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
|
#include "drm-client-protocol.h"
|
|
#include <drm_fourcc.h>
|
|
|
|
#include "xwayland-glamor.h"
|
|
#include "xwayland-glx.h"
|
|
#include "xwayland-screen.h"
|
|
#include "xwayland-window.h"
|
|
|
|
static void
|
|
glamor_egl_make_current(struct glamor_context *glamor_ctx)
|
|
{
|
|
eglMakeCurrent(glamor_ctx->display, EGL_NO_SURFACE,
|
|
EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
if (!eglMakeCurrent(glamor_ctx->display,
|
|
EGL_NO_SURFACE, EGL_NO_SURFACE,
|
|
glamor_ctx->ctx))
|
|
FatalError("Failed to make EGL context current\n");
|
|
}
|
|
|
|
void
|
|
xwl_glamor_egl_make_current(struct xwl_screen *xwl_screen)
|
|
{
|
|
if (lastGLContext == xwl_screen->glamor_ctx)
|
|
return;
|
|
|
|
lastGLContext = xwl_screen->glamor_ctx;
|
|
xwl_screen->glamor_ctx->make_current(xwl_screen->glamor_ctx);
|
|
}
|
|
|
|
void
|
|
glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx)
|
|
{
|
|
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
|
|
|
|
glamor_enable_dri3(screen);
|
|
glamor_ctx->ctx = xwl_screen->egl_context;
|
|
glamor_ctx->display = xwl_screen->egl_display;
|
|
|
|
glamor_ctx->make_current = glamor_egl_make_current;
|
|
|
|
xwl_screen->glamor_ctx = glamor_ctx;
|
|
}
|
|
|
|
Bool
|
|
xwl_glamor_check_flip(PixmapPtr pixmap)
|
|
{
|
|
struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen);
|
|
|
|
if (xwl_screen->egl_backend->check_flip)
|
|
return xwl_screen->egl_backend->check_flip(pixmap);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
Bool
|
|
xwl_glamor_is_modifier_supported(struct xwl_screen *xwl_screen,
|
|
uint32_t format, uint64_t modifier)
|
|
{
|
|
struct xwl_format *xwl_format = NULL;
|
|
int i;
|
|
|
|
for (i = 0; i < xwl_screen->num_formats; i++) {
|
|
if (xwl_screen->formats[i].format == format) {
|
|
xwl_format = &xwl_screen->formats[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (xwl_format) {
|
|
for (i = 0; i < xwl_format->num_modifiers; i++) {
|
|
if (xwl_format->modifiers[i] == modifier) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
uint32_t
|
|
wl_drm_format_for_depth(int depth)
|
|
{
|
|
switch (depth) {
|
|
case 15:
|
|
return WL_DRM_FORMAT_XRGB1555;
|
|
case 16:
|
|
return WL_DRM_FORMAT_RGB565;
|
|
case 24:
|
|
return WL_DRM_FORMAT_XRGB8888;
|
|
case 30:
|
|
return WL_DRM_FORMAT_ARGB2101010;
|
|
default:
|
|
ErrorF("unexpected depth: %d\n", depth);
|
|
case 32:
|
|
return WL_DRM_FORMAT_ARGB8888;
|
|
}
|
|
}
|
|
|
|
Bool
|
|
xwl_glamor_get_formats(ScreenPtr screen,
|
|
CARD32 *num_formats, CARD32 **formats)
|
|
{
|
|
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
|
|
int i;
|
|
|
|
/* Explicitly zero the count as the caller may ignore the return value */
|
|
*num_formats = 0;
|
|
|
|
if (!xwl_screen->dmabuf)
|
|
return FALSE;
|
|
|
|
if (xwl_screen->num_formats == 0)
|
|
return TRUE;
|
|
|
|
*formats = calloc(xwl_screen->num_formats, sizeof(CARD32));
|
|
if (*formats == NULL)
|
|
return FALSE;
|
|
|
|
for (i = 0; i < xwl_screen->num_formats; i++)
|
|
(*formats)[i] = xwl_screen->formats[i].format;
|
|
*num_formats = xwl_screen->num_formats;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
Bool
|
|
xwl_glamor_get_modifiers(ScreenPtr screen, uint32_t format,
|
|
uint32_t *num_modifiers, uint64_t **modifiers)
|
|
{
|
|
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
|
|
struct xwl_format *xwl_format = NULL;
|
|
int i;
|
|
|
|
/* Explicitly zero the count as the caller may ignore the return value */
|
|
*num_modifiers = 0;
|
|
|
|
if (!xwl_screen->dmabuf)
|
|
return FALSE;
|
|
|
|
if (xwl_screen->num_formats == 0)
|
|
return TRUE;
|
|
|
|
for (i = 0; i < xwl_screen->num_formats; i++) {
|
|
if (xwl_screen->formats[i].format == format) {
|
|
xwl_format = &xwl_screen->formats[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!xwl_format ||
|
|
(xwl_format->num_modifiers == 1 &&
|
|
xwl_format->modifiers[0] == DRM_FORMAT_MOD_INVALID))
|
|
return FALSE;
|
|
|
|
*modifiers = calloc(xwl_format->num_modifiers, sizeof(uint64_t));
|
|
if (*modifiers == NULL)
|
|
return FALSE;
|
|
|
|
for (i = 0; i < xwl_format->num_modifiers; i++)
|
|
(*modifiers)[i] = xwl_format->modifiers[i];
|
|
*num_modifiers = xwl_format->num_modifiers;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
xwl_dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
|
|
uint32_t format)
|
|
{
|
|
}
|
|
|
|
static void
|
|
xwl_dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
|
|
uint32_t format, uint32_t modifier_hi,
|
|
uint32_t modifier_lo)
|
|
{
|
|
struct xwl_screen *xwl_screen = data;
|
|
struct xwl_format *xwl_format = NULL;
|
|
int i;
|
|
|
|
for (i = 0; i < xwl_screen->num_formats; i++) {
|
|
if (xwl_screen->formats[i].format == format) {
|
|
xwl_format = &xwl_screen->formats[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (xwl_format == NULL) {
|
|
xwl_screen->num_formats++;
|
|
xwl_screen->formats = realloc(xwl_screen->formats,
|
|
xwl_screen->num_formats * sizeof(*xwl_format));
|
|
if (!xwl_screen->formats)
|
|
return;
|
|
xwl_format = &xwl_screen->formats[xwl_screen->num_formats - 1];
|
|
xwl_format->format = format;
|
|
xwl_format->num_modifiers = 0;
|
|
xwl_format->modifiers = NULL;
|
|
}
|
|
|
|
xwl_format->num_modifiers++;
|
|
xwl_format->modifiers = realloc(xwl_format->modifiers,
|
|
xwl_format->num_modifiers * sizeof(uint64_t));
|
|
if (!xwl_format->modifiers)
|
|
return;
|
|
xwl_format->modifiers[xwl_format->num_modifiers - 1] = (uint64_t) modifier_lo;
|
|
xwl_format->modifiers[xwl_format->num_modifiers - 1] |= (uint64_t) modifier_hi << 32;
|
|
}
|
|
|
|
static const struct zwp_linux_dmabuf_v1_listener xwl_dmabuf_listener = {
|
|
.format = xwl_dmabuf_handle_format,
|
|
.modifier = xwl_dmabuf_handle_modifier
|
|
};
|
|
|
|
Bool
|
|
xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen,
|
|
uint32_t id, uint32_t version)
|
|
{
|
|
if (version < 3)
|
|
return FALSE;
|
|
|
|
xwl_screen->dmabuf =
|
|
wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 3);
|
|
zwp_linux_dmabuf_v1_add_listener(xwl_screen->dmabuf, &xwl_dmabuf_listener, xwl_screen);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
xwl_glamor_init_wl_registry(struct xwl_screen *xwl_screen,
|
|
struct wl_registry *registry,
|
|
uint32_t id, const char *interface,
|
|
uint32_t version)
|
|
{
|
|
if (xwl_screen->gbm_backend.is_available &&
|
|
xwl_screen->gbm_backend.init_wl_registry(xwl_screen,
|
|
registry,
|
|
id,
|
|
interface,
|
|
version)) {
|
|
/* no-op */
|
|
} else if (xwl_screen->eglstream_backend.is_available &&
|
|
xwl_screen->eglstream_backend.init_wl_registry(xwl_screen,
|
|
registry,
|
|
id,
|
|
interface,
|
|
version)) {
|
|
/* no-op */
|
|
}
|
|
}
|
|
|
|
Bool
|
|
xwl_glamor_has_wl_interfaces(struct xwl_screen *xwl_screen,
|
|
struct xwl_egl_backend *xwl_egl_backend)
|
|
{
|
|
return xwl_egl_backend->has_wl_interfaces(xwl_screen);
|
|
}
|
|
|
|
struct wl_buffer *
|
|
xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap)
|
|
{
|
|
struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen);
|
|
|
|
if (xwl_screen->egl_backend->get_wl_buffer_for_pixmap)
|
|
return xwl_screen->egl_backend->get_wl_buffer_for_pixmap(pixmap);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
xwl_glamor_post_damage(struct xwl_window *xwl_window,
|
|
PixmapPtr pixmap, RegionPtr region)
|
|
{
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
if (xwl_screen->egl_backend->post_damage)
|
|
xwl_screen->egl_backend->post_damage(xwl_window, pixmap, region);
|
|
}
|
|
|
|
Bool
|
|
xwl_glamor_allow_commits(struct xwl_window *xwl_window)
|
|
{
|
|
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
|
|
|
if (xwl_screen->egl_backend->allow_commits)
|
|
return xwl_screen->egl_backend->allow_commits(xwl_window);
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
xwl_glamor_create_screen_resources(ScreenPtr screen)
|
|
{
|
|
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
|
|
int ret;
|
|
|
|
screen->CreateScreenResources = xwl_screen->CreateScreenResources;
|
|
ret = (*screen->CreateScreenResources) (screen);
|
|
xwl_screen->CreateScreenResources = screen->CreateScreenResources;
|
|
screen->CreateScreenResources = xwl_glamor_create_screen_resources;
|
|
|
|
if (!ret)
|
|
return ret;
|
|
|
|
if (xwl_screen->rootless) {
|
|
screen->devPrivate =
|
|
fbCreatePixmap(screen, 0, 0, screen->rootDepth, 0);
|
|
}
|
|
else {
|
|
screen->devPrivate = screen->CreatePixmap(
|
|
screen, screen->width, screen->height, screen->rootDepth,
|
|
CREATE_PIXMAP_USAGE_BACKING_PIXMAP);
|
|
}
|
|
|
|
SetRootClip(screen, xwl_screen->root_clip_mode);
|
|
|
|
return screen->devPrivate != NULL;
|
|
}
|
|
|
|
int
|
|
glamor_egl_fd_name_from_pixmap(ScreenPtr screen,
|
|
PixmapPtr pixmap,
|
|
CARD16 *stride, CARD32 *size)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
Bool
|
|
xwl_glamor_needs_buffer_flush(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_NEEDS_BUFFER_FLUSH);
|
|
}
|
|
|
|
Bool
|
|
xwl_glamor_needs_n_buffering(struct xwl_screen *xwl_screen)
|
|
{
|
|
/* wl_shm benefits from n-buffering */
|
|
if (!xwl_screen->glamor || !xwl_screen->egl_backend)
|
|
return TRUE;
|
|
|
|
return (xwl_screen->egl_backend->backend_flags &
|
|
XWL_EGL_BACKEND_NEEDS_N_BUFFERING);
|
|
}
|
|
|
|
void
|
|
xwl_glamor_init_backends(struct xwl_screen *xwl_screen, Bool use_eglstream)
|
|
{
|
|
#ifdef GLAMOR_HAS_GBM
|
|
xwl_glamor_init_gbm(xwl_screen);
|
|
if (!xwl_screen->gbm_backend.is_available && !use_eglstream)
|
|
ErrorF("xwayland glamor: GBM backend (default) is not available\n");
|
|
#endif
|
|
#ifdef XWL_HAS_EGLSTREAM
|
|
xwl_glamor_init_eglstream(xwl_screen);
|
|
if (!xwl_screen->eglstream_backend.is_available && use_eglstream)
|
|
ErrorF("xwayland glamor: EGLStream backend requested but not available\n");
|
|
#endif
|
|
}
|
|
|
|
static Bool
|
|
xwl_glamor_select_gbm_backend(struct xwl_screen *xwl_screen)
|
|
{
|
|
#ifdef GLAMOR_HAS_GBM
|
|
if (xwl_screen->gbm_backend.is_available &&
|
|
xwl_glamor_has_wl_interfaces(xwl_screen, &xwl_screen->gbm_backend)) {
|
|
xwl_screen->egl_backend = &xwl_screen->gbm_backend;
|
|
return TRUE;
|
|
}
|
|
else
|
|
ErrorF("Missing Wayland requirements for glamor GBM backend\n");
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static Bool
|
|
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)) {
|
|
xwl_screen->egl_backend = &xwl_screen->eglstream_backend;
|
|
return TRUE;
|
|
}
|
|
else
|
|
ErrorF("Missing Wayland requirements for glamor EGLStream backend\n");
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
xwl_glamor_select_backend(struct xwl_screen *xwl_screen, Bool use_eglstream)
|
|
{
|
|
if (use_eglstream) {
|
|
if (!xwl_glamor_select_eglstream_backend(xwl_screen))
|
|
xwl_glamor_select_gbm_backend(xwl_screen);
|
|
}
|
|
else {
|
|
if (!xwl_glamor_select_gbm_backend(xwl_screen))
|
|
xwl_glamor_select_eglstream_backend(xwl_screen);
|
|
}
|
|
}
|
|
|
|
Bool
|
|
xwl_glamor_init(struct xwl_screen *xwl_screen)
|
|
{
|
|
ScreenPtr screen = xwl_screen->screen;
|
|
const char *no_glamor_env;
|
|
|
|
no_glamor_env = getenv("XWAYLAND_NO_GLAMOR");
|
|
if (no_glamor_env && *no_glamor_env != '0') {
|
|
ErrorF("Disabling glamor and dri3 support, XWAYLAND_NO_GLAMOR is set\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!xwl_screen->egl_backend->init_egl(xwl_screen)) {
|
|
ErrorF("EGL setup failed, disabling glamor\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!glamor_init(xwl_screen->screen, GLAMOR_USE_EGL_SCREEN)) {
|
|
ErrorF("Failed to initialize glamor\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!xwl_screen->egl_backend->init_screen(xwl_screen)) {
|
|
ErrorF("EGL backend init_screen() failed, disabling glamor\n");
|
|
return FALSE;
|
|
}
|
|
|
|
xwl_screen->CreateScreenResources = screen->CreateScreenResources;
|
|
screen->CreateScreenResources = xwl_glamor_create_screen_resources;
|
|
|
|
#ifdef XV
|
|
if (!xwl_glamor_xv_init(screen))
|
|
ErrorF("Failed to initialize glamor Xv extension\n");
|
|
#endif
|
|
|
|
#ifdef GLXEXT
|
|
GlxPushProvider(&glamor_provider);
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|