<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">2015-07-01 23:31 GMT+08:00 Boyan Ding <span dir="ltr"><<a href="mailto:boyan.j.ding@gmail.com" target="_blank">boyan.j.ding@gmail.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Signed-off-by: Boyan Ding <<a href="mailto:boyan.j.ding@gmail.com">boyan.j.ding@gmail.com</a>><br>
---<br>
<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a> | 3 +<br>
src/egl/drivers/dri2/Makefile.am | 5 +<br>
src/egl/drivers/dri2/egl_dri2.c | 65 +-<br>
src/egl/drivers/dri2/egl_dri2.h | 12 +-<br>
src/egl/drivers/dri2/platform_x11.c | 127 ++-<br>
src/egl/drivers/dri2/platform_x11_dri3.c | 1591 ++++++++++++++++++++++++++++++<br>
src/egl/drivers/dri2/platform_x11_dri3.h | 140 +++<br>
7 files changed, 1926 insertions(+), 17 deletions(-)<br>
create mode 100644 src/egl/drivers/dri2/platform_x11_dri3.c<br>
create mode 100644 src/egl/drivers/dri2/platform_x11_dri3.h<br>
<br>
diff --git a/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a> b/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a><br>
index af61aa2..090e6c9 100644<br>
--- a/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a><br>
+++ b/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a><br>
@@ -1545,6 +1545,9 @@ if test "x$enable_egl" = xyes; then<br>
if test "x$enable_shared_glapi" = xno; then<br>
AC_MSG_ERROR([egl_dri2 requires --enable-shared-glapi])<br>
fi<br>
+ if test "x$enable_dri3" = xyes; then<br>
+ EGL_LIB_DEPS="$EGL_LIB_DEPS -lxcb-dri3 -lxcb-present -lXxf86vm -lxshmfence -lxcb-sync"<br>
+ fi<br>
else<br>
# Avoid building an "empty" libEGL. Drop/update this<br>
# when other backends (haiku?) come along.<br>
diff --git a/src/egl/drivers/dri2/Makefile.am b/src/egl/drivers/dri2/Makefile.am<br>
index 55be4a7..d5b511c 100644<br>
--- a/src/egl/drivers/dri2/Makefile.am<br>
+++ b/src/egl/drivers/dri2/Makefile.am<br>
@@ -52,6 +52,11 @@ if HAVE_EGL_PLATFORM_X11<br>
libegl_dri2_la_SOURCES += platform_x11.c<br>
AM_CFLAGS += -DHAVE_X11_PLATFORM<br>
AM_CFLAGS += $(XCB_DRI2_CFLAGS)<br>
+if HAVE_DRI3<br>
+libegl_dri2_la_SOURCES += \<br>
+ platform_x11_dri3.c \<br>
+ platform_x11_dri3.h<br>
+endif<br>
endif<br>
<br>
if HAVE_EGL_PLATFORM_WAYLAND<br>
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c<br>
index b1b65f7..052c579 100644<br>
--- a/src/egl/drivers/dri2/egl_dri2.c<br>
+++ b/src/egl/drivers/dri2/egl_dri2.c<br>
@@ -322,6 +322,12 @@ struct dri2_extension_match {<br>
int offset;<br>
};<br>
<br>
+static struct dri2_extension_match dri3_driver_extensions[] = {<br>
+ { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },<br>
+ { __DRI_IMAGE_DRIVER, 1, offsetof(struct dri2_egl_display, image_driver) },<br>
+ { NULL, 0, 0 }<br>
+};<br>
+<br>
static struct dri2_extension_match dri2_driver_extensions[] = {<br>
{ __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },<br>
{ __DRI_DRI2, 2, offsetof(struct dri2_egl_display, dri2) },<br>
@@ -464,6 +470,24 @@ dri2_open_driver(_EGLDisplay *disp)<br>
}<br>
<br>
EGLBoolean<br>
+dri2_load_driver_dri3(_EGLDisplay *disp)<br>
+{<br>
+ struct dri2_egl_display *dri2_dpy = disp->DriverData;<br>
+ const __DRIextension **extensions;<br>
+<br>
+ extensions = dri2_open_driver(disp);<br>
+ if (!extensions)<br>
+ return EGL_FALSE;<br>
+<br>
+ if (!dri2_bind_extensions(dri2_dpy, dri3_driver_extensions, extensions)) {<br>
+ dlclose(dri2_dpy->driver);<br></blockquote><div><br></div><div>I missed a return EGL_FALSE here. Have been fixed locally.</div><div><br></div><div>Boyan Ding</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+ }<br>
+ dri2_dpy->driver_extensions = extensions;<br>
+<br>
+ return EGL_TRUE;<br>
+}<br>
+<br>
+EGLBoolean<br>
dri2_load_driver(_EGLDisplay *disp)<br>
{<br>
struct dri2_egl_display *dri2_dpy = disp->DriverData;<br>
@@ -507,7 +531,9 @@ dri2_setup_screen(_EGLDisplay *disp)<br>
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);<br>
unsigned int api_mask;<br>
<br>
- if (dri2_dpy->dri2) {<br>
+ if (dri2_dpy->image_driver) {<br>
+ api_mask = dri2_dpy->image_driver->getAPIMask(dri2_dpy->dri_screen);<br>
+ } else if (dri2_dpy->dri2) {<br>
api_mask = dri2_dpy->dri2->getAPIMask(dri2_dpy->dri_screen);<br>
} else {<br>
assert(dri2_dpy->swrast);<br>
@@ -527,11 +553,12 @@ dri2_setup_screen(_EGLDisplay *disp)<br>
if (api_mask & (1 << __DRI_API_GLES3))<br>
disp->ClientAPIs |= EGL_OPENGL_ES3_BIT_KHR;<br>
<br>
- assert(dri2_dpy->dri2 || dri2_dpy->swrast);<br>
+ assert(dri2_dpy->image_driver || dri2_dpy->dri2 || dri2_dpy->swrast);<br>
disp->Extensions.KHR_surfaceless_context = EGL_TRUE;<br>
disp->Extensions.MESA_configless_context = EGL_TRUE;<br>
<br>
- if ((dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) ||<br>
+ if (dri2_dpy->image_driver ||<br>
+ (dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) ||<br>
(dri2_dpy->swrast && dri2_dpy->swrast->base.version >= 3)) {<br>
disp->Extensions.KHR_create_context = EGL_TRUE;<br>
<br>
@@ -591,7 +618,14 @@ dri2_create_screen(_EGLDisplay *disp)<br>
<br>
dri2_dpy = disp->DriverData;<br>
<br>
- if (dri2_dpy->dri2) {<br>
+ if (dri2_dpy->image_driver) {<br>
+ dri2_dpy->dri_screen =<br>
+ dri2_dpy->image_driver->createNewScreen2(0, dri2_dpy->fd,<br>
+ dri2_dpy->extensions,<br>
+ dri2_dpy->driver_extensions,<br>
+ &dri2_dpy->driver_configs,<br>
+ disp);<br>
+ } else if (dri2_dpy->dri2) {<br>
if (dri2_dpy->dri2->base.version >= 4) {<br>
dri2_dpy->dri_screen =<br>
dri2_dpy->dri2->createNewScreen2(0, dri2_dpy->fd,<br>
@@ -627,7 +661,7 @@ dri2_create_screen(_EGLDisplay *disp)<br>
<br>
extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);<br>
<br>
- if (dri2_dpy->dri2) {<br>
+ if (dri2_dpy->image_driver || dri2_dpy->dri2) {<br>
if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions))<br>
goto cleanup_dri_screen;<br>
} else {<br>
@@ -971,7 +1005,26 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,<br>
else<br>
dri_config = NULL;<br>
<br>
- if (dri2_dpy->dri2) {<br>
+ if (dri2_dpy->image_driver) {<br>
+ unsigned error;<br>
+ unsigned num_attribs = 8;<br>
+ uint32_t ctx_attribs[8];<br>
+<br>
+ if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs,<br>
+ &num_attribs))<br>
+ goto cleanup;<br>
+<br>
+ dri2_ctx->dri_context =<br>
+ dri2_dpy->image_driver->createContextAttribs(dri2_dpy->dri_screen,<br>
+ api,<br>
+ dri_config,<br>
+ shared,<br>
+ num_attribs / 2,<br>
+ ctx_attribs,<br>
+ & error,<br>
+ dri2_ctx);<br>
+ dri2_create_context_attribs_error(error);<br>
+ } else if (dri2_dpy->dri2) {<br>
if (dri2_dpy->dri2->base.version >= 3) {<br>
unsigned error;<br>
unsigned num_attribs = 8;<br>
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h<br>
index f0cc6da..d258753 100644<br>
--- a/src/egl/drivers/dri2/egl_dri2.h<br>
+++ b/src/egl/drivers/dri2/egl_dri2.h<br>
@@ -153,11 +153,16 @@ struct dri2_egl_display<br>
<br>
int dri2_major;<br>
int dri2_minor;<br>
+ int dri3_major;<br>
+ int dri3_minor;<br>
+ int present_major;<br>
+ int present_minor;<br>
__DRIscreen *dri_screen;<br>
int own_dri_screen;<br>
const __DRIconfig **driver_configs;<br>
void *driver;<br>
const __DRIcoreExtension *core;<br>
+ const __DRIimageDriverExtension *image_driver;<br>
const __DRIdri2Extension *dri2;<br>
const __DRIswrastExtension *swrast;<br>
const __DRI2flushExtension *flush;<br>
@@ -189,6 +194,7 @@ struct dri2_egl_display<br>
#ifdef HAVE_X11_PLATFORM<br>
xcb_connection_t *conn;<br>
int screen;<br>
+ Display *dpy;<br>
#endif<br>
<br>
#ifdef HAVE_WAYLAND_PLATFORM<br>
@@ -202,8 +208,9 @@ struct dri2_egl_display<br>
int formats;<br>
uint32_t capabilities;<br>
int is_render_node;<br>
- int is_different_gpu;<br>
#endif<br>
+<br>
+ int is_different_gpu;<br>
};<br>
<br>
struct dri2_egl_context<br>
@@ -324,6 +331,9 @@ EGLBoolean<br>
dri2_load_driver_swrast(_EGLDisplay *disp);<br>
<br>
EGLBoolean<br>
+dri2_load_driver_dri3(_EGLDisplay *disp);<br>
+<br>
+EGLBoolean<br>
dri2_create_screen(_EGLDisplay *disp);<br>
<br>
__DRIimage *<br>
diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c<br>
index ad40bd5..2ce260f 100644<br>
--- a/src/egl/drivers/dri2/platform_x11.c<br>
+++ b/src/egl/drivers/dri2/platform_x11.c<br>
@@ -45,6 +45,10 @@<br>
#include "egl_dri2_fallbacks.h"<br>
#include "loader.h"<br>
<br>
+#ifdef HAVE_DRI3<br>
+#include "platform_x11_dri3.h"<br>
+#endif<br>
+<br>
static EGLBoolean<br>
dri2_x11_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,<br>
EGLint interval);<br>
@@ -1094,13 +1098,17 @@ dri2_initialize_x11_swrast(_EGLDriver *drv, _EGLDisplay *disp)<br>
<br>
disp->DriverData = (void *) dri2_dpy;<br>
if (disp->PlatformDisplay == NULL) {<br>
- dri2_dpy->conn = xcb_connect(0, &dri2_dpy->screen);<br>
+ dri2_dpy->dpy = XOpenDisplay(NULL);<br>
+<br>
+ dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);<br>
+ dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);<br>
+<br>
dri2_dpy->own_device = true;<br>
} else {<br>
- Display *dpy = disp->PlatformDisplay;<br>
+ dri2_dpy->dpy = disp->PlatformDisplay;<br>
<br>
- dri2_dpy->conn = XGetXCBConnection(dpy);<br>
- dri2_dpy->screen = DefaultScreen(dpy);<br>
+ dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);<br>
+ dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);<br>
}<br>
<br>
if (xcb_connection_has_error(dri2_dpy->conn)) {<br>
@@ -1202,6 +1210,94 @@ dri2_x11_setup_swap_interval(struct dri2_egl_display *dri2_dpy)<br>
}<br>
}<br>
<br>
+#ifdef HAVE_DRI3<br>
+static EGLBoolean<br>
+dri2_initialize_x11_dri3(_EGLDriver *drv, _EGLDisplay *disp)<br>
+{<br>
+ struct dri2_egl_display *dri2_dpy;<br>
+<br>
+ dri2_dpy = calloc(1, sizeof *dri2_dpy);<br>
+ if (!dri2_dpy)<br>
+ return _eglError(EGL_BAD_ALLOC, "eglInitialize");<br>
+<br>
+ disp->DriverData = (void *) dri2_dpy;<br>
+ if (disp->PlatformDisplay == NULL) {<br>
+ dri2_dpy->dpy = XOpenDisplay(NULL);<br>
+<br>
+ dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);<br>
+ dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);<br>
+<br>
+ dri2_dpy->own_device = true;<br>
+ } else {<br>
+ dri2_dpy->dpy = disp->PlatformDisplay;<br>
+<br>
+ dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);<br>
+ dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);<br>
+ }<br>
+<br>
+ if (xcb_connection_has_error(dri2_dpy->conn)) {<br>
+ _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");<br>
+ goto cleanup_dpy;<br>
+ }<br>
+<br>
+ if (dri2_dpy->conn) {<br>
+ if (!dri3_x11_connect(dri2_dpy))<br>
+ goto cleanup_conn;<br>
+ }<br>
+<br>
+ if (!dri2_load_driver_dri3(disp))<br>
+ goto cleanup_conn;<br>
+<br>
+ dri2_dpy->extensions[0] = &dri3_image_loader_extension.base;<br>
+ dri2_dpy->extensions[1] = &dri3_system_time_extension.base;<br>
+ dri2_dpy->extensions[2] = &use_invalidate.base;<br>
+ dri2_dpy->extensions[3] = &image_lookup_extension.base;<br>
+ dri2_dpy->extensions[4] = NULL;<br>
+<br>
+ dri2_dpy->swap_available = true;<br>
+ dri2_dpy->invalidate_available = true;<br>
+<br>
+ if (!dri2_create_screen(disp))<br>
+ goto cleanup_fd;<br>
+<br>
+ dri2_x11_setup_swap_interval(dri2_dpy);<br>
+<br>
+ disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;<br>
+ disp->Extensions.CHROMIUM_sync_control = EGL_TRUE;<br>
+ disp->Extensions.EXT_buffer_age = EGL_TRUE;<br>
+<br>
+#ifdef HAVE_WAYLAND_PLATFORM<br>
+ disp->Extensions.WL_bind_wayland_display = EGL_TRUE;<br>
+#endif<br>
+<br>
+ if (dri2_dpy->conn) {<br>
+ if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp))<br>
+ goto cleanup_configs;<br>
+ }<br>
+<br>
+ /* Fill vtbl last to prevent accidentally calling virtual function during<br>
+ * initialization.<br>
+ */<br>
+ dri2_dpy->vtbl = &dri3_x11_display_vtbl;<br>
+<br>
+ return EGL_TRUE;<br>
+<br>
+ cleanup_configs:<br>
+ _eglCleanupDisplay(disp);<br>
+ dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);<br>
+ dlclose(dri2_dpy->driver);<br>
+ cleanup_fd:<br>
+ close(dri2_dpy->fd);<br>
+ cleanup_conn:<br>
+ if (disp->PlatformDisplay == NULL)<br>
+ xcb_disconnect(dri2_dpy->conn);<br>
+ cleanup_dpy:<br>
+ free(dri2_dpy);<br>
+<br>
+ return EGL_FALSE;<br>
+}<br>
+#endif<br>
+<br>
static EGLBoolean<br>
dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp)<br>
{<br>
@@ -1213,13 +1309,17 @@ dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp)<br>
<br>
disp->DriverData = (void *) dri2_dpy;<br>
if (disp->PlatformDisplay == NULL) {<br>
- dri2_dpy->conn = xcb_connect(0, &dri2_dpy->screen);<br>
+ dri2_dpy->dpy = XOpenDisplay(NULL);<br>
+<br>
+ dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);<br>
+ dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);<br>
+<br>
dri2_dpy->own_device = true;<br>
} else {<br>
- Display *dpy = disp->PlatformDisplay;<br>
+ dri2_dpy->dpy = disp->PlatformDisplay;<br>
<br>
- dri2_dpy->conn = XGetXCBConnection(dpy);<br>
- dri2_dpy->screen = DefaultScreen(dpy);<br>
+ dri2_dpy->conn = XGetXCBConnection(dri2_dpy->dpy);<br>
+ dri2_dpy->screen = DefaultScreen(dri2_dpy->dpy);<br>
}<br>
<br>
if (xcb_connection_has_error(dri2_dpy->conn)) {<br>
@@ -1321,9 +1421,16 @@ dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp)<br>
int x11_dri2_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL);<br>
<br>
if (x11_dri2_accel) {<br>
- if (!dri2_initialize_x11_dri2(drv, disp)) {<br>
- initialized = dri2_initialize_x11_swrast(drv, disp);<br>
+#ifdef HAVE_DRI3<br>
+ if (getenv("LIBGL_DRI3_ENABLE") == NULL ||<br>
+ !dri2_initialize_x11_dri3(drv, disp)) {<br>
+#endif<br>
+ if (!dri2_initialize_x11_dri2(drv, disp)) {<br>
+ initialized = dri2_initialize_x11_swrast(drv, disp);<br>
+ }<br>
+#ifdef HAVE_DRI3<br>
}<br>
+#endif<br>
} else {<br>
initialized = dri2_initialize_x11_swrast(drv, disp);<br>
}<br>
diff --git a/src/egl/drivers/dri2/platform_x11_dri3.c b/src/egl/drivers/dri2/platform_x11_dri3.c<br>
new file mode 100644<br>
index 0000000..dcd7128<br>
--- /dev/null<br>
+++ b/src/egl/drivers/dri2/platform_x11_dri3.c<br>
@@ -0,0 +1,1591 @@<br>
+/*<br>
+ * Copyright © 2013 Keith Packard<br>
+ *<br>
+ * Permission to use, copy, modify, distribute, and sell this software and its<br>
+ * documentation for any purpose is hereby granted without fee, provided that<br>
+ * the above copyright notice appear in all copies and that both that copyright<br>
+ * notice and this permission notice appear in supporting documentation, and<br>
+ * that the name of the copyright holders not be used in advertising or<br>
+ * publicity pertaining to distribution of the software without specific,<br>
+ * written prior permission. The copyright holders make no representations<br>
+ * about the suitability of this software for any purpose. It is provided "as<br>
+ * is" without express or implied warranty.<br>
+ *<br>
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,<br>
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO<br>
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR<br>
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,<br>
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER<br>
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE<br>
+ * OF THIS SOFTWARE.<br>
+ */<br>
+<br>
+#include <fcntl.h><br>
+#include <stdbool.h><br>
+#include <stdlib.h><br>
+#include <string.h><br>
+#include <unistd.h><br>
+#include <sys/time.h><br>
+<br>
+#ifdef XF86VIDMODE<br>
+#include <X11/extensions/xf86vmode.h><br>
+#endif<br>
+#include <X11/xshmfence.h><br>
+#include <xcb/xcb.h><br>
+#include <xcb/dri3.h><br>
+#include <xcb/present.h><br>
+#include <xf86drm.h><br>
+<br>
+#include "egl_dri2.h"<br>
+#include "egl_dri2_fallbacks.h"<br>
+#include "platform_x11_dri3.h"<br>
+<br>
+#include "loader.h"<br>
+<br>
+static inline void<br>
+dri3_fence_reset(xcb_connection_t *c, struct dri3_buffer *buffer)<br>
+{<br>
+ xshmfence_reset(buffer->shm_fence);<br>
+}<br>
+<br>
+static inline void<br>
+dri3_fence_set(struct dri3_buffer *buffer)<br>
+{<br>
+ xshmfence_trigger(buffer->shm_fence);<br>
+}<br>
+<br>
+static inline void<br>
+dri3_fence_trigger(xcb_connection_t *c, struct dri3_buffer *buffer)<br>
+{<br>
+ xcb_sync_trigger_fence(c, buffer->sync_fence);<br>
+}<br>
+<br>
+static inline void<br>
+dri3_fence_await(xcb_connection_t *c, struct dri3_buffer *buffer)<br>
+{<br>
+ xcb_flush(c);<br>
+ xshmfence_await(buffer->shm_fence);<br>
+}<br>
+<br>
+static void<br>
+dri3_update_num_back(struct dri3_egl_surface *dri3_surf)<br>
+{<br>
+ dri3_surf->num_back = 1;<br>
+ if (dri3_surf->flipping) {<br>
+ if (!dri3_surf->is_pixmap && !(dri3_surf->present_capabilities & XCB_PRESENT_CAPABILITY_ASYNC))<br>
+ dri3_surf->num_back++;<br>
+ dri3_surf->num_back++;<br>
+ }<br>
+ if (dri3_surf->base.SwapInterval == 0)<br>
+ dri3_surf->num_back++;<br>
+}<br>
+<br>
+/** dri3_free_render_buffer<br>
+ *<br>
+ * Free everything associated with one render buffer including pixmap, fence<br>
+ * stuff and the driver image<br>
+ */<br>
+static void<br>
+dri3_free_render_buffer(struct dri2_egl_display *dri2_dpy,<br>
+ struct dri3_egl_surface *dri3_surf,<br>
+ struct dri3_buffer *buffer)<br>
+{<br>
+ if (buffer->own_pixmap)<br>
+ xcb_free_pixmap(dri2_dpy->conn, buffer->pixmap);<br>
+ xcb_sync_destroy_fence(dri2_dpy->conn, buffer->sync_fence);<br>
+ xshmfence_unmap_shm(buffer->shm_fence);<br>
+ (*dri2_dpy->image->destroyImage)(buffer->image);<br>
+ if (buffer->linear_buffer)<br>
+ (*dri2_dpy->image->destroyImage)(buffer->linear_buffer);<br>
+ free(buffer);<br>
+}<br>
+<br>
+static EGLBoolean<br>
+dri3_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)<br>
+{<br>
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);<br>
+ struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);<br>
+ int i;<br>
+<br>
+ (void) drv;<br>
+<br>
+ if (!_eglPutSurface(surf))<br>
+ return EGL_TRUE;<br>
+<br>
+ (*dri2_dpy->core->destroyDrawable) (dri3_surf->dri_drawable);<br>
+<br>
+ for (i = 0; i < DRI3_NUM_BUFFERS; i++) {<br>
+ if (dri3_surf->buffers[i])<br>
+ dri3_free_render_buffer(dri2_dpy, dri3_surf, dri3_surf->buffers[i]);<br>
+ }<br>
+<br>
+ if (dri3_surf->special_event)<br>
+ xcb_unregister_for_special_event(dri2_dpy->conn, dri3_surf->special_event);<br>
+ free(surf);<br>
+<br>
+ return EGL_TRUE;<br>
+}<br>
+<br>
+static EGLBoolean<br>
+dri3_set_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,<br>
+ EGLint interval)<br>
+{<br>
+ struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);<br>
+<br>
+ if (interval > surf->Config->MaxSwapInterval)<br>
+ interval = surf->Config->MaxSwapInterval;<br>
+ else if (interval < surf->Config->MinSwapInterval)<br>
+ interval = surf->Config->MinSwapInterval;<br>
+<br>
+ dri3_surf->base.SwapInterval = interval;<br>
+ dri3_update_num_back(dri3_surf);<br>
+<br>
+ return EGL_TRUE;<br>
+}<br>
+<br>
+static xcb_screen_t *<br>
+get_xcb_screen(xcb_screen_iterator_t iter, int screen)<br>
+{<br>
+ for (; iter.rem; --screen, xcb_screen_next(&iter))<br>
+ if (screen == 0)<br>
+ return iter.data;<br>
+<br>
+ return NULL;<br>
+}<br>
+<br>
+/* xDrawable in glx maps to drawable here */<br>
+static _EGLSurface *<br>
+dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,<br>
+ _EGLConfig *conf, void *native_surface,<br>
+ const EGLint *attrib_list)<br>
+{<br>
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);<br>
+ struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);<br>
+ struct dri3_egl_surface *dri3_surf;<br>
+ xcb_drawable_t drawable;<br>
+ xcb_get_geometry_cookie_t cookie;<br>
+ xcb_get_geometry_reply_t *reply;<br>
+ xcb_screen_iterator_t s;<br>
+ xcb_generic_error_t *error;<br>
+ xcb_screen_t *screen;<br>
+ GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;<br>
+<br>
+ STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));<br>
+ drawable = (uintptr_t) native_surface;<br>
+<br>
+ (void) drv;<br>
+<br>
+ dri3_surf = calloc(1, sizeof *dri3_surf);<br>
+ if (!dri3_surf) {<br>
+ _eglError(EGL_BAD_ALLOC, "dri3_create_surface");<br>
+ return NULL;<br>
+ }<br>
+<br>
+ if (!_eglInitSurface(&dri3_surf->base, disp, type, conf, attrib_list))<br>
+ goto cleanup_surf;<br>
+<br>
+ if (type == EGL_PBUFFER_BIT) {<br>
+ s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));<br>
+ screen = get_xcb_screen(s, dri2_dpy->screen);<br>
+ if (!screen) {<br>
+ _eglError(EGL_BAD_NATIVE_WINDOW, "dri3_create_surface");<br>
+ goto cleanup_surf;<br>
+ }<br>
+<br>
+ dri3_surf->drawable = xcb_generate_id(dri2_dpy->conn);<br>
+ xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,<br>
+ dri3_surf->drawable, screen->root,<br>
+ dri3_surf->base.Width, dri3_surf->base.Height);<br>
+ } else {<br>
+ dri3_surf->drawable = drawable;<br>
+ }<br>
+<br>
+ dri3_surf->base.SwapInterval = 1; /* default may be overridden below */<br>
+ dri3_surf->have_back = 0;<br>
+ dri3_surf->have_fake_front = 0;<br>
+ dri3_surf->first_init = true;<br>
+<br>
+ if (dri2_dpy->config)<br>
+ dri2_dpy->config->configQueryi(dri2_dpy->dri_screen,<br>
+ "vblank_mode", &vblank_mode);<br>
+<br>
+ switch (vblank_mode) {<br>
+ case DRI_CONF_VBLANK_NEVER:<br>
+ case DRI_CONF_VBLANK_DEF_INTERVAL_0:<br>
+ dri3_surf->base.SwapInterval = 0;<br>
+ break;<br>
+ case DRI_CONF_VBLANK_DEF_INTERVAL_1:<br>
+ case DRI_CONF_VBLANK_ALWAYS_SYNC:<br>
+ default:<br>
+ dri3_surf->base.SwapInterval = 1;<br>
+ break;<br>
+ }<br>
+<br>
+ dri3_update_num_back(dri3_surf);<br>
+<br>
+ /* Create a new drawable */<br>
+ dri3_surf->dri_drawable =<br>
+ (*dri2_dpy->image_driver->createNewDrawable) (dri2_dpy->dri_screen,<br>
+ type == EGL_WINDOW_BIT ?<br>
+ dri2_conf->dri_double_config :<br>
+ dri2_conf->dri_single_config,<br>
+ dri3_surf);<br>
+<br>
+ if (!dri3_surf->dri_drawable) {<br>
+ _eglError(EGL_BAD_ALLOC, "dri3->createNewDrawable");<br>
+ goto cleanup_pixmap;<br>
+ }<br>
+<br>
+ if (type != EGL_PBUFFER_BIT) {<br>
+ cookie = xcb_get_geometry (dri2_dpy->conn, dri3_surf->drawable);<br>
+ reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);<br>
+ if (reply == NULL || error != NULL) {<br>
+ _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");<br>
+ free(error);<br>
+ goto cleanup_dri_drawable;<br>
+ }<br>
+<br>
+ dri3_surf->base.Width = reply->width;<br>
+ dri3_surf->base.Height = reply->height;<br>
+ dri3_surf->depth = reply->depth;<br>
+ free(reply);<br>
+ }<br>
+<br>
+ /*<br>
+ * Make sure server has the same swap interval we do for the new<br>
+ * drawable.<br>
+ */<br>
+ dri3_set_swap_interval(drv, disp, &dri3_surf->base,<br>
+ dri3_surf->base.SwapInterval);<br>
+<br>
+ return &dri3_surf->base;<br>
+<br>
+ cleanup_dri_drawable:<br>
+ dri2_dpy->core->destroyDrawable(dri3_surf->dri_drawable);<br>
+ cleanup_pixmap:<br>
+ if (type == EGL_PBUFFER_BIT)<br>
+ xcb_free_pixmap(dri2_dpy->conn, dri3_surf->drawable);<br>
+ cleanup_surf:<br>
+ free(dri3_surf);<br>
+<br>
+ return NULL;<br>
+}<br>
+<br>
+/**<br>
+ * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().<br>
+ */<br>
+static _EGLSurface *<br>
+dri3_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,<br>
+ _EGLConfig *conf, void *native_window,<br>
+ const EGLint *attrib_list)<br>
+{<br>
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);<br>
+ _EGLSurface *surf;<br>
+<br>
+ surf = dri3_create_surface(drv, disp, EGL_WINDOW_BIT, conf,<br>
+ native_window, attrib_list);<br>
+ if (surf != NULL)<br>
+ dri3_set_swap_interval(drv, disp, surf, dri2_dpy->default_swap_interval);<br>
+<br>
+ return surf;<br>
+}<br>
+<br>
+static _EGLSurface *<br>
+dri3_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,<br>
+ _EGLConfig *conf, void *native_pixmap,<br>
+ const EGLint *attrib_list)<br>
+{<br>
+ return dri3_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,<br>
+ native_pixmap, attrib_list);<br>
+}<br>
+<br>
+static _EGLSurface *<br>
+dri3_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,<br>
+ _EGLConfig *conf, const EGLint *attrib_list)<br>
+{<br>
+ return dri3_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,<br>
+ XCB_WINDOW_NONE, attrib_list);<br>
+}<br>
+<br>
+/*<br>
+ * Process one Present event<br>
+ */<br>
+static void<br>
+dri3_handle_present_event(struct dri2_egl_display *dri2_dpy,<br>
+ struct dri3_egl_surface *dri3_surf,<br>
+ xcb_present_generic_event_t *ge)<br>
+{<br>
+ switch (ge->evtype) {<br>
+ case XCB_PRESENT_CONFIGURE_NOTIFY: {<br>
+ xcb_present_configure_notify_event_t *ce = (void *) ge;<br>
+<br>
+ dri3_surf->base.Width = ce->width;<br>
+ dri3_surf->base.Height = ce->height;<br>
+ break;<br>
+ }<br>
+ case XCB_PRESENT_COMPLETE_NOTIFY: {<br>
+ xcb_present_complete_notify_event_t *ce = (void *) ge;<br>
+<br>
+ /* Compute the processed SBC number from the received 32-bit serial number merged<br>
+ * with the upper 32-bits of the sent 64-bit serial number while checking for<br>
+ * wrap<br>
+ */<br>
+ if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) {<br>
+ dri3_surf->recv_sbc = (dri3_surf->send_sbc & 0xffffffff00000000LL) | ce->serial;<br>
+ if (dri3_surf->recv_sbc > dri3_surf->send_sbc)<br>
+ dri3_surf->recv_sbc -= 0x100000000;<br>
+ switch (ce->mode) {<br>
+ case XCB_PRESENT_COMPLETE_MODE_FLIP:<br>
+ dri3_surf->flipping = true;<br>
+ break;<br>
+ case XCB_PRESENT_COMPLETE_MODE_COPY:<br>
+ dri3_surf->flipping = false;<br>
+ break;<br>
+ }<br>
+ dri3_update_num_back(dri3_surf);<br>
+<br>
+ /*<br>
+ if (psc->show_fps_interval)<br>
+ show_fps(priv, ce->ust); */<br>
+<br>
+ dri3_surf->ust = ce->ust;<br>
+ dri3_surf->msc = ce->msc;<br>
+ } else {<br>
+ dri3_surf->recv_msc_serial = ce->serial;<br>
+ dri3_surf->notify_ust = ce->ust;<br>
+ dri3_surf->notify_msc = ce->msc;<br>
+ }<br>
+ break;<br>
+ }<br>
+ case XCB_PRESENT_EVENT_IDLE_NOTIFY: {<br>
+ xcb_present_idle_notify_event_t *ie = (void *) ge;<br>
+ int b;<br>
+<br>
+ for (b = 0; b < sizeof (dri3_surf->buffers) / sizeof (dri3_surf->buffers[0]); b++) {<br>
+ struct dri3_buffer *buf = dri3_surf->buffers[b];<br>
+<br>
+ if (buf && buf->pixmap == ie->pixmap) {<br>
+ buf->busy = 0;<br>
+ if (dri3_surf->num_back <= b && b < DRI3_MAX_BACK) {<br>
+ dri3_free_render_buffer(dri2_dpy, dri3_surf, buf);<br>
+ dri3_surf->buffers[b] = NULL;<br>
+ }<br>
+ break;<br>
+ }<br>
+ }<br>
+ break;<br>
+ }<br>
+ }<br>
+ free(ge);<br>
+}<br>
+<br>
+static bool<br>
+dri3_wait_for_event(struct dri2_egl_display *dri2_dpy,<br>
+ struct dri3_egl_surface *dri3_surf)<br>
+{<br>
+ xcb_generic_event_t *ev;<br>
+ xcb_present_generic_event_t *ge;<br>
+<br>
+ xcb_flush(dri2_dpy->conn);<br>
+ ev = xcb_wait_for_special_event(dri2_dpy->conn, dri3_surf->special_event);<br>
+ if (!ev)<br>
+ return false;<br>
+ ge = (void *) ev;<br>
+ dri3_handle_present_event(dri2_dpy, dri3_surf, ge);<br>
+ return true;<br>
+}<br>
+<br>
+/** dri3_wait_for_msc<br>
+ *<br>
+ * Get the X server to send an event when the target msc/divisor/remainder is<br>
+ * reached.<br>
+ */<br>
+static EGLBoolean<br>
+dri3_wait_for_msc(struct dri2_egl_display *dri2_dpy,<br>
+ struct dri3_egl_surface *dri3_surf,<br>
+ int64_t target_msc, int64_t divisor, int64_t remainder,<br>
+ int64_t *ust, int64_t *msc, int64_t *sbc)<br>
+{<br>
+ uint32_t msc_serial;<br>
+<br>
+ msc_serial = ++dri3_surf->send_msc_serial;<br>
+ xcb_present_notify_msc(dri2_dpy->conn,<br>
+ dri3_surf->drawable,<br>
+ msc_serial,<br>
+ target_msc,<br>
+ divisor,<br>
+ remainder);<br>
+<br>
+ xcb_flush(dri2_dpy->conn);<br>
+<br>
+ /* Wait for the event */<br>
+ if (dri3_surf->special_event) {<br>
+ while ((int32_t) (msc_serial - dri3_surf->recv_msc_serial) > 0) {<br>
+ if (!dri3_wait_for_event(dri2_dpy, dri3_surf))<br>
+ return EGL_FALSE;<br>
+ }<br>
+ }<br>
+<br>
+ *ust = dri3_surf->notify_ust;<br>
+ *msc = dri3_surf->notify_msc;<br>
+ *sbc = dri3_surf->recv_sbc;<br>
+<br>
+ return EGL_TRUE;<br>
+}<br>
+<br>
+static EGLBoolean<br>
+dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,<br>
+ EGLuint64KHR *ust, EGLuint64KHR *msc,<br>
+ EGLuint64KHR *sbc)<br>
+{<br>
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(display);<br>
+ struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surface);<br>
+<br>
+ return dri3_wait_for_msc(dri2_dpy, dri3_surf, 0, 0, 0, ust, msc, sbc);<br>
+}<br>
+<br>
+/**<br>
+ * Asks the driver to flush any queued work necessary for serializing with the<br>
+ * X command stream, and optionally the slightly more strict requirement of<br>
+ * glFlush() equivalence (which would require flushing even if nothing had<br>
+ * been drawn to a window system framebuffer, for example).<br>
+ */<br>
+static void<br>
+dri3_flush(struct dri2_egl_display *dri2_dpy,<br>
+ struct dri3_egl_surface *dri3_surf,<br>
+ unsigned flags,<br>
+ enum __DRI2throttleReason throttle_reason)<br>
+{<br>
+ _EGLContext *ctx = _eglGetCurrentContext();<br>
+ struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);<br>
+<br>
+ if (dri2_ctx)<br>
+ (*dri2_dpy->flush->flush_with_flags)(dri2_ctx->dri_context,<br>
+ dri3_surf->dri_drawable,<br>
+ flags, throttle_reason);<br>
+}<br>
+<br>
+static xcb_gcontext_t<br>
+dri3_drawable_gc(struct dri2_egl_display *dri2_dpy,<br>
+ struct dri3_egl_surface *dri3_surf)<br>
+{<br>
+ if (!dri3_surf->gc) {<br>
+ uint32_t v = 0;<br>
+ xcb_create_gc(dri2_dpy->conn,<br>
+ (dri3_surf->gc = xcb_generate_id(dri2_dpy->conn)),<br>
+ dri3_surf->drawable,<br>
+ XCB_GC_GRAPHICS_EXPOSURES,<br>
+ &v);<br>
+ }<br>
+ return dri3_surf->gc;<br>
+}<br>
+<br>
+<br>
+static struct dri3_buffer *<br>
+dri3_back_buffer(struct dri3_egl_surface *dri3_surf)<br>
+{<br>
+ return dri3_surf->buffers[DRI3_BACK_ID(dri3_surf->cur_back)];<br>
+}<br>
+<br>
+static struct dri3_buffer *<br>
+dri3_fake_front_buffer(struct dri3_egl_surface *dri3_surf)<br>
+{<br>
+ return dri3_surf->buffers[DRI3_FRONT_ID];<br>
+}<br>
+<br>
+static void<br>
+dri3_copy_area (xcb_connection_t *c /**< */,<br>
+ xcb_drawable_t src_drawable /**< */,<br>
+ xcb_drawable_t dst_drawable /**< */,<br>
+ xcb_gcontext_t gc /**< */,<br>
+ int16_t src_x /**< */,<br>
+ int16_t src_y /**< */,<br>
+ int16_t dst_x /**< */,<br>
+ int16_t dst_y /**< */,<br>
+ uint16_t width /**< */,<br>
+ uint16_t height /**< */)<br>
+{<br>
+ xcb_void_cookie_t cookie;<br>
+<br>
+ cookie = xcb_copy_area_checked(c,<br>
+ src_drawable,<br>
+ dst_drawable,<br>
+ gc,<br>
+ src_x,<br>
+ src_y,<br>
+ dst_x,<br>
+ dst_y,<br>
+ width,<br>
+ height);<br>
+ xcb_discard_reply(c, cookie.sequence);<br>
+}<br>
+<br>
+/**<br>
+ * Called by the driver when it needs to update the real front buffer with the<br>
+ * contents of its fake front buffer.<br>
+ */<br>
+static void<br>
+dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)<br>
+{<br>
+#if 0<br>
+ struct glx_context *gc;<br>
+ struct dri3_drawable *pdraw = loaderPrivate;<br>
+ struct dri3_screen *psc;<br>
+<br>
+ if (!pdraw)<br>
+ return;<br>
+<br>
+ if (!pdraw->base.psc)<br>
+ return;<br>
+<br>
+ psc = (struct dri3_screen *) pdraw->base.psc;<br>
+<br>
+ (void) __glXInitialize(psc->base.dpy);<br>
+<br>
+ gc = __glXGetCurrentContext();<br>
+<br>
+ dri3_flush(psc, pdraw, __DRI2_FLUSH_DRAWABLE, __DRI2_THROTTLE_FLUSHFRONT);<br>
+<br>
+ dri3_wait_gl(gc);<br>
+#endif<br>
+ /* FIXME */<br>
+ (void) driDrawable;<br>
+ (void) loaderPrivate;<br>
+}<br>
+<br>
+static uint32_t<br>
+dri3_cpp_for_format(uint32_t format) {<br>
+ switch (format) {<br>
+ case __DRI_IMAGE_FORMAT_R8:<br>
+ return 1;<br>
+ case __DRI_IMAGE_FORMAT_RGB565:<br>
+ case __DRI_IMAGE_FORMAT_GR88:<br>
+ return 2;<br>
+ case __DRI_IMAGE_FORMAT_XRGB8888:<br>
+ case __DRI_IMAGE_FORMAT_ARGB8888:<br>
+ case __DRI_IMAGE_FORMAT_ABGR8888:<br>
+ case __DRI_IMAGE_FORMAT_XBGR8888:<br>
+ case __DRI_IMAGE_FORMAT_XRGB2101010:<br>
+ case __DRI_IMAGE_FORMAT_ARGB2101010:<br>
+ case __DRI_IMAGE_FORMAT_SARGB8:<br>
+ return 4;<br>
+ case __DRI_IMAGE_FORMAT_NONE:<br>
+ default:<br>
+ return 0;<br>
+ }<br>
+}<br>
+<br>
+/** dri3_alloc_render_buffer<br>
+ *<br>
+ * Use the driver createImage function to construct a __DRIimage, then<br>
+ * get a file descriptor for that and create an X pixmap from that<br>
+ *<br>
+ * Allocate an xshmfence for synchronization<br>
+ */<br>
+static struct dri3_buffer *<br>
+dri3_alloc_render_buffer(struct dri2_egl_display *dri2_dpy, xcb_drawable_t draw,<br>
+ unsigned int format, int width, int height, int depth)<br>
+{<br>
+ struct dri3_buffer *buffer;<br>
+ __DRIimage *pixmap_buffer;<br>
+ xcb_pixmap_t pixmap;<br>
+ xcb_sync_fence_t sync_fence;<br>
+ struct xshmfence *shm_fence;<br>
+ int buffer_fd, fence_fd;<br>
+ int stride;<br>
+<br>
+ /* Create an xshmfence object and<br>
+ * prepare to send that to the X server<br>
+ */<br>
+<br>
+ fence_fd = xshmfence_alloc_shm();<br>
+ if (fence_fd < 0) {<br>
+ _eglLog(_EGL_WARNING, "DRI3 Fence object allocation failure %s\n", strerror(errno));<br>
+ return NULL;<br>
+ }<br>
+ shm_fence = xshmfence_map_shm(fence_fd);<br>
+ if (shm_fence == NULL) {<br>
+ _eglLog(_EGL_WARNING, "DRI3 Fence object map failure %s\n", strerror(errno));<br>
+ goto no_shm_fence;<br>
+ }<br>
+<br>
+ /* Allocate the image from the driver<br>
+ */<br>
+ buffer = calloc(1, sizeof (struct dri3_buffer));<br>
+ if (!buffer)<br>
+ goto no_buffer;<br>
+<br>
+ buffer->cpp = dri3_cpp_for_format(format);<br>
+ if (!buffer->cpp) {<br>
+ _eglLog(_EGL_WARNING, "DRI3 buffer format %d invalid\n", format);<br>
+ goto no_image;<br>
+ }<br>
+<br>
+ if (!dri2_dpy->is_different_gpu) {<br>
+ buffer->image = (*dri2_dpy->image->createImage) (dri2_dpy->dri_screen,<br>
+ width, height,<br>
+ format,<br>
+ __DRI_IMAGE_USE_SHARE |<br>
+ __DRI_IMAGE_USE_SCANOUT,<br>
+ buffer);<br>
+ pixmap_buffer = buffer->image;<br>
+<br>
+ if (!buffer->image) {<br>
+ _eglLog(_EGL_WARNING, "DRI3 gpu image creation failure\n");<br>
+ goto no_image;<br>
+ }<br>
+ } else {<br>
+ buffer->image = (*dri2_dpy->image->createImage) (dri2_dpy->dri_screen,<br>
+ width, height,<br>
+ format,<br>
+ 0,<br>
+ buffer);<br>
+<br>
+ if (!buffer->image) {<br>
+ _eglLog(_EGL_WARNING, "DRI3 other gpu image creation failure\n");<br>
+ goto no_image;<br>
+ }<br>
+<br>
+ buffer->linear_buffer = (*dri2_dpy->image->createImage) (dri2_dpy->dri_screen,<br>
+ width, height,<br>
+ format,<br>
+ __DRI_IMAGE_USE_SHARE |<br>
+ __DRI_IMAGE_USE_LINEAR,<br>
+ buffer);<br>
+ pixmap_buffer = buffer->linear_buffer;<br>
+<br>
+ if (!buffer->linear_buffer) {<br>
+ _eglLog(_EGL_WARNING, "DRI3 gpu linear image creation failure\n");<br>
+ goto no_linear_buffer;<br>
+ }<br>
+ }<br>
+<br>
+ /* X wants the stride, so ask the image for it<br>
+ */<br>
+ if (!(*dri2_dpy->image->queryImage)(pixmap_buffer, __DRI_IMAGE_ATTRIB_STRIDE, &stride)) {<br>
+ _eglLog(_EGL_WARNING, "DRI3 get image stride failed\n");<br>
+ goto no_buffer_attrib;<br>
+ }<br>
+<br>
+ buffer->pitch = stride;<br>
+<br>
+ if (!(*dri2_dpy->image->queryImage)(pixmap_buffer, __DRI_IMAGE_ATTRIB_FD, &buffer_fd)) {<br>
+ _eglLog(_EGL_WARNING, "DRI3 get image FD failed\n");<br>
+ goto no_buffer_attrib;<br>
+ }<br>
+<br>
+ xcb_dri3_pixmap_from_buffer(dri2_dpy->conn,<br>
+ (pixmap = xcb_generate_id(dri2_dpy->conn)),<br>
+ draw,<br>
+ buffer->size,<br>
+ width, height, buffer->pitch,<br>
+ depth, buffer->cpp * 8,<br>
+ buffer_fd);<br>
+<br>
+ xcb_dri3_fence_from_fd(dri2_dpy->conn,<br>
+ pixmap,<br>
+ (sync_fence = xcb_generate_id(dri2_dpy->conn)),<br>
+ false,<br>
+ fence_fd);<br>
+<br>
+ buffer->pixmap = pixmap;<br>
+ buffer->own_pixmap = true;<br>
+ buffer->sync_fence = sync_fence;<br>
+ buffer->shm_fence = shm_fence;<br>
+ buffer->width = width;<br>
+ buffer->height = height;<br>
+<br>
+ /* Mark the buffer as idle<br>
+ */<br>
+ dri3_fence_set(buffer);<br>
+<br>
+ return buffer;<br>
+<br>
+no_buffer_attrib:<br>
+ (*dri2_dpy->image->destroyImage)(pixmap_buffer);<br>
+no_linear_buffer:<br>
+ if (dri2_dpy->is_different_gpu)<br>
+ (*dri2_dpy->image->destroyImage)(buffer->image);<br>
+no_image:<br>
+ free(buffer);<br>
+no_buffer:<br>
+ xshmfence_unmap_shm(shm_fence);<br>
+no_shm_fence:<br>
+ close(fence_fd);<br>
+ _eglLog(_EGL_WARNING, "DRI3 alloc_render_buffer failed\n");<br>
+ return NULL;<br>
+}<br>
+<br>
+/** dri3_flush_present_events<br>
+ *<br>
+ * Process any present events that have been received from the X server<br>
+ */<br>
+static void<br>
+dri3_flush_present_events(struct dri2_egl_display *dri2_dpy,<br>
+ struct dri3_egl_surface *dri3_surf)<br>
+{<br>
+ /* Check to see if any configuration changes have occurred<br>
+ * since we were last invoked<br>
+ */<br>
+ if (dri3_surf->special_event) {<br>
+ xcb_generic_event_t *ev;<br>
+<br>
+ while ((ev = xcb_poll_for_special_event(dri2_dpy->conn,<br>
+ dri3_surf->special_event)) != NULL) {<br>
+ xcb_present_generic_event_t *ge = (void *) ev;<br>
+ dri3_handle_present_event(dri2_dpy, dri3_surf, ge);<br>
+ }<br>
+ }<br>
+}<br>
+<br>
+/** dri3_update_drawable<br>
+ *<br>
+ * Called the first time we use the drawable and then<br>
+ * after we receive present configure notify events to<br>
+ * track the geometry of the drawable<br>
+ */<br>
+static int<br>
+dri3_update_drawable(__DRIdrawable *driDrawable,<br>
+ struct dri3_egl_surface *dri3_surf,<br>
+ struct dri2_egl_display *dri2_dpy)<br>
+{<br>
+ /* First time through, go get the current drawable geometry<br>
+ */<br>
+ if (dri3_surf->first_init) {<br>
+ xcb_void_cookie_t cookie;<br>
+ xcb_generic_error_t *error;<br>
+ xcb_present_query_capabilities_cookie_t present_capabilities_cookie;<br>
+ xcb_present_query_capabilities_reply_t *present_capabilities_reply;<br>
+<br>
+ dri3_surf->first_init = false;<br>
+<br>
+ /* Try to select for input on the window.<br>
+ *<br>
+ * If the drawable is a window, this will get our events<br>
+ * delivered.<br>
+ *<br>
+ * Otherwise, we'll get a BadWindow error back from this request which<br>
+ * will let us know that the drawable is a pixmap instead.<br>
+ */<br>
+<br>
+<br>
+ cookie = xcb_present_select_input_checked(dri2_dpy->conn,<br>
+ (dri3_surf->eid = xcb_generate_id(dri2_dpy->conn)),<br>
+ dri3_surf->drawable,<br>
+ XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY|<br>
+ XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY|<br>
+ XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);<br>
+<br>
+ present_capabilities_cookie = xcb_present_query_capabilities(dri2_dpy->conn,<br>
+ dri3_surf->drawable);<br>
+<br>
+ /* Create an XCB event queue to hold present events outside of the usual<br>
+ * application event queue<br>
+ */<br>
+ dri3_surf->special_event = xcb_register_for_special_xge(dri2_dpy->conn,<br>
+ &xcb_present_id,<br>
+ dri3_surf->eid,<br>
+ dri3_surf->stamp);<br>
+<br>
+ dri3_surf->is_pixmap = false;<br>
+<br>
+ /* Check to see if our select input call failed. If it failed with a<br>
+ * BadWindow error, then assume the drawable is a pixmap. Destroy the<br>
+ * special event queue created above and mark the drawable as a pixmap<br>
+ */<br>
+<br>
+ error = xcb_request_check(dri2_dpy->conn, cookie);<br>
+<br>
+ present_capabilities_reply = xcb_present_query_capabilities_reply(dri2_dpy->conn,<br>
+ present_capabilities_cookie,<br>
+ NULL);<br>
+<br>
+ if (present_capabilities_reply) {<br>
+ dri3_surf->present_capabilities = present_capabilities_reply->capabilities;<br>
+ free(present_capabilities_reply);<br>
+ } else<br>
+ dri3_surf->present_capabilities = 0;<br>
+<br>
+ if (error) {<br>
+ if (error->error_code != BadWindow) {<br>
+ free(error);<br>
+ return false;<br>
+ }<br>
+ dri3_surf->is_pixmap = true;<br>
+ xcb_unregister_for_special_event(dri2_dpy->conn, dri3_surf->special_event);<br>
+ dri3_surf->special_event = NULL;<br>
+ }<br>
+ }<br>
+ dri3_flush_present_events(dri2_dpy, dri3_surf);<br>
+ return true;<br>
+}<br>
+<br>
+/* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while<br>
+ * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid<br>
+ * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and<br>
+ * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds<br>
+ */<br>
+static int<br>
+image_format_to_fourcc(int format)<br>
+{<br>
+<br>
+ /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */<br>
+ switch (format) {<br>
+ case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888;<br>
+ case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565;<br>
+ case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888;<br>
+ case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888;<br>
+ case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888;<br>
+ case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888;<br>
+ }<br>
+ return 0;<br>
+}<br>
+<br>
+/** dri3_get_pixmap_buffer<br>
+ *<br>
+ * Get the DRM object for a pixmap from the X server and<br>
+ * wrap that with a __DRIimage structure using createImageFromFds<br>
+ */<br>
+static struct dri3_buffer *<br>
+dri3_get_pixmap_buffer(__DRIdrawable *driDrawable,<br>
+ unsigned int format,<br>
+ enum dri3_buffer_type buffer_type,<br>
+ struct dri3_egl_surface *dri3_surf,<br>
+ struct dri2_egl_display *dri2_dpy)<br>
+{<br>
+ int buf_id = dri3_pixmap_buf_id(buffer_type);<br>
+ struct dri3_buffer *buffer = dri3_surf->buffers[buf_id];<br>
+ xcb_drawable_t pixmap;<br>
+ xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;<br>
+ xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;<br>
+ int *fds;<br>
+ xcb_sync_fence_t sync_fence;<br>
+ struct xshmfence *shm_fence;<br>
+ int fence_fd;<br>
+ __DRIimage *image_planar;<br>
+ int stride, offset;<br>
+<br>
+ if (buffer)<br>
+ return buffer;<br>
+<br>
+ pixmap = dri3_surf->drawable;<br>
+<br>
+ buffer = calloc(1, sizeof (struct dri3_buffer));<br>
+ if (!buffer)<br>
+ goto no_buffer;<br>
+<br>
+ fence_fd = xshmfence_alloc_shm();<br>
+ if (fence_fd < 0)<br>
+ goto no_fence;<br>
+ shm_fence = xshmfence_map_shm(fence_fd);<br>
+ if (shm_fence == NULL) {<br>
+ close (fence_fd);<br>
+ goto no_fence;<br>
+ }<br>
+<br>
+ xcb_dri3_fence_from_fd(dri2_dpy->conn,<br>
+ pixmap,<br>
+ (sync_fence = xcb_generate_id(dri2_dpy->conn)),<br>
+ false,<br>
+ fence_fd);<br>
+<br>
+ /* Get an FD for the pixmap object<br>
+ */<br>
+ bp_cookie = xcb_dri3_buffer_from_pixmap(dri2_dpy->conn, pixmap);<br>
+ bp_reply = xcb_dri3_buffer_from_pixmap_reply(dri2_dpy->conn,<br>
+ bp_cookie, NULL);<br>
+ if (!bp_reply)<br>
+ goto no_image;<br>
+ fds = xcb_dri3_buffer_from_pixmap_reply_fds(dri2_dpy->conn, bp_reply);<br>
+<br>
+ stride = bp_reply->stride;<br>
+ offset = 0;<br>
+<br>
+ /* createImageFromFds creates a wrapper __DRIimage structure which<br>
+ * can deal with multiple planes for things like Yuv images. So, once<br>
+ * we've gotten the planar wrapper, pull the single plane out of it and<br>
+ * discard the wrapper.<br>
+ */<br>
+ image_planar = (*dri2_dpy->image->createImageFromFds) (dri2_dpy->dri_screen,<br>
+ bp_reply->width,<br>
+ bp_reply->height,<br>
+ image_format_to_fourcc(format),<br>
+ fds, 1,<br>
+ &stride, &offset, buffer);<br>
+ close(fds[0]);<br>
+ if (!image_planar)<br>
+ goto no_image;<br>
+<br>
+ buffer->image = (*dri2_dpy->image->fromPlanar)(image_planar, 0, buffer);<br>
+<br>
+ (*dri2_dpy->image->destroyImage)(image_planar);<br>
+<br>
+ if (!buffer->image)<br>
+ goto no_image;<br>
+<br>
+ buffer->pixmap = pixmap;<br>
+ buffer->own_pixmap = false;<br>
+ buffer->width = bp_reply->width;<br>
+ buffer->height = bp_reply->height;<br>
+ buffer->buffer_type = buffer_type;<br>
+ buffer->shm_fence = shm_fence;<br>
+ buffer->sync_fence = sync_fence;<br>
+<br>
+ dri3_surf->buffers[buf_id] = buffer;<br>
+ return buffer;<br>
+<br>
+no_image:<br>
+ xcb_sync_destroy_fence(dri2_dpy->conn, sync_fence);<br>
+ xshmfence_unmap_shm(shm_fence);<br>
+no_fence:<br>
+ free(buffer);<br>
+no_buffer:<br>
+ return NULL;<br>
+}<br>
+<br>
+/** dri3_find_back<br>
+ *<br>
+ * Find an idle back buffer. If there isn't one, then<br>
+ * wait for a present idle notify event from the X server<br>
+ */<br>
+static int<br>
+dri3_find_back(struct dri2_egl_display *dri2_dpy,<br>
+ struct dri3_egl_surface *dri3_surf)<br>
+{<br>
+ int b;<br>
+ xcb_generic_event_t *ev;<br>
+ xcb_present_generic_event_t *ge;<br>
+<br>
+ for (;;) {<br>
+ for (b = 0; b < dri3_surf->num_back; b++) {<br>
+ int id = DRI3_BACK_ID((b + dri3_surf->cur_back) % dri3_surf->num_back);<br>
+ struct dri3_buffer *buffer = dri3_surf->buffers[id];<br>
+<br>
+ if (!buffer || !buffer->busy) {<br>
+ dri3_surf->cur_back = id;<br>
+ return id;<br>
+ }<br>
+ }<br>
+ xcb_flush(dri2_dpy->conn);<br>
+ ev = xcb_wait_for_special_event(dri2_dpy->conn, dri3_surf->special_event);<br>
+ if (!ev)<br>
+ return -1;<br>
+ ge = (void *) ev;<br>
+ dri3_handle_present_event(dri2_dpy, dri3_surf, ge);<br>
+ }<br>
+}<br>
+<br>
+/** dri3_get_buffer<br>
+ *<br>
+ * Find a front or back buffer, allocating new ones as necessary<br>
+ */<br>
+static struct dri3_buffer *<br>
+dri3_get_buffer(__DRIdrawable *driDrawable,<br>
+ unsigned int format,<br>
+ enum dri3_buffer_type buffer_type,<br>
+ struct dri3_egl_surface *dri3_surf,<br>
+ struct dri2_egl_display *dri2_dpy)<br>
+{<br>
+ struct dri3_buffer *buffer;<br>
+ _EGLContext *ctx = _eglGetCurrentContext();<br>
+ struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);<br>
+ int buf_id;<br>
+<br>
+ if (buffer_type == dri3_buffer_back) {<br>
+ buf_id = dri3_find_back(dri2_dpy, dri3_surf);<br>
+<br>
+ if (buf_id < 0)<br>
+ return NULL;<br>
+ } else {<br>
+ buf_id = DRI3_FRONT_ID;<br>
+ }<br>
+<br>
+ buffer = dri3_surf->buffers[buf_id];<br>
+<br>
+ /* Allocate a new buffer if there isn't an old one, or if that<br>
+ * old one is the wrong size<br>
+ */<br>
+ if (!buffer || buffer->width != dri3_surf->base.Width ||<br>
+ buffer->height != dri3_surf->base.Height) {<br>
+ struct dri3_buffer *new_buffer;<br>
+<br>
+ /* Allocate the new buffers<br>
+ */<br>
+ new_buffer = dri3_alloc_render_buffer(dri2_dpy,<br>
+ dri3_surf->drawable,<br>
+ format,<br>
+ dri3_surf->base.Width,<br>
+ dri3_surf->base.Height,<br>
+ dri3_surf->depth);<br>
+ if (!new_buffer)<br>
+ return NULL;<br>
+<br>
+ /* When resizing, copy the contents of the old buffer, waiting for that<br>
+ * copy to complete using our fences before proceeding<br>
+ */<br>
+ switch (buffer_type) {<br>
+ case dri3_buffer_back:<br>
+ if (buffer) {<br>
+ if (!buffer->linear_buffer) {<br>
+ dri3_fence_reset(dri2_dpy->conn, new_buffer);<br>
+ dri3_fence_await(dri2_dpy->conn, buffer);<br>
+ dri3_copy_area(dri2_dpy->conn,<br>
+ buffer->pixmap,<br>
+ new_buffer->pixmap,<br>
+ dri3_drawable_gc(dri2_dpy, dri3_surf),<br>
+ 0, 0, 0, 0,<br>
+ dri3_surf->base.Width,<br>
+ dri3_surf->base.Height);<br>
+ dri3_fence_trigger(dri2_dpy->conn, new_buffer);<br>
+ } else if (dri2_ctx->base.Resource.Display == dri3_surf->base.Resource.Display) {<br>
+ dri2_dpy->image->blitImage(dri2_ctx->dri_context,<br>
+ new_buffer->image,<br>
+ buffer->image,<br>
+ 0, 0, dri3_surf->base.Width,<br>
+ dri3_surf->base.Height,<br>
+ 0, 0, dri3_surf->base.Width,<br>
+ dri3_surf->base.Height, 0);<br>
+ }<br>
+ dri3_free_render_buffer(dri2_dpy, dri3_surf, buffer);<br>
+ }<br>
+ break;<br>
+ case dri3_buffer_front:<br>
+ dri3_fence_reset(dri2_dpy->conn, new_buffer);<br>
+ dri3_copy_area(dri2_dpy->conn,<br>
+ dri3_surf->drawable,<br>
+ new_buffer->pixmap,<br>
+ dri3_drawable_gc(dri2_dpy, dri3_surf),<br>
+ 0, 0, 0, 0,<br>
+ dri3_surf->base.Width,<br>
+ dri3_surf->base.Height);<br>
+ dri3_fence_trigger(dri2_dpy->conn, new_buffer);<br>
+<br>
+ if (new_buffer->linear_buffer &&<br>
+ dri2_ctx->base.Resource.Display == dri3_surf->base.Resource.Display) {<br>
+ dri3_fence_await(dri2_dpy->conn, new_buffer);<br>
+ dri2_dpy->image->blitImage(dri2_ctx->dri_context,<br>
+ new_buffer->image,<br>
+ new_buffer->linear_buffer,<br>
+ 0, 0, dri3_surf->base.Width,<br>
+ dri3_surf->base.Height,<br>
+ 0, 0, dri3_surf->base.Width,<br>
+ dri3_surf->base.Height, 0);<br>
+ }<br>
+ break;<br>
+ }<br>
+ buffer = new_buffer;<br>
+ buffer->buffer_type = buffer_type;<br>
+ dri3_surf->buffers[buf_id] = buffer;<br>
+ }<br>
+ dri3_fence_await(dri2_dpy->conn, buffer);<br>
+<br>
+ /* Return the requested buffer */<br>
+ return buffer;<br>
+}<br>
+<br>
+/** dri3_free_buffers<br>
+ *<br>
+ * Free the front bufffer or all of the back buffers. Used<br>
+ * when the application changes which buffers it needs<br>
+ */<br>
+static void<br>
+dri3_free_buffers(__DRIdrawable *driDrawable,<br>
+ enum dri3_buffer_type buffer_type,<br>
+ struct dri3_egl_surface *dri3_surf,<br>
+ struct dri2_egl_display *dri2_dpy)<br>
+{<br>
+ struct dri3_buffer *buffer;<br>
+ int first_id;<br>
+ int n_id;<br>
+ int buf_id;<br>
+<br>
+ switch (buffer_type) {<br>
+ case dri3_buffer_back:<br>
+ first_id = DRI3_BACK_ID(0);<br>
+ n_id = DRI3_MAX_BACK;<br>
+ break;<br>
+ case dri3_buffer_front:<br>
+ first_id = DRI3_FRONT_ID;<br>
+ n_id = 1;<br>
+ }<br>
+<br>
+ for (buf_id = first_id; buf_id < first_id + n_id; buf_id++) {<br>
+ buffer = dri3_surf->buffers[buf_id];<br>
+ if (buffer) {<br>
+ dri3_free_render_buffer(dri2_dpy, dri3_surf, buffer);<br>
+ dri3_surf->buffers[buf_id] = NULL;<br>
+ }<br>
+ }<br>
+}<br>
+<br>
+/** dri3_get_buffers<br>
+ *<br>
+ * The published buffer allocation API.<br>
+ * Returns all of the necessary buffers, allocating<br>
+ * as needed.<br>
+ */<br>
+static int<br>
+dri3_get_buffers(__DRIdrawable *driDrawable,<br>
+ unsigned int format,<br>
+ uint32_t *stamp,<br>
+ void *loaderPrivate,<br>
+ uint32_t buffer_mask,<br>
+ struct __DRIimageList *buffers)<br>
+{<br>
+ struct dri3_egl_surface *dri3_surf = loaderPrivate;<br>
+ struct dri2_egl_display *dri2_dpy =<br>
+ dri2_egl_display(dri3_surf->base.Resource.Display);<br>
+ struct dri3_buffer *front, *back;<br>
+<br>
+ buffers->image_mask = 0;<br>
+ buffers->front = NULL;<br>
+ buffers->back = NULL;<br>
+<br>
+ front = NULL;<br>
+ back = NULL;<br>
+<br>
+ if (!dri3_update_drawable(driDrawable, dri3_surf, dri2_dpy))<br>
+ return false;<br>
+<br>
+ /* pixmaps always have front buffers */<br>
+ if (dri3_surf->is_pixmap)<br>
+ buffer_mask |= __DRI_IMAGE_BUFFER_FRONT;<br>
+<br>
+ if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {<br>
+ /* All pixmaps are owned by the server gpu.<br>
+ * When we use a different gpu, we can't use the pixmap<br>
+ * as buffer since it is potentially tiled a way<br>
+ * our device can't understand. In this case, use<br>
+ * a fake front buffer. Hopefully the pixmap<br>
+ * content will get synced with the fake front<br>
+ * buffer.<br>
+ */<br>
+ if (dri3_surf->is_pixmap && !dri2_dpy->is_different_gpu)<br>
+ front = dri3_get_pixmap_buffer(driDrawable,<br>
+ format,<br>
+ dri3_buffer_front,<br>
+ dri3_surf,<br>
+ dri2_dpy);<br>
+ else<br>
+ front = dri3_get_buffer(driDrawable,<br>
+ format,<br>
+ dri3_buffer_front,<br>
+ dri3_surf,<br>
+ dri2_dpy);<br>
+<br>
+ if (!front)<br>
+ return false;<br>
+ } else {<br>
+ dri3_free_buffers(driDrawable, dri3_buffer_front, dri3_surf, dri2_dpy);<br>
+ dri3_surf->have_fake_front = 0;<br>
+ }<br>
+<br>
+ if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) {<br>
+ back = dri3_get_buffer(driDrawable,<br>
+ format,<br>
+ dri3_buffer_back,<br>
+ dri3_surf,<br>
+ dri2_dpy);<br>
+ if (!back)<br>
+ return false;<br>
+ dri3_surf->have_back = 1;<br>
+ } else {<br>
+ dri3_free_buffers(driDrawable, dri3_buffer_back, dri3_surf, dri2_dpy);<br>
+ dri3_surf->have_back = 0;<br>
+ }<br>
+<br>
+ if (front) {<br>
+ buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT;<br>
+ buffers->front = front->image;<br>
+ dri3_surf->have_fake_front = dri2_dpy->is_different_gpu || !dri3_surf->is_pixmap;<br>
+ }<br>
+<br>
+ if (back) {<br>
+ buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK;<br>
+ buffers->back = back->image;<br>
+ }<br>
+<br>
+ dri3_surf->stamp = stamp;<br>
+<br>
+ return true;<br>
+}<br>
+<br>
+const __DRIimageLoaderExtension dri3_image_loader_extension = {<br>
+ .base = { __DRI_IMAGE_LOADER, 1 },<br>
+<br>
+ .getBuffers = dri3_get_buffers,<br>
+ .flushFrontBuffer = dri3_flush_front_buffer,<br>
+};<br>
+<br>
+static int<br>
+dri3_get_ust(int64_t *ust)<br>
+{<br>
+ struct timeval tv;<br>
+<br>
+ if (ust == NULL)<br>
+ return -EFAULT;<br>
+<br>
+ if (gettimeofday(&tv, NULL) == 0) {<br>
+ ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec;<br>
+ return 0;<br>
+ } else<br>
+ return -errno;<br>
+}<br>
+<br>
+static GLboolean<br>
+dri3_get_msc_rate(__DRIdrawable *draw, int32_t *numerator,<br>
+ int32_t *denominator, void *loaderPrivate)<br>
+{<br>
+#ifdef XF86VIDMODE<br>
+ dri3_egl_surface *dri3_surf = loaderPrivate;<br>
+ struct dri2_egl_display *dri2_dpy =<br>
+ dri2_egl_display(dri3_surf->base.Resource.Display);<br>
+ XF86VidModeModeLine mode_line;<br>
+ int dot_clock;<br>
+ int i;<br>
+<br>
+ if (XF86VidModeQueryVersion(dri2_dpy->dpy, &i, &i) &&<br>
+ XF86VidModeGetModeLine(dri2_dpy->dpy, dri2_dpy->screen,<br>
+ &dot_clock, &mode_line)) {<br>
+ unsigned n = dot_clock * 1000;<br>
+ unsigned d = mode_line.vtotal * mode_line.htotal;<br>
+<br>
+# define V_INTERLACE 0x010<br>
+# define V_DBLSCAN 0x020<br>
+<br>
+ if (mode_line.flags & V_INTERLACE)<br>
+ n *= 2;<br>
+ else if (mode_line.flags & V_DBLSCAN)<br>
+ d *= 2;<br>
+<br>
+ /* The OML_sync_control spec requires that if the refresh rate is a<br>
+ * whole number, that the returned numerator be equal to the refresh<br>
+ * rate and the denominator be 1.<br>
+ */<br>
+<br>
+ if (n % d == 0) {<br>
+ n /= d;<br>
+ d = 1;<br>
+ }<br>
+ else {<br>
+ static const unsigned f[] = { 13, 11, 7, 5, 3, 2, 0 };<br>
+<br>
+ /* This is a poor man's way to reduce a fraction. It's far from<br>
+ * perfect, but it will work well enough for this situation.<br>
+ */<br>
+<br>
+ for (i = 0; f[i] != 0; i++) {<br>
+ while (n % f[i] == 0 && d % f[i] == 0) {<br>
+ d /= f[i];<br>
+ n /= f[i];<br>
+ }<br>
+ }<br>
+ }<br>
+<br>
+ *numerator = n;<br>
+ *denominator = d;<br>
+<br>
+ return True;<br>
+<br>
+#endif<br>
+ return False;<br>
+}<br>
+<br>
+const __DRIsystemTimeExtension dri3_system_time_extension = {<br>
+ .base = { __DRI_SYSTEM_TIME, 1 },<br>
+<br>
+ .getUST = dri3_get_ust,<br>
+ .getMSCRate = dri3_get_msc_rate,<br>
+};<br>
+<br>
+/** dri3_swap_buffers_msc<br>
+ *<br>
+ * Make the current back buffer visible using the present extension<br>
+ */<br>
+static int64_t<br>
+dri3_swap_buffers_msc(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,<br>
+ int64_t target_msc, int64_t divisor,<br>
+ int64_t remainder)<br>
+{<br>
+ struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw);<br>
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);<br>
+ struct dri3_buffer *back;<br>
+ _EGLContext *ctx = _eglGetCurrentContext();<br>
+ struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);<br>
+ int64_t ret = 0;<br>
+ uint32_t options = XCB_PRESENT_OPTION_NONE;<br>
+<br>
+ dri2_flush_drawable_for_swapbuffers(disp, draw);<br>
+<br>
+ back = dri3_surf->buffers[DRI3_BACK_ID(dri3_surf->cur_back)];<br>
+ if (dri2_dpy->is_different_gpu && back) {<br>
+ /* Update the linear buffer before presenting the pixmap */<br>
+ dri2_dpy->image->blitImage(dri2_ctx->dri_context,<br>
+ back->linear_buffer,<br>
+ back->image,<br>
+ 0, 0, back->width,<br>
+ back->height,<br>
+ 0, 0, back->width,<br>
+ back->height, __BLIT_FLAG_FLUSH);<br>
+ /* Update the fake front */<br>
+ if (dri3_surf->have_fake_front)<br>
+ dri2_dpy->image->blitImage(dri2_ctx->dri_context,<br>
+ dri3_surf->buffers[DRI3_FRONT_ID]->image,<br>
+ back->image,<br>
+ 0, 0, dri3_surf->base.Width,<br>
+ dri3_surf->base.Height,<br>
+ 0, 0, dri3_surf->base.Width,<br>
+ dri3_surf->base.Height,<br>
+ __BLIT_FLAG_FLUSH);<br>
+ }<br>
+<br>
+ dri3_flush_present_events(dri2_dpy, dri3_surf);<br>
+<br>
+ if (back && !dri3_surf->is_pixmap) {<br>
+ dri3_fence_reset(dri2_dpy->conn, back);<br>
+<br>
+ /* Compute when we want the frame shown by taking the last known successful<br>
+ * MSC and adding in a swap interval for each outstanding swap request.<br>
+ * target_msc=divisor=remainder=0 means "Use glXSwapBuffers() semantic"<br>
+ */<br>
+ ++dri3_surf->send_sbc;<br>
+ if (target_msc == 0 && divisor == 0 && remainder == 0)<br>
+ target_msc = dri3_surf->msc + dri3_surf->base.SwapInterval * (dri3_surf->send_sbc - dri3_surf->recv_sbc);<br>
+ else if (divisor == 0 && remainder > 0) {<br>
+ /*<br>
+ * "If <divisor> = 0, the swap will occur when MSC becomes<br>
+ * greater than or equal to <target_msc>."<br>
+ *<br>
+ * Note that there's no mention of the remainder. The Present extension<br>
+ * throws BadValue for remainder != 0 with divisor == 0, so just drop<br>
+ * the passed in value.<br>
+ */<br>
+ remainder = 0;<br>
+ }<br>
+<br>
+ /* From the EGL 1.4 spec (page 53):<br>
+ *<br>
+ * "If <interval> is set to a value of 0, buffer swaps are not<br>
+ * synchronized to a video frame."<br>
+ *<br>
+ * Implementation note: It is possible to enable triple buffering behaviour<br>
+ * by not using XCB_PRESENT_OPTION_ASYNC, but this should not be the default.<br>
+ */<br>
+ if (dri3_surf->base.SwapInterval == 0)<br>
+ options |= XCB_PRESENT_OPTION_ASYNC;<br>
+<br>
+ back->busy = 1;<br>
+ back->last_swap = dri3_surf->send_sbc;<br>
+ xcb_present_pixmap(dri2_dpy->conn,<br>
+ dri3_surf->drawable,<br>
+ back->pixmap,<br>
+ (uint32_t) dri3_surf->send_sbc,<br>
+ 0, /* valid */<br>
+ 0, /* update */<br>
+ 0, /* x_off */<br>
+ 0, /* y_off */<br>
+ None, /* target_crtc */<br>
+ None,<br>
+ back->sync_fence,<br>
+ options,<br>
+ target_msc,<br>
+ divisor,<br>
+ remainder, 0, NULL);<br>
+ ret = (int64_t) dri3_surf->send_sbc;<br>
+<br>
+ /* If there's a fake front, then copy the source back buffer<br>
+ * to the fake front to keep it up to date. This needs<br>
+ * to reset the fence and make future users block until<br>
+ * the X server is done copying the bits<br>
+ */<br>
+ if (dri3_surf->have_fake_front && !dri2_dpy->is_different_gpu) {<br>
+ dri3_fence_reset(dri2_dpy->conn, dri3_surf->buffers[DRI3_FRONT_ID]);<br>
+ dri3_copy_area(dri2_dpy->conn,<br>
+ back->pixmap,<br>
+ dri3_surf->buffers[DRI3_FRONT_ID]->pixmap,<br>
+ dri3_drawable_gc(dri2_dpy, dri3_surf),<br>
+ 0, 0, 0, 0,<br>
+ dri3_surf->base.Width,<br>
+ dri3_surf->base.Height);<br>
+ dri3_fence_trigger(dri2_dpy->conn, dri3_surf->buffers[DRI3_FRONT_ID]);<br>
+ }<br>
+ xcb_flush(dri2_dpy->conn);<br>
+ if (dri3_surf->stamp)<br>
+ ++(*dri3_surf->stamp);<br>
+ }<br>
+<br>
+ (*dri2_dpy->flush->invalidate)(dri3_surf->dri_drawable);<br>
+<br>
+ return ret;<br>
+}<br>
+<br>
+static EGLBoolean<br>
+dri3_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)<br>
+{<br>
+ return dri3_swap_buffers_msc(drv, disp, draw, 0, 0, 0) != -1;<br>
+}<br>
+<br>
+static int<br>
+dri3_query_buffer_age(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)<br>
+{<br>
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);<br>
+ struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);<br>
+ int back_id = DRI3_BACK_ID(dri3_find_back(dri2_dpy, dri3_surf));<br>
+<br>
+ if (back_id < 0 || !dri3_surf->buffers[back_id])<br>
+ return 0;<br>
+<br>
+ if (dri3_surf->buffers[back_id]->last_swap != 0)<br>
+ return dri3_surf->send_sbc - dri3_surf->buffers[back_id]->last_swap + 1;<br>
+ else<br>
+ return 0;<br>
+}<br>
+<br>
+/* FIXME: Is this right? Seems problematic for WL_bind_wayland_display */<br>
+static int<br>
+dri3_authenticate(_EGLDisplay *disp, uint32_t id)<br>
+{<br>
+ return 0;<br>
+}<br>
+<br>
+struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {<br>
+ .authenticate = dri3_authenticate,<br>
+ .create_window_surface = dri3_create_window_surface,<br>
+ .create_pixmap_surface = dri3_create_pixmap_surface,<br>
+ .create_pbuffer_surface = dri3_create_pbuffer_surface,<br>
+ .destroy_surface = dri3_destroy_surface,<br>
+ .create_image = dri2_create_image_khr,<br>
+ .swap_interval = dri3_set_swap_interval,<br>
+ .swap_buffers = dri3_swap_buffers,<br>
+ .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,<br>
+ .swap_buffers_region = dri2_fallback_swap_buffers_region,<br>
+ .post_sub_buffer = dri2_fallback_post_sub_buffer,<br>
+ .copy_buffers = dri2_fallback_copy_buffers,<br>
+ .query_buffer_age = dri3_query_buffer_age,<br>
+ .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,<br>
+ .get_sync_values = dri3_get_sync_values,<br>
+};<br>
+<br>
+/** dri3_open<br>
+ *<br>
+ * Wrapper around xcb_dri3_open<br>
+ */<br>
+static int<br>
+dri3_open(xcb_connection_t *conn,<br>
+ xcb_window_t root,<br>
+ uint32_t provider)<br>
+{<br>
+ xcb_dri3_open_cookie_t cookie;<br>
+ xcb_dri3_open_reply_t *reply;<br>
+ int fd;<br>
+<br>
+ cookie = xcb_dri3_open(conn,<br>
+ root,<br>
+ provider);<br>
+<br>
+ reply = xcb_dri3_open_reply(conn, cookie, NULL);<br>
+ if (!reply)<br>
+ return -1;<br>
+<br>
+ if (reply->nfd != 1) {<br>
+ free(reply);<br>
+ return -1;<br>
+ }<br>
+<br>
+ fd = xcb_dri3_open_reply_fds(conn, reply)[0];<br>
+ fcntl(fd, F_SETFD, FD_CLOEXEC);<br>
+<br>
+ return fd;<br>
+}<br>
+<br>
+EGLBoolean<br>
+dri3_x11_connect(struct dri2_egl_display *dri2_dpy)<br>
+{<br>
+ xcb_dri3_query_version_reply_t *dri3_query;<br>
+ xcb_dri3_query_version_cookie_t dri3_query_cookie;<br>
+ xcb_present_query_version_reply_t *present_query;<br>
+ xcb_present_query_version_cookie_t present_query_cookie;<br>
+ xcb_generic_error_t *error;<br>
+ xcb_screen_iterator_t s;<br>
+ xcb_screen_t *screen;<br>
+ const xcb_query_extension_reply_t *extension;<br>
+<br>
+ xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri3_id);<br>
+ xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_present_id);<br>
+<br>
+ extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri3_id);<br>
+ if (!(extension && extension->present))<br>
+ return EGL_FALSE;<br>
+<br>
+ extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_present_id);<br>
+ if (!(extension && extension->present))<br>
+ return EGL_FALSE;<br>
+<br>
+ dri3_query_cookie = xcb_dri3_query_version(dri2_dpy->conn,<br>
+ XCB_DRI3_MAJOR_VERSION,<br>
+ XCB_DRI3_MINOR_VERSION);<br>
+<br>
+ present_query_cookie = xcb_present_query_version(dri2_dpy->conn,<br>
+ XCB_PRESENT_MAJOR_VERSION,<br>
+ XCB_PRESENT_MINOR_VERSION);<br>
+<br>
+ /* FIXME: a little bit memory leak here */<br>
+ dri3_query =<br>
+ xcb_dri3_query_version_reply(dri2_dpy->conn, dri3_query_cookie, &error);<br>
+ if (dri3_query == NULL || error != NULL) {<br>
+ _eglLog(_EGL_WARNING, "DRI2: failed to query dri3 version");<br>
+ free(error);<br>
+ return EGL_FALSE;<br>
+ }<br>
+ dri2_dpy->dri3_major = dri3_query->major_version;<br>
+ dri2_dpy->dri3_minor = dri3_query->minor_version;<br>
+ free(dri3_query);<br>
+<br>
+ present_query =<br>
+ xcb_present_query_version_reply(dri2_dpy->conn,<br>
+ present_query_cookie, &error);<br>
+ if (present_query == NULL || error != NULL) {<br>
+ _eglLog(_EGL_WARNING, "DRI2: failed to query Present version");<br>
+ free(error);<br>
+ return EGL_FALSE;<br>
+ }<br>
+ dri2_dpy->present_major = present_query->major_version;<br>
+ dri2_dpy->present_minor = present_query->minor_version;<br>
+ free(present_query);<br>
+<br>
+ s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));<br>
+ screen = get_xcb_screen(s, dri2_dpy->screen);<br>
+ if (!screen) {<br>
+ _eglError(EGL_BAD_NATIVE_WINDOW, "dri3_x11_connect");<br>
+ return EGL_FALSE;<br>
+ }<br>
+<br>
+ dri2_dpy->fd = dri3_open(dri2_dpy->conn, screen->root, 0);<br>
+ if (dri2_dpy->fd < 0) {<br>
+ int conn_error = xcb_connection_has_error(dri2_dpy->conn);<br>
+ _eglLog(_EGL_WARNING, "DRI2: Screen seem not DRI3 capable");<br>
+<br>
+ if (conn_error)<br>
+ _eglLog(_EGL_WARNING, "DRI2: Failed to initialize DRI3");<br>
+<br>
+ return EGL_FALSE;<br>
+ }<br>
+<br>
+ dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu);<br>
+<br>
+ dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd, 0);<br>
+ if (!dri2_dpy->driver_name) {<br>
+ _eglLog(_EGL_WARNING, "DRI2: No driver found");<br>
+ close(dri2_dpy->fd);<br>
+ return EGL_FALSE;<br>
+ }<br>
+<br>
+ dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);<br>
+ if (!dri2_dpy->device_name) {<br>
+ _eglLog(_EGL_WARNING, "DRI2: Cannot find device name");<br>
+ close(dri2_dpy->fd);<br>
+ return EGL_FALSE;<br>
+ }<br>
+<br>
+ return EGL_TRUE;<br>
+}<br>
diff --git a/src/egl/drivers/dri2/platform_x11_dri3.h b/src/egl/drivers/dri2/platform_x11_dri3.h<br>
new file mode 100644<br>
index 0000000..efdfcdb<br>
--- /dev/null<br>
+++ b/src/egl/drivers/dri2/platform_x11_dri3.h<br>
@@ -0,0 +1,140 @@<br>
+/*<br>
+ * Copyright © 2013 Keith Packard<br>
+ *<br>
+ * Permission to use, copy, modify, distribute, and sell this software and its<br>
+ * documentation for any purpose is hereby granted without fee, provided that<br>
+ * the above copyright notice appear in all copies and that both that copyright<br>
+ * notice and this permission notice appear in supporting documentation, and<br>
+ * that the name of the copyright holders not be used in advertising or<br>
+ * publicity pertaining to distribution of the software without specific,<br>
+ * written prior permission. The copyright holders make no representations<br>
+ * about the suitability of this software for any purpose. It is provided "as<br>
+ * is" without express or implied warranty.<br>
+ *<br>
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,<br>
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO<br>
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR<br>
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,<br>
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER<br>
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE<br>
+ * OF THIS SOFTWARE.<br>
+ */<br>
+<br>
+#ifndef EGL_X11_DRI3_INCLUDED<br>
+#define EGL_X11_DRI3_INCLUDED<br>
+<br>
+#include <stdbool.h><br>
+#include <xcb/xcb.h><br>
+#include <xcb/present.h><br>
+<br>
+#include "egl_dri2.h"<br>
+<br>
+_EGL_DRIVER_TYPECAST(dri3_egl_surface, _EGLSurface, obj)<br>
+enum dri3_buffer_type {<br>
+ dri3_buffer_back = 0,<br>
+ dri3_buffer_front = 1<br>
+};<br>
+<br>
+struct dri3_buffer {<br>
+ __DRIimage *image;<br>
+ __DRIimage *linear_buffer;<br>
+ uint32_t pixmap;<br>
+<br>
+ /* Synchronization between the client and X server is done using an<br>
+ * xshmfence that is mapped into an X server SyncFence. This lets the<br>
+ * client check whether the X server is done using a buffer with a simple<br>
+ * xshmfence call, rather than going to read X events from the wire.<br>
+ *<br>
+ * However, we can only wait for one xshmfence to be triggered at a time,<br>
+ * so we need to know *which* buffer is going to be idle next. We do that<br>
+ * by waiting for a PresentIdleNotify event. When that event arrives, the<br>
+ * 'busy' flag gets cleared and the client knows that the fence has been<br>
+ * triggered, and that the wait call will not block.<br>
+ */<br>
+<br>
+ uint32_t sync_fence; /* XID of X SyncFence object */<br>
+ struct xshmfence *shm_fence; /* pointer to xshmfence object */<br>
+ bool busy; /* Set on swap, cleared on IdleNotify */<br>
+ bool own_pixmap; /* We allocated the pixmap ID, free on destroy */<br>
+<br>
+ uint32_t size;<br>
+ uint32_t pitch;<br>
+ uint32_t cpp;<br>
+ uint32_t flags;<br>
+ uint32_t width, height;<br>
+ uint64_t last_swap;<br>
+<br>
+ enum dri3_buffer_type buffer_type;<br>
+};<br>
+<br>
+<br>
+#define DRI3_MAX_BACK 4<br>
+#define DRI3_BACK_ID(i) (i)<br>
+#define DRI3_FRONT_ID (DRI3_MAX_BACK)<br>
+<br>
+static inline int<br>
+dri3_pixmap_buf_id(enum dri3_buffer_type buffer_type)<br>
+{<br>
+ if (buffer_type == dri3_buffer_back)<br>
+ return DRI3_BACK_ID(0);<br>
+ else<br>
+ return DRI3_FRONT_ID;<br>
+}<br>
+<br>
+#define DRI3_NUM_BUFFERS (1 + DRI3_MAX_BACK)<br>
+<br>
+struct dri3_egl_surface {<br>
+ _EGLSurface base;<br>
+ __DRIdrawable *dri_drawable;<br>
+ xcb_drawable_t drawable;<br>
+ int depth;<br>
+ uint8_t have_back;<br>
+ uint8_t have_fake_front;<br>
+ uint8_t is_pixmap;<br>
+ uint8_t flipping;<br>
+<br>
+ /* Present extension capabilities<br>
+ */<br>
+ uint32_t present_capabilities;<br>
+<br>
+ /* SBC numbers are tracked by using the serial numbers<br>
+ * in the present request and complete events<br>
+ */<br>
+ uint64_t send_sbc;<br>
+ uint64_t recv_sbc;<br>
+<br>
+ /* Last received UST/MSC values for pixmap present complete */<br>
+ uint64_t ust, msc;<br>
+<br>
+ /* Last received UST/MSC values from present notify msc event */<br>
+ uint64_t notify_ust, notify_msc;<br>
+<br>
+ /* Serial numbers for tracking wait_for_msc events */<br>
+ uint32_t send_msc_serial;<br>
+ uint32_t recv_msc_serial;<br>
+<br>
+ struct dri3_buffer *buffers[DRI3_NUM_BUFFERS];<br>
+ int cur_back;<br>
+ int num_back;<br>
+<br>
+ uint32_t *stamp;<br>
+<br>
+ xcb_present_event_t eid;<br>
+ xcb_gcontext_t gc;<br>
+ xcb_special_event_t *special_event;<br>
+<br>
+ /* LIBGL_SHOW_FPS support */<br>
+ uint64_t previous_ust;<br>
+ unsigned frames;<br>
+<br>
+ bool first_init;<br>
+};<br>
+<br>
+extern const __DRIimageLoaderExtension dri3_image_loader_extension;<br>
+extern const __DRIsystemTimeExtension dri3_system_time_extension;<br>
+extern struct dri2_egl_display_vtbl dri3_x11_display_vtbl;<br>
+<br>
+EGLBoolean<br>
+dri3_x11_connect(struct dri2_egl_display *dri2_dpy);<br>
+<br>
+#endif<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.4.4<br>
<br>
</font></span></blockquote></div><br></div></div>