[PATCH 5/6] dri3: Add DRI3 support to GLX, DRI common and Intel driver
Keith Packard
keithp at keithp.com
Fri Nov 1 00:13:15 CET 2013
This hooks DRI3 support into the GLX layer, the DRI common layer and the Intel
driver.
Signed-off-by: Keith Packard <keithp at keithp.com>
---
configure.ac | 10 +-
include/GL/internal/dri_interface.h | 158 +++
src/glx/Makefile.am | 2 +
src/glx/dri3_common.c | 146 +++
src/glx/dri3_glx.c | 1539 +++++++++++++++++++++++++
src/glx/dri3_priv.h | 128 ++
src/glx/glxclient.h | 2 +
src/glx/glxext.c | 6 +-
src/mesa/drivers/dri/common/dri_util.c | 163 ++-
src/mesa/drivers/dri/common/dri_util.h | 23 +
src/mesa/drivers/dri/i915/intel_context.c | 109 +-
src/mesa/drivers/dri/i915/intel_mipmap_tree.c | 33 +
src/mesa/drivers/dri/i915/intel_mipmap_tree.h | 8 +
src/mesa/drivers/dri/i965/brw_context.c | 110 +-
src/mesa/drivers/dri/i965/intel_mipmap_tree.c | 61 +
src/mesa/drivers/dri/i965/intel_mipmap_tree.h | 8 +
src/mesa/drivers/dri/i965/intel_screen.c | 107 +-
17 files changed, 2594 insertions(+), 19 deletions(-)
create mode 100644 src/glx/dri3_common.c
create mode 100644 src/glx/dri3_glx.c
create mode 100644 src/glx/dri3_priv.h
diff --git a/configure.ac b/configure.ac
index f94c9b9..b6158d9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -38,6 +38,8 @@ LIBDRM_NVVIEUX_REQUIRED=2.4.33
LIBDRM_NOUVEAU_REQUIRED="2.4.33 libdrm >= 2.4.41"
LIBDRM_FREEDRENO_REQUIRED=2.4.39
DRI2PROTO_REQUIRED=2.6
+DRI3PROTO_REQUIRED=1.0
+LIBUDEV_REQUIRED=151
GLPROTO_REQUIRED=1.4.14
LIBDRM_XORG_REQUIRED=2.4.24
LIBKMS_XORG_REQUIRED=1.0.0
@@ -820,10 +822,12 @@ xyesno)
fi
PKG_CHECK_MODULES([DRI2PROTO], [dri2proto >= $DRI2PROTO_REQUIRED])
GL_PC_REQ_PRIV="$GL_PC_REQ_PRIV libdrm >= $LIBDRM_REQUIRED"
+ PKG_CHECK_MODULES([DRI3PROTO], [dri3proto >= $DRI3PROTO_REQUIRED])
+ PKG_CHECK_MODULES([LIBUDEV], [libudev >= $LIBUDEV_REQUIRED])
fi
# find the DRI deps for libGL
- dri_modules="x11 xext xdamage xfixes x11-xcb xcb-glx >= 1.8.1 xcb-dri2 >= 1.8"
+ dri_modules="x11 xext xdamage xfixes x11-xcb xcb-glx >= 1.8.1 xcb-dri2 >= 1.8 xcb-dri3 xcb-sync xshmfence"
# add xf86vidmode if available
PKG_CHECK_MODULES([XF86VIDMODE], [xxf86vm], HAVE_XF86VIDMODE=yes, HAVE_XF86VIDMODE=no)
@@ -833,8 +837,8 @@ xyesno)
PKG_CHECK_MODULES([DRIGL], [$dri_modules])
GL_PC_REQ_PRIV="$GL_PC_REQ_PRIV $dri_modules"
- X11_INCLUDES="$X11_INCLUDES $DRIGL_CFLAGS"
- GL_LIB_DEPS="$DRIGL_LIBS"
+ X11_INCLUDES="$X11_INCLUDES $DRIGL_CFLAGS $LIBUDEV_CFLAGS"
+ GL_LIB_DEPS="$DRIGL_LIBS $LIBUDEV_LIBS"
# need DRM libs, $PTHREAD_LIBS, etc.
GL_LIB_DEPS="$GL_LIB_DEPS $LIBDRM_LIBS -lm $PTHREAD_LIBS $DLOPEN_LIBS"
diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h
index 48993b9..b06ad8d 100644
--- a/include/GL/internal/dri_interface.h
+++ b/include/GL/internal/dri_interface.h
@@ -86,6 +86,11 @@ typedef struct __DRIdri2LoaderExtensionRec __DRIdri2LoaderExtension;
typedef struct __DRI2flushExtensionRec __DRI2flushExtension;
typedef struct __DRI2throttleExtensionRec __DRI2throttleExtension;
+
+typedef struct __DRIdri3BufferRec __DRIdri3Buffer;
+typedef struct __DRIdri3ExtensionRec __DRIdri3Extension;
+typedef struct __DRIdri3LoaderExtensionRec __DRIdri3LoaderExtension;
+
/*@}*/
@@ -966,6 +971,159 @@ struct __DRIdri2ExtensionRec {
/**
+ * DRI3 Loader extension.
+ */
+
+#define __DRI3_DRIVER_EXTENSIONS "__dri3DriverExtensions"
+
+enum __DRI3bufferType {
+ __DRI3_BUFFER_BACK = 0,
+ __DRI3_BUFFER_FRONT = 1
+};
+
+struct __DRIdri3BufferRec {
+ unsigned int size;
+ unsigned int pitch;
+ unsigned int cpp;
+ unsigned int flags;
+ unsigned int width, height;
+ enum __DRI3bufferType buffer_type;
+ uint32_t pixmap;
+ uint32_t sync_fence;
+ int32_t *shm_fence;
+ void *driverPrivate;
+};
+
+#define __DRI_DRI3_LOADER "DRI_DRI3Loader"
+#define __DRI_DRI3_LOADER_VERSION 1
+
+struct __DRIdri3LoaderExtensionRec {
+ __DRIextension base;
+
+ int (*getBuffers)(__DRIdrawable *driDrawable,
+ int *width, int *height,
+ unsigned int format,
+ void *loaderPrivate,
+ int need_front,
+ int need_back,
+ __DRIdri3Buffer **front,
+ __DRIdri3Buffer **back);
+
+ /**
+ * Flush pending front-buffer rendering
+ *
+ * Any rendering that has been performed to the
+ * \c __DRI3_BUFFER_FAKE_FRONT_LEFT will be flushed to the
+ * \c __DRI3_BUFFER_FRONT_LEFT.
+ *
+ * \param driDrawable Drawable whose front-buffer is to be flushed
+ * \param loaderPrivate Loader's private data that was previously passed
+ * into __DRIdri2ExtensionRec::createNewDrawable
+ */
+ void (*flushFrontBuffer)(__DRIdrawable *driDrawable, void *loaderPrivate);
+};
+
+/**
+ * DRI3 extension.
+ */
+
+struct gl_context;
+struct dd_function_table;
+
+typedef __DRIscreen *
+(*__DRIcreateNewScreen2)(int screen, int fd,
+ const __DRIextension **extensions,
+ const __DRIextension **driver_extensions,
+ const __DRIconfig ***driver_configs,
+ void *loaderPrivate);
+
+typedef __DRIdrawable *
+(*__DRIcreateNewDrawable)(__DRIscreen *screen,
+ const __DRIconfig *config,
+ void *loaderPrivate);
+
+typedef __DRIcontext *
+(*__DRIcreateNewContext)(__DRIscreen *screen,
+ const __DRIconfig *config,
+ __DRIcontext *shared,
+ void *loaderPrivate);
+
+typedef __DRIcontext *
+(*__DRIcreateContextAttribs)(__DRIscreen *screen,
+ int api,
+ const __DRIconfig *config,
+ __DRIcontext *shared,
+ unsigned num_attribs,
+ const uint32_t *attribs,
+ unsigned *error,
+ void *loaderPrivate);
+
+typedef unsigned int
+(*__DRIgetAPIMask)(__DRIscreen *screen);
+
+typedef __DRIdri3Buffer *
+(*__DRIdri3AllocateBuffer)(__DRIscreen *screen,
+ unsigned int bpp,
+ int width,
+ int height);
+
+typedef void
+(*__DRIdri3ReleaseBuffer)(__DRIscreen *screen,
+ __DRIdri3Buffer *buffer);
+
+typedef int
+(*__DRIdri3BufferToFd)(__DRIscreen *screen,
+ __DRIdri3Buffer *buffer);
+
+typedef __DRIdri3Buffer *
+(*__DRIdri3FdToBuffer)(__DRIscreen *screen,
+ int fd, unsigned int bpp,
+ int width, int height, int stride,
+ unsigned int size);
+
+typedef uint32_t *
+(*__DRIdri3Stamp)(__DRIdrawable *drawable);
+
+#define __DRI_DRI3 "DRI_DRI3"
+#define __DRI_DRI3_VERSION 1
+
+struct __DRIdri3ExtensionRec {
+ __DRIextension base;
+
+ /* Common DRI functions, shared with DRI2 */
+ __DRIcreateNewScreen2 createNewScreen2;
+ __DRIcreateNewDrawable createNewDrawable;
+ __DRIcreateNewContext createNewContext;
+ __DRIcreateContextAttribs createContextAttribs;
+ __DRIgetAPIMask getAPIMask;
+
+ /* DRI3-specific functions*/
+
+ /* Allocate color buffer for front/back of windows and pixmaps
+ */
+ __DRIdri3AllocateBuffer allocateBuffer;
+
+ /* Release color buffer
+ */
+ __DRIdri3ReleaseBuffer releaseBuffer;
+
+ /* Given a buffer, wrap it in a DMA-BUF file descriptor
+ */
+ __DRIdri3BufferToFd bufferToFd;
+
+ /* Given a DMA-BUF file descriptor, construct a suitable
+ * color buffer
+ */
+ __DRIdri3FdToBuffer fdToBuffer;
+
+ /* Ask the driver for a pointer to an integer which
+ * can be incremented when the drawable needs to be
+ * revalidated
+ */
+ __DRIdri3Stamp stamp;
+};
+
+/**
* This extension provides functionality to enable various EGLImage
* extensions.
*/
diff --git a/src/glx/Makefile.am b/src/glx/Makefile.am
index f01709b..854025d 100644
--- a/src/glx/Makefile.am
+++ b/src/glx/Makefile.am
@@ -92,6 +92,8 @@ libglx_la_SOURCES = \
glxhash.c \
dri2_glx.c \
dri2.c \
+ dri3_glx.c \
+ dri3_common.c \
applegl_glx.c
GL_LIBS = \
diff --git a/src/glx/dri3_common.c b/src/glx/dri3_common.c
new file mode 100644
index 0000000..c758f96
--- /dev/null
+++ b/src/glx/dri3_common.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright © 2013 Keith Packard
+ *
+ * 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.
+ */
+
+/*
+ * This code is derived from src/egl/drivers/dri2/common.c which
+ * carries the following copyright:
+ *
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Kristian Høgsberg <krh at bitplanet.net>
+ * Benjamin Franzke <benjaminfranzke at googlemail.com>
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <GL/gl.h>
+#include "glapi.h"
+#include "glxclient.h"
+#include "xf86dri.h"
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include "xf86drm.h"
+#include "dri_common.h"
+#include "dri3_priv.h"
+
+#define DRIVER_MAP_DRI3_ONLY
+#include "pci_ids/pci_id_driver_map.h"
+
+#include <libudev.h>
+
+static struct udev_device *
+dri3_udev_device_new_from_fd(struct udev *udev, int fd)
+{
+ struct udev_device *device;
+ struct stat buf;
+
+ if (fstat(fd, &buf) < 0) {
+ ErrorMessageF("DRI3: failed to stat fd %d", fd);
+ return NULL;
+ }
+
+ device = udev_device_new_from_devnum(udev, 'c', buf.st_rdev);
+ if (device == NULL) {
+ ErrorMessageF("DRI3: could not create udev device for fd %d", fd);
+ return NULL;
+ }
+
+ return device;
+}
+
+char *
+dri3_get_driver_for_fd(int fd)
+{
+ struct udev *udev;
+ struct udev_device *device, *parent;
+ const char *pci_id;
+ char *driver = NULL;
+ int vendor_id, chip_id, i, j;
+
+ udev = udev_new();
+ device = dri3_udev_device_new_from_fd(udev, fd);
+ if (device == NULL)
+ return NULL;
+
+ parent = udev_device_get_parent(device);
+ if (parent == NULL) {
+ ErrorMessageF("DRI3: could not get parent device");
+ goto out;
+ }
+
+ pci_id = udev_device_get_property_value(parent, "PCI_ID");
+ if (pci_id == NULL ||
+ sscanf(pci_id, "%x:%x", &vendor_id, &chip_id) != 2) {
+ ErrorMessageF("DRI3: malformed or no PCI ID");
+ goto out;
+ }
+
+ for (i = 0; driver_map[i].driver; i++) {
+ if (vendor_id != driver_map[i].vendor_id)
+ continue;
+ if (driver_map[i].num_chips_ids == -1) {
+ driver = strdup(driver_map[i].driver);
+ goto out;
+ }
+
+ for (j = 0; j < driver_map[i].num_chips_ids; j++)
+ if (driver_map[i].chip_ids[j] == chip_id) {
+ driver = strdup(driver_map[i].driver);
+ goto out;
+ }
+ }
+
+out:
+ udev_device_unref(device);
+ udev_unref(udev);
+
+ return driver;
+}
diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c
new file mode 100644
index 0000000..4d275f2
--- /dev/null
+++ b/src/glx/dri3_glx.c
@@ -0,0 +1,1539 @@
+/*
+ * Copyright © 2013 Keith Packard
+ *
+ * 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.
+ */
+
+/*
+ * Portions of this code were adapted from dri2_glx.c which carries the
+ * following copyright:
+ *
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL 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 PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Authors:
+ * Kristian Høgsberg (krh at redhat.com)
+ */
+
+#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
+
+#include <X11/Xlib.h>
+#include <X11/extensions/Xfixes.h>
+#include <X11/Xlib-xcb.h>
+#include <X11/xshmfence.h>
+#include <xcb/xcb.h>
+#include <xcb/dri3.h>
+#include <xcb/present.h>
+#include <GL/gl.h>
+#include "glapi.h"
+#include "glxclient.h"
+#include "xf86dri.h"
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include "xf86drm.h"
+#include "dri_common.h"
+#include "dri3_priv.h"
+
+static const struct glx_context_vtable dri3_context_vtable;
+
+#define HAS_SBC 0
+
+#if HAS_SBC
+
+/* For XCB's handling of ust/msc/sbc counters, we have to hand it the high and
+ * low halves separately. This helps you split them.
+ */
+static void
+split_counter(uint64_t counter, uint32_t *hi, uint32_t *lo)
+{
+ *hi = (counter >> 32);
+ *lo = counter & 0xffffffff;
+}
+
+static uint64_t
+merge_counter(uint32_t hi, uint32_t lo)
+{
+ return ((uint64_t)hi << 32) | lo;
+}
+#endif /* HAS_SBC */
+
+static inline void
+dri3_fence_reset(xcb_connection_t *c, __DRIdri3Buffer *buffer) {
+ xshmfence_reset(buffer->shm_fence);
+}
+
+static inline void
+dri3_fence_trigger(xcb_connection_t *c, __DRIdri3Buffer *buffer) {
+ xcb_sync_trigger_fence(c, buffer->sync_fence);
+}
+
+static inline void
+dri3_fence_await(xcb_connection_t *c, __DRIdri3Buffer *buffer) {
+ xcb_flush(c);
+ xshmfence_await(buffer->shm_fence);
+}
+
+static void
+dri3_destroy_context(struct glx_context *context)
+{
+ struct dri3_context *pcp = (struct dri3_context *) context;
+ struct dri3_screen *psc = (struct dri3_screen *) context->psc;
+
+ driReleaseDrawables(&pcp->base);
+
+ free((char *) context->extensions);
+
+ (*psc->core->destroyContext) (pcp->driContext);
+
+ free(pcp);
+}
+
+static Bool
+dri3_bind_context(struct glx_context *context, struct glx_context *old,
+ GLXDrawable draw, GLXDrawable read)
+{
+ struct dri3_context *pcp = (struct dri3_context *) context;
+ struct dri3_screen *psc = (struct dri3_screen *) pcp->base.psc;
+ struct dri3_drawable *pdraw, *pread;
+
+ pdraw = (struct dri3_drawable *) driFetchDrawable(context, draw);
+ pread = (struct dri3_drawable *) driFetchDrawable(context, read);
+
+ driReleaseDrawables(&pcp->base);
+
+ if (pdraw == NULL || pread == NULL)
+ return GLXBadDrawable;
+
+ if (!(*psc->core->bindContext) (pcp->driContext,
+ pdraw->driDrawable, pread->driDrawable))
+ return GLXBadContext;
+
+ return Success;
+}
+
+static void
+dri3_unbind_context(struct glx_context *context, struct glx_context *new)
+{
+ struct dri3_context *pcp = (struct dri3_context *) context;
+ struct dri3_screen *psc = (struct dri3_screen *) pcp->base.psc;
+
+ (*psc->core->unbindContext) (pcp->driContext);
+}
+
+static struct glx_context *
+dri3_create_context(struct glx_screen *base,
+ struct glx_config *config_base,
+ struct glx_context *shareList, int renderType)
+{
+ struct dri3_context *pcp, *pcp_shared;
+ struct dri3_screen *psc = (struct dri3_screen *) base;
+ __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
+ __DRIcontext *shared = NULL;
+
+ if (shareList) {
+ /* If the shareList context is not a DRI3 context, we cannot possibly
+ * create a DRI3 context that shares it.
+ */
+ if (shareList->vtable->destroy != dri3_destroy_context) {
+ return NULL;
+ }
+
+ pcp_shared = (struct dri3_context *) shareList;
+ shared = pcp_shared->driContext;
+ }
+
+ pcp = calloc(1, sizeof *pcp);
+ if (pcp == NULL)
+ return NULL;
+
+ if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
+ free(pcp);
+ return NULL;
+ }
+
+ pcp->driContext =
+ (*psc->dri3->createNewContext) (psc->driScreen,
+ config->driConfig, shared, pcp);
+
+ if (pcp->driContext == NULL) {
+ free(pcp);
+ return NULL;
+ }
+
+ pcp->base.vtable = &dri3_context_vtable;
+
+ return &pcp->base;
+}
+
+static struct glx_context *
+dri3_create_context_attribs(struct glx_screen *base,
+ struct glx_config *config_base,
+ struct glx_context *shareList,
+ unsigned num_attribs,
+ const uint32_t *attribs,
+ unsigned *error)
+{
+ struct dri3_context *pcp = NULL;
+ struct dri3_context *pcp_shared = NULL;
+ struct dri3_screen *psc = (struct dri3_screen *) base;
+ __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
+ __DRIcontext *shared = NULL;
+
+ uint32_t minor_ver = 1;
+ uint32_t major_ver = 2;
+ uint32_t flags = 0;
+ unsigned api;
+ int reset = __DRI_CTX_RESET_NO_NOTIFICATION;
+ uint32_t ctx_attribs[2 * 5];
+ unsigned num_ctx_attribs = 0;
+ uint32_t render_type;
+
+ /* Remap the GLX tokens to DRI2 tokens.
+ */
+ if (!dri2_convert_glx_attribs(num_attribs, attribs,
+ &major_ver, &minor_ver,
+ &render_type, &flags, &api,
+ &reset, error))
+ goto error_exit;
+
+ /* Check the renderType value */
+ if (!validate_renderType_against_config(config_base, render_type))
+ goto error_exit;
+
+ if (shareList) {
+ pcp_shared = (struct dri3_context *) shareList;
+ shared = pcp_shared->driContext;
+ }
+
+ pcp = calloc(1, sizeof *pcp);
+ if (pcp == NULL) {
+ *error = __DRI_CTX_ERROR_NO_MEMORY;
+ goto error_exit;
+ }
+
+ if (!glx_context_init(&pcp->base, &psc->base, &config->base))
+ goto error_exit;
+
+ ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
+ ctx_attribs[num_ctx_attribs++] = major_ver;
+ ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
+ ctx_attribs[num_ctx_attribs++] = minor_ver;
+
+ /* Only send a value when the non-default value is requested. By doing
+ * this we don't have to check the driver's DRI3 version before sending the
+ * default value.
+ */
+ if (reset != __DRI_CTX_RESET_NO_NOTIFICATION) {
+ ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY;
+ ctx_attribs[num_ctx_attribs++] = reset;
+ }
+
+ if (flags != 0) {
+ ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
+
+ /* The current __DRI_CTX_FLAG_* values are identical to the
+ * GLX_CONTEXT_*_BIT values.
+ */
+ ctx_attribs[num_ctx_attribs++] = flags;
+ }
+
+ pcp->driContext =
+ (*psc->dri3->createContextAttribs) (psc->driScreen,
+ api,
+ config->driConfig,
+ shared,
+ num_ctx_attribs / 2,
+ ctx_attribs,
+ error,
+ pcp);
+
+ if (pcp->driContext == NULL)
+ goto error_exit;
+
+ pcp->base.vtable = &dri3_context_vtable;
+
+ return &pcp->base;
+
+error_exit:
+ free(pcp);
+
+ return NULL;
+}
+
+static void
+dri3_destroy_drawable(__GLXDRIdrawable *base)
+{
+ struct dri3_screen *psc = (struct dri3_screen *) base->psc;
+ struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
+
+ (*psc->core->destroyDrawable) (pdraw->driDrawable);
+
+ free(pdraw);
+}
+
+static __GLXDRIdrawable *
+dri3_create_drawable(struct glx_screen *base, XID xDrawable,
+ GLXDrawable drawable, struct glx_config *config_base)
+{
+ struct dri3_drawable *pdraw;
+ struct dri3_screen *psc = (struct dri3_screen *) base;
+ __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
+ GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
+
+ pdraw = calloc(1, sizeof(*pdraw));
+ if (!pdraw)
+ return NULL;
+
+ pdraw->base.destroyDrawable = dri3_destroy_drawable;
+ pdraw->base.xDrawable = xDrawable;
+ pdraw->base.drawable = drawable;
+ pdraw->base.psc = &psc->base;
+// pdraw->bufferCount = 0;
+ pdraw->swap_interval = 1; /* default may be overridden below */
+ pdraw->have_back = 0;
+ pdraw->have_fake_front = 0;
+
+ if (psc->config)
+ psc->config->configQueryi(psc->driScreen,
+ "vblank_mode", &vblank_mode);
+
+ switch (vblank_mode) {
+ case DRI_CONF_VBLANK_NEVER:
+ case DRI_CONF_VBLANK_DEF_INTERVAL_0:
+ pdraw->swap_interval = 0;
+ break;
+ case DRI_CONF_VBLANK_DEF_INTERVAL_1:
+ case DRI_CONF_VBLANK_ALWAYS_SYNC:
+ default:
+ pdraw->swap_interval = 1;
+ break;
+ }
+
+ (void) __glXInitialize(psc->base.dpy);
+
+ /* Create a new drawable */
+ pdraw->driDrawable =
+ (*psc->dri3->createNewDrawable) (psc->driScreen,
+ config->driConfig, pdraw);
+
+ if (!pdraw->driDrawable) {
+ free(pdraw);
+ return NULL;
+ }
+
+ /*
+ * Make sure server has the same swap interval we do for the new
+ * drawable.
+ */
+ if (psc->vtable.setSwapInterval)
+ psc->vtable.setSwapInterval(&pdraw->base, pdraw->swap_interval);
+
+ return &pdraw->base;
+}
+
+#if HAS_SBC
+static int
+dri3_drawable_get_msc(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
+ int64_t *ust, int64_t *msc, int64_t *sbc)
+{
+ xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
+ xcb_dri2_get_msc_cookie_t get_msc_cookie;
+ xcb_dri2_get_msc_reply_t *get_msc_reply;
+
+ get_msc_cookie = xcb_dri2_get_msc_unchecked(c, pdraw->xDrawable);
+ get_msc_reply = xcb_dri2_get_msc_reply(c, get_msc_cookie, NULL);
+
+ if (!get_msc_reply)
+ return 0;
+
+ *ust = merge_counter(get_msc_reply->ust_hi, get_msc_reply->ust_lo);
+ *msc = merge_counter(get_msc_reply->msc_hi, get_msc_reply->msc_lo);
+ *sbc = merge_counter(get_msc_reply->sbc_hi, get_msc_reply->sbc_lo);
+ free(get_msc_reply);
+
+ return 1;
+}
+
+static int
+dri3_wait_for_msc(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
+ int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
+{
+ xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
+ xcb_dri2_wait_msc_cookie_t wait_msc_cookie;
+ xcb_dri2_wait_msc_reply_t *wait_msc_reply;
+ uint32_t target_msc_hi, target_msc_lo;
+ uint32_t divisor_hi, divisor_lo;
+ uint32_t remainder_hi, remainder_lo;
+
+ split_counter(target_msc, &target_msc_hi, &target_msc_lo);
+ split_counter(divisor, &divisor_hi, &divisor_lo);
+ split_counter(remainder, &remainder_hi, &remainder_lo);
+
+ wait_msc_cookie = xcb_dri2_wait_msc_unchecked(c, pdraw->xDrawable,
+ target_msc_hi, target_msc_lo,
+ divisor_hi, divisor_lo,
+ remainder_hi, remainder_lo);
+ wait_msc_reply = xcb_dri2_wait_msc_reply(c, wait_msc_cookie, NULL);
+
+ if (!wait_msc_reply)
+ return 0;
+
+ *ust = merge_counter(wait_msc_reply->ust_hi, wait_msc_reply->ust_lo);
+ *msc = merge_counter(wait_msc_reply->msc_hi, wait_msc_reply->msc_lo);
+ *sbc = merge_counter(wait_msc_reply->sbc_hi, wait_msc_reply->sbc_lo);
+ free(wait_msc_reply);
+
+ return 1;
+}
+
+static int
+dri3_wait_for_sbc(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
+ int64_t *msc, int64_t *sbc)
+{
+ xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
+ xcb_dri2_wait_sbc_cookie_t wait_sbc_cookie;
+ xcb_dri2_wait_sbc_reply_t *wait_sbc_reply;
+ uint32_t target_sbc_hi, target_sbc_lo;
+
+ split_counter(target_sbc, &target_sbc_hi, &target_sbc_lo);
+
+ wait_sbc_cookie = xcb_dri2_wait_sbc_unchecked(c, pdraw->xDrawable,
+ target_sbc_hi, target_sbc_lo);
+ wait_sbc_reply = xcb_dri2_wait_sbc_reply(c, wait_sbc_cookie, NULL);
+
+ if (!wait_sbc_reply)
+ return 0;
+
+ *ust = merge_counter(wait_sbc_reply->ust_hi, wait_sbc_reply->ust_lo);
+ *msc = merge_counter(wait_sbc_reply->msc_hi, wait_sbc_reply->msc_lo);
+ *sbc = merge_counter(wait_sbc_reply->sbc_hi, wait_sbc_reply->sbc_lo);
+ free(wait_sbc_reply);
+
+ return 1;
+}
+#endif /* HAS_SBC */
+
+static __DRIcontext *
+dri3_get_current_context(void)
+{
+ struct glx_context *gc = __glXGetCurrentContext();
+ struct dri3_context *dri3Ctx = (struct dri3_context *)gc;
+
+ return dri3Ctx ? dri3Ctx->driContext : NULL;
+}
+
+/**
+ * dri3Throttle - Request driver throttling
+ *
+ * This function uses the DRI2 throttle extension to give the
+ * driver the opportunity to throttle on flush front, copysubbuffer
+ * and swapbuffers.
+ */
+static void
+dri3_throttle(struct dri3_screen *psc,
+ struct dri3_drawable *draw,
+ enum __DRI2throttleReason reason)
+{
+ if (psc->throttle) {
+ __DRIcontext *ctx = dri3_get_current_context();
+
+ psc->throttle->throttle(ctx, draw->driDrawable, reason);
+ }
+}
+
+/**
+ * Asks the driver to flush any queued work necessary for serializing with the
+ * X command stream, and optionally the slightly more strict requirement of
+ * glFlush() equivalence (which would require flushing even if nothing had
+ * been drawn to a window system framebuffer, for example).
+ */
+static void
+dri3_flush(struct dri3_screen *psc,
+ __DRIcontext *ctx,
+ struct dri3_drawable *draw,
+ unsigned flags,
+ enum __DRI2throttleReason throttle_reason)
+{
+ if (ctx && psc->f && psc->f->base.version >= 4) {
+ psc->f->flush_with_flags(ctx, draw->driDrawable, flags, throttle_reason);
+ } else {
+ if (flags & __DRI2_FLUSH_CONTEXT)
+ glFlush();
+
+ if (psc->f)
+ psc->f->flush(draw->driDrawable);
+
+ dri3_throttle(psc, draw, throttle_reason);
+ }
+}
+
+static xcb_gcontext_t
+dri3_drawable_gc(struct dri3_drawable *priv)
+{
+ if (!priv->gc) {
+ uint32_t v;
+ xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
+
+ v = 0;
+ xcb_create_gc(c,
+ (priv->gc = xcb_generate_id(c)),
+ priv->base.xDrawable,
+ XCB_GC_GRAPHICS_EXPOSURES,
+ &v);
+ }
+ return priv->gc;
+}
+
+static __DRIdri3Buffer *
+dri3_back_buffer(struct dri3_drawable *priv)
+{
+ return priv->buffers[__DRI3_BUFFER_BACK];
+}
+
+static __DRIdri3Buffer *
+dri3_fake_front_buffer(struct dri3_drawable *priv)
+{
+ return priv->buffers[__DRI3_BUFFER_FRONT];
+}
+
+static void
+dri3_copy_area (xcb_connection_t *c /**< */,
+ xcb_drawable_t src_drawable /**< */,
+ xcb_drawable_t dst_drawable /**< */,
+ xcb_gcontext_t gc /**< */,
+ int16_t src_x /**< */,
+ int16_t src_y /**< */,
+ int16_t dst_x /**< */,
+ int16_t dst_y /**< */,
+ uint16_t width /**< */,
+ uint16_t height /**< */)
+{
+ xcb_void_cookie_t cookie;
+
+ cookie = xcb_copy_area_checked(c,
+ src_drawable,
+ dst_drawable,
+ gc,
+ src_x,
+ src_y,
+ dst_x,
+ dst_y,
+ width,
+ height);
+ xcb_discard_reply(c, cookie.sequence);
+}
+
+static void
+_dri3_copy_sub_buffer(__GLXDRIdrawable *pdraw, int x, int y,
+ int width, int height,
+ enum __DRI2throttleReason reason, Bool flush)
+{
+ struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
+ struct dri3_screen *psc = (struct dri3_screen *) pdraw->psc;
+ xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
+ __DRIcontext *ctx = dri3_get_current_context();
+ __DRIdri3Buffer *back = dri3_back_buffer(priv);
+
+ unsigned flags;
+
+ /* Check we have the right attachments */
+ if (!priv->have_back || priv->is_pixmap)
+ return;
+
+ flags = __DRI2_FLUSH_DRAWABLE;
+ if (flush)
+ flags |= __DRI2_FLUSH_CONTEXT;
+ dri3_flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
+
+ y = priv->height - y - height;
+
+ dri3_fence_reset(c, back);
+ dri3_copy_area(c,
+ dri3_back_buffer(priv)->pixmap,
+ priv->base.xDrawable,
+ dri3_drawable_gc(priv),
+ x, y, x, y, width, height);
+ dri3_fence_trigger(c, back);
+ /* Refresh the fake front (if present) after we just damaged the real
+ * front.
+ */
+ if (priv->have_fake_front) {
+ dri3_fence_reset(c, dri3_fake_front_buffer(priv));
+ dri3_copy_area(c,
+ dri3_back_buffer(priv)->pixmap,
+ dri3_fake_front_buffer(priv)->pixmap,
+ dri3_drawable_gc(priv),
+ x, y, x, y, width, height);
+ dri3_fence_trigger(c, dri3_fake_front_buffer(priv));
+ dri3_fence_await(c, dri3_fake_front_buffer(priv));
+ }
+ dri3_fence_await(c, back);
+}
+
+static void
+dri3_copy_sub_buffer(__GLXDRIdrawable *pdraw, int x, int y,
+ int width, int height, Bool flush)
+{
+ _dri3_copy_sub_buffer(pdraw, x, y, width, height,
+ __DRI2_THROTTLE_COPYSUBBUFFER, flush);
+}
+
+
+static void
+dri3_copy_drawable(struct dri3_drawable *priv, Drawable dest, Drawable src)
+{
+ struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
+ xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
+
+ if (psc->f)
+ (*psc->f->flush) (priv->driDrawable);
+
+ dri3_copy_area(c,
+ src, dest,
+ dri3_drawable_gc(priv),
+ 0, 0, 0, 0, priv->width, priv->height);
+}
+
+static void
+dri3_wait_x(struct glx_context *gc)
+{
+ struct dri3_drawable *priv = (struct dri3_drawable *)
+ GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
+
+ if (priv == NULL || !priv->have_fake_front)
+ return;
+
+ dri3_copy_drawable(priv, dri3_fake_front_buffer(priv)->pixmap, priv->base.xDrawable);
+}
+
+static void
+dri3_wait_gl(struct glx_context *gc)
+{
+ struct dri3_drawable *priv = (struct dri3_drawable *)
+ GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
+
+ if (priv == NULL || !priv->have_fake_front)
+ return;
+
+ dri3_copy_drawable(priv, priv->base.xDrawable, dri3_fake_front_buffer(priv)->pixmap);
+}
+
+/**
+ * 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)
+{
+ struct glx_context *gc;
+ struct dri3_drawable *pdraw = loaderPrivate;
+ struct dri3_screen *psc;
+
+ if (!pdraw)
+ return;
+
+ if (!pdraw->base.psc)
+ return;
+
+ psc = (struct dri3_screen *) pdraw->base.psc;
+
+ (void) __glXInitialize(psc->base.dpy);
+
+ gc = __glXGetCurrentContext();
+
+ dri3_throttle(psc, pdraw, __DRI2_THROTTLE_FLUSHFRONT);
+
+ dri3_wait_gl(gc);
+}
+
+static __DRIdri3Buffer *
+dri3_alloc_render_buffer(struct glx_screen *glx_screen, Drawable draw, unsigned int format, int width, int height, int depth)
+{
+ struct dri3_screen *psc = (struct dri3_screen *) glx_screen;
+ Display *dpy = glx_screen->dpy;
+ __DRIdri3Buffer *buffer;
+ xcb_connection_t *c = XGetXCBConnection(dpy);
+ xcb_pixmap_t pixmap;
+ xcb_sync_fence_t sync_fence;
+ int32_t *shm_fence;
+ int buffer_fd, fence_fd;
+
+ fence_fd = xshmfence_alloc_shm();
+ if (fence_fd < 0)
+ return NULL;
+ shm_fence = xshmfence_map_shm(fence_fd);
+ if (shm_fence == NULL)
+ goto no_shm_fence;
+
+ buffer = (*psc->dri3->allocateBuffer) (psc->driScreen,
+ format,
+ width,
+ height);
+ if (buffer == NULL)
+ goto no_buffer;
+
+ buffer_fd = (*psc->dri3->bufferToFd)(psc->driScreen, buffer);
+ if (buffer_fd < 0)
+ goto no_buffer_fd;
+
+ xcb_dri3_pixmap_from_buffer(c,
+ (pixmap = xcb_generate_id(c)),
+ draw,
+ buffer->size,
+ width, height, buffer->pitch,
+ depth, buffer->cpp * 8,
+ buffer_fd);
+
+ xcb_dri3_fence_from_fd(c,
+ pixmap,
+ (sync_fence = xcb_generate_id(c)),
+ false,
+ fence_fd);
+
+ buffer->pixmap = pixmap;
+ buffer->sync_fence = sync_fence;
+ buffer->shm_fence = shm_fence;
+ buffer->width = width;
+ buffer->height = height;
+ return buffer;
+
+no_buffer_fd:
+ (*psc->dri3->releaseBuffer)(psc->driScreen, buffer);
+no_buffer:
+ xshmfence_unmap_shm(shm_fence);
+no_shm_fence:
+ close(fence_fd);
+ return NULL;
+}
+
+static void
+dri3_free_render_buffer(struct dri3_drawable *pdraw, __DRIdri3Buffer *buffer)
+{
+ struct dri3_screen *psc = (struct dri3_screen *) pdraw->base.psc;
+ xcb_connection_t *c = XGetXCBConnection(pdraw->base.psc->dpy);
+
+ xcb_free_pixmap(c, buffer->pixmap);
+ xcb_sync_destroy_fence(c, buffer->sync_fence);
+ xshmfence_unmap_shm(buffer->shm_fence);
+ (*psc->dri3->releaseBuffer)(psc->driScreen, buffer);
+}
+
+static int
+dri3_update_drawable(__DRIdrawable *driDrawable, void *loaderPrivate)
+{
+ struct dri3_drawable *priv = loaderPrivate;
+ xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
+
+ /* First time through, go get the current drawable geometry
+ */
+ if (priv->width == 0 || priv->height == 0 || priv->depth == 0) {
+ xcb_get_geometry_cookie_t geom_cookie;
+ xcb_get_geometry_reply_t *geom_reply;
+ struct dri3_screen *psc;
+ xcb_void_cookie_t cookie;
+ xcb_generic_error_t *error;
+
+ cookie = xcb_present_select_input_checked(c,
+ (priv->eid = xcb_generate_id(c)),
+ priv->base.xDrawable,
+ XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY|
+ XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
+
+ if (!priv->present_extension) {
+ priv->present_extension = xcb_get_extension_data(c, &xcb_present_id);
+ if (!priv->present_extension)
+ return false;
+ }
+
+ psc = (struct dri3_screen *) priv->base.psc;
+ priv->special_event = xcb_register_for_special_event(c,
+ priv->present_extension->major_opcode,
+ priv->eid,
+ psc->dri3->stamp(driDrawable));
+
+ geom_cookie = xcb_get_geometry(c, priv->base.xDrawable);
+
+ geom_reply = xcb_get_geometry_reply(c, geom_cookie, NULL);
+
+ if (!geom_reply)
+ return false;
+
+ priv->width = geom_reply->width;
+ priv->height = geom_reply->height;
+ priv->depth = geom_reply->depth;
+ priv->is_pixmap = false;
+
+ free(geom_reply);
+
+ error = xcb_request_check(c, cookie);
+
+ if (error) {
+ if (error->error_code != BadWindow) {
+ free(error);
+ return false;
+ }
+ priv->is_pixmap = true;
+ xcb_unregister_for_special_event(c, priv->special_event);
+ priv->special_event = NULL;
+ }
+ }
+
+ /* Check to see if any configuration changes have occurred
+ * since we were last invoked
+ */
+ if (priv->special_event) {
+ xcb_generic_event_t *ev;
+
+ while ((ev = xcb_check_for_special_event(c, priv->special_event)) != NULL) {
+ xcb_present_generic_event_t *pe = (void *) ev;
+
+ switch (pe->evtype) {
+ case XCB_PRESENT_EVENT_CONFIGURE_NOTIFY: {
+ xcb_configure_notify_event_t *ce = (void *) ev;
+
+ priv->width = ce->width;
+ priv->height = ce->height;
+ break;
+ }
+ case XCB_PRESENT_EVENT_IDLE_NOTIFY:
+ break;
+ }
+ free(ev);
+ }
+ }
+ return true;
+}
+
+static __DRIdri3Buffer *
+dri3_get_pixmap_buffer(__DRIdrawable *driDrawable,
+ unsigned int format,
+ enum __DRI3bufferType buffer_type,
+ void *loaderPrivate)
+{
+ struct dri3_drawable *pdraw = loaderPrivate;
+ __DRIdri3Buffer *buffer = pdraw->buffers[buffer_type];
+ Pixmap pixmap;
+ xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
+ xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
+ int *fds;
+ int buffer_fd;
+ Display *dpy;
+ struct dri3_screen *psc;
+ xcb_connection_t *c;
+ xcb_sync_fence_t sync_fence;
+ int32_t *shm_fence;
+ int fence_fd;
+
+ if (buffer)
+ return buffer;
+
+ pixmap = pdraw->base.xDrawable;
+ psc = (struct dri3_screen *) pdraw->base.psc;
+ dpy = psc->base.dpy;
+ c = XGetXCBConnection(dpy);
+
+ fence_fd = xshmfence_alloc_shm();
+ if (fence_fd < 0)
+ return NULL;
+ shm_fence = xshmfence_map_shm(fence_fd);
+ if (shm_fence == NULL) {
+ close (fence_fd);
+ return NULL;
+ }
+
+ xcb_dri3_fence_from_fd(c,
+ pixmap,
+ (sync_fence = xcb_generate_id(c)),
+ false,
+ fence_fd);
+
+ bp_cookie = xcb_dri3_buffer_from_pixmap(c, pixmap);
+ bp_reply = xcb_dri3_buffer_from_pixmap_reply(c, bp_cookie, NULL);
+ if (!bp_reply)
+ goto no_pixmap;
+ fds = xcb_dri3_buffer_from_pixmap_reply_fds(c, bp_reply);
+ buffer_fd = fds[0];
+ buffer = (*psc->dri3->fdToBuffer)(psc->driScreen,
+ buffer_fd,
+ format,
+ bp_reply->width,
+ bp_reply->height,
+ bp_reply->stride,
+ bp_reply->size);
+ close(buffer_fd);
+ if (!buffer)
+ goto no_pixmap;
+
+ buffer->pixmap = pixmap;
+ buffer->width = bp_reply->width;
+ buffer->height = bp_reply->height;
+ buffer->buffer_type = buffer_type;
+ buffer->shm_fence = shm_fence;
+ buffer->sync_fence = sync_fence;
+
+ pdraw->buffers[buffer_type] = buffer;
+ return buffer;
+
+no_pixmap:
+ xcb_sync_destroy_fence(c, sync_fence);
+ xshmfence_unmap_shm(shm_fence);
+ return NULL;
+}
+
+static __DRIdri3Buffer *
+dri3_get_buffer(__DRIdrawable *driDrawable,
+ unsigned int format,
+ enum __DRI3bufferType buffer_type,
+ void *loaderPrivate)
+{
+ struct dri3_drawable *priv = loaderPrivate;
+ __DRIdri3Buffer *buffer = priv->buffers[buffer_type];
+
+ if (!buffer || buffer->width != priv->width || buffer->height != priv->height) {
+ xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
+ __DRIdri3Buffer *new_buffer;
+
+ /* Allocate the new buffers
+ */
+ new_buffer = dri3_alloc_render_buffer(priv->base.psc,
+ priv->base.xDrawable,
+ format, priv->width, priv->height, priv->depth);
+ if (!new_buffer)
+ return NULL;
+ switch (buffer_type) {
+ case __DRI3_BUFFER_BACK:
+ if (buffer) {
+ dri3_fence_reset(c, new_buffer);
+ dri3_fence_await(c, buffer);
+ dri3_copy_area(c,
+ buffer->pixmap,
+ new_buffer->pixmap,
+ dri3_drawable_gc(priv),
+ 0, 0, 0, 0, priv->width, priv->height);
+ dri3_fence_trigger(c, new_buffer);
+ dri3_free_render_buffer(priv, buffer);
+ dri3_fence_await(c, new_buffer);
+ }
+ break;
+ case __DRI3_BUFFER_FRONT:
+ dri3_fence_reset(c, new_buffer);
+ dri3_copy_area(c,
+ priv->base.xDrawable,
+ new_buffer->pixmap,
+ dri3_drawable_gc(priv),
+ 0, 0, 0, 0, priv->width, priv->height);
+ dri3_fence_trigger(c, new_buffer);
+ dri3_fence_await(c, new_buffer);
+ break;
+ }
+ buffer = new_buffer;
+ buffer->buffer_type = buffer_type;
+ priv->buffers[buffer_type] = buffer;
+ }
+
+ /* Return the requested buffer */
+ return buffer;
+}
+
+static void
+dri3_free_buffer(__DRIdrawable *driDrawable,
+ enum __DRI3bufferType buffer_type,
+ void *loaderPrivate)
+{
+ struct dri3_drawable *priv = loaderPrivate;
+ __DRIdri3Buffer *buffer = priv->buffers[buffer_type];
+
+ if (buffer) {
+ dri3_free_render_buffer(priv, buffer);
+ priv->buffers[buffer_type] = NULL;
+ }
+}
+
+static int
+dri3_get_buffers(__DRIdrawable *driDrawable,
+ int *width, int *height,
+ unsigned int format,
+ void *loaderPrivate,
+ int need_front,
+ int need_back,
+ __DRIdri3Buffer **front,
+ __DRIdri3Buffer **back)
+{
+ struct dri3_drawable *priv = loaderPrivate;
+
+ *front = NULL;
+ *back = NULL;
+
+ if (!dri3_update_drawable(driDrawable, loaderPrivate))
+ return false;
+
+ if (priv->is_pixmap)
+ need_front = 1;
+
+ if (need_front) {
+ if (priv->is_pixmap)
+ *front = dri3_get_pixmap_buffer(driDrawable,
+ format,
+ __DRI3_BUFFER_FRONT,
+ loaderPrivate);
+ else
+ *front = dri3_get_buffer(driDrawable,
+ format,
+ __DRI3_BUFFER_FRONT,
+ loaderPrivate);
+
+ if (!*front)
+ return false;
+ priv->have_fake_front = !priv->is_pixmap;
+ } else {
+ dri3_free_buffer(driDrawable, __DRI3_BUFFER_FRONT, loaderPrivate);
+ priv->have_fake_front = 0;
+ }
+
+ if (need_back) {
+ *back = dri3_get_buffer(driDrawable,
+ format,
+ __DRI3_BUFFER_BACK,
+ loaderPrivate);
+ if (!*back)
+ return false;
+ priv->have_back = 1;
+ } else {
+ dri3_free_buffer(driDrawable, __DRI3_BUFFER_BACK, loaderPrivate);
+ priv->have_back = 0;
+ }
+
+ /* Report back current geometry */
+ *width = priv->width;
+ *height = priv->height;
+ return true;
+}
+
+static int64_t
+dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
+ int64_t remainder, Bool flush)
+{
+ struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
+ struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
+ xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
+ int64_t ret = 0;
+
+ __DRIcontext *ctx = dri3_get_current_context();
+ unsigned flags = __DRI2_FLUSH_DRAWABLE;
+ if (flush)
+ flags |= __DRI2_FLUSH_CONTEXT;
+ dri3_flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
+
+ if (priv->buffers[0] && !priv->is_pixmap) {
+ dri3_fence_reset(c, priv->buffers[0]);
+ dri3_copy_area(c,
+ priv->buffers[0]->pixmap,
+ priv->base.xDrawable,
+ dri3_drawable_gc(priv),
+ 0, 0, 0, 0, priv->width, priv->height);
+ dri3_fence_trigger(c, priv->buffers[0]);
+ if (priv->have_fake_front) {
+ dri3_fence_reset(c, priv->buffers[1]);
+ dri3_copy_area(c,
+ priv->buffers[0]->pixmap,
+ priv->buffers[1]->pixmap,
+ dri3_drawable_gc(priv),
+ 0, 0, 0, 0, priv->width, priv->height);
+ dri3_fence_trigger(c, priv->buffers[1]);
+ }
+ dri3_fence_await(c, priv->buffers[0]);
+ if (priv->have_fake_front)
+ dri3_fence_await(c, priv->buffers[1]);
+ }
+
+ return ret;
+}
+
+static int
+dri3_query_version(Display *dpy, int *major, int *minor)
+{
+ xcb_dri3_query_version_cookie_t cookie;
+ xcb_dri3_query_version_reply_t *reply;
+ xcb_connection_t *c = XGetXCBConnection(dpy);
+ xcb_generic_error_t *error;
+
+ cookie = xcb_dri3_query_version(c,
+ XCB_DRI3_MAJOR_VERSION,
+ XCB_DRI3_MINOR_VERSION);
+ reply = xcb_dri3_query_version_reply(c, cookie, &error);
+ if (!reply) {
+ if (error) {
+ free(error);
+ }
+ return 0;
+ }
+ *major = reply->major_version;
+ *minor = reply->minor_version;
+ free(reply);
+ return 1;
+}
+
+static int
+dri3_open(Display *dpy,
+ Window root,
+ CARD32 provider)
+{
+ xcb_dri3_open_cookie_t cookie;
+ xcb_dri3_open_reply_t *reply;
+ xcb_connection_t *c = XGetXCBConnection(dpy);
+ xcb_generic_error_t *error;
+ int fd;
+
+ cookie = xcb_dri3_open(c,
+ root,
+ provider);
+
+ reply = xcb_dri3_open_reply(c, cookie, &error);
+ if (!reply)
+ return -1;
+
+ if (reply->nfd != 1) {
+ free(reply);
+ return -1;
+ }
+
+ fd = xcb_dri3_open_reply_fds(c, reply)[0];
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ return fd;
+}
+
+
+static void
+dri3_destroy_screen(struct glx_screen *base)
+{
+ struct dri3_screen *psc = (struct dri3_screen *) base;
+
+ /* Free the direct rendering per screen data */
+ (*psc->core->destroyScreen) (psc->driScreen);
+ driDestroyConfigs(psc->driver_configs);
+ close(psc->fd);
+ free(psc);
+}
+
+#if HAS_SBC
+static int
+dri3_set_swap_interval(__GLXDRIdrawable *pdraw, int interval)
+{
+ xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
+ struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
+ GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
+ struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
+
+ if (psc->config)
+ psc->config->configQueryi(psc->driScreen,
+ "vblank_mode", &vblank_mode);
+
+ switch (vblank_mode) {
+ case DRI_CONF_VBLANK_NEVER:
+ if (interval != 0)
+ return GLX_BAD_VALUE;
+ break;
+ case DRI_CONF_VBLANK_ALWAYS_SYNC:
+ if (interval <= 0)
+ return GLX_BAD_VALUE;
+ break;
+ default:
+ break;
+ }
+
+ xcb_dri2_swap_interval(c, priv->base.xDrawable, interval);
+ priv->swap_interval = interval;
+
+ return 0;
+}
+
+static int
+dri3_get_swap_interval(__GLXDRIdrawable *pdraw)
+{
+ struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
+
+ return priv->swap_interval;
+}
+#endif
+
+static const __DRIdri3LoaderExtension dri3LoaderExtension = {
+ {__DRI_DRI3_LOADER, __DRI_DRI3_LOADER_VERSION},
+ .getBuffers = dri3_get_buffers,
+ .flushFrontBuffer = dri3_flush_front_buffer,
+};
+
+static void
+dri3_bind_tex_image(Display * dpy,
+ GLXDrawable drawable,
+ int buffer, const int *attrib_list)
+{
+ struct glx_context *gc = __glXGetCurrentContext();
+ struct dri3_context *pcp = (struct dri3_context *) gc;
+ __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
+ struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
+ struct dri3_screen *psc;
+
+ if (pdraw != NULL) {
+ psc = (struct dri3_screen *) base->psc;
+
+ if (psc->f &&
+ psc->f->base.version >= 3 && psc->f->invalidate)
+ psc->f->invalidate(pdraw->driDrawable);
+
+ XSync(dpy, false);
+ if (psc->texBuffer->base.version >= 2 &&
+ psc->texBuffer->setTexBuffer2 != NULL) {
+ (*psc->texBuffer->setTexBuffer2) (pcp->driContext,
+ pdraw->base.textureTarget,
+ pdraw->base.textureFormat,
+ pdraw->driDrawable);
+ }
+ else {
+ (*psc->texBuffer->setTexBuffer) (pcp->driContext,
+ pdraw->base.textureTarget,
+ pdraw->driDrawable);
+ }
+ }
+}
+
+static void
+dri3_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
+{
+#if __DRI_TEX_BUFFER_VERSION >= 3
+ struct glx_context *gc = __glXGetCurrentContext();
+ struct dri3_context *pcp = (struct dri3_context *) gc;
+ __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
+ struct glx_display *dpyPriv = __glXInitialize(dpy);
+ struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
+ struct dri3_display *pdp =
+ (struct dri3_display *) dpyPriv->dri3Display;
+ struct dri3_screen *psc;
+
+ if (pdraw != NULL) {
+ psc = (struct dri3_screen *) base->psc;
+
+ if (psc->texBuffer->base.version >= 3 &&
+ psc->texBuffer->releaseTexBuffer != NULL) {
+ (*psc->texBuffer->releaseTexBuffer) (pcp->driContext,
+ pdraw->base.textureTarget,
+ pdraw->driDrawable);
+ }
+ }
+#endif
+}
+
+static const struct glx_context_vtable dri3_context_vtable = {
+ dri3_destroy_context,
+ dri3_bind_context,
+ dri3_unbind_context,
+ dri3_wait_gl,
+ dri3_wait_x,
+ DRI_glXUseXFont,
+ dri3_bind_tex_image,
+ dri3_release_tex_image,
+ NULL, /* get_proc_address */
+};
+
+static void
+dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv,
+ const char *driverName)
+{
+// const struct dri3_display *const pdp = (struct dri3_display *) priv->dri3Display;
+ const __DRIextension **extensions;
+ unsigned mask;
+ int i;
+
+ extensions = psc->core->getExtensions(psc->driScreen);
+
+ __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
+ __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
+ __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
+ __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
+
+ /*
+ * GLX_INTEL_swap_event is broken on the server side, where it's
+ * currently unconditionally enabled. This completely breaks
+ * systems running on drivers which don't support that extension.
+ * There's no way to test for its presence on this side, so instead
+ * of disabling it unconditionally, just disable it for drivers
+ * which are known to not support it, or for DDX drivers supporting
+ * only an older (pre-ScheduleSwap) version of DRI2.
+ *
+ * This is a hack which is required until:
+ * http://lists.x.org/archives/xorg-devel/2013-February/035449.html
+ * is merged and updated xserver makes it's way into distros:
+ */
+// if (pdp->swapAvailable && strcmp(driverName, "vmwgfx") != 0) {
+// __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event");
+// }
+
+ mask = psc->dri3->getAPIMask(psc->driScreen);
+
+ __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context");
+ __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile");
+
+ if ((mask & (1 << __DRI_API_GLES2)) != 0)
+ __glXEnableDirectExtension(&psc->base,
+ "GLX_EXT_create_context_es2_profile");
+
+ for (i = 0; extensions[i]; i++) {
+ if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
+ psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
+ __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
+ }
+
+ if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) {
+ psc->f = (__DRI2flushExtension *) extensions[i];
+ /* internal driver extension, no GL extension exposed */
+ }
+
+ if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0))
+ psc->config = (__DRI2configQueryExtension *) extensions[i];
+
+ if (((strcmp(extensions[i]->name, __DRI2_THROTTLE) == 0)))
+ psc->throttle = (__DRI2throttleExtension *) extensions[i];
+
+ if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0)
+ __glXEnableDirectExtension(&psc->base,
+ "GLX_ARB_create_context_robustness");
+ }
+}
+
+static const struct glx_screen_vtable dri3_screen_vtable = {
+ dri3_create_context,
+ dri3_create_context_attribs
+};
+
+static struct glx_screen *
+dri3_create_screen(int screen, struct glx_display * priv)
+{
+ const __DRIconfig **driver_configs;
+ const __DRIextension **extensions;
+ const struct dri3_display *const pdp = (struct dri3_display *)
+ priv->dri3Display;
+ struct dri3_screen *psc;
+ __GLXDRIscreen *psp;
+ struct glx_config *configs = NULL, *visuals = NULL;
+ char *driverName, *deviceName, *tmp;
+ int i;
+
+ psc = calloc(1, sizeof *psc);
+ if (psc == NULL)
+ return NULL;
+
+ psc->fd = -1;
+
+ if (!glx_screen_init(&psc->base, screen, priv)) {
+ free(psc);
+ return NULL;
+ }
+
+ psc->fd = dri3_open(priv->dpy, RootWindow(priv->dpy, screen), None);
+ if (psc->fd < 0) {
+ glx_screen_cleanup(&psc->base);
+ free(psc);
+ InfoMessageF("screen %d does not appear to be DRI3 capable\n", screen);
+ return NULL;
+ }
+ deviceName = NULL;
+
+ driverName = dri3_get_driver_for_fd(psc->fd);
+ if (!driverName) {
+ ErrorMessageF("No driver found\n");
+ goto handle_error;
+ }
+
+ psc->driver = driOpenDriver(driverName);
+ if (psc->driver == NULL) {
+ ErrorMessageF("driver pointer missing\n");
+ goto handle_error;
+ }
+
+ extensions = driGetDriverExtensions(psc->driver, driverName);
+ if (extensions == NULL)
+ goto handle_error;
+
+ for (i = 0; extensions[i]; i++) {
+ if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
+ psc->core = (__DRIcoreExtension *) extensions[i];
+ if (strcmp(extensions[i]->name, __DRI_DRI3) == 0)
+ psc->dri3 = (__DRIdri3Extension *) extensions[i];
+ }
+
+ if (psc->core == NULL || psc->dri3 == NULL) {
+ ErrorMessageF("core dri or dri3 extension not found\n");
+ goto handle_error;
+ }
+
+ psc->driScreen =
+ psc->dri3->createNewScreen2(screen, psc->fd,
+ (const __DRIextension **)
+ &pdp->loader_extensions[0],
+ extensions,
+ &driver_configs, psc);
+
+ if (psc->driScreen == NULL) {
+ ErrorMessageF("failed to create dri screen\n");
+ goto handle_error;
+ }
+
+ dri3_bind_extensions(psc, priv, driverName);
+
+ configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
+ visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
+
+ if (!configs || !visuals)
+ goto handle_error;
+
+ glx_config_destroy_list(psc->base.configs);
+ psc->base.configs = configs;
+ glx_config_destroy_list(psc->base.visuals);
+ psc->base.visuals = visuals;
+
+ psc->driver_configs = driver_configs;
+
+ psc->base.vtable = &dri3_screen_vtable;
+ psp = &psc->vtable;
+ psc->base.driScreen = psp;
+ psp->destroyScreen = dri3_destroy_screen;
+ psp->createDrawable = dri3_create_drawable;
+ psp->swapBuffers = dri3_swap_buffers;
+ psp->getDrawableMSC = NULL;
+ psp->waitForMSC = NULL;
+ psp->waitForSBC = NULL;
+ psp->setSwapInterval = NULL;
+ psp->getSwapInterval = NULL;
+
+#if HAS_SBC
+ if (pdp->driMinor >= 2) {
+ psp->getDrawableMSC = dri3DrawableGetMSC;
+ psp->waitForMSC = dri3WaitForMSC;
+ psp->waitForSBC = dri3WaitForSBC;
+ psp->setSwapInterval = dri3SetSwapInterval;
+ psp->getSwapInterval = dri3GetSwapInterval;
+ __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
+ }
+#endif
+
+ psp->copySubBuffer = dri3_copy_sub_buffer;
+ __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
+
+ free(driverName);
+ free(deviceName);
+
+ tmp = getenv("LIBGL_SHOW_FPS");
+ psc->show_fps = tmp && strcmp(tmp, "1") == 0;
+
+ return &psc->base;
+
+handle_error:
+ CriticalErrorMessageF("failed to load driver: %s\n", driverName);
+
+ if (configs)
+ glx_config_destroy_list(configs);
+ if (visuals)
+ glx_config_destroy_list(visuals);
+ if (psc->driScreen)
+ psc->core->destroyScreen(psc->driScreen);
+ psc->driScreen = NULL;
+ if (psc->fd >= 0)
+ close(psc->fd);
+ if (psc->driver)
+ dlclose(psc->driver);
+
+ free(driverName);
+ free(deviceName);
+ glx_screen_cleanup(&psc->base);
+ free(psc);
+
+ return NULL;
+}
+
+/* Called from __glXFreeDisplayPrivate.
+ */
+static void
+dri3_destroy_display(__GLXDRIdisplay * dpy)
+{
+ free(dpy);
+}
+
+/*
+ * Allocate, initialize and return a __DRIdisplayPrivate object.
+ * This is called from __glXInitialize() when we are given a new
+ * display pointer.
+ */
+_X_HIDDEN __GLXDRIdisplay *
+dri3_create_display(Display * dpy)
+{
+ struct dri3_display *pdp;
+ int i;
+
+ pdp = malloc(sizeof *pdp);
+ if (pdp == NULL)
+ return NULL;
+
+ if (!dri3_query_version(dpy, &pdp->dri3Major, &pdp->dri3Minor)) {
+ free(pdp);
+ return NULL;
+ }
+
+ pdp->base.destroyDisplay = dri3_destroy_display;
+ pdp->base.createScreen = dri3_create_screen;
+
+ i = 0;
+
+ pdp->loader_extensions[i++] = &dri3LoaderExtension.base;
+
+ pdp->loader_extensions[i++] = &systemTimeExtension.base;
+
+ pdp->loader_extensions[i++] = NULL;
+
+ return &pdp->base;
+}
+
+#endif /* GLX_DIRECT_RENDERING */
diff --git a/src/glx/dri3_priv.h b/src/glx/dri3_priv.h
new file mode 100644
index 0000000..8703b39
--- /dev/null
+++ b/src/glx/dri3_priv.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright © 2013 Keith Packard
+ *
+ * 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.
+ */
+
+/* This file was derived from dri2_priv.h which carries the following
+ * copyright:
+ *
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL 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 PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Authors:
+ * Kristian Høgsberg (krh at redhat.com)
+ */
+
+#include <xcb/xcb.h>
+#include <xcb/dri3.h>
+#include <xcb/sync.h>
+
+/* From xmlpool/options.h, user exposed so should be stable */
+#define DRI_CONF_VBLANK_NEVER 0
+#define DRI_CONF_VBLANK_DEF_INTERVAL_0 1
+#define DRI_CONF_VBLANK_DEF_INTERVAL_1 2
+#define DRI_CONF_VBLANK_ALWAYS_SYNC 3
+
+struct dri3_display
+{
+ __GLXDRIdisplay base;
+
+ const __DRIextension *loader_extensions[8];
+
+ /* DRI3 bits */
+ int dri3Major;
+ int dri3Minor;
+};
+
+struct dri3_screen {
+ struct glx_screen base;
+
+ __DRIscreen *driScreen;
+ __GLXDRIscreen vtable;
+
+ const __DRIdri3Extension *dri3;
+ const __DRIcoreExtension *core;
+ const __DRI2flushExtension *f;
+ const __DRI2configQueryExtension *config;
+ const __DRItexBufferExtension *texBuffer;
+ const __DRI2throttleExtension *throttle;
+ const __DRIconfig **driver_configs;
+
+ void *driver;
+ int fd;
+
+ Bool show_fps;
+};
+
+struct dri3_context
+{
+ struct glx_context base;
+ __DRIcontext *driContext;
+};
+
+struct dri3_drawable
+{
+ __GLXDRIdrawable base;
+ __DRIdrawable *driDrawable;
+ int width, height;
+ int swap_interval;
+ uint8_t have_back;
+ uint8_t have_fake_front;
+ uint8_t is_pixmap;
+
+ uint64_t previous_time;
+ unsigned frames;
+
+ __DRIdri3Buffer *buffers[2];
+ int depth;
+
+ xcb_present_event_t eid;
+ xcb_gcontext_t gc;
+ const xcb_query_extension_reply_t *dri3_extension;
+ const xcb_query_extension_reply_t *present_extension;
+ xcb_special_event_t *special_event;
+};
+
+char *
+dri3_get_driver_for_fd(int fd);
diff --git a/src/glx/glxclient.h b/src/glx/glxclient.h
index 81ae792..ec168aa 100644
--- a/src/glx/glxclient.h
+++ b/src/glx/glxclient.h
@@ -150,6 +150,7 @@ extern __GLXDRIdisplay *dri2CreateDisplay(Display * dpy);
extern void dri2InvalidateBuffers(Display *dpy, XID drawable);
extern unsigned dri2GetSwapEventType(Display *dpy, XID drawable);
+extern __GLXDRIdisplay *dri3_create_display(Display * dpy);
/*
** Functions to obtain driver configuration information from a direct
@@ -582,6 +583,7 @@ struct glx_display
__GLXDRIdisplay *driswDisplay;
__GLXDRIdisplay *driDisplay;
__GLXDRIdisplay *dri2Display;
+ __GLXDRIdisplay *dri3Display;
#endif
};
diff --git a/src/glx/glxext.c b/src/glx/glxext.c
index bea1ccb..c6e4d9f 100644
--- a/src/glx/glxext.c
+++ b/src/glx/glxext.c
@@ -770,7 +770,9 @@ AllocAndFetchScreenConfigs(Display * dpy, struct glx_display * priv)
for (i = 0; i < screens; i++, psc++) {
psc = NULL;
#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
- if (priv->dri2Display)
+ if (priv->dri3Display)
+ psc = (*priv->dri3Display->createScreen) (i, priv);
+ if (psc == NULL && priv->dri2Display)
psc = (*priv->dri2Display->createScreen) (i, priv);
if (psc == NULL && priv->driDisplay)
psc = (*priv->driDisplay->createScreen) (i, priv);
@@ -863,6 +865,8 @@ __glXInitialize(Display * dpy)
** (e.g., those called in AllocAndFetchScreenConfigs).
*/
if (glx_direct && glx_accel) {
+ if (!getenv("LIBGL_DRI3_DISABLE"))
+ dpyPriv->dri3Display = dri3_create_display(dpy);
dpyPriv->dri2Display = dri2CreateDisplay(dpy);
dpyPriv->driDisplay = driCreateDisplay(dpy);
}
diff --git a/src/mesa/drivers/dri/common/dri_util.c b/src/mesa/drivers/dri/common/dri_util.c
index 539fb4b..9b24e54 100644
--- a/src/mesa/drivers/dri/common/dri_util.c
+++ b/src/mesa/drivers/dri/common/dri_util.c
@@ -729,7 +729,7 @@ const __DRIcoreExtension driCoreExtension = {
.createNewDrawable = NULL,
.destroyDrawable = driDestroyDrawable,
.swapBuffers = driSwapBuffers, /* swrast */
- .createNewContext = dri2CreateNewContext, /* swrast */
+ .createNewContext = driCreateNewContext, /* swrast */
.copyContext = driCopyContext,
.destroyContext = driDestroyContext,
.bindContext = driBindContext,
@@ -747,16 +747,16 @@ const __DRIdri2Extension driDRI2Extension = {
.createNewContextForAPI = driCreateNewContextForAPI,
.allocateBuffer = dri2AllocateBuffer,
.releaseBuffer = dri2ReleaseBuffer,
- .createContextAttribs = driCreateContextAttribs
+ .createContextAttribs = driCreateContextAttribs,
.createNewScreen2 = dri2CreateNewScreen2,
};
const __DRIswrastExtension driSWRastExtension = {
{ __DRI_SWRAST, 4 },
driSWRastCreateNewScreen,
- dri2CreateNewDrawable,
- dri2CreateNewContextForAPI,
- dri2CreateContextAttribs,
+ driCreateNewDrawable,
+ driCreateNewContextForAPI,
+ driCreateContextAttribs,
driSWRastCreateNewScreen2,
};
@@ -792,3 +792,156 @@ driUpdateFramebufferSize(struct gl_context *ctx, const __DRIdrawable *dPriv)
assert(fb->Height == dPriv->h);
}
}
+
+/*
+ * Copyright © 2013 Keith Packard
+ *
+ * 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.
+ */
+
+uint32_t *
+dri3DrawableStamp(__DRIdrawable *drawable)
+{
+ return &drawable->dri2.stamp;
+}
+
+static __DRIdri3Buffer *
+dri3AllocateBuffer(__DRIscreen *screen, unsigned int depth, int width, int height)
+{
+ return (*dri3DriverAPI.allocate_buffer) (screen, depth, width, height);
+}
+
+static void
+dri3ReleaseBuffer(__DRIscreen *screen, __DRIdri3Buffer *buffer)
+{
+ return (*dri3DriverAPI.release_buffer) (screen, buffer);
+}
+
+static int
+dri3BufferToFd(__DRIscreen *screen, __DRIdri3Buffer *buffer)
+{
+ return (*dri3DriverAPI.buffer_to_fd)(screen, buffer);
+}
+
+static __DRIdri3Buffer *
+dri3FdToBuffer(__DRIscreen *screen, int fd, unsigned int format, int width, int height, int stride, unsigned int size)
+{
+ return (*dri3DriverAPI.fd_to_buffer)(screen, fd, format, width, height, stride, size);
+}
+
+static uint32_t *
+dri3Stamp(__DRIdrawable *drawable)
+{
+ return (*dri3DriverAPI.stamp)(drawable);
+}
+
+PUBLIC const char __dri3ConfigOptions[] =
+ DRI_CONF_BEGIN
+ DRI_CONF_SECTION_PERFORMANCE
+ DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_1)
+ DRI_CONF_SECTION_END
+ DRI_CONF_END;
+
+static __DRIscreen *
+dri3CreateNewScreen2(int scrn, int fd,
+ const __DRIextension **extensions,
+ const __DRIextension **driver_extensions,
+ const __DRIconfig ***driver_configs, void *data)
+{
+ static const __DRIextension *emptyExtensionList[] = { NULL };
+ __DRIscreen *psp;
+ drmVersionPtr version;
+
+ psp = calloc(1, sizeof(*psp));
+ if (!psp)
+ return NULL;
+
+ /* By default, use the global driDriverAPI symbol (non-megadrivers). */
+ psp->driver = globalDriverAPI;
+
+ /* If the driver exposes its vtable through its extensions list
+ * (megadrivers), use that instead.
+ */
+ if (driver_extensions) {
+ for (int i = 0; driver_extensions[i]; i++) {
+ if (strcmp(driver_extensions[i]->name, __DRI_DRIVER_VTABLE) == 0) {
+ psp->driver =
+ ((__DRIDriverVtableExtension *)driver_extensions[i])->vtable;
+ }
+ }
+ }
+
+ setupLoaderExtensions(psp, extensions);
+ setup_dri3_loader_extensions(psp, extensions);
+
+ version = drmGetVersion(fd);
+ if (version) {
+ psp->drm_version.major = version->version_major;
+ psp->drm_version.minor = version->version_minor;
+ psp->drm_version.patch = version->version_patchlevel;
+ drmFreeVersion(version);
+ }
+
+ psp->loaderPrivate = data;
+
+ psp->extensions = emptyExtensionList;
+ psp->fd = fd;
+ psp->myNum = scrn;
+
+ psp->api_mask = (1 << __DRI_API_OPENGL);
+
+ *driver_configs = psp->driver->InitScreen(psp);
+ if (*driver_configs == NULL) {
+ free(psp);
+ return NULL;
+ }
+
+ driParseOptionInfo(&psp->optionInfo, __dri3ConfigOptions);
+ driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum, "dri3");
+
+ return psp;
+}
+
+void
+setup_dri3_loader_extensions(__DRIscreen *psp,
+ const __DRIextension *const*extensions)
+{
+ int i;
+
+ for (i = 0; extensions[i]; i++) {
+ if (strcmp(extensions[i]->name, __DRI_DRI3_LOADER) == 0)
+ psp->dri3.loader = (__DRIdri3LoaderExtension *) extensions[i];
+ }
+}
+
+/** DRI3 interface */
+const __DRIdri3Extension driDRI3Extension = {
+ .base = { __DRI_DRI3, 1 },
+
+ .createNewScreen2 = dri3CreateNewScreen2,
+ .createNewDrawable = driCreateNewDrawable,
+ .createNewContext = driCreateNewContext,
+ .getAPIMask = driGetAPIMask,
+ .createContextAttribs = driCreateContextAttribs,
+ .allocateBuffer = dri3AllocateBuffer,
+ .releaseBuffer = dri3ReleaseBuffer,
+ .bufferToFd = dri3BufferToFd,
+ .fdToBuffer = dri3FdToBuffer,
+ .stamp = dri3Stamp,
+};
diff --git a/src/mesa/drivers/dri/common/dri_util.h b/src/mesa/drivers/dri/common/dri_util.h
index 5b56061..9e96282 100644
--- a/src/mesa/drivers/dri/common/dri_util.h
+++ b/src/mesa/drivers/dri/common/dri_util.h
@@ -174,6 +174,10 @@ struct __DRIscreenRec {
__DRIuseInvalidateExtension *useInvalidate;
} dri2;
+ struct {
+ __DRIdri3LoaderExtension *loader;
+ } dri3;
+
driOptionCache optionInfo;
driOptionCache optionCache;
@@ -277,4 +281,23 @@ dri2InvalidateDrawable(__DRIdrawable *drawable);
extern void
driUpdateFramebufferSize(struct gl_context *ctx, const __DRIdrawable *dPriv);
+uint32_t *
+dri3DrawableStamp(__DRIdrawable *drawable);
+
+void
+setup_dri3_loader_extensions(__DRIscreen *psp,
+ const __DRIextension *const*extensions);
+
+struct __dri3DriverAPIRec {
+ __DRIdri3AllocateBuffer allocate_buffer;
+ __DRIdri3ReleaseBuffer release_buffer;
+ __DRIdri3BufferToFd buffer_to_fd;
+ __DRIdri3FdToBuffer fd_to_buffer;
+ __DRIdri3Stamp stamp;
+};
+
+extern const struct __dri3DriverAPIRec dri3DriverAPI;
+
+extern const __DRIdri3Extension driDRI3Extension;
+
#endif /* _DRI_UTIL_H_ */
diff --git a/src/mesa/drivers/dri/i915/intel_context.c b/src/mesa/drivers/dri/i915/intel_context.c
index 1798bc7..b99ff09 100644
--- a/src/mesa/drivers/dri/i915/intel_context.c
+++ b/src/mesa/drivers/dri/i915/intel_context.c
@@ -91,6 +91,8 @@ intelGetString(struct gl_context * ctx, GLenum name)
}
}
+#define flushFront(screen) ((screen)->dri3.loader ? (screen)->dri3.loader->flushFrontBuffer : (screen)->dri2.loader->flushFrontBuffer)
+
static void
intel_flush_front(struct gl_context *ctx)
{
@@ -100,11 +102,10 @@ intel_flush_front(struct gl_context *ctx)
__DRIscreen *const screen = intel->intelScreen->driScrnPriv;
if (intel->front_buffer_dirty && _mesa_is_winsys_fbo(ctx->DrawBuffer)) {
- if (screen->dri2.loader->flushFrontBuffer != NULL &&
+ if (flushFront(screen) &&
driDrawable &&
driDrawable->loaderPrivate) {
- screen->dri2.loader->flushFrontBuffer(driDrawable,
- driDrawable->loaderPrivate);
+ flushFront(screen)(driDrawable, driDrawable->loaderPrivate);
/* We set the dirty bit in intel_prepare_render() if we're
* front buffer rendering once we get there.
@@ -114,6 +115,9 @@ intel_flush_front(struct gl_context *ctx)
}
}
+static void
+intel_update_dri3_buffers(struct intel_context *intel, __DRIdrawable *drawable);
+
static unsigned
intel_bits_per_pixel(const struct intel_renderbuffer *rb)
{
@@ -194,7 +198,10 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
if (unlikely(INTEL_DEBUG & DEBUG_DRI))
fprintf(stderr, "enter %s, drawable %p\n", __func__, drawable);
- intel_update_dri2_buffers(intel, drawable);
+ if (screen->dri3.loader)
+ intel_update_dri3_buffers(intel, drawable);
+ else
+ intel_update_dri2_buffers(intel, drawable);
driUpdateFramebufferSize(&intel->ctx, drawable);
}
@@ -787,3 +794,97 @@ intel_process_dri2_buffer(struct intel_context *intel,
region);
intel_region_release(®ion);
}
+
+/**
+ * \brief Query DRI3 to obtain a DRIdrawable's buffers.
+ *
+ * To determine which DRI buffers to request, examine the renderbuffers
+ * attached to the drawable's framebuffer. Then request the buffers with
+ * dri3
+ *
+ * This is called from intel_update_renderbuffers().
+ *
+ * \param drawable Drawable whose buffers are queried.
+ * \param buffers [out] List of buffers returned by DRI2 query.
+ * \param buffer_count [out] Number of buffers returned.
+ *
+ * \see intel_update_renderbuffers()
+ */
+
+static void
+intel_update_dri3_buffer(struct intel_context *intel,
+ __DRIdrawable *drawable,
+ struct intel_renderbuffer *rb,
+ __DRIdri3Buffer *buffer)
+{
+ struct intel_region *region = buffer->driverPrivate;
+
+ if (!rb || !region)
+ return;
+
+ unsigned num_samples = rb->Base.Base.NumSamples;
+
+ if (rb->mt &&
+ rb->mt->region &&
+ rb->mt->region == region)
+ return;
+
+ intel_miptree_release(&rb->mt);
+ rb->mt = intel_miptree_create_for_dri3_buffer(intel,
+ buffer->buffer_type,
+ intel_rb_format(rb),
+ num_samples,
+ region);
+}
+
+
+static void
+intel_update_dri3_buffers(struct intel_context *intel, __DRIdrawable *drawable)
+{
+ struct gl_framebuffer *fb = drawable->driverPrivate;
+ __DRIscreen *screen = intel->intelScreen->driScrnPriv;
+ struct intel_renderbuffer *front_rb;
+ struct intel_renderbuffer *back_rb;
+ int need_front = 0, need_back = 0;
+ __DRIdri3Buffer *front, *back;
+ unsigned int format;
+
+ front_rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT);
+ back_rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT);
+
+ if (back_rb)
+ format = intel_rb_format(back_rb);
+ else if (front_rb)
+ format = intel_rb_format(front_rb);
+ else
+ return;
+
+ if ((intel->is_front_buffer_rendering || intel->is_front_buffer_reading || !back_rb) && front_rb)
+ need_front = 1;
+
+ if (back_rb)
+ need_back = 1;
+
+ (*screen->dri3.loader->getBuffers) (drawable,
+ &drawable->w,
+ &drawable->h,
+ format,
+ drawable->loaderPrivate,
+ need_front,
+ need_back,
+ &front,
+ &back);
+
+ if (front) {
+ assert(front_rb);
+ intel_update_dri3_buffer(intel,
+ drawable,
+ front_rb,
+ front);
+ }
+ if (back)
+ intel_update_dri3_buffer(intel,
+ drawable,
+ back_rb,
+ back);
+}
diff --git a/src/mesa/drivers/dri/i915/intel_mipmap_tree.c b/src/mesa/drivers/dri/i915/intel_mipmap_tree.c
index 8432b6d..97dcf80 100644
--- a/src/mesa/drivers/dri/i915/intel_mipmap_tree.c
+++ b/src/mesa/drivers/dri/i915/intel_mipmap_tree.c
@@ -322,6 +322,39 @@ intel_miptree_create_for_dri2_buffer(struct intel_context *intel,
return mt;
}
+/**
+ * For a singlesample DRI3 buffer, this simply wraps the given region with a miptree.
+ *
+ * For a multisample DRI3 buffer, this wraps the given region with
+ * a singlesample miptree, then creates a multisample miptree into which the
+ * singlesample miptree is embedded as a child.
+ */
+struct intel_mipmap_tree*
+intel_miptree_create_for_dri3_buffer(struct intel_context *intel,
+ enum __DRI3bufferType buffer_type,
+ gl_format format,
+ uint32_t num_samples,
+ struct intel_region *region)
+{
+ struct intel_mipmap_tree *mt = NULL;
+
+ /* Only the front and back buffers, which are color buffers, are allocated
+ * through DRI3.
+ */
+ assert(_mesa_get_format_base_format(format) == GL_RGB ||
+ _mesa_get_format_base_format(format) == GL_RGBA);
+
+ mt = intel_miptree_create_for_bo(intel,
+ region->bo,
+ format,
+ 0,
+ region->width,
+ region->height,
+ region->pitch,
+ region->tiling);
+ return mt;
+}
+
struct intel_mipmap_tree*
intel_miptree_create_for_renderbuffer(struct intel_context *intel,
gl_format format,
diff --git a/src/mesa/drivers/dri/i915/intel_mipmap_tree.h b/src/mesa/drivers/dri/i915/intel_mipmap_tree.h
index 1142af6..299ae99 100644
--- a/src/mesa/drivers/dri/i915/intel_mipmap_tree.h
+++ b/src/mesa/drivers/dri/i915/intel_mipmap_tree.h
@@ -32,6 +32,7 @@
#include "intel_screen.h"
#include "intel_regions.h"
+#include "GL/internal/dri_interface.h"
#ifdef __cplusplus
extern "C" {
@@ -258,6 +259,13 @@ intel_miptree_create_for_dri2_buffer(struct intel_context *intel,
gl_format format,
struct intel_region *region);
+struct intel_mipmap_tree*
+intel_miptree_create_for_dri3_buffer(struct intel_context *intel,
+ enum __DRI3bufferType buffer_type,
+ gl_format format,
+ uint32_t num_samples,
+ struct intel_region *region);
+
/**
* Create a miptree appropriate as the storage for a non-texture renderbuffer.
* The miptree has the following properties:
diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c
index c213b31..ecf5bd7 100644
--- a/src/mesa/drivers/dri/i965/brw_context.c
+++ b/src/mesa/drivers/dri/i965/brw_context.c
@@ -151,6 +151,8 @@ intelInvalidateState(struct gl_context * ctx, GLuint new_state)
brw->NewGLState |= new_state;
}
+#define flushFront(screen) ((screen)->dri3.loader ? (screen)->dri3.loader->flushFrontBuffer : (screen)->dri2.loader->flushFrontBuffer)
+
static void
intel_flush_front(struct gl_context *ctx)
{
@@ -160,8 +162,7 @@ intel_flush_front(struct gl_context *ctx)
__DRIscreen *const screen = brw->intelScreen->driScrnPriv;
if (brw->front_buffer_dirty && _mesa_is_winsys_fbo(ctx->DrawBuffer)) {
- if (screen->dri2.loader->flushFrontBuffer != NULL &&
- driDrawable &&
+ if (flushFront(screen) && driDrawable &&
driDrawable->loaderPrivate) {
/* Resolve before flushing FAKE_FRONT_LEFT to FRONT_LEFT.
@@ -174,8 +175,7 @@ intel_flush_front(struct gl_context *ctx)
intel_resolve_for_dri2_flush(brw, driDrawable);
intel_batchbuffer_flush(brw);
- screen->dri2.loader->flushFrontBuffer(driDrawable,
- driDrawable->loaderPrivate);
+ flushFront(screen)(driDrawable, driDrawable->loaderPrivate);
/* We set the dirty bit in intel_prepare_render() if we're
* front buffer rendering once we get there.
@@ -930,6 +930,9 @@ intel_process_dri2_buffer(struct brw_context *brw,
const char *buffer_name);
static void
+intel_update_dri3_buffers(struct brw_context *brw, __DRIdrawable *drawable);
+
+static void
intel_update_dri2_buffers(struct brw_context *brw, __DRIdrawable *drawable)
{
struct gl_framebuffer *fb = drawable->driverPrivate;
@@ -989,6 +992,7 @@ void
intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
{
struct brw_context *brw = context->driverPrivate;
+ __DRIscreen *screen = brw->intelScreen->driScrnPriv;
/* Set this up front, so that in case our buffers get invalidated
* while we're getting new buffers, we don't clobber the stamp and
@@ -998,7 +1002,10 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
if (unlikely(INTEL_DEBUG & DEBUG_DRI))
fprintf(stderr, "enter %s, drawable %p\n", __func__, drawable);
- intel_update_dri2_buffers(brw, drawable);
+ if (screen->dri3.loader)
+ intel_update_dri3_buffers(brw, drawable);
+ else
+ intel_update_dri2_buffers(brw, drawable);
driUpdateFramebufferSize(&brw->ctx, drawable);
}
@@ -1204,3 +1211,96 @@ intel_process_dri2_buffer(struct brw_context *brw,
region);
intel_region_release(®ion);
}
+
+/**
+ * \brief Query DRI3 to obtain a DRIdrawable's buffers.
+ *
+ * To determine which DRI buffers to request, examine the renderbuffers
+ * attached to the drawable's framebuffer. Then request the buffers with
+ * dri3
+ *
+ * This is called from intel_update_renderbuffers().
+ *
+ * \param drawable Drawable whose buffers are queried.
+ * \param buffers [out] List of buffers returned by DRI2 query.
+ * \param buffer_count [out] Number of buffers returned.
+ *
+ * \see intel_update_renderbuffers()
+ */
+
+static void
+intel_update_dri3_buffer(struct brw_context *intel,
+ __DRIdrawable *drawable,
+ struct intel_renderbuffer *rb,
+ __DRIdri3Buffer *buffer)
+{
+ struct intel_region *region = buffer->driverPrivate;
+
+ if (!rb || !region)
+ return;
+
+ unsigned num_samples = rb->Base.Base.NumSamples;
+
+ if (rb->mt &&
+ rb->mt->region &&
+ rb->mt->region == region)
+ return;
+
+ intel_miptree_release(&rb->mt);
+ rb->mt = intel_miptree_create_for_dri3_buffer(intel,
+ buffer->buffer_type,
+ intel_rb_format(rb),
+ num_samples,
+ region);
+}
+
+static void
+intel_update_dri3_buffers(struct brw_context *brw, __DRIdrawable *drawable)
+{
+ struct gl_framebuffer *fb = drawable->driverPrivate;
+ __DRIscreen *screen = brw->intelScreen->driScrnPriv;
+ struct intel_renderbuffer *front_rb;
+ struct intel_renderbuffer *back_rb;
+ int need_front = 0, need_back = 0;
+ __DRIdri3Buffer *front, *back;
+ unsigned int format;
+
+ front_rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT);
+ back_rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT);
+
+ if (back_rb)
+ format = intel_rb_format(back_rb);
+ else if (front_rb)
+ format = intel_rb_format(front_rb);
+ else
+ return;
+
+ if ((brw->is_front_buffer_rendering || brw->is_front_buffer_reading || !back_rb) && front_rb)
+ need_front = 1;
+
+ if (back_rb)
+ need_back = 1;
+
+ (*screen->dri3.loader->getBuffers) (drawable,
+ &drawable->w,
+ &drawable->h,
+ format,
+ drawable->loaderPrivate,
+ need_front,
+ need_back,
+ &front,
+ &back);
+
+ if (front) {
+ assert(front_rb);
+ intel_update_dri3_buffer(brw,
+ drawable,
+ front_rb,
+ front);
+ }
+ if (back)
+ intel_update_dri3_buffer(brw,
+ drawable,
+ back_rb,
+ back);
+}
diff --git a/src/mesa/drivers/dri/i965/intel_mipmap_tree.c b/src/mesa/drivers/dri/i965/intel_mipmap_tree.c
index 2f5e04f..5c62a74 100644
--- a/src/mesa/drivers/dri/i965/intel_mipmap_tree.c
+++ b/src/mesa/drivers/dri/i965/intel_mipmap_tree.c
@@ -725,6 +725,67 @@ intel_miptree_create_for_dri2_buffer(struct brw_context *brw,
return multisample_mt;
}
+/**
+ * For a singlesample DRI3 buffer, this simply wraps the given region with a miptree.
+ *
+ * For a multisample DRI3 buffer, this wraps the given region with
+ * a singlesample miptree, then creates a multisample miptree into which the
+ * singlesample miptree is embedded as a child.
+ */
+struct intel_mipmap_tree*
+intel_miptree_create_for_dri3_buffer(struct brw_context *intel,
+ enum __DRI3bufferType buffer_type,
+ gl_format format,
+ uint32_t num_samples,
+ struct intel_region *region)
+{
+ struct intel_mipmap_tree *singlesample_mt = NULL;
+ struct intel_mipmap_tree *multisample_mt = NULL;
+
+ /* Only the front and back buffers, which are color buffers, are allocated
+ * through DRI3.
+ */
+ assert(_mesa_get_format_base_format(format) == GL_RGB ||
+ _mesa_get_format_base_format(format) == GL_RGBA);
+
+ singlesample_mt = intel_miptree_create_for_bo(intel,
+ region->bo,
+ format,
+ 0,
+ region->width,
+ region->height,
+ region->pitch,
+ region->tiling);
+ if (!singlesample_mt)
+ return NULL;
+
+ intel_region_reference(&singlesample_mt->region, region);
+
+ if (num_samples == 0)
+ return singlesample_mt;
+
+ multisample_mt = intel_miptree_create_for_renderbuffer(intel,
+ format,
+ region->width,
+ region->height,
+ num_samples);
+ if (!multisample_mt) {
+ intel_miptree_release(&singlesample_mt);
+ return NULL;
+ }
+
+ multisample_mt->singlesample_mt = singlesample_mt;
+ multisample_mt->need_downsample = false;
+
+ intel_region_reference(&multisample_mt->region, region);
+
+ if (intel->is_front_buffer_rendering && buffer_type == __DRI3_BUFFER_FRONT) {
+ intel_miptree_upsample(intel, multisample_mt);
+ }
+
+ return multisample_mt;
+}
+
struct intel_mipmap_tree*
intel_miptree_create_for_renderbuffer(struct brw_context *brw,
gl_format format,
diff --git a/src/mesa/drivers/dri/i965/intel_mipmap_tree.h b/src/mesa/drivers/dri/i965/intel_mipmap_tree.h
index d718125..0c1922d 100644
--- a/src/mesa/drivers/dri/i965/intel_mipmap_tree.h
+++ b/src/mesa/drivers/dri/i965/intel_mipmap_tree.h
@@ -32,6 +32,7 @@
#include "intel_regions.h"
#include "intel_resolve_map.h"
+#include <GL/internal/dri_interface.h>
#ifdef __cplusplus
extern "C" {
@@ -529,6 +530,13 @@ intel_miptree_create_for_dri2_buffer(struct brw_context *brw,
uint32_t num_samples,
struct intel_region *region);
+struct intel_mipmap_tree*
+intel_miptree_create_for_dri3_buffer(struct brw_context *intel,
+ enum __DRI3bufferType buffer_type,
+ gl_format format,
+ uint32_t num_samples,
+ struct intel_region *region);
+
/**
* Create a miptree appropriate as the storage for a non-texture renderbuffer.
* The miptree has the following properties:
diff --git a/src/mesa/drivers/dri/i965/intel_screen.c b/src/mesa/drivers/dri/i965/intel_screen.c
index 0bd0789..b975142 100644
--- a/src/mesa/drivers/dri/i965/intel_screen.c
+++ b/src/mesa/drivers/dri/i965/intel_screen.c
@@ -1225,7 +1225,8 @@ __DRIconfig **intelInitScreen2(__DRIscreen *psp)
{
struct intel_screen *intelScreen;
- if (psp->dri2.loader->base.version <= 2 ||
+ if (psp->dri3.loader) {
+ } else if (psp->dri2.loader->base.version <= 2 ||
psp->dri2.loader->getBuffersWithFormat == NULL) {
fprintf(stderr,
"\nERROR! DRI2 loader with getBuffersWithFormat() "
@@ -1313,6 +1314,109 @@ intelReleaseBuffer(__DRIscreen *screen, __DRIbuffer *buffer)
free(intelBuffer);
}
+/*
+ * DRI3 bits
+ */
+
+static __DRIdri3Buffer *
+intel_dri3_allocate_buffer(__DRIscreen *screen,
+ unsigned int format,
+ int width,
+ int height)
+{
+ struct intel_screen *intel_screen = screen->driverPrivate;
+ __DRIdri3Buffer *buffer;
+ struct intel_region *region;
+
+ buffer = calloc(1, sizeof *buffer);
+ if (buffer == NULL)
+ return NULL;
+
+ /* The front and back buffers are color buffers, which are X tiled. */
+ region = intel_region_alloc(intel_screen,
+ I915_TILING_X,
+ _mesa_get_format_bytes(format),
+ width,
+ height,
+ true);
+
+ if (region == NULL) {
+ free(buffer);
+ return NULL;
+ }
+
+ buffer->cpp = region->cpp;
+ buffer->pitch = region->pitch;
+ buffer->size = region->bo->size;
+ buffer->width = width;
+ buffer->height = height;
+ buffer->driverPrivate = region;
+
+ return buffer;
+}
+
+static void
+intel_dri3_release_buffer(__DRIscreen *screen,
+ __DRIdri3Buffer *buffer)
+{
+ intel_region_release((struct intel_region **) &buffer->driverPrivate);
+ free(buffer);
+}
+
+static int
+intel_dri3_buffer_to_fd(__DRIscreen *screen,
+ __DRIdri3Buffer *buffer)
+{
+ struct intel_screen *intel_screen = screen->driverPrivate;
+ struct intel_region *region = buffer->driverPrivate;
+
+ if (!region)
+ return -1;
+ return intel_fd_for_region(intel_screen, region);
+}
+
+static __DRIdri3Buffer *
+intel_dri3_fd_to_buffer(__DRIscreen *screen,
+ int fd,
+ unsigned int format,
+ int width,
+ int height,
+ int pitch,
+ unsigned int size)
+{
+ struct intel_screen *intel_screen = screen->driverPrivate;
+ struct intel_region *region;
+ __DRIdri3Buffer *buffer;
+
+ buffer = calloc(1, sizeof *buffer);
+ if (!buffer)
+ return NULL;
+
+ region = intel_region_alloc_for_fd(intel_screen,
+ _mesa_get_format_bytes(format),
+ width, height, pitch, size,
+ fd, "buffer");
+ if (region == NULL) {
+ free (buffer);
+ return NULL;
+ }
+
+ buffer->cpp = region->cpp;
+ buffer->pitch = region->pitch;
+ buffer->width = width;
+ buffer->height = height;
+ buffer->driverPrivate = region;
+
+ return buffer;
+}
+
+const struct __dri3DriverAPIRec dri3DriverAPI = {
+ .allocate_buffer = intel_dri3_allocate_buffer,
+ .release_buffer = intel_dri3_release_buffer,
+ .buffer_to_fd = intel_dri3_buffer_to_fd,
+ .fd_to_buffer = intel_dri3_fd_to_buffer,
+ .stamp = dri3DrawableStamp,
+};
static const struct __DriverAPIRec brw_driver_api = {
.InitScreen = intelInitScreen2,
@@ -1334,6 +1438,7 @@ static const struct __DRIDriverVtableExtensionRec brw_vtable = {
static const __DRIextension *brw_driver_extensions[] = {
&driCoreExtension.base,
+ &driDRI3Extension.base,
&driDRI2Extension.base,
&brw_vtable.base,
&brw_config_options.base,
--
1.8.4.2
------------------------------------------------------------------------------
Android is increasing in popularity, but the open development platform that
developers love is also attractive to malware creators. Download this white
paper to learn more about secure code signing practices that can help keep
Android apps secure.
http://pubads.g.doubleclick.net/gampad/clk?id=65839951&iu=/4140/ostg.clktrk
--
_______________________________________________
Dri-devel mailing list
Dri-devel at lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel
More information about the dri-devel
mailing list