xserver/hw/xwayland/xwayland-glamor.c

416 lines
12 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>
#include <compositeext.h>
#include "compositeext_priv.h"
#define MESA_EGL_NO_X11_HEADERS
#define EGL_NO_X11
#include <glamor_egl.h>
#include <glamor.h>
#include <glamor_context.h>
#include <glamor_glx_provider.h>
#ifdef GLXEXT
#include "glx_extinit.h"
#endif
#include "drm-client-protocol.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "xwayland-dmabuf.h"
#include "xwayland-glamor.h"
#include "xwayland-glamor-gbm.h"
#include "xwayland-screen.h"
#include "xwayland-window.h"
#include "xwayland-window-buffers.h"
#include <sys/mman.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)
{
EGLContext ctx = xwl_screen->glamor_ctx->ctx;
if (lastGLContext == ctx)
return;
lastGLContext = 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_set_glvnd_vendor(screen, xwl_screen->glvnd_vendor);
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(WindowPtr present_window, PixmapPtr pixmap)
{
ScreenPtr screen = pixmap->drawable.pScreen;
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
PixmapPtr backing_pixmap = screen->GetWindowPixmap(present_window);
if (pixmap->drawable.depth != backing_pixmap->drawable.depth)
return FALSE;
if (xwl_screen->egl_backend->check_flip)
return xwl_screen->egl_backend->check_flip(pixmap);
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 (strcmp(interface, wl_drm_interface.name) == 0)
xwl_screen_set_drm_interface(xwl_screen, id, version);
else if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0)
xwl_screen_set_dmabuf_interface(xwl_screen, id, version);
}
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;
}
Bool
xwl_glamor_post_damage(struct xwl_window *xwl_window,
PixmapPtr pixmap)
{
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
RegionPtr region = xwl_window_get_damage_region(xwl_window);
if (xwl_screen->egl_backend->post_damage)
return xwl_screen->egl_backend->post_damage(xwl_window, pixmap, region);
return TRUE;
}
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 void
xwl_avoid_implicit_redirect(WindowPtr window)
{
ScreenPtr screen = window->drawable.pScreen;
WindowOptPtr parent_optional;
VisualPtr parent_visual = NULL;
VisualPtr window_visual = NULL;
DepthPtr depth32 = NULL;
int i;
if (!window->optional)
return;
parent_optional = FindWindowWithOptional(window)->optional;
if (window->optional == parent_optional ||
window->optional->visual == parent_optional->visual ||
CompositeIsImplicitRedirectException(screen, parent_optional->visual,
window->optional->visual))
return;
for (i = 0; i < screen->numDepths; i++) {
if (screen->allowedDepths[i].depth == 32) {
depth32 = &screen->allowedDepths[i];
break;
}
}
if (!depth32)
return;
for (i = 0; i < depth32->numVids; i++) {
XID argb_vid = depth32->vids[i];
if (argb_vid != parent_optional->visual)
continue;
if (!compIsAlternateVisual(screen, argb_vid))
break;
for (i = 0; i < screen->numVisuals; i++) {
if (screen->visuals[i].vid == argb_vid) {
parent_visual = &screen->visuals[i];
break;
}
}
}
if (!parent_visual)
return;
for (i = 0; i < screen->numVisuals; i++) {
if (screen->visuals[i].vid == window->optional->visual) {
window_visual = &screen->visuals[i];
break;
}
}
if ((window_visual->class != TrueColor &&
window_visual->class != DirectColor) ||
window_visual->redMask != parent_visual->redMask ||
window_visual->greenMask != parent_visual->greenMask ||
window_visual->blueMask != parent_visual->blueMask ||
window_visual->offsetRed != parent_visual->offsetRed ||
window_visual->offsetGreen != parent_visual->offsetGreen ||
window_visual->offsetBlue != parent_visual->offsetBlue)
return;
CompositeRegisterImplicitRedirectionException(screen, parent_visual->vid, window_visual->vid);
}
static Bool
xwl_glamor_create_window(WindowPtr window)
{
ScreenPtr screen = window->drawable.pScreen;
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
Bool ret;
if (window->parent)
xwl_avoid_implicit_redirect(window);
screen->CreateWindow = xwl_screen->CreateWindow;
ret = (*screen->CreateWindow) (window);
xwl_screen->CreateWindow = screen->CreateWindow;
screen->CreateWindow = xwl_glamor_create_window;
return ret;
}
static void
xwl_glamor_reparent_window(WindowPtr window, WindowPtr old_parent)
{
ScreenPtr screen = window->drawable.pScreen;
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
xwl_avoid_implicit_redirect(window);
screen->ReparentWindow = xwl_screen->ReparentWindow;
(*screen->ReparentWindow) (window, old_parent);
xwl_screen->ReparentWindow = screen->ReparentWindow;
screen->ReparentWindow = xwl_glamor_reparent_window;
}
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;
xwl_screen->CreateWindow = screen->CreateWindow;
screen->CreateWindow = xwl_glamor_create_window;
xwl_screen->ReparentWindow = screen->ReparentWindow;
screen->ReparentWindow = xwl_glamor_reparent_window;
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);
}
PixmapPtr
xwl_glamor_create_pixmap_for_window(struct xwl_window *xwl_window)
{
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
if (!xwl_screen->glamor || !xwl_screen->egl_backend)
return NullPixmap;
if (xwl_screen->egl_backend->create_pixmap_for_window)
return xwl_screen->egl_backend->create_pixmap_for_window(xwl_window);
else
return NullPixmap;
}
void
xwl_glamor_init_backends(struct xwl_screen *xwl_screen)
{
#ifdef GLAMOR_HAS_GBM
xwl_glamor_init_gbm(xwl_screen);
if (!xwl_screen->gbm_backend.is_available)
ErrorF("Xwayland glamor: GBM backend is 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;
LogMessageVerb(X_INFO, 3, "glamor: Using GBM backend\n");
return TRUE;
}
else
LogMessageVerb(X_INFO, 3,
"Missing Wayland requirements for glamor GBM backend\n");
#endif
return FALSE;
}
void
xwl_glamor_select_backend(struct xwl_screen *xwl_screen)
{
xwl_glamor_select_gbm_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;
}