[Mesa-dev] [PATCH RFC 7/9] egl/x11: Implement dri3 support with loader's dri3 helper
Emil Velikov
emil.l.velikov at gmail.com
Tue Jul 28 05:35:02 PDT 2015
On 21 July 2015 at 16:44, Boyan Ding <boyan.j.ding at gmail.com> wrote:
> Signed-off-by: Boyan Ding <boyan.j.ding at gmail.com>
> ---
> configure.ac | 6 +
> src/egl/drivers/dri2/Makefile.am | 5 +
> src/egl/drivers/dri2/egl_dri2.c | 66 +++-
> src/egl/drivers/dri2/egl_dri2.h | 14 +-
> src/egl/drivers/dri2/platform_x11.c | 105 ++++++-
> src/egl/drivers/dri2/platform_x11_dri3.c | 517 +++++++++++++++++++++++++++++++
> src/egl/drivers/dri2/platform_x11_dri3.h | 44 +++
> 7 files changed, 748 insertions(+), 9 deletions(-)
> create mode 100644 src/egl/drivers/dri2/platform_x11_dri3.c
> create mode 100644 src/egl/drivers/dri2/platform_x11_dri3.h
>
> diff --git a/configure.ac b/configure.ac
> index 872f15b..5727db9 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -72,6 +72,7 @@ LIBDRM_INTEL_REQUIRED=2.4.61
> LIBDRM_NVVIEUX_REQUIRED=2.4.33
> LIBDRM_NOUVEAU_REQUIRED=2.4.62
> LIBDRM_FREEDRENO_REQUIRED=2.4.57
> +LIBDRM_EGL_DRI3_REQUIRED=2.4.60
I wouldn't bother with this, but directly bump LIBDRM_REQUIRED.
> DRI2PROTO_REQUIRED=2.6
> DRI3PROTO_REQUIRED=1.0
> PRESENTPROTO_REQUIRED=1.0
> @@ -1771,6 +1772,11 @@ for plat in $egl_platforms; do
>
> x11)
> PKG_CHECK_MODULES([XCB_DRI2], [x11-xcb xcb xcb-dri2 >= $XCBDRI2_REQUIRED xcb-xfixes])
> +
> + PKG_CHECK_EXISTS([libdrm >= LIBDRM_EGL_DRI3_REQUIRED], [libdrm_render_node=yes], [libdrm_render_node=no])
> + if test "x$libdrm_render_node" = xyes; then
> + DEFINES="$DEFINES -DLIBDRM_HAS_RENDERNODE_SUPPORT"
> + fi
> ;;
>
> drm)
> diff --git a/src/egl/drivers/dri2/Makefile.am b/src/egl/drivers/dri2/Makefile.am
> index 55be4a7..d5b511c 100644
> --- a/src/egl/drivers/dri2/Makefile.am
> +++ b/src/egl/drivers/dri2/Makefile.am
> @@ -52,6 +52,11 @@ if HAVE_EGL_PLATFORM_X11
> libegl_dri2_la_SOURCES += platform_x11.c
> AM_CFLAGS += -DHAVE_X11_PLATFORM
> AM_CFLAGS += $(XCB_DRI2_CFLAGS)
> +if HAVE_DRI3
> +libegl_dri2_la_SOURCES += \
> + platform_x11_dri3.c \
> + platform_x11_dri3.h
> +endif
I did reshuffle things recently so I fear that there'll be some conflicts here.
> endif
>
> if HAVE_EGL_PLATFORM_WAYLAND
> diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
> index dcce04c..139fe29 100644
> --- a/src/egl/drivers/dri2/egl_dri2.c
> +++ b/src/egl/drivers/dri2/egl_dri2.c
> @@ -322,6 +322,12 @@ struct dri2_extension_match {
> int offset;
> };
>
> +static struct dri2_extension_match dri3_driver_extensions[] = {
> + { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
> + { __DRI_IMAGE_DRIVER, 1, offsetof(struct dri2_egl_display, image_driver) },
> + { NULL, 0, 0 }
> +};
> +
> static struct dri2_extension_match dri2_driver_extensions[] = {
> { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
> { __DRI_DRI2, 2, offsetof(struct dri2_egl_display, dri2) },
> @@ -464,6 +470,25 @@ dri2_open_driver(_EGLDisplay *disp)
> }
>
> EGLBoolean
> +dri2_load_driver_dri3(_EGLDisplay *disp)
> +{
> + struct dri2_egl_display *dri2_dpy = disp->DriverData;
> + const __DRIextension **extensions;
> +
> + extensions = dri2_open_driver(disp);
> + if (!extensions)
> + return EGL_FALSE;
> +
> + if (!dri2_bind_extensions(dri2_dpy, dri3_driver_extensions, extensions)) {
> + dlclose(dri2_dpy->driver);
> + return EGL_FALSE;
> + }
> + dri2_dpy->driver_extensions = extensions;
> +
> + return EGL_TRUE;
> +}
> +
> +EGLBoolean
> dri2_load_driver(_EGLDisplay *disp)
> {
> struct dri2_egl_display *dri2_dpy = disp->DriverData;
> @@ -507,7 +532,9 @@ dri2_setup_screen(_EGLDisplay *disp)
> struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
> unsigned int api_mask;
>
> - if (dri2_dpy->dri2) {
> + if (dri2_dpy->image_driver) {
> + api_mask = dri2_dpy->image_driver->getAPIMask(dri2_dpy->dri_screen);
> + } else if (dri2_dpy->dri2) {
> api_mask = dri2_dpy->dri2->getAPIMask(dri2_dpy->dri_screen);
> } else {
> assert(dri2_dpy->swrast);
> @@ -527,11 +554,12 @@ dri2_setup_screen(_EGLDisplay *disp)
> if (api_mask & (1 << __DRI_API_GLES3))
> disp->ClientAPIs |= EGL_OPENGL_ES3_BIT_KHR;
>
> - assert(dri2_dpy->dri2 || dri2_dpy->swrast);
> + assert(dri2_dpy->image_driver || dri2_dpy->dri2 || dri2_dpy->swrast);
> disp->Extensions.KHR_surfaceless_context = EGL_TRUE;
> disp->Extensions.MESA_configless_context = EGL_TRUE;
>
> - if ((dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) ||
> + if (dri2_dpy->image_driver ||
> + (dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) ||
> (dri2_dpy->swrast && dri2_dpy->swrast->base.version >= 3)) {
> disp->Extensions.KHR_create_context = EGL_TRUE;
>
> @@ -591,7 +619,14 @@ dri2_create_screen(_EGLDisplay *disp)
>
> dri2_dpy = disp->DriverData;
>
> - if (dri2_dpy->dri2) {
> + if (dri2_dpy->image_driver) {
> + dri2_dpy->dri_screen =
> + dri2_dpy->image_driver->createNewScreen2(0, dri2_dpy->fd,
> + dri2_dpy->extensions,
> + dri2_dpy->driver_extensions,
> + &dri2_dpy->driver_configs,
> + disp);
> + } else if (dri2_dpy->dri2) {
> if (dri2_dpy->dri2->base.version >= 4) {
> dri2_dpy->dri_screen =
> dri2_dpy->dri2->createNewScreen2(0, dri2_dpy->fd,
> @@ -627,7 +662,7 @@ dri2_create_screen(_EGLDisplay *disp)
>
> extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);
>
> - if (dri2_dpy->dri2) {
> + if (dri2_dpy->image_driver || dri2_dpy->dri2) {
> if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions))
> goto cleanup_dri_screen;
> } else {
> @@ -971,7 +1006,26 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
> else
> dri_config = NULL;
>
> - if (dri2_dpy->dri2) {
> + if (dri2_dpy->image_driver) {
> + unsigned error;
> + unsigned num_attribs = 8;
> + uint32_t ctx_attribs[8];
> +
> + if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs,
> + &num_attribs))
> + goto cleanup;
> +
> + dri2_ctx->dri_context =
> + dri2_dpy->image_driver->createContextAttribs(dri2_dpy->dri_screen,
> + api,
> + dri_config,
> + shared,
> + num_attribs / 2,
> + ctx_attribs,
> + & error,
> + dri2_ctx);
> + dri2_create_context_attribs_error(error);
> + } else if (dri2_dpy->dri2) {
> if (dri2_dpy->dri2->base.version >= 3) {
> unsigned error;
> unsigned num_attribs = 8;
> diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
> index 435c670..238e81d 100644
> --- a/src/egl/drivers/dri2/egl_dri2.h
> +++ b/src/egl/drivers/dri2/egl_dri2.h
> @@ -35,6 +35,10 @@
> #include <xcb/dri2.h>
> #include <xcb/xfixes.h>
> #include <X11/Xlib-xcb.h>
> +
> +#ifdef HAVE_DRI3
> +#include "loader_dri3_helper.h"
> +#endif
> #endif
>
> #ifdef HAVE_WAYLAND_PLATFORM
> @@ -160,6 +164,7 @@ struct dri2_egl_display
> const __DRIconfig **driver_configs;
> void *driver;
> const __DRIcoreExtension *core;
> + const __DRIimageDriverExtension *image_driver;
> const __DRIdri2Extension *dri2;
> const __DRIswrastExtension *swrast;
> const __DRI2flushExtension *flush;
> @@ -191,6 +196,9 @@ struct dri2_egl_display
> #ifdef HAVE_X11_PLATFORM
> xcb_connection_t *conn;
> int screen;
> +#ifdef HAVE_DRI3
> + struct loader_dri3_extensions loader_dri3_ext;
> +#endif
> #endif
>
> #ifdef HAVE_WAYLAND_PLATFORM
> @@ -204,8 +212,9 @@ struct dri2_egl_display
> int formats;
> uint32_t capabilities;
> int is_render_node;
> - int is_different_gpu;
> #endif
> +
> + int is_different_gpu;
> };
>
> struct dri2_egl_context
> @@ -326,6 +335,9 @@ EGLBoolean
> dri2_load_driver_swrast(_EGLDisplay *disp);
>
> EGLBoolean
> +dri2_load_driver_dri3(_EGLDisplay *disp);
> +
> +EGLBoolean
> dri2_create_screen(_EGLDisplay *disp);
>
> __DRIdrawable *
> diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c
> index 7e1e9e1..a3bc8e1 100644
> --- a/src/egl/drivers/dri2/platform_x11.c
> +++ b/src/egl/drivers/dri2/platform_x11.c
> @@ -45,6 +45,10 @@
> #include "egl_dri2_fallbacks.h"
> #include "loader.h"
>
> +#ifdef HAVE_DRI3
> +#include "platform_x11_dri3.h"
> +#endif
> +
> static EGLBoolean
> dri2_x11_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
> EGLint interval);
> @@ -1204,6 +1208,96 @@ dri2_x11_setup_swap_interval(struct dri2_egl_display *dri2_dpy)
> }
> }
>
> +#ifdef HAVE_DRI3
> +static EGLBoolean
> +dri2_initialize_x11_dri3(_EGLDriver *drv, _EGLDisplay *disp)
> +{
> + struct dri2_egl_display *dri2_dpy;
> +
> + dri2_dpy = calloc(1, sizeof *dri2_dpy);
> + if (!dri2_dpy)
> + return _eglError(EGL_BAD_ALLOC, "eglInitialize");
> +
> + disp->DriverData = (void *) dri2_dpy;
> + if (disp->PlatformDisplay == NULL) {
> + dri2_dpy->conn = xcb_connect(0, &dri2_dpy->screen);
> + dri2_dpy->own_device = true;
> + } else {
> + Display *dpy = disp->PlatformDisplay;
> +
> + dri2_dpy->conn = XGetXCBConnection(dpy);
> + dri2_dpy->screen = DefaultScreen(dpy);
> + }
> +
> + if (xcb_connection_has_error(dri2_dpy->conn)) {
> + _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");
> + goto cleanup_dpy;
> + }
> +
> + if (dri2_dpy->conn) {
> + if (!dri3_x11_connect(dri2_dpy))
> + goto cleanup_conn;
> + }
> +
> + if (!dri2_load_driver_dri3(disp))
> + goto cleanup_conn;
> +
> + dri2_dpy->extensions[0] = &dri3_image_loader_extension.base;
> + dri2_dpy->extensions[1] = &use_invalidate.base;
> + dri2_dpy->extensions[2] = &image_lookup_extension.base;
> + dri2_dpy->extensions[3] = NULL;
> +
> + dri2_dpy->swap_available = true;
> + dri2_dpy->invalidate_available = true;
> +
> + if (!dri2_create_screen(disp))
> + goto cleanup_fd;
> +
> + dri2_x11_setup_swap_interval(dri2_dpy);
> +
> + disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;
> + disp->Extensions.CHROMIUM_sync_control = EGL_TRUE;
> + disp->Extensions.EXT_buffer_age = EGL_TRUE;
> +
> +#ifdef HAVE_WAYLAND_PLATFORM
> + disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
> +#endif
> +
> + if (dri2_dpy->conn) {
> + if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp))
> + goto cleanup_configs;
> + }
> +
> + dri2_dpy->loader_dri3_ext.core = dri2_dpy->core;
> + dri2_dpy->loader_dri3_ext.image_driver = dri2_dpy->image_driver;
> + dri2_dpy->loader_dri3_ext.flush = dri2_dpy->flush;
> + dri2_dpy->loader_dri3_ext.tex_buffer = dri2_dpy->tex_buffer;
> + dri2_dpy->loader_dri3_ext.image = dri2_dpy->image;
> + dri2_dpy->loader_dri3_ext.config = dri2_dpy->config;
> +
> + /* Fill vtbl last to prevent accidentally calling virtual function during
> + * initialization.
> + */
> + dri2_dpy->vtbl = &dri3_x11_display_vtbl;
> +
> + return EGL_TRUE;
> +
> + cleanup_configs:
> + _eglCleanupDisplay(disp);
> + dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
> + dlclose(dri2_dpy->driver);
> + cleanup_fd:
> + close(dri2_dpy->fd);
> + cleanup_conn:
> + if (disp->PlatformDisplay == NULL)
> + xcb_disconnect(dri2_dpy->conn);
> + cleanup_dpy:
> + free(dri2_dpy);
> +
> + return EGL_FALSE;
> +}
> +#endif
> +
> static EGLBoolean
> dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp)
> {
> @@ -1323,9 +1417,16 @@ dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp)
> int x11_dri2_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL);
>
> if (x11_dri2_accel) {
> - if (!dri2_initialize_x11_dri2(drv, disp)) {
> - initialized = dri2_initialize_x11_swrast(drv, disp);
> +#ifdef HAVE_DRI3
> + if (getenv("LIBGL_DRI3_DISABLE") != NULL ||
> + !dri2_initialize_x11_dri3(drv, disp)) {
> +#endif
> + if (!dri2_initialize_x11_dri2(drv, disp)) {
> + initialized = dri2_initialize_x11_swrast(drv, disp);
> + }
> +#ifdef HAVE_DRI3
> }
> +#endif
> } else {
> initialized = dri2_initialize_x11_swrast(drv, disp);
> }
> diff --git a/src/egl/drivers/dri2/platform_x11_dri3.c b/src/egl/drivers/dri2/platform_x11_dri3.c
> new file mode 100644
> index 0000000..b570a57
> --- /dev/null
> +++ b/src/egl/drivers/dri2/platform_x11_dri3.c
> @@ -0,0 +1,517 @@
> +/*
> + * Copyright © 2015 Boyan Ding
> + *
> + * 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 <stdbool.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +#include <xcb/xcb.h>
> +#include <xcb/dri3.h>
> +#include <xcb/present.h>
> +
> +#ifdef HAVE_LIBDRM
While correct, we can drop the guard as we require libdrm.
> +#include <xf86drm.h>
> +#endif
> +
> +#include "egl_dri2.h"
> +#include "egl_dri2_fallbacks.h"
> +#include "platform_x11_dri3.h"
> +
> +#include "loader.h"
> +#include "loader_dri3_helper.h"
> +
> +static int
> +egl_dri3_get_swap_interval(struct loader_dri3_drawable *draw)
> +{
> + struct dri3_egl_surface *dri3_surf = draw->priv;
> +
> + return dri3_surf->base.SwapInterval;
> +}
> +
> +static int
> +egl_dri3_clamp_swap_interval(struct loader_dri3_drawable *draw, int interval)
> +{
> + struct dri3_egl_surface *dri3_surf = draw->priv;
> +
> + if (interval > dri3_surf->base.Config->MaxSwapInterval)
> + interval = dri3_surf->base.Config->MaxSwapInterval;
> + else if (interval < dri3_surf->base.Config->MinSwapInterval)
> + interval = dri3_surf->base.Config->MinSwapInterval;
> +
> + return interval;
> +}
> +
> +static void
> +egl_dri3_set_swap_interval(struct loader_dri3_drawable *draw, int interval)
> +{
> + struct dri3_egl_surface *dri3_surf = draw->priv;
> +
> + dri3_surf->base.SwapInterval = interval;
> +}
> +
> +static void
> +egl_dri3_set_drawable_size(struct loader_dri3_drawable *draw,
> + int width, int height)
> +{
> + struct dri3_egl_surface *dri3_surf = draw->priv;
> +
> + dri3_surf->base.Width = width;
> + dri3_surf->base.Height = height;
> +}
> +
> +static int
> +egl_dri3_get_width(struct loader_dri3_drawable *draw)
> +{
> + struct dri3_egl_surface *dri3_surf = draw->priv;
> +
> + return dri3_surf->base.Width;
> +}
> +
> +static int
> +egl_dri3_get_height(struct loader_dri3_drawable *draw)
> +{
> + struct dri3_egl_surface *dri3_surf = draw->priv;
> +
> + return dri3_surf->base.Height;
> +}
> +
> +static bool
> +egl_dri3_is_different_gpu(struct loader_dri3_drawable *draw)
> +{
> + struct dri3_egl_surface *dri3_surf = draw->priv;
> + struct dri2_egl_display *dri2_dpy =
> + dri2_egl_display(dri3_surf->base.Resource.Display);
> +
> + return dri2_dpy->is_different_gpu;
> +}
> +
> +static bool
> +egl_dri3_in_current_context(struct loader_dri3_drawable *draw)
> +{
> + struct dri3_egl_surface *dri3_surf = draw->priv;
> + _EGLContext *ctx = _eglGetCurrentContext();
> +
> + return ctx->Resource.Display == dri3_surf->base.Resource.Display;
> +}
> +
> +static __DRIcontext *
> +egl_dri3_get_dri_context(struct loader_dri3_drawable *draw)
> +{
> + _EGLContext *ctx = _eglGetCurrentContext();
> + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
> +
> + return dri2_ctx->dri_context;
> +}
> +
> +static __DRIscreen *
> +egl_dri3_get_dri_screen(struct loader_dri3_drawable *draw)
> +{
> + struct dri3_egl_surface *dri3_surf = draw->priv;
> + struct dri2_egl_display *dri2_dpy =
> + dri2_egl_display(dri3_surf->base.Resource.Display);
> +
> + return dri2_dpy->dri_screen;
> +}
> +
> +static void
> +egl_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags)
> +{
> + struct dri3_egl_surface *dri3_surf = draw->priv;
> + _EGLDisplay *disp = dri3_surf->base.Resource.Display;
> +
> + dri2_flush_drawable_for_swapbuffers(disp, &dri3_surf->base);
> +}
> +
> +static struct loader_dri3_vtable egl_dri3_vtable = {
> + .get_swap_interval = egl_dri3_get_swap_interval,
> + .clamp_swap_interval = egl_dri3_clamp_swap_interval,
> + .set_swap_interval = egl_dri3_set_swap_interval,
> + .set_drawable_size = egl_dri3_set_drawable_size,
> + .get_width = egl_dri3_get_width,
> + .get_height = egl_dri3_get_height,
> + .is_different_gpu = egl_dri3_is_different_gpu,
> + .in_current_context = egl_dri3_in_current_context,
> + .get_dri_context = egl_dri3_get_dri_context,
> + .get_dri_screen = egl_dri3_get_dri_screen,
> + .flush_drawable = egl_dri3_flush_drawable,
> + .show_fps = NULL,
> +};
> +
> +static EGLBoolean
> +dri3_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
> +{
> + struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
> +
> + (void) drv;
> +
> + if (!_eglPutSurface(surf))
> + return EGL_TRUE;
> +
> + loader_dri3_destroy_drawable(dri3_surf->loader_drawable);
> +
> + free(surf);
> +
> + return EGL_TRUE;
> +}
> +
> +static EGLBoolean
> +dri3_set_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
> + EGLint interval)
> +{
> + struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
> +
> + loader_dri3_set_swap_interval(dri3_surf->loader_drawable, interval);
> +
> + return EGL_TRUE;
> +}
> +
> +static xcb_screen_t *
> +get_xcb_screen(xcb_screen_iterator_t iter, int screen)
> +{
> + for (; iter.rem; --screen, xcb_screen_next(&iter))
> + if (screen == 0)
> + return iter.data;
> +
> + return NULL;
> +}
> +
> +static _EGLSurface *
> +dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
> + _EGLConfig *conf, void *native_surface,
> + const EGLint *attrib_list)
> +{
> + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
> + struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
> + struct dri3_egl_surface *dri3_surf;
> + xcb_drawable_t drawable;
> + xcb_screen_iterator_t s;
> + xcb_screen_t *screen;
> +
> + STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));
> + drawable = (uintptr_t) native_surface;
> +
> + (void) drv;
> +
> + dri3_surf = calloc(1, sizeof *dri3_surf);
> + if (!dri3_surf) {
> + _eglError(EGL_BAD_ALLOC, "dri3_create_surface");
> + return NULL;
> + }
> +
> + if (!_eglInitSurface(&dri3_surf->base, disp, type, conf, attrib_list))
> + goto cleanup_surf;
> +
> + if (type == EGL_PBUFFER_BIT) {
> + s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
> + screen = get_xcb_screen(s, dri2_dpy->screen);
> + if (!screen) {
> + _eglError(EGL_BAD_NATIVE_WINDOW, "dri3_create_surface");
> + goto cleanup_surf;
> + }
> +
> + drawable = xcb_generate_id(dri2_dpy->conn);
> + xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
> + drawable, screen->root,
> + dri3_surf->base.Width, dri3_surf->base.Height);
> + }
> +
> + dri3_surf->loader_drawable =
> + loader_dri3_create_drawable(dri2_dpy->conn, drawable,
> + dri2_dpy->dri_screen,
> + type == EGL_WINDOW_BIT ?
> + dri2_conf->dri_double_config :
> + dri2_conf->dri_single_config,
> + &dri2_dpy->loader_dri3_ext,
> + &egl_dri3_vtable,
> + dri3_surf);
> + if (!dri3_surf->loader_drawable) {
> + _eglError(EGL_BAD_ALLOC, "dri3_surface_create");
> + goto cleanup_pixmap;
> + }
> +
> + return &dri3_surf->base;
> +
> + cleanup_pixmap:
> + if (type == EGL_PBUFFER_BIT)
> + xcb_free_pixmap(dri2_dpy->conn, drawable);
> + cleanup_surf:
> + free(dri3_surf);
> +
> + return NULL;
> +}
> +
> +/**
> + * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
> + */
> +static _EGLSurface *
> +dri3_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
> + _EGLConfig *conf, void *native_window,
> + const EGLint *attrib_list)
> +{
> + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
> + _EGLSurface *surf;
> +
> + surf = dri3_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
> + native_window, attrib_list);
> + if (surf != NULL)
> + dri3_set_swap_interval(drv, disp, surf, dri2_dpy->default_swap_interval);
> +
> + return surf;
> +}
> +
> +static _EGLSurface *
> +dri3_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
> + _EGLConfig *conf, void *native_pixmap,
> + const EGLint *attrib_list)
> +{
> + return dri3_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
> + native_pixmap, attrib_list);
> +}
> +
> +static _EGLSurface *
> +dri3_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,
> + _EGLConfig *conf, const EGLint *attrib_list)
> +{
> + return dri3_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,
> + XCB_WINDOW_NONE, attrib_list);
> +}
> +
> +static EGLBoolean
> +dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
> + EGLuint64KHR *ust, EGLuint64KHR *msc,
> + EGLuint64KHR *sbc)
> +{
> + struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surface);
> +
> + return loader_dri3_wait_for_msc(dri3_surf->loader_drawable, 0, 0, 0,
> + ust, msc, sbc) ? EGL_TRUE : EGL_FALSE;
> +}
> +
> +/**
> + * Called by the driver when it needs to update the real front buffer with the
> + * contents of its fake front buffer.
> + */
> +static void
> +dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
> +{
> + /* FIXME: Does EGL support front buffer rendering at all? */
> + _eglLog(_EGL_WARNING, "FIXME: egl/x11 doesn't support front buffer rendering.");
I believe that EGL does not support front buffer rendering. Although I
could be wrong.
> + (void) driDrawable;
> + (void) loaderPrivate;
> +}
> +
> +const __DRIimageLoaderExtension dri3_image_loader_extension = {
> + .base = { __DRI_IMAGE_LOADER, 1 },
> +
> + .getBuffers = loader_dri3_get_buffers,
> + .flushFrontBuffer = dri3_flush_front_buffer,
> +};
> +
> +static EGLBoolean
> +dri3_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
> +{
> + struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw);
> +
> + /* No-op for a pixmap or pbuffer surface */
> + if (draw->Type == EGL_PIXMAP_BIT || draw->Type == EGL_PBUFFER_BIT)
> + return 0;
> +
> + return loader_dri3_swap_buffers_msc(dri3_surf->loader_drawable,
> + 0, 0, 0, 0,
> + draw->SwapBehavior == EGL_BUFFER_PRESERVED) != -1;
> +}
> +
> +static EGLBoolean
> +dri3_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
> + void *native_pixmap_target)
> +{
> + struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
> + xcb_pixmap_t target;
> +
> + STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));
> + target = (uintptr_t) native_pixmap_target;
> +
> + loader_dri3_copy_drawable(dri3_surf->loader_drawable, target,
> + dri3_surf->loader_drawable->drawable);
> +
> + return EGL_TRUE;
> +}
> +
> +static int
> +dri3_query_buffer_age(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
> +{
> + struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
> +
> + return loader_dri3_query_buffer_age(dri3_surf->loader_drawable);
> +}
> +
> +static int
> +dri3_authenticate(_EGLDisplay *disp, uint32_t id)
> +{
> + /* If the device is render node, authentication is not needed, if it is
> + * master, authentication won't succeed anyway.
> + */
> + _eglLog(_EGL_WARNING, "authentication shouldn't be called on dri3");
> +
Last time I've looked (a little while ago) one can just omit this
function, and set the vtbl entry to NULL.
> + return 0;
> +}
> +
> +static __DRIdrawable *
> +dri3_get_dri_drawable(_EGLSurface *surf)
> +{
> + struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
> +
> + return dri3_surf->loader_drawable->dri_drawable;
> +}
> +
> +struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
> + .authenticate = dri3_authenticate,
> + .create_window_surface = dri3_create_window_surface,
> + .create_pixmap_surface = dri3_create_pixmap_surface,
> + .create_pbuffer_surface = dri3_create_pbuffer_surface,
> + .destroy_surface = dri3_destroy_surface,
> + .create_image = dri2_create_image_khr,
> + .swap_interval = dri3_set_swap_interval,
> + .swap_buffers = dri3_swap_buffers,
> + .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
> + .swap_buffers_region = dri2_fallback_swap_buffers_region,
> + .post_sub_buffer = dri2_fallback_post_sub_buffer,
> + .copy_buffers = dri3_copy_buffers,
> + .query_buffer_age = dri3_query_buffer_age,
> + .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
> + .get_sync_values = dri3_get_sync_values,
> + .get_dri_drawable = dri3_get_dri_drawable,
> +};
> +
> +static char *
> +dri3_get_device_name(int fd)
> +{
> + char *ret = NULL;
> +
> +#ifdef LIBDRM_HAS_RENDERNODE_SUPPORT
> + ret = drmGetRenderDeviceNameFromFd(fd);
> +#endif
> + if (ret)
> + return ret;
> +
> + /* For dri3, render node support is required for WL_bind_wayland_display.
> + * In order not to regress on older systems without kernel or libdrm
> + * support, fall back to dri2. User can override it with environment
> + * variable if they don't need to use that extension.
> + */
Can we just disable the extension, if the above call fails ?
> + if (getenv("EGL_FORCE_DRI3") == NULL) {
> + _eglLog(_EGL_WARNING, "Render node support not available, falling back to dri2");
> + _eglLog(_EGL_WARNING, "If you want to force dri3, set EGL_FORCE_DRI3 environment variable");
> + } else
> + ret = loader_get_device_name_for_fd(fd);
> +
> + return ret;
> +}
> +
> +EGLBoolean
> +dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
> +{
> + xcb_dri3_query_version_reply_t *dri3_query;
> + xcb_dri3_query_version_cookie_t dri3_query_cookie;
> + xcb_present_query_version_reply_t *present_query;
> + xcb_present_query_version_cookie_t present_query_cookie;
> + xcb_generic_error_t *error;
> + xcb_screen_iterator_t s;
> + xcb_screen_t *screen;
> + const xcb_query_extension_reply_t *extension;
> +
> + xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri3_id);
> + xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_present_id);
> +
> + extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri3_id);
> + if (!(extension && extension->present))
> + return EGL_FALSE;
> +
> + extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_present_id);
> + if (!(extension && extension->present))
> + return EGL_FALSE;
> +
> + dri3_query_cookie = xcb_dri3_query_version(dri2_dpy->conn,
> + XCB_DRI3_MAJOR_VERSION,
> + XCB_DRI3_MINOR_VERSION);
> +
> + present_query_cookie = xcb_present_query_version(dri2_dpy->conn,
> + XCB_PRESENT_MAJOR_VERSION,
> + XCB_PRESENT_MINOR_VERSION);
> +
> + dri3_query =
> + xcb_dri3_query_version_reply(dri2_dpy->conn, dri3_query_cookie, &error);
> + if (dri3_query == NULL || error != NULL) {
> + _eglLog(_EGL_WARNING, "DRI2: failed to query dri3 version");
> + free(dri3_query);
> + free(error);
> + return EGL_FALSE;
> + }
> + free(dri3_query);
> +
> + present_query =
> + xcb_present_query_version_reply(dri2_dpy->conn,
> + present_query_cookie, &error);
> + if (present_query == NULL || error != NULL) {
> + _eglLog(_EGL_WARNING, "DRI2: failed to query Present version");
> + free(present_query);
> + free(error);
> + return EGL_FALSE;
> + }
> + free(present_query);
> +
> + s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
> + screen = get_xcb_screen(s, dri2_dpy->screen);
> + if (!screen) {
> + _eglError(EGL_BAD_NATIVE_WINDOW, "dri3_x11_connect");
> + return EGL_FALSE;
> + }
> +
> + dri2_dpy->fd = loader_dri3_open(dri2_dpy->conn, screen->root, 0);
> + if (dri2_dpy->fd < 0) {
> + int conn_error = xcb_connection_has_error(dri2_dpy->conn);
> + _eglLog(_EGL_WARNING, "DRI2: Screen seem not DRI3 capable");
> +
> + if (conn_error)
> + _eglLog(_EGL_WARNING, "DRI2: Failed to initialize DRI3");
> +
> + return EGL_FALSE;
> + }
> +
> + dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu);
> +
> + dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd, 0);
> + if (!dri2_dpy->driver_name) {
> + _eglLog(_EGL_WARNING, "DRI2: No driver found");
> + close(dri2_dpy->fd);
> + return EGL_FALSE;
> + }
> +
> + dri2_dpy->device_name = dri3_get_device_name(dri2_dpy->fd);
> + if (!dri2_dpy->device_name) {
> + close(dri2_dpy->fd);
> + return EGL_FALSE;
> + }
> +
> + return EGL_TRUE;
> +}
> diff --git a/src/egl/drivers/dri2/platform_x11_dri3.h b/src/egl/drivers/dri2/platform_x11_dri3.h
> new file mode 100644
> index 0000000..b9d0f3d
> --- /dev/null
> +++ b/src/egl/drivers/dri2/platform_x11_dri3.h
> @@ -0,0 +1,44 @@
> +/*
> + * Copyright © 2015 Boyan Ding
> + *
> + * 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.
> + */
> +
> +#ifndef EGL_X11_DRI3_INCLUDED
> +#define EGL_X11_DRI3_INCLUDED
> +
> +#include <GL/gl.h>
This include feels a bit odd. We don't seem to (directly) require it
by of the following code.
> +#include <GL/internal/dri_interface.h>
> +
> +#include "egl_dri2.h"
> +
> +_EGL_DRIVER_TYPECAST(dri3_egl_surface, _EGLSurface, obj)
> +
> +struct dri3_egl_surface {
> + _EGLSurface base;
> + struct loader_dri3_drawable *loader_drawable;
> +};
> +
> +extern const __DRIimageLoaderExtension dri3_image_loader_extension;
> +extern struct dri2_egl_display_vtbl dri3_x11_display_vtbl;
> +
> +EGLBoolean
> +dri3_x11_connect(struct dri2_egl_display *dri2_dpy);
> +
> +#endif
> --
> 2.4.4
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
More information about the mesa-dev
mailing list