summaryrefslogtreecommitdiffstats
path: root/src/loader/loader_dri3_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/loader/loader_dri3_helper.c')
-rw-r--r--src/loader/loader_dri3_helper.c308
1 files changed, 263 insertions, 45 deletions
diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c
index 426966a786a..6587281c4ab 100644
--- a/src/loader/loader_dri3_helper.c
+++ b/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>
@@ -34,6 +35,7 @@
#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
@@ -257,6 +259,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,
@@ -274,6 +277,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;
@@ -1023,6 +1027,41 @@ image_format_to_fourcc(int format)
return 0;
}
+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;
+}
+
/** loader_dri3_alloc_render_buffer
*
* Use the driver createImage function to construct a __DRIimage, then
@@ -1039,8 +1078,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
@@ -1065,13 +1106,79 @@ 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);
+ 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->drawable,
+ 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);
+ }
+
+ 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)
@@ -1099,25 +1206,67 @@ 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;
+
+ for (i = 0; i < num_planes; i++) {
+ __DRIimage *image = draw->ext->image->fromPlanar(pixmap_buffer, i, NULL);
- buffer->pitch = stride;
+ if (!image) {
+ assert(i == 0);
+ image = pixmap_buffer;
+ }
- if (!draw->ext->image->queryImage(pixmap_buffer, __DRI_IMAGE_ATTRIB_FD,
- &buffer_fd))
- goto no_buffer_attrib;
+ 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);
+ if (draw->multiplanes_available &&
+ buffer->modifier != DRM_FORMAT_MOD_INVALID) {
+ xcb_dri3_pixmap_from_buffers(draw->conn,
+ pixmap,
+ draw->drawable,
+ 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 {
+ 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,
@@ -1139,6 +1288,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)
@@ -1295,6 +1447,48 @@ loader_dri3_create_image(xcb_connection_t *c,
return ret;
}
+__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;
+}
+
/** dri3_get_pixmap_buffer
*
* Get the DRM object for a pixmap from the X server and
@@ -1308,10 +1502,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;
@@ -1333,17 +1527,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.
@@ -1353,27 +1536,62 @@ 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);
+
+ 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 {
+ 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: