diff options
Diffstat (limited to 'src/loader/loader_dri3_helper.c')
-rw-r--r-- | src/loader/loader_dri3_helper.c | 308 |
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: |