diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2019-01-29 11:52:33 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2019-01-29 11:52:33 +0000 |
commit | 37bbf6a1792773f11c15a4da1588a7520ee2fb4e (patch) | |
tree | 64944d4aa665a1e479cfc004e446593062254550 /lib/mesa/src/loader | |
parent | 6b139c2063623e9310025247cd966490b9aa57ea (diff) |
Merge Mesa 18.3.2
Diffstat (limited to 'lib/mesa/src/loader')
-rw-r--r-- | lib/mesa/src/loader/Makefile.am | 3 | ||||
-rw-r--r-- | lib/mesa/src/loader/Makefile.in | 48 | ||||
-rw-r--r-- | lib/mesa/src/loader/loader.c | 226 | ||||
-rw-r--r-- | lib/mesa/src/loader/loader.h | 3 | ||||
-rw-r--r-- | lib/mesa/src/loader/loader_dri3_helper.c | 560 | ||||
-rw-r--r-- | lib/mesa/src/loader/loader_dri3_helper.h | 25 |
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, |