diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c index bf74ae329..c226c0089 100644 --- a/hw/xwayland/xwayland-glamor-eglstream.c +++ b/hw/xwayland/xwayland-glamor-eglstream.c @@ -638,7 +638,7 @@ const struct wl_eglstream_display_listener eglstream_display_listener = { .swapinterval_override = xwl_eglstream_display_handle_swapinterval_override, }; -static void +static Bool xwl_glamor_eglstream_init_wl_registry(struct xwl_screen *xwl_screen, struct wl_registry *wl_registry, uint32_t id, const char *name, @@ -654,10 +654,15 @@ xwl_glamor_eglstream_init_wl_registry(struct xwl_screen *xwl_screen, wl_eglstream_display_add_listener(xwl_eglstream->display, &eglstream_display_listener, xwl_screen); + return TRUE; } else if (strcmp(name, "wl_eglstream_controller") == 0) { xwl_eglstream->controller = wl_registry_bind( wl_registry, id, &wl_eglstream_controller_interface, version); + return TRUE; } + + /* no match */ + return FALSE; } static Bool @@ -882,23 +887,24 @@ out: return device; } -Bool +void xwl_glamor_init_eglstream(struct xwl_screen *xwl_screen) { struct xwl_eglstream_private *xwl_eglstream; EGLDeviceEXT egl_device; + xwl_screen->eglstream_backend.is_available = FALSE; egl_device = xwl_eglstream_get_device(xwl_screen); if (egl_device == EGL_NO_DEVICE_EXT) - return FALSE; + return; if (!dixRegisterPrivateKey(&xwl_eglstream_private_key, PRIVATE_SCREEN, 0)) - return FALSE; + return; xwl_eglstream = calloc(sizeof(*xwl_eglstream), 1); if (!xwl_eglstream) { - ErrorF("Failed to allocate memory required to init eglstream support\n"); - return FALSE; + ErrorF("Failed to allocate memory required to init EGLStream support\n"); + return; } dixSetPrivate(&xwl_screen->screen->devPrivates, @@ -907,15 +913,12 @@ xwl_glamor_init_eglstream(struct xwl_screen *xwl_screen) xwl_eglstream->egl_device = egl_device; xorg_list_init(&xwl_eglstream->pending_streams); - xwl_screen->egl_backend.init_egl = xwl_glamor_eglstream_init_egl; - xwl_screen->egl_backend.init_wl_registry = xwl_glamor_eglstream_init_wl_registry; - xwl_screen->egl_backend.has_wl_interfaces = xwl_glamor_eglstream_has_wl_interfaces; - xwl_screen->egl_backend.init_screen = xwl_glamor_eglstream_init_screen; - xwl_screen->egl_backend.get_wl_buffer_for_pixmap = xwl_glamor_eglstream_get_wl_buffer_for_pixmap; - xwl_screen->egl_backend.post_damage = xwl_glamor_eglstream_post_damage; - xwl_screen->egl_backend.allow_commits = xwl_glamor_eglstream_allow_commits; - - ErrorF("glamor: Using nvidia's eglstream interface, direct rendering impossible.\n"); - ErrorF("glamor: Performance may be affected. Ask your vendor to support GBM!\n"); - return TRUE; + xwl_screen->eglstream_backend.init_egl = xwl_glamor_eglstream_init_egl; + xwl_screen->eglstream_backend.init_wl_registry = xwl_glamor_eglstream_init_wl_registry; + xwl_screen->eglstream_backend.has_wl_interfaces = xwl_glamor_eglstream_has_wl_interfaces; + xwl_screen->eglstream_backend.init_screen = xwl_glamor_eglstream_init_screen; + xwl_screen->eglstream_backend.get_wl_buffer_for_pixmap = xwl_glamor_eglstream_get_wl_buffer_for_pixmap; + xwl_screen->eglstream_backend.post_damage = xwl_glamor_eglstream_post_damage; + xwl_screen->eglstream_backend.allow_commits = xwl_glamor_eglstream_allow_commits; + xwl_screen->eglstream_backend.is_available = TRUE; } diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c index 8a56801e6..bb29cc28e 100644 --- a/hw/xwayland/xwayland-glamor-gbm.c +++ b/hw/xwayland/xwayland-glamor-gbm.c @@ -734,16 +734,29 @@ xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen, return TRUE; } -static void +static Bool xwl_glamor_gbm_init_wl_registry(struct xwl_screen *xwl_screen, struct wl_registry *wl_registry, uint32_t id, const char *name, uint32_t version) { - if (strcmp(name, "wl_drm") == 0) + if (strcmp(name, "wl_drm") == 0) { xwl_screen_set_drm_interface(xwl_screen, id, version); - else if (strcmp(name, "zwp_linux_dmabuf_v1") == 0) + return TRUE; + } else if (strcmp(name, "zwp_linux_dmabuf_v1") == 0) { xwl_screen_set_dmabuf_interface(xwl_screen, id, version); + return TRUE; + } + + /* no match */ + return FALSE; +} + +static Bool +xwl_glamor_gbm_has_egl_extension(void) +{ + return (epoxy_has_egl_extension(NULL, "EGL_MESA_platform_gbm") || + epoxy_has_egl_extension(NULL, "EGL_KHR_platform_gbm")); } static Bool @@ -882,28 +895,32 @@ error: return FALSE; } -Bool +void xwl_glamor_init_gbm(struct xwl_screen *xwl_screen) { struct xwl_gbm_private *xwl_gbm; + xwl_screen->gbm_backend.is_available = FALSE; + + if (!xwl_glamor_gbm_has_egl_extension()) + return; + if (!dixRegisterPrivateKey(&xwl_gbm_private_key, PRIVATE_SCREEN, 0)) - return FALSE; + return; xwl_gbm = calloc(sizeof(*xwl_gbm), 1); if (!xwl_gbm) { ErrorF("glamor: Not enough memory to setup GBM, disabling\n"); - return FALSE; + return; } dixSetPrivate(&xwl_screen->screen->devPrivates, &xwl_gbm_private_key, xwl_gbm); - xwl_screen->egl_backend.init_wl_registry = xwl_glamor_gbm_init_wl_registry; - xwl_screen->egl_backend.has_wl_interfaces = xwl_glamor_gbm_has_wl_interfaces; - xwl_screen->egl_backend.init_egl = xwl_glamor_gbm_init_egl; - xwl_screen->egl_backend.init_screen = xwl_glamor_gbm_init_screen; - xwl_screen->egl_backend.get_wl_buffer_for_pixmap = xwl_glamor_gbm_get_wl_buffer_for_pixmap; - - return TRUE; + xwl_screen->gbm_backend.init_wl_registry = xwl_glamor_gbm_init_wl_registry; + xwl_screen->gbm_backend.has_wl_interfaces = xwl_glamor_gbm_has_wl_interfaces; + xwl_screen->gbm_backend.init_egl = xwl_glamor_gbm_init_egl; + xwl_screen->gbm_backend.init_screen = xwl_glamor_gbm_init_screen; + xwl_screen->gbm_backend.get_wl_buffer_for_pixmap = xwl_glamor_gbm_get_wl_buffer_for_pixmap; + xwl_screen->gbm_backend.is_available = TRUE; } diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c index 3792dfa8c..2f64d0500 100644 --- a/hw/xwayland/xwayland-glamor.c +++ b/hw/xwayland/xwayland-glamor.c @@ -71,9 +71,20 @@ xwl_glamor_init_wl_registry(struct xwl_screen *xwl_screen, uint32_t id, const char *interface, uint32_t version) { - if (xwl_screen->egl_backend.init_wl_registry) - xwl_screen->egl_backend.init_wl_registry(xwl_screen, registry, - id, interface, version); + if (xwl_screen->gbm_backend.is_available && + xwl_screen->gbm_backend.init_wl_registry && + 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->eglstream_backend.init_wl_registry(xwl_screen, + registry, + id, + interface, + version)); /* no-op */ } Bool @@ -95,8 +106,8 @@ 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, + if (xwl_screen->egl_backend->get_wl_buffer_for_pixmap) + return xwl_screen->egl_backend->get_wl_buffer_for_pixmap(pixmap, width, height, created); @@ -110,8 +121,8 @@ xwl_glamor_post_damage(struct xwl_window *xwl_window, { 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); + if (xwl_screen->egl_backend->post_damage) + xwl_screen->egl_backend->post_damage(xwl_window, pixmap, region); } Bool @@ -119,8 +130,8 @@ 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); + if (xwl_screen->egl_backend->allow_commits) + return xwl_screen->egl_backend->allow_commits(xwl_window); else return TRUE; } @@ -165,17 +176,62 @@ glamor_egl_fd_name_from_pixmap(ScreenPtr screen, void xwl_glamor_init_backends(struct xwl_screen *xwl_screen, Bool use_eglstream) { -#ifdef XWL_HAS_EGLSTREAM - if (use_eglstream) { - if (!xwl_glamor_init_eglstream(xwl_screen)) { - ErrorF("xwayland glamor: failed to setup EGLStream backend\n"); - use_eglstream = FALSE; - } - } +#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 - if (!use_eglstream && !xwl_glamor_init_gbm(xwl_screen)) { - ErrorF("xwayland glamor: failed to setup GBM backend, falling back to sw accel\n"); - xwl_screen->glamor = 0; +#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)) { + 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; + } + 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); } } @@ -191,7 +247,7 @@ xwl_glamor_init(struct xwl_screen *xwl_screen) return FALSE; } - if (!xwl_screen->egl_backend.init_egl(xwl_screen)) { + if (!xwl_screen->egl_backend->init_egl(xwl_screen)) { ErrorF("EGL setup failed, disabling glamor\n"); return FALSE; } @@ -201,7 +257,7 @@ xwl_glamor_init(struct xwl_screen *xwl_screen) return FALSE; } - if (!xwl_screen->egl_backend.init_screen(xwl_screen)) { + if (!xwl_screen->egl_backend->init_screen(xwl_screen)) { ErrorF("EGL backend init_screen() failed, disabling glamor\n"); return FALSE; } diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c index c043da1d5..410f0f16e 100644 --- a/hw/xwayland/xwayland-present.c +++ b/hw/xwayland/xwayland-present.c @@ -549,7 +549,7 @@ xwl_present_init(ScreenPtr screen) * doesn't work with the streams backend. we don't have an explicit * boolean for that, but we do know gbm doesn't fill in this hook... */ - if (xwl_screen->egl_backend.post_damage != NULL) + if (xwl_screen->egl_backend->post_damage != NULL) return FALSE; if (!dixRegisterPrivateKey(&xwl_present_window_private_key, PRIVATE_WINDOW, 0)) diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c index 8c02c02f8..7ea01ab86 100644 --- a/hw/xwayland/xwayland.c +++ b/hw/xwayland/xwayland.c @@ -737,7 +737,7 @@ xwl_screen_post_damage(struct xwl_screen *xwl_screen) continue; #ifdef XWL_HAS_GLAMOR - if (!xwl_glamor_allow_commits(xwl_window)) + if (xwl_screen->glamor && !xwl_glamor_allow_commits(xwl_window)) continue; #endif @@ -1079,9 +1079,13 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) return FALSE; #ifdef XWL_HAS_GLAMOR - if (xwl_screen->glamor && !xwl_glamor_init(xwl_screen)) { - ErrorF("Failed to initialize glamor, falling back to sw\n"); - xwl_screen->glamor = 0; + if (xwl_screen->glamor) { + xwl_glamor_select_backend(xwl_screen, use_eglstreams); + + if (xwl_screen->egl_backend == NULL || !xwl_glamor_init(xwl_screen)) { + ErrorF("Failed to initialize glamor, falling back to sw\n"); + xwl_screen->glamor = 0; + } } if (xwl_screen->glamor && xwl_screen->rootless) diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index 304484ccc..0fa5cb588 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -60,11 +60,14 @@ struct xwl_window; struct xwl_screen; struct xwl_egl_backend { + /* Set by the backend if available */ + Bool is_available; + /* Called once for each interface in the global registry. Backends * should use this to bind to any wayland interfaces they need. This * callback is optional. */ - void (*init_wl_registry)(struct xwl_screen *xwl_screen, + Bool (*init_wl_registry)(struct xwl_screen *xwl_screen, struct wl_registry *wl_registry, uint32_t id, const char *name, uint32_t version); @@ -164,8 +167,10 @@ struct xwl_screen { struct xwl_format *formats; void *egl_display, *egl_context; - /* the current backend for creating pixmaps on wayland */ - struct xwl_egl_backend egl_backend; + struct xwl_egl_backend gbm_backend; + struct xwl_egl_backend eglstream_backend; + /* pointer to the current backend for creating pixmaps on wayland */ + struct xwl_egl_backend *egl_backend; struct glamor_context *glamor_ctx; @@ -425,6 +430,8 @@ struct wl_buffer *xwl_shm_pixmap_get_wl_buffer(PixmapPtr pixmap); #ifdef XWL_HAS_GLAMOR void xwl_glamor_init_backends(struct xwl_screen *xwl_screen, Bool use_eglstream); +void xwl_glamor_select_backend(struct xwl_screen *xwl_screen, + Bool use_eglstream); Bool xwl_glamor_init(struct xwl_screen *xwl_screen); Bool xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen, @@ -467,20 +474,18 @@ void xwlVidModeExtensionInit(void); #endif #ifdef GLAMOR_HAS_GBM -Bool xwl_glamor_init_gbm(struct xwl_screen *xwl_screen); +void xwl_glamor_init_gbm(struct xwl_screen *xwl_screen); #else -static inline Bool xwl_glamor_init_gbm(struct xwl_screen *xwl_screen) +static inline void xwl_glamor_init_gbm(struct xwl_screen *xwl_screen) { - return FALSE; } #endif #ifdef XWL_HAS_EGLSTREAM -Bool xwl_glamor_init_eglstream(struct xwl_screen *xwl_screen); +void xwl_glamor_init_eglstream(struct xwl_screen *xwl_screen); #else -static inline Bool xwl_glamor_init_eglstream(struct xwl_screen *xwl_screen) +static inline void xwl_glamor_init_eglstream(struct xwl_screen *xwl_screen) { - return FALSE; } #endif