summaryrefslogtreecommitdiff
path: root/lib/mesa/src/loader
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2019-01-29 11:52:33 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2019-01-29 11:52:33 +0000
commit37bbf6a1792773f11c15a4da1588a7520ee2fb4e (patch)
tree64944d4aa665a1e479cfc004e446593062254550 /lib/mesa/src/loader
parent6b139c2063623e9310025247cd966490b9aa57ea (diff)
Merge Mesa 18.3.2
Diffstat (limited to 'lib/mesa/src/loader')
-rw-r--r--lib/mesa/src/loader/Makefile.am3
-rw-r--r--lib/mesa/src/loader/Makefile.in48
-rw-r--r--lib/mesa/src/loader/loader.c226
-rw-r--r--lib/mesa/src/loader/loader.h3
-rw-r--r--lib/mesa/src/loader/loader_dri3_helper.c560
-rw-r--r--lib/mesa/src/loader/loader_dri3_helper.h25
6 files changed, 677 insertions, 188 deletions
diff --git a/lib/mesa/src/loader/Makefile.am b/lib/mesa/src/loader/Makefile.am
index 74ac6c51e..762525642 100644
--- a/lib/mesa/src/loader/Makefile.am
+++ b/lib/mesa/src/loader/Makefile.am
@@ -21,7 +21,7 @@
include Makefile.sources
-EXTRA_DIST = SConscript
+EXTRA_DIST = SConscript meson.build
noinst_LTLIBRARIES = libloader.la
@@ -30,6 +30,7 @@ AM_CPPFLAGS = \
-DUSE_DRICONF \
$(DEFINES) \
-I$(top_srcdir)/include \
+ -I$(top_srcdir)/include/drm-uapi \
-I$(top_srcdir)/src \
$(VISIBILITY_CFLAGS) \
$(XCB_DRI3_CFLAGS) \
diff --git a/lib/mesa/src/loader/Makefile.in b/lib/mesa/src/loader/Makefile.in
index fb418ac81..fea55e6c5 100644
--- a/lib/mesa/src/loader/Makefile.in
+++ b/lib/mesa/src/loader/Makefile.in
@@ -174,6 +174,8 @@ AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
+BACKTRACE_CFLAGS = @BACKTRACE_CFLAGS@
+BACKTRACE_LIBS = @BACKTRACE_LIBS@
BSYMBOLIC = @BSYMBOLIC@
CC = @CC@
CCAS = @CCAS@
@@ -187,6 +189,7 @@ CLOVER_STD_OVERRIDE = @CLOVER_STD_OVERRIDE@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
+CXX11_CXXFLAGS = @CXX11_CXXFLAGS@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
@@ -220,8 +223,6 @@ EXEEXT = @EXEEXT@
EXPAT_CFLAGS = @EXPAT_CFLAGS@
EXPAT_LIBS = @EXPAT_LIBS@
FGREP = @FGREP@
-FREEDRENO_CFLAGS = @FREEDRENO_CFLAGS@
-FREEDRENO_LIBS = @FREEDRENO_LIBS@
GALLIUM_PIPE_LOADER_DEFINES = @GALLIUM_PIPE_LOADER_DEFINES@
GBM_PC_LIB_PRIV = @GBM_PC_LIB_PRIV@
GBM_PC_REQ_PRIV = @GBM_PC_REQ_PRIV@
@@ -240,8 +241,8 @@ GL_LIB_DEPS = @GL_LIB_DEPS@
GL_PC_CFLAGS = @GL_PC_CFLAGS@
GL_PC_LIB_PRIV = @GL_PC_LIB_PRIV@
GL_PC_REQ_PRIV = @GL_PC_REQ_PRIV@
+GL_PKGCONF_LIB = @GL_PKGCONF_LIB@
GREP = @GREP@
-HAVE_XF86VIDMODE = @HAVE_XF86VIDMODE@
I915_CFLAGS = @I915_CFLAGS@
I915_LIBS = @I915_LIBS@
INDENT = @INDENT@
@@ -253,6 +254,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LD = @LD@
LDFLAGS = @LDFLAGS@
+LD_BUILD_ID = @LD_BUILD_ID@
LD_NO_UNDEFINED = @LD_NO_UNDEFINED@
LEX = @LEX@
LEXLIB = @LEXLIB@
@@ -290,7 +292,7 @@ MSVC2013_COMPAT_CFLAGS = @MSVC2013_COMPAT_CFLAGS@
MSVC2013_COMPAT_CXXFLAGS = @MSVC2013_COMPAT_CXXFLAGS@
NINE_MAJOR = @NINE_MAJOR@
NINE_MINOR = @NINE_MINOR@
-NINE_TINY = @NINE_TINY@
+NINE_PATCH = @NINE_PATCH@
NINE_VERSION = @NINE_VERSION@
NM = @NM@
NMEDIT = @NMEDIT@
@@ -303,6 +305,9 @@ OBJEXT = @OBJEXT@
OMX_BELLAGIO_CFLAGS = @OMX_BELLAGIO_CFLAGS@
OMX_BELLAGIO_LIBS = @OMX_BELLAGIO_LIBS@
OMX_BELLAGIO_LIB_INSTALL_DIR = @OMX_BELLAGIO_LIB_INSTALL_DIR@
+OMX_TIZONIA_CFLAGS = @OMX_TIZONIA_CFLAGS@
+OMX_TIZONIA_LIBS = @OMX_TIZONIA_LIBS@
+OMX_TIZONIA_LIB_INSTALL_DIR = @OMX_TIZONIA_LIB_INSTALL_DIR@
OPENCL_LIBNAME = @OPENCL_LIBNAME@
OPENCL_VERSION = @OPENCL_VERSION@
OSMESA_LIB = @OSMESA_LIB@
@@ -330,11 +335,16 @@ PTHREAD_CC = @PTHREAD_CC@
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
PTHREAD_LIBS = @PTHREAD_LIBS@
PWR8_CFLAGS = @PWR8_CFLAGS@
-PYTHON2 = @PYTHON2@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
RADEON_CFLAGS = @RADEON_CFLAGS@
RADEON_LIBS = @RADEON_LIBS@
RANLIB = @RANLIB@
RM = @RM@
+SCANNER_ARG = @SCANNER_ARG@
SED = @SED@
SELINUX_CFLAGS = @SELINUX_CFLAGS@
SELINUX_LIBS = @SELINUX_LIBS@
@@ -346,9 +356,10 @@ SSE41_CFLAGS = @SSE41_CFLAGS@
STRIP = @STRIP@
SWR_AVX2_CXXFLAGS = @SWR_AVX2_CXXFLAGS@
SWR_AVX_CXXFLAGS = @SWR_AVX_CXXFLAGS@
-SWR_CXX11_CXXFLAGS = @SWR_CXX11_CXXFLAGS@
SWR_KNL_CXXFLAGS = @SWR_KNL_CXXFLAGS@
SWR_SKX_CXXFLAGS = @SWR_SKX_CXXFLAGS@
+V3D_SIMULATOR_CFLAGS = @V3D_SIMULATOR_CFLAGS@
+V3D_SIMULATOR_LIBS = @V3D_SIMULATOR_LIBS@
VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
VALGRIND_LIBS = @VALGRIND_LIBS@
VA_CFLAGS = @VA_CFLAGS@
@@ -356,8 +367,8 @@ VA_LIBS = @VA_LIBS@
VA_LIB_INSTALL_DIR = @VA_LIB_INSTALL_DIR@
VA_MAJOR = @VA_MAJOR@
VA_MINOR = @VA_MINOR@
-VC5_SIMULATOR_CFLAGS = @VC5_SIMULATOR_CFLAGS@
-VC5_SIMULATOR_LIBS = @VC5_SIMULATOR_LIBS@
+VC4_CFLAGS = @VC4_CFLAGS@
+VC4_LIBS = @VC4_LIBS@
VDPAU_CFLAGS = @VDPAU_CFLAGS@
VDPAU_LIBS = @VDPAU_LIBS@
VDPAU_LIB_INSTALL_DIR = @VDPAU_LIB_INSTALL_DIR@
@@ -371,7 +382,11 @@ VL_LIBS = @VL_LIBS@
VULKAN_ICD_INSTALL_DIR = @VULKAN_ICD_INSTALL_DIR@
WAYLAND_CLIENT_CFLAGS = @WAYLAND_CLIENT_CFLAGS@
WAYLAND_CLIENT_LIBS = @WAYLAND_CLIENT_LIBS@
+WAYLAND_EGL_CFLAGS = @WAYLAND_EGL_CFLAGS@
+WAYLAND_EGL_LIBS = @WAYLAND_EGL_LIBS@
+WAYLAND_PROTOCOLS_CFLAGS = @WAYLAND_PROTOCOLS_CFLAGS@
WAYLAND_PROTOCOLS_DATADIR = @WAYLAND_PROTOCOLS_DATADIR@
+WAYLAND_PROTOCOLS_LIBS = @WAYLAND_PROTOCOLS_LIBS@
WAYLAND_SCANNER = @WAYLAND_SCANNER@
WAYLAND_SCANNER_CFLAGS = @WAYLAND_SCANNER_CFLAGS@
WAYLAND_SCANNER_LIBS = @WAYLAND_SCANNER_LIBS@
@@ -381,16 +396,20 @@ WNO_OVERRIDE_INIT = @WNO_OVERRIDE_INIT@
X11_INCLUDES = @X11_INCLUDES@
XA_MAJOR = @XA_MAJOR@
XA_MINOR = @XA_MINOR@
-XA_TINY = @XA_TINY@
+XA_PATCH = @XA_PATCH@
XA_VERSION = @XA_VERSION@
XCB_DRI2_CFLAGS = @XCB_DRI2_CFLAGS@
XCB_DRI2_LIBS = @XCB_DRI2_LIBS@
XCB_DRI3_CFLAGS = @XCB_DRI3_CFLAGS@
XCB_DRI3_LIBS = @XCB_DRI3_LIBS@
-XF86VIDMODE_CFLAGS = @XF86VIDMODE_CFLAGS@
-XF86VIDMODE_LIBS = @XF86VIDMODE_LIBS@
+XCB_DRI3_MODIFIERS_CFLAGS = @XCB_DRI3_MODIFIERS_CFLAGS@
+XCB_DRI3_MODIFIERS_LIBS = @XCB_DRI3_MODIFIERS_LIBS@
+XCB_RANDR_CFLAGS = @XCB_RANDR_CFLAGS@
+XCB_RANDR_LIBS = @XCB_RANDR_LIBS@
XLIBGL_CFLAGS = @XLIBGL_CFLAGS@
XLIBGL_LIBS = @XLIBGL_LIBS@
+XLIB_RANDR_CFLAGS = @XLIB_RANDR_CFLAGS@
+XLIB_RANDR_LIBS = @XLIB_RANDR_LIBS@
XVMC_CFLAGS = @XVMC_CFLAGS@
XVMC_LIBS = @XVMC_LIBS@
XVMC_LIB_INSTALL_DIR = @XVMC_LIB_INSTALL_DIR@
@@ -445,9 +464,13 @@ mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
@@ -466,13 +489,14 @@ LOADER_C_FILES := \
pci_id_driver_map.c \
pci_id_driver_map.h
-EXTRA_DIST = SConscript
+EXTRA_DIST = SConscript meson.build
noinst_LTLIBRARIES = libloader.la $(am__append_2)
AM_CPPFLAGS = \
-I$(top_builddir)/src/util/ \
-DUSE_DRICONF \
$(DEFINES) \
-I$(top_srcdir)/include \
+ -I$(top_srcdir)/include/drm-uapi \
-I$(top_srcdir)/src \
$(VISIBILITY_CFLAGS) \
$(XCB_DRI3_CFLAGS) \
diff --git a/lib/mesa/src/loader/loader.c b/lib/mesa/src/loader/loader.c
index 182ba90a0..461f96aa6 100644
--- a/lib/mesa/src/loader/loader.c
+++ b/lib/mesa/src/loader/loader.c
@@ -82,15 +82,118 @@ loader_open_device(const char *device_name)
return fd;
}
+static char *loader_get_kernel_driver_name(int fd)
+{
+#if HAVE_LIBDRM
+ char *driver;
+ drmVersionPtr version = drmGetVersion(fd);
+
+ if (!version) {
+ log_(_LOADER_WARNING, "failed to get driver name for fd %d\n", fd);
+ return NULL;
+ }
+
+ driver = strndup(version->name, version->name_len);
+
+ drmFreeVersion(version);
+ return driver;
+#else
+ return NULL;
+#endif
+}
+
#if defined(HAVE_LIBDRM)
+int
+loader_open_render_node(const char *name)
+{
+ drmDevicePtr *devices, device;
+ int err, render = -ENOENT, fd;
+ unsigned int num, i;
+
+ err = drmGetDevices2(0, NULL, 0);
+ if (err < 0)
+ return err;
+
+ num = err;
+
+ devices = calloc(num, sizeof(*devices));
+ if (!devices)
+ return -ENOMEM;
+
+ err = drmGetDevices2(0, devices, num);
+ if (err < 0) {
+ render = err;
+ goto free;
+ }
+
+ for (i = 0; i < num; i++) {
+ device = devices[i];
+
+ if ((device->available_nodes & (1 << DRM_NODE_RENDER)) &&
+ (device->bustype == DRM_BUS_PLATFORM)) {
+ drmVersionPtr version;
+
+ fd = open(device->nodes[DRM_NODE_RENDER], O_RDWR | O_CLOEXEC);
+ if (fd < 0)
+ continue;
+
+ version = drmGetVersion(fd);
+ if (!version) {
+ close(fd);
+ continue;
+ }
+
+ if (strcmp(version->name, name) != 0) {
+ drmFreeVersion(version);
+ close(fd);
+ continue;
+ }
+
+ drmFreeVersion(version);
+ render = fd;
+ break;
+ }
+ }
+
+ drmFreeDevices(devices, num);
+
+free:
+ free(devices);
+ return render;
+}
+
#ifdef USE_DRICONF
static const char __driConfigOptionsLoader[] =
DRI_CONF_BEGIN
DRI_CONF_SECTION_INITIALIZATION
DRI_CONF_DEVICE_ID_PATH_TAG()
+ DRI_CONF_DRI_DRIVER()
DRI_CONF_SECTION_END
DRI_CONF_END;
+static char *loader_get_dri_config_driver(int fd)
+{
+ driOptionCache defaultInitOptions;
+ driOptionCache userInitOptions;
+ char *dri_driver = NULL;
+ char *kernel_driver = loader_get_kernel_driver_name(fd);
+
+ driParseOptionInfo(&defaultInitOptions, __driConfigOptionsLoader);
+ driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0,
+ "loader", kernel_driver);
+ if (driCheckOption(&userInitOptions, "dri_driver", DRI_STRING)) {
+ char *opt = driQueryOptionstr(&userInitOptions, "dri_driver");
+ /* not an empty string */
+ if (*opt)
+ dri_driver = strdup(opt);
+ }
+ driDestroyOptionCache(&userInitOptions);
+ driDestroyOptionInfo(&defaultInitOptions);
+
+ free(kernel_driver);
+ return dri_driver;
+}
+
static char *loader_get_dri_config_device_id(void)
{
driOptionCache defaultInitOptions;
@@ -98,7 +201,7 @@ static char *loader_get_dri_config_device_id(void)
char *prime = NULL;
driParseOptionInfo(&defaultInitOptions, __driConfigOptionsLoader);
- driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0, "loader");
+ driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0, "loader", NULL);
if (driCheckOption(&userInitOptions, "device_id", DRI_STRING))
prime = strdup(driQueryOptionstr(&userInitOptions, "device_id"));
driDestroyOptionCache(&userInitOptions);
@@ -110,18 +213,43 @@ static char *loader_get_dri_config_device_id(void)
static char *drm_construct_id_path_tag(drmDevicePtr device)
{
-/* Length of "pci-xxxx_xx_xx_x\0" */
-#define PCI_ID_PATH_TAG_LENGTH 17
char *tag = NULL;
if (device->bustype == DRM_BUS_PCI) {
- tag = calloc(PCI_ID_PATH_TAG_LENGTH, sizeof(char));
- if (tag == NULL)
- return NULL;
+ if (asprintf(&tag, "pci-%04x_%02x_%02x_%1u",
+ device->businfo.pci->domain,
+ device->businfo.pci->bus,
+ device->businfo.pci->dev,
+ device->businfo.pci->func) < 0) {
+ return NULL;
+ }
+ } else if (device->bustype == DRM_BUS_PLATFORM ||
+ device->bustype == DRM_BUS_HOST1X) {
+ char *fullname, *name, *address;
+
+ if (device->bustype == DRM_BUS_PLATFORM)
+ fullname = device->businfo.platform->fullname;
+ else
+ fullname = device->businfo.host1x->fullname;
+
+ name = strrchr(fullname, '/');
+ if (!name)
+ name = strdup(fullname);
+ else
+ name = strdup(name + 1);
+
+ address = strchr(name, '@');
+ if (address) {
+ *address++ = '\0';
+
+ if (asprintf(&tag, "platform-%s_%s", address, name) < 0)
+ tag = NULL;
+ } else {
+ if (asprintf(&tag, "platform-%s", name) < 0)
+ tag = NULL;
+ }
- snprintf(tag, PCI_ID_PATH_TAG_LENGTH, "pci-%04x_%02x_%02x_%1u",
- device->businfo.pci->domain, device->businfo.pci->bus,
- device->businfo.pci->dev, device->businfo.pci->func);
+ free(name);
}
return tag;
}
@@ -237,33 +365,16 @@ int loader_get_user_preferred_fd(int default_fd, bool *different_device)
return default_fd;
}
#else
-int loader_get_user_preferred_fd(int default_fd, bool *different_device)
+int
+loader_open_render_node(const char *name)
{
- *different_device = false;
- return default_fd;
+ return -1;
}
-#endif
-#if defined(HAVE_LIBDRM)
-static int
-dev_node_from_fd(int fd, unsigned int *maj, unsigned int *min)
+int loader_get_user_preferred_fd(int default_fd, bool *different_device)
{
- struct stat buf;
-
- if (fstat(fd, &buf) < 0) {
- log_(_LOADER_WARNING, "MESA-LOADER: failed to stat fd %d\n", fd);
- return -1;
- }
-
- if (!S_ISCHR(buf.st_mode)) {
- log_(_LOADER_WARNING, "MESA-LOADER: fd %d not a character device\n", fd);
- return -1;
- }
-
- *maj = major(buf.st_rdev);
- *min = minor(buf.st_rdev);
-
- return 0;
+ *different_device = false;
+ return default_fd;
}
#endif
@@ -307,35 +418,15 @@ loader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
return 0;
}
-
-#if defined(HAVE_LIBDRM)
-static char *
-drm_get_device_name_for_fd(int fd)
-{
- unsigned int maj, min;
- char buf[0x40];
- int n;
-
- if (dev_node_from_fd(fd, &maj, &min) < 0)
- return NULL;
-
- n = snprintf(buf, sizeof(buf), DRM_DEV_NAME, DRM_DIR_NAME, min);
- if (n == -1 || n >= sizeof(buf))
- return NULL;
-
- return strdup(buf);
-}
-#endif
-
char *
loader_get_device_name_for_fd(int fd)
{
char *result = NULL;
#if HAVE_LIBDRM
- if ((result = drm_get_device_name_for_fd(fd)))
- return result;
+ result = drmGetDeviceNameFromFd2(fd);
#endif
+
return result;
}
@@ -356,23 +447,16 @@ loader_get_driver_for_fd(int fd)
return strdup(driver);
}
- if (!loader_get_pci_id_for_fd(fd, &vendor_id, &chip_id)) {
-
-#if HAVE_LIBDRM
- /* fallback to drmGetVersion(): */
- drmVersionPtr version = drmGetVersion(fd);
-
- if (!version) {
- log_(_LOADER_WARNING, "failed to get driver name for fd %d\n", fd);
- return NULL;
- }
-
- driver = strndup(version->name, version->name_len);
- log_(_LOADER_INFO, "using driver %s for %d\n", driver, fd);
-
- drmFreeVersion(version);
+#if defined(HAVE_LIBDRM) && defined(USE_DRICONF)
+ driver = loader_get_dri_config_driver(fd);
+ if (driver)
+ return driver;
#endif
+ if (!loader_get_pci_id_for_fd(fd, &vendor_id, &chip_id)) {
+ driver = loader_get_kernel_driver_name(fd);
+ if (driver)
+ log_(_LOADER_INFO, "using driver %s for %d\n", driver, fd);
return driver;
}
@@ -426,8 +510,8 @@ loader_get_extensions_name(const char *driver_name)
const size_t len = strlen(name);
for (size_t i = 0; i < len; i++) {
- if (name[i] == '-')
- name[i] = '_';
+ if (name[i] == '-')
+ name[i] = '_';
}
return name;
diff --git a/lib/mesa/src/loader/loader.h b/lib/mesa/src/loader/loader.h
index 3859b45dc..7b4dd0114 100644
--- a/lib/mesa/src/loader/loader.h
+++ b/lib/mesa/src/loader/loader.h
@@ -39,6 +39,9 @@ int
loader_open_device(const char *);
int
+loader_open_render_node(const char *name);
+
+int
loader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id);
char *
diff --git a/lib/mesa/src/loader/loader_dri3_helper.c b/lib/mesa/src/loader/loader_dri3_helper.c
index b4c458201..7cd6b1e8a 100644
--- a/lib/mesa/src/loader/loader_dri3_helper.c
+++ b/lib/mesa/src/loader/loader_dri3_helper.c
@@ -24,6 +24,7 @@
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
+#include <string.h>
#include <X11/xshmfence.h>
#include <xcb/xcb.h>
@@ -33,6 +34,8 @@
#include <X11/Xlib-xcb.h>
#include "loader_dri3_helper.h"
+#include "util/macros.h"
+#include "drm_fourcc.h"
/* From xmlpool/options.h, user exposed so should be stable */
#define DRI_CONF_VBLANK_NEVER 0
@@ -61,6 +64,55 @@ dri3_flush_present_events(struct loader_dri3_drawable *draw);
static struct loader_dri3_buffer *
dri3_find_back_alloc(struct loader_dri3_drawable *draw);
+static xcb_screen_t *
+get_screen_for_root(xcb_connection_t *conn, xcb_window_t root)
+{
+ xcb_screen_iterator_t screen_iter =
+ xcb_setup_roots_iterator(xcb_get_setup(conn));
+
+ for (; screen_iter.rem; xcb_screen_next (&screen_iter)) {
+ if (screen_iter.data->root == root)
+ return screen_iter.data;
+ }
+
+ return NULL;
+}
+
+static xcb_visualtype_t *
+get_xcb_visualtype_for_depth(struct loader_dri3_drawable *draw, int depth)
+{
+ xcb_visualtype_iterator_t visual_iter;
+ xcb_screen_t *screen = draw->screen;
+ xcb_depth_iterator_t depth_iter;
+
+ if (!screen)
+ return NULL;
+
+ depth_iter = xcb_screen_allowed_depths_iterator(screen);
+ for (; depth_iter.rem; xcb_depth_next(&depth_iter)) {
+ if (depth_iter.data->depth != depth)
+ continue;
+
+ visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
+ if (visual_iter.rem)
+ return visual_iter.data;
+ }
+
+ return NULL;
+}
+
+/* Get red channel mask for given drawable at given depth. */
+static unsigned int
+dri3_get_red_mask_for_depth(struct loader_dri3_drawable *draw, int depth)
+{
+ xcb_visualtype_t *visual = get_xcb_visualtype_for_depth(draw, depth);
+
+ if (visual)
+ return visual->red_mask;
+
+ return 0;
+}
+
/**
* Do we have blit functionality in the image blit extension?
*
@@ -195,7 +247,7 @@ dri3_fence_await(xcb_connection_t *c, struct loader_dri3_drawable *draw,
static void
dri3_update_num_back(struct loader_dri3_drawable *draw)
{
- if (draw->flipping)
+ if (draw->last_present_mode == XCB_PRESENT_COMPLETE_MODE_FLIP)
draw->num_back = 3;
else
draw->num_back = 2;
@@ -233,7 +285,7 @@ loader_dri3_drawable_fini(struct loader_dri3_drawable *draw)
draw->ext->core->destroyDrawable(draw->dri_drawable);
- for (i = 0; i < LOADER_DRI3_NUM_BUFFERS; i++) {
+ for (i = 0; i < ARRAY_SIZE(draw->buffers); i++) {
if (draw->buffers[i])
dri3_free_render_buffer(draw, draw->buffers[i]);
}
@@ -256,6 +308,7 @@ loader_dri3_drawable_init(xcb_connection_t *conn,
xcb_drawable_t drawable,
__DRIscreen *dri_screen,
bool is_different_gpu,
+ bool multiplanes_available,
const __DRIconfig *dri_config,
struct loader_dri3_extensions *ext,
const struct loader_dri3_vtable *vtable,
@@ -273,6 +326,7 @@ loader_dri3_drawable_init(xcb_connection_t *conn,
draw->drawable = drawable;
draw->dri_screen = dri_screen;
draw->is_different_gpu = is_different_gpu;
+ draw->multiplanes_available = multiplanes_available;
draw->have_back = 0;
draw->have_fake_front = 0;
@@ -318,6 +372,7 @@ loader_dri3_drawable_init(xcb_connection_t *conn,
return 1;
}
+ draw->screen = get_screen_for_root(draw->conn, reply->root);
draw->width = reply->width;
draw->height = reply->height;
draw->depth = reply->depth;
@@ -365,25 +420,50 @@ dri3_handle_present_event(struct loader_dri3_drawable *draw,
* checking for wrap.
*/
if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
- draw->recv_sbc = (draw->send_sbc & 0xffffffff00000000LL) | ce->serial;
- if (draw->recv_sbc > draw->send_sbc)
- draw->recv_sbc -= 0x100000000;
- switch (ce->mode) {
- case XCB_PRESENT_COMPLETE_MODE_FLIP:
- draw->flipping = true;
- break;
- case XCB_PRESENT_COMPLETE_MODE_COPY:
- draw->flipping = false;
- break;
+ uint64_t recv_sbc = (draw->send_sbc & 0xffffffff00000000LL) | ce->serial;
+
+ /* Only assume wraparound if that results in exactly the previous
+ * SBC + 1, otherwise ignore received SBC > sent SBC (those are
+ * probably from a previous loader_dri3_drawable instance) to avoid
+ * calculating bogus target MSC values in loader_dri3_swap_buffers_msc
+ */
+ if (recv_sbc <= draw->send_sbc)
+ draw->recv_sbc = recv_sbc;
+ else if (recv_sbc == (draw->recv_sbc + 0x100000001ULL))
+ draw->recv_sbc = recv_sbc - 0x100000000ULL;
+
+ /* When moving from flip to copy, we assume that we can allocate in
+ * a more optimal way if we don't need to cater for the display
+ * controller.
+ */
+ if (ce->mode == XCB_PRESENT_COMPLETE_MODE_COPY &&
+ draw->last_present_mode == XCB_PRESENT_COMPLETE_MODE_FLIP) {
+ for (int b = 0; b < ARRAY_SIZE(draw->buffers); b++) {
+ if (draw->buffers[b])
+ draw->buffers[b]->reallocate = true;
+ }
+ }
+
+ /* If the server tells us that our allocation is suboptimal, we
+ * reallocate once.
+ */
+#ifdef HAVE_DRI3_MODIFIERS
+ if (ce->mode == XCB_PRESENT_COMPLETE_MODE_SUBOPTIMAL_COPY &&
+ draw->last_present_mode != ce->mode) {
+ for (int b = 0; b < ARRAY_SIZE(draw->buffers); b++) {
+ if (draw->buffers[b])
+ draw->buffers[b]->reallocate = true;
+ }
}
+#endif
+ draw->last_present_mode = ce->mode;
if (draw->vtable->show_fps)
draw->vtable->show_fps(draw, ce->ust);
draw->ust = ce->ust;
draw->msc = ce->msc;
- } else {
- draw->recv_msc_serial = ce->serial;
+ } else if (ce->serial == draw->eid) {
draw->notify_ust = ce->ust;
draw->notify_msc = ce->msc;
}
@@ -393,18 +473,11 @@ dri3_handle_present_event(struct loader_dri3_drawable *draw,
xcb_present_idle_notify_event_t *ie = (void *) ge;
int b;
- for (b = 0; b < sizeof(draw->buffers) / sizeof(draw->buffers[0]); b++) {
+ for (b = 0; b < ARRAY_SIZE(draw->buffers); b++) {
struct loader_dri3_buffer *buf = draw->buffers[b];
if (buf && buf->pixmap == ie->pixmap)
buf->busy = 0;
-
- if (buf && draw->num_back <= b && b < LOADER_DRI3_MAX_BACK &&
- draw->cur_blit_source != b &&
- !buf->busy) {
- dri3_free_render_buffer(draw, buf);
- draw->buffers[b] = NULL;
- }
}
break;
}
@@ -452,28 +525,29 @@ loader_dri3_wait_for_msc(struct loader_dri3_drawable *draw,
int64_t divisor, int64_t remainder,
int64_t *ust, int64_t *msc, int64_t *sbc)
{
- uint32_t msc_serial;
-
- msc_serial = ++draw->send_msc_serial;
- xcb_present_notify_msc(draw->conn,
- draw->drawable,
- msc_serial,
- target_msc,
- divisor,
- remainder);
+ xcb_void_cookie_t cookie = xcb_present_notify_msc(draw->conn,
+ draw->drawable,
+ draw->eid,
+ target_msc,
+ divisor,
+ remainder);
+ xcb_generic_event_t *ev;
+ unsigned full_sequence;
mtx_lock(&draw->mtx);
xcb_flush(draw->conn);
/* Wait for the event */
- if (draw->special_event) {
- while ((int32_t) (msc_serial - draw->recv_msc_serial) > 0) {
- if (!dri3_wait_for_event_locked(draw)) {
- mtx_unlock(&draw->mtx);
- return false;
- }
+ do {
+ ev = xcb_wait_for_special_event(draw->conn, draw->special_event);
+ if (!ev) {
+ mtx_unlock(&draw->mtx);
+ return false;
}
- }
+
+ full_sequence = ev->full_sequence;
+ dri3_handle_present_event(draw, (void *) ev);
+ } while (full_sequence != cookie.sequence || draw->notify_msc < target_msc);
*ust = draw->notify_ust;
*msc = draw->notify_msc;
@@ -536,7 +610,6 @@ dri3_find_back(struct loader_dri3_drawable *draw)
/* Check whether we need to reuse the current back buffer as new back.
* In that case, wait until it's not busy anymore.
*/
- dri3_update_num_back(draw);
num_to_consider = draw->num_back;
if (!loader_dri3_have_image_blit(draw) && draw->cur_blit_source != -1) {
num_to_consider = 1;
@@ -881,7 +954,10 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
*/
if (!loader_dri3_have_image_blit(draw) && draw->cur_blit_source != -1)
options |= XCB_PRESENT_OPTION_COPY;
-
+#ifdef HAVE_DRI3_MODIFIERS
+ if (draw->multiplanes_available)
+ options |= XCB_PRESENT_OPTION_SUBOPTIMAL;
+#endif
back->busy = 1;
back->last_swap = draw->send_sbc;
xcb_present_pixmap(draw->conn,
@@ -993,7 +1069,10 @@ dri3_cpp_for_format(uint32_t format) {
case __DRI_IMAGE_FORMAT_XBGR8888:
case __DRI_IMAGE_FORMAT_XRGB2101010:
case __DRI_IMAGE_FORMAT_ARGB2101010:
+ case __DRI_IMAGE_FORMAT_XBGR2101010:
+ case __DRI_IMAGE_FORMAT_ABGR2101010:
case __DRI_IMAGE_FORMAT_SARGB8:
+ case __DRI_IMAGE_FORMAT_SABGR8:
return 4;
case __DRI_IMAGE_FORMAT_NONE:
default:
@@ -1001,6 +1080,36 @@ dri3_cpp_for_format(uint32_t format) {
}
}
+/* Map format of render buffer to corresponding format for the linear_buffer
+ * used for sharing with the display gpu of a Prime setup (== is_different_gpu).
+ * Usually linear_format == format, except for depth >= 30 formats, where
+ * different gpu vendors have different preferences wrt. color channel ordering.
+ */
+static uint32_t
+dri3_linear_format_for_format(struct loader_dri3_drawable *draw, uint32_t format)
+{
+ switch (format) {
+ case __DRI_IMAGE_FORMAT_XRGB2101010:
+ case __DRI_IMAGE_FORMAT_XBGR2101010:
+ /* Different preferred formats for different hw */
+ if (dri3_get_red_mask_for_depth(draw, 30) == 0x3ff)
+ return __DRI_IMAGE_FORMAT_XBGR2101010;
+ else
+ return __DRI_IMAGE_FORMAT_XRGB2101010;
+
+ case __DRI_IMAGE_FORMAT_ARGB2101010:
+ case __DRI_IMAGE_FORMAT_ABGR2101010:
+ /* Different preferred formats for different hw */
+ if (dri3_get_red_mask_for_depth(draw, 30) == 0x3ff)
+ return __DRI_IMAGE_FORMAT_ABGR2101010;
+ else
+ return __DRI_IMAGE_FORMAT_ARGB2101010;
+
+ default:
+ return format;
+ }
+}
+
/* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while
* the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid
* complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and
@@ -1013,15 +1122,57 @@ image_format_to_fourcc(int format)
/* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */
switch (format) {
case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888;
+ case __DRI_IMAGE_FORMAT_SABGR8: return __DRI_IMAGE_FOURCC_SABGR8888;
case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565;
case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888;
case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888;
case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888;
case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888;
+ case __DRI_IMAGE_FORMAT_XRGB2101010: return __DRI_IMAGE_FOURCC_XRGB2101010;
+ case __DRI_IMAGE_FORMAT_ARGB2101010: return __DRI_IMAGE_FOURCC_ARGB2101010;
+ case __DRI_IMAGE_FORMAT_XBGR2101010: return __DRI_IMAGE_FOURCC_XBGR2101010;
+ case __DRI_IMAGE_FORMAT_ABGR2101010: return __DRI_IMAGE_FOURCC_ABGR2101010;
}
return 0;
}
+#ifdef HAVE_DRI3_MODIFIERS
+static bool
+has_supported_modifier(struct loader_dri3_drawable *draw, unsigned int format,
+ uint64_t *modifiers, uint32_t count)
+{
+ uint64_t *supported_modifiers;
+ int32_t supported_modifiers_count;
+ bool found = false;
+ int i, j;
+
+ if (!draw->ext->image->queryDmaBufModifiers(draw->dri_screen,
+ format, 0, NULL, NULL,
+ &supported_modifiers_count) ||
+ supported_modifiers_count == 0)
+ return false;
+
+ supported_modifiers = malloc(supported_modifiers_count * sizeof(uint64_t));
+ if (!supported_modifiers)
+ return false;
+
+ draw->ext->image->queryDmaBufModifiers(draw->dri_screen, format,
+ supported_modifiers_count,
+ supported_modifiers, NULL,
+ &supported_modifiers_count);
+
+ for (i = 0; !found && i < supported_modifiers_count; i++) {
+ for (j = 0; !found && j < count; j++) {
+ if (supported_modifiers[i] == modifiers[j])
+ found = true;
+ }
+ }
+
+ free(supported_modifiers);
+ return found;
+}
+#endif
+
/** loader_dri3_alloc_render_buffer
*
* Use the driver createImage function to construct a __DRIimage, then
@@ -1038,8 +1189,10 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
xcb_pixmap_t pixmap;
xcb_sync_fence_t sync_fence;
struct xshmfence *shm_fence;
- int buffer_fd, fence_fd;
- int stride;
+ int buffer_fds[4], fence_fd;
+ int num_planes = 0;
+ int i, mod;
+ int ret;
/* Create an xshmfence object and
* prepare to send that to the X server
@@ -1064,13 +1217,80 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
goto no_image;
if (!draw->is_different_gpu) {
- buffer->image = draw->ext->image->createImage(draw->dri_screen,
- width, height,
- format,
- __DRI_IMAGE_USE_SHARE |
- __DRI_IMAGE_USE_SCANOUT |
- __DRI_IMAGE_USE_BACKBUFFER,
- buffer);
+#ifdef HAVE_DRI3_MODIFIERS
+ if (draw->multiplanes_available &&
+ draw->ext->image->base.version >= 15 &&
+ draw->ext->image->queryDmaBufModifiers &&
+ draw->ext->image->createImageWithModifiers) {
+ xcb_dri3_get_supported_modifiers_cookie_t mod_cookie;
+ xcb_dri3_get_supported_modifiers_reply_t *mod_reply;
+ xcb_generic_error_t *error = NULL;
+ uint64_t *modifiers = NULL;
+ uint32_t count = 0;
+
+ mod_cookie = xcb_dri3_get_supported_modifiers(draw->conn,
+ draw->window,
+ depth, buffer->cpp * 8);
+ mod_reply = xcb_dri3_get_supported_modifiers_reply(draw->conn,
+ mod_cookie,
+ &error);
+ if (!mod_reply)
+ goto no_image;
+
+ if (mod_reply->num_window_modifiers) {
+ count = mod_reply->num_window_modifiers;
+ modifiers = malloc(count * sizeof(uint64_t));
+ if (!modifiers) {
+ free(mod_reply);
+ goto no_image;
+ }
+
+ memcpy(modifiers,
+ xcb_dri3_get_supported_modifiers_window_modifiers(mod_reply),
+ count * sizeof(uint64_t));
+
+ if (!has_supported_modifier(draw, image_format_to_fourcc(format),
+ modifiers, count)) {
+ free(modifiers);
+ count = 0;
+ modifiers = NULL;
+ }
+ }
+
+ if (mod_reply->num_screen_modifiers && modifiers == NULL) {
+ count = mod_reply->num_screen_modifiers;
+ modifiers = malloc(count * sizeof(uint64_t));
+ if (!modifiers) {
+ free(modifiers);
+ free(mod_reply);
+ goto no_image;
+ }
+
+ memcpy(modifiers,
+ xcb_dri3_get_supported_modifiers_screen_modifiers(mod_reply),
+ count * sizeof(uint64_t));
+ }
+
+ free(mod_reply);
+
+ buffer->image = draw->ext->image->createImageWithModifiers(draw->dri_screen,
+ width, height,
+ format,
+ modifiers,
+ count,
+ buffer);
+ free(modifiers);
+ }
+#endif
+ if (!buffer->image)
+ buffer->image = draw->ext->image->createImage(draw->dri_screen,
+ width, height,
+ format,
+ __DRI_IMAGE_USE_SHARE |
+ __DRI_IMAGE_USE_SCANOUT |
+ __DRI_IMAGE_USE_BACKBUFFER,
+ buffer);
+
pixmap_buffer = buffer->image;
if (!buffer->image)
@@ -1087,7 +1307,8 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
buffer->linear_buffer =
draw->ext->image->createImage(draw->dri_screen,
- width, height, format,
+ width, height,
+ dri3_linear_format_for_format(draw, format),
__DRI_IMAGE_USE_SHARE |
__DRI_IMAGE_USE_LINEAR |
__DRI_IMAGE_USE_BACKBUFFER,
@@ -1098,25 +1319,70 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
goto no_linear_buffer;
}
- /* X wants the stride, so ask the image for it
+ /* X want some information about the planes, so ask the image for it
*/
- if (!draw->ext->image->queryImage(pixmap_buffer, __DRI_IMAGE_ATTRIB_STRIDE,
- &stride))
- goto no_buffer_attrib;
+ if (!draw->ext->image->queryImage(pixmap_buffer, __DRI_IMAGE_ATTRIB_NUM_PLANES,
+ &num_planes))
+ num_planes = 1;
- buffer->pitch = stride;
+ for (i = 0; i < num_planes; i++) {
+ __DRIimage *image = draw->ext->image->fromPlanar(pixmap_buffer, i, NULL);
- if (!draw->ext->image->queryImage(pixmap_buffer, __DRI_IMAGE_ATTRIB_FD,
- &buffer_fd))
- goto no_buffer_attrib;
+ if (!image) {
+ assert(i == 0);
+ image = pixmap_buffer;
+ }
+
+ ret = draw->ext->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD,
+ &buffer_fds[i]);
+ ret &= draw->ext->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE,
+ &buffer->strides[i]);
+ ret &= draw->ext->image->queryImage(image, __DRI_IMAGE_ATTRIB_OFFSET,
+ &buffer->offsets[i]);
+ if (image != pixmap_buffer)
+ draw->ext->image->destroyImage(image);
+
+ if (!ret)
+ goto no_buffer_attrib;
+ }
- xcb_dri3_pixmap_from_buffer(draw->conn,
- (pixmap = xcb_generate_id(draw->conn)),
- draw->drawable,
- buffer->size,
- width, height, buffer->pitch,
- depth, buffer->cpp * 8,
- buffer_fd);
+ ret = draw->ext->image->queryImage(pixmap_buffer,
+ __DRI_IMAGE_ATTRIB_MODIFIER_UPPER, &mod);
+ buffer->modifier = (uint64_t) mod << 32;
+ ret &= draw->ext->image->queryImage(pixmap_buffer,
+ __DRI_IMAGE_ATTRIB_MODIFIER_LOWER, &mod);
+ buffer->modifier |= (uint64_t)(mod & 0xffffffff);
+
+ if (!ret)
+ buffer->modifier = DRM_FORMAT_MOD_INVALID;
+
+ pixmap = xcb_generate_id(draw->conn);
+#ifdef HAVE_DRI3_MODIFIERS
+ if (draw->multiplanes_available &&
+ buffer->modifier != DRM_FORMAT_MOD_INVALID) {
+ xcb_dri3_pixmap_from_buffers(draw->conn,
+ pixmap,
+ draw->window,
+ num_planes,
+ width, height,
+ buffer->strides[0], buffer->offsets[0],
+ buffer->strides[1], buffer->offsets[1],
+ buffer->strides[2], buffer->offsets[2],
+ buffer->strides[3], buffer->offsets[3],
+ depth, buffer->cpp * 8,
+ buffer->modifier,
+ buffer_fds);
+ } else
+#endif
+ {
+ xcb_dri3_pixmap_from_buffer(draw->conn,
+ pixmap,
+ draw->drawable,
+ buffer->size,
+ width, height, buffer->strides[0],
+ depth, buffer->cpp * 8,
+ buffer_fds[0]);
+ }
xcb_dri3_fence_from_fd(draw->conn,
pixmap,
@@ -1138,6 +1404,9 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
return buffer;
no_buffer_attrib:
+ do {
+ close(buffer_fds[i]);
+ } while (--i >= 0);
draw->ext->image->destroyImage(pixmap_buffer);
no_linear_buffer:
if (draw->is_different_gpu)
@@ -1158,8 +1427,7 @@ no_shm_fence:
* track the geometry of the drawable
*/
static int
-dri3_update_drawable(__DRIdrawable *driDrawable,
- struct loader_dri3_drawable *draw)
+dri3_update_drawable(struct loader_dri3_drawable *draw)
{
mtx_lock(&draw->mtx);
if (draw->first_init) {
@@ -1169,6 +1437,7 @@ dri3_update_drawable(__DRIdrawable *driDrawable,
xcb_generic_error_t *error;
xcb_present_query_capabilities_cookie_t present_capabilities_cookie;
xcb_present_query_capabilities_reply_t *present_capabilities_reply;
+ xcb_window_t root_win;
draw->first_init = false;
@@ -1206,11 +1475,11 @@ dri3_update_drawable(__DRIdrawable *driDrawable,
mtx_unlock(&draw->mtx);
return false;
}
-
draw->width = geom_reply->width;
draw->height = geom_reply->height;
draw->depth = geom_reply->depth;
draw->vtable->set_drawable_size(draw, draw->width, draw->height);
+ root_win = geom_reply->root;
free(geom_reply);
@@ -1240,10 +1509,16 @@ dri3_update_drawable(__DRIdrawable *driDrawable,
mtx_unlock(&draw->mtx);
return false;
}
+ free(error);
draw->is_pixmap = true;
xcb_unregister_for_special_event(draw->conn, draw->special_event);
draw->special_event = NULL;
}
+
+ if (draw->is_pixmap)
+ draw->window = root_win;
+ else
+ draw->window = draw->drawable;
}
dri3_flush_present_events(draw);
mtx_unlock(&draw->mtx);
@@ -1286,11 +1561,58 @@ loader_dri3_create_image(xcb_connection_t *c,
ret = image->fromPlanar(image_planar, 0, loaderPrivate);
- image->destroyImage(image_planar);
+ if (!ret)
+ ret = image_planar;
+ else
+ image->destroyImage(image_planar);
return ret;
}
+#ifdef HAVE_DRI3_MODIFIERS
+__DRIimage *
+loader_dri3_create_image_from_buffers(xcb_connection_t *c,
+ xcb_dri3_buffers_from_pixmap_reply_t *bp_reply,
+ unsigned int format,
+ __DRIscreen *dri_screen,
+ const __DRIimageExtension *image,
+ void *loaderPrivate)
+{
+ __DRIimage *ret;
+ int *fds;
+ uint32_t *strides_in, *offsets_in;
+ int strides[4], offsets[4];
+ unsigned error;
+ int i;
+
+ if (bp_reply->nfd > 4)
+ return NULL;
+
+ fds = xcb_dri3_buffers_from_pixmap_reply_fds(c, bp_reply);
+ strides_in = xcb_dri3_buffers_from_pixmap_strides(bp_reply);
+ offsets_in = xcb_dri3_buffers_from_pixmap_offsets(bp_reply);
+ for (i = 0; i < bp_reply->nfd; i++) {
+ strides[i] = strides_in[i];
+ offsets[i] = offsets_in[i];
+ }
+
+ ret = image->createImageFromDmaBufs2(dri_screen,
+ bp_reply->width,
+ bp_reply->height,
+ image_format_to_fourcc(format),
+ bp_reply->modifier,
+ fds, bp_reply->nfd,
+ strides, offsets,
+ 0, 0, 0, 0, /* UNDEFINED */
+ &error, loaderPrivate);
+
+ for (i = 0; i < bp_reply->nfd; i++)
+ close(fds[i]);
+
+ return ret;
+}
+#endif
+
/** dri3_get_pixmap_buffer
*
* Get the DRM object for a pixmap from the X server and
@@ -1304,10 +1626,10 @@ dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, unsigned int format,
int buf_id = loader_dri3_pixmap_buf_id(buffer_type);
struct loader_dri3_buffer *buffer = draw->buffers[buf_id];
xcb_drawable_t pixmap;
- xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
- xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
xcb_sync_fence_t sync_fence;
struct xshmfence *shm_fence;
+ int width;
+ int height;
int fence_fd;
__DRIscreen *cur_screen;
@@ -1329,17 +1651,6 @@ dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, unsigned int format,
goto no_fence;
}
- xcb_dri3_fence_from_fd(draw->conn,
- pixmap,
- (sync_fence = xcb_generate_id(draw->conn)),
- false,
- fence_fd);
-
- bp_cookie = xcb_dri3_buffer_from_pixmap(draw->conn, pixmap);
- bp_reply = xcb_dri3_buffer_from_pixmap_reply(draw->conn, bp_cookie, NULL);
- if (!bp_reply)
- goto no_image;
-
/* Get the currently-bound screen or revert to using the drawable's screen if
* no contexts are currently bound. The latter case is at least necessary for
* obs-studio, when using Window Capture (Xcomposite) as a Source.
@@ -1349,27 +1660,64 @@ dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, unsigned int format,
cur_screen = draw->dri_screen;
}
- buffer->image = loader_dri3_create_image(draw->conn, bp_reply, format,
- cur_screen, draw->ext->image,
- buffer);
+ xcb_dri3_fence_from_fd(draw->conn,
+ pixmap,
+ (sync_fence = xcb_generate_id(draw->conn)),
+ false,
+ fence_fd);
+#ifdef HAVE_DRI3_MODIFIERS
+ if (draw->multiplanes_available &&
+ draw->ext->image->base.version >= 15 &&
+ draw->ext->image->createImageFromDmaBufs2) {
+ xcb_dri3_buffers_from_pixmap_cookie_t bps_cookie;
+ xcb_dri3_buffers_from_pixmap_reply_t *bps_reply;
+
+ bps_cookie = xcb_dri3_buffers_from_pixmap(draw->conn, pixmap);
+ bps_reply = xcb_dri3_buffers_from_pixmap_reply(draw->conn, bps_cookie,
+ NULL);
+ if (!bps_reply)
+ goto no_image;
+ buffer->image =
+ loader_dri3_create_image_from_buffers(draw->conn, bps_reply, format,
+ cur_screen, draw->ext->image,
+ buffer);
+ width = bps_reply->width;
+ height = bps_reply->height;
+ free(bps_reply);
+ } else
+#endif
+ {
+ xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
+ xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
+
+ bp_cookie = xcb_dri3_buffer_from_pixmap(draw->conn, pixmap);
+ bp_reply = xcb_dri3_buffer_from_pixmap_reply(draw->conn, bp_cookie, NULL);
+ if (!bp_reply)
+ goto no_image;
+
+ buffer->image = loader_dri3_create_image(draw->conn, bp_reply, format,
+ cur_screen, draw->ext->image,
+ buffer);
+ width = bp_reply->width;
+ height = bp_reply->height;
+ free(bp_reply);
+ }
+
if (!buffer->image)
goto no_image;
buffer->pixmap = pixmap;
buffer->own_pixmap = false;
- buffer->width = bp_reply->width;
- buffer->height = bp_reply->height;
+ buffer->width = width;
+ buffer->height = height;
buffer->shm_fence = shm_fence;
buffer->sync_fence = sync_fence;
draw->buffers[buf_id] = buffer;
- free(bp_reply);
-
return buffer;
no_image:
- free(bp_reply);
xcb_sync_destroy_fence(draw->conn, sync_fence);
xshmfence_unmap_shm(shm_fence);
no_fence:
@@ -1389,6 +1737,7 @@ dri3_get_buffer(__DRIdrawable *driDrawable,
struct loader_dri3_drawable *draw)
{
struct loader_dri3_buffer *buffer;
+ bool fence_await = buffer_type == loader_dri3_buffer_back;
int buf_id;
if (buffer_type == loader_dri3_buffer_back) {
@@ -1404,11 +1753,12 @@ dri3_get_buffer(__DRIdrawable *driDrawable,
buffer = draw->buffers[buf_id];
- /* Allocate a new buffer if there isn't an old one, or if that
- * old one is the wrong size
+ /* Allocate a new buffer if there isn't an old one, if that
+ * old one is the wrong size, or if it's suboptimal
*/
if (!buffer || buffer->width != draw->width ||
- buffer->height != draw->height) {
+ buffer->height != draw->height ||
+ buffer->reallocate) {
struct loader_dri3_buffer *new_buffer;
/* Allocate the new buffers
@@ -1429,7 +1779,6 @@ dri3_get_buffer(__DRIdrawable *driDrawable,
&& buffer) {
/* Fill the new buffer with data from an old buffer */
- dri3_fence_await(draw->conn, draw, buffer);
if (!loader_dri3_blit_image(draw,
new_buffer->image,
buffer->image,
@@ -1444,6 +1793,7 @@ dri3_get_buffer(__DRIdrawable *driDrawable,
0, 0, 0, 0,
draw->width, draw->height);
dri3_fence_trigger(draw->conn, new_buffer);
+ fence_await = true;
}
dri3_free_render_buffer(draw, buffer);
} else if (buffer_type == loader_dri3_buffer_front) {
@@ -1465,12 +1815,15 @@ dri3_get_buffer(__DRIdrawable *driDrawable,
new_buffer->linear_buffer,
0, 0, draw->width, draw->height,
0, 0, 0);
- }
+ } else
+ fence_await = true;
}
buffer = new_buffer;
draw->buffers[buf_id] = buffer;
}
- dri3_fence_await(draw->conn, draw, buffer);
+
+ if (fence_await)
+ dri3_fence_await(draw->conn, draw, buffer);
/*
* Do we need to preserve the content of a previous buffer?
@@ -1553,6 +1906,7 @@ loader_dri3_get_buffers(__DRIdrawable *driDrawable,
{
struct loader_dri3_drawable *draw = loaderPrivate;
struct loader_dri3_buffer *front, *back;
+ int buf_id;
buffers->image_mask = 0;
buffers->front = NULL;
@@ -1561,9 +1915,19 @@ loader_dri3_get_buffers(__DRIdrawable *driDrawable,
front = NULL;
back = NULL;
- if (!dri3_update_drawable(driDrawable, draw))
+ if (!dri3_update_drawable(draw))
return false;
+ dri3_update_num_back(draw);
+
+ /* Free no longer needed back buffers */
+ for (buf_id = draw->num_back; buf_id < LOADER_DRI3_MAX_BACK; buf_id++) {
+ if (draw->cur_blit_source != buf_id && draw->buffers[buf_id]) {
+ dri3_free_render_buffer(draw, draw->buffers[buf_id]);
+ draw->buffers[buf_id] = NULL;
+ }
+ }
+
/* pixmaps always have front buffers.
* Exchange swaps also mandate fake front buffers.
*/
@@ -1706,7 +2070,7 @@ dri3_find_back_alloc(struct loader_dri3_drawable *draw)
back = draw->buffers[id];
/* Allocate a new back if we haven't got one */
if (!back && draw->back_format != __DRI_IMAGE_FORMAT_NONE &&
- dri3_update_drawable(draw->dri_drawable, draw))
+ dri3_update_drawable(draw))
back = dri3_alloc_render_buffer(draw, draw->back_format,
draw->width, draw->height, draw->depth);
diff --git a/lib/mesa/src/loader/loader_dri3_helper.h b/lib/mesa/src/loader/loader_dri3_helper.h
index 790f78427..0d1818131 100644
--- a/lib/mesa/src/loader/loader_dri3_helper.h
+++ b/lib/mesa/src/loader/loader_dri3_helper.h
@@ -61,9 +61,13 @@ struct loader_dri3_buffer {
struct xshmfence *shm_fence; /* pointer to xshmfence object */
bool busy; /* Set on swap, cleared on IdleNotify */
bool own_pixmap; /* We allocated the pixmap ID, free on destroy */
+ bool reallocate; /* Buffer should be reallocated and not reused */
+ uint32_t num_planes;
uint32_t size;
- uint32_t pitch;
+ int strides[4];
+ int offsets[4];
+ uint64_t modifier;
uint32_t cpp;
uint32_t flags;
uint32_t width, height;
@@ -108,19 +112,21 @@ struct loader_dri3_vtable {
struct loader_dri3_drawable {
xcb_connection_t *conn;
+ xcb_screen_t *screen;
__DRIdrawable *dri_drawable;
xcb_drawable_t drawable;
+ xcb_window_t window;
int width;
int height;
int depth;
uint8_t have_back;
uint8_t have_fake_front;
uint8_t is_pixmap;
- uint8_t flipping;
/* Information about the GPU owning the buffer */
__DRIscreen *dri_screen;
bool is_different_gpu;
+ bool multiplanes_available;
/* Present extension capabilities
*/
@@ -138,10 +144,6 @@ struct loader_dri3_drawable {
/* Last received UST/MSC values from present notify msc event */
uint64_t notify_ust, notify_msc;
- /* Serial numbers for tracking wait_for_msc events */
- uint32_t send_msc_serial;
- uint32_t recv_msc_serial;
-
struct loader_dri3_buffer *buffers[LOADER_DRI3_NUM_BUFFERS];
int cur_back;
int num_back;
@@ -161,6 +163,7 @@ struct loader_dri3_drawable {
unsigned int swap_method;
unsigned int back_format;
+ xcb_present_complete_mode_t last_present_mode;
/* Currently protects the following fields:
* event_cnd, has_event_waiter,
@@ -184,6 +187,7 @@ loader_dri3_drawable_init(xcb_connection_t *conn,
xcb_drawable_t drawable,
__DRIscreen *dri_screen,
bool is_different_gpu,
+ bool is_multiplanes_available,
const __DRIconfig *dri_config,
struct loader_dri3_extensions *ext,
const struct loader_dri3_vtable *vtable,
@@ -241,6 +245,15 @@ loader_dri3_create_image(xcb_connection_t *c,
const __DRIimageExtension *image,
void *loaderPrivate);
+#ifdef HAVE_DRI3_MODIFIERS
+__DRIimage *
+loader_dri3_create_image_from_buffers(xcb_connection_t *c,
+ xcb_dri3_buffers_from_pixmap_reply_t *bp_reply,
+ unsigned int format,
+ __DRIscreen *dri_screen,
+ const __DRIimageExtension *image,
+ void *loaderPrivate);
+#endif
int
loader_dri3_get_buffers(__DRIdrawable *driDrawable,
unsigned int format,