From 34a57e50ed7c0a1623067a43dbc22ebbe95eab4b Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Fri, 3 Nov 2023 15:12:24 -0400 Subject: [PATCH 1/4] types/buffer: add prefer_shadow field to wlr_dmabuf_attribute This new field is used when the underlying buffer implementation prefers to use shadow buffers instead of rendering directly to the hardware buffer. --- include/wlr/render/dmabuf.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/wlr/render/dmabuf.h b/include/wlr/render/dmabuf.h index 62f8e0217..3100ece84 100644 --- a/include/wlr/render/dmabuf.h +++ b/include/wlr/render/dmabuf.h @@ -35,6 +35,7 @@ struct wlr_dmabuf_attributes { int32_t width, height; uint32_t format; // FourCC code, see DRM_FORMAT_* in uint64_t modifier; // see DRM_FORMAT_MOD_* in + bool prefer_shadow; int n_planes; uint32_t offset[WLR_DMABUF_MAX_PLANES]; From b8d36a94993a45d90b533eb8f100b90e0266cb24 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Fri, 3 Nov 2023 15:41:09 -0400 Subject: [PATCH 2/4] renderer/pixman: use wlr_addon for wlr_pixman_buffer --- include/render/pixman.h | 4 ++-- render/pixman/renderer.c | 47 +++++++++++++++++----------------------- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/include/render/pixman.h b/include/render/pixman.h index 24a27055d..77b37b43c 100644 --- a/include/render/pixman.h +++ b/include/render/pixman.h @@ -29,11 +29,11 @@ struct wlr_pixman_renderer { struct wlr_pixman_buffer { struct wlr_buffer *buffer; struct wlr_pixman_renderer *renderer; + struct wl_list link; // wlr_pixman_renderer.buffers pixman_image_t *image; - struct wl_listener buffer_destroy; - struct wl_list link; // wlr_pixman_renderer.buffers + struct wlr_addon addon; }; struct wlr_pixman_texture { diff --git a/render/pixman/renderer.c b/render/pixman/renderer.c index e30390fa3..feabe2005 100644 --- a/render/pixman/renderer.c +++ b/render/pixman/renderer.c @@ -57,17 +57,6 @@ bool begin_pixman_data_ptr_access(struct wlr_buffer *wlr_buffer, pixman_image_t return true; } -static struct wlr_pixman_buffer *get_buffer( - struct wlr_pixman_renderer *renderer, struct wlr_buffer *wlr_buffer) { - struct wlr_pixman_buffer *buffer; - wl_list_for_each(buffer, &renderer->buffers, link) { - if (buffer->buffer == wlr_buffer) { - return buffer; - } - } - return NULL; -} - static const struct wlr_texture_impl texture_impl; bool wlr_texture_is_pixman(struct wlr_texture *texture) { @@ -96,21 +85,32 @@ static const struct wlr_texture_impl texture_impl = { static void destroy_buffer(struct wlr_pixman_buffer *buffer) { wl_list_remove(&buffer->link); - wl_list_remove(&buffer->buffer_destroy.link); + wlr_addon_finish(&buffer->addon); pixman_image_unref(buffer->image); free(buffer); } -static void handle_destroy_buffer(struct wl_listener *listener, void *data) { - struct wlr_pixman_buffer *buffer = - wl_container_of(listener, buffer, buffer_destroy); +static void handle_buffer_destroy(struct wlr_addon *addon) { + struct wlr_pixman_buffer *buffer = wl_container_of(addon, buffer, addon); destroy_buffer(buffer); } -static struct wlr_pixman_buffer *create_buffer( - struct wlr_pixman_renderer *renderer, struct wlr_buffer *wlr_buffer) { +static const struct wlr_addon_interface buffer_addon_impl = { + .name = "wlr_pixman_buffer", + .destroy = handle_buffer_destroy, +}; + +static struct wlr_pixman_buffer *get_or_create_buffer(struct wlr_pixman_renderer *renderer, + struct wlr_buffer *wlr_buffer) { + struct wlr_addon *addon = + wlr_addon_find(&wlr_buffer->addons, renderer, &buffer_addon_impl); + if (addon) { + struct wlr_pixman_buffer *buffer = wl_container_of(addon, buffer, addon); + return buffer; + } + struct wlr_pixman_buffer *buffer = calloc(1, sizeof(*buffer)); if (buffer == NULL) { wlr_log_errno(WLR_ERROR, "Allocation failed"); @@ -144,8 +144,7 @@ static struct wlr_pixman_buffer *create_buffer( goto error_buffer; } - buffer->buffer_destroy.notify = handle_destroy_buffer; - wl_signal_add(&wlr_buffer->events.destroy, &buffer->buffer_destroy); + wlr_addon_init(&buffer->addon, &wlr_buffer->addons, renderer, &buffer_addon_impl); wl_list_insert(&renderer->buffers, &buffer->link); @@ -416,10 +415,7 @@ static bool pixman_bind_buffer(struct wlr_renderer *wlr_renderer, return true; } - struct wlr_pixman_buffer *buffer = get_buffer(renderer, wlr_buffer); - if (buffer == NULL) { - buffer = create_buffer(renderer, wlr_buffer); - } + struct wlr_pixman_buffer *buffer = get_or_create_buffer(renderer, wlr_buffer); if (buffer == NULL) { return false; } @@ -495,10 +491,7 @@ static struct wlr_render_pass *pixman_begin_buffer_pass(struct wlr_renderer *wlr struct wlr_buffer *wlr_buffer, const struct wlr_buffer_pass_options *options) { struct wlr_pixman_renderer *renderer = get_renderer(wlr_renderer); - struct wlr_pixman_buffer *buffer = get_buffer(renderer, wlr_buffer); - if (buffer == NULL) { - buffer = create_buffer(renderer, wlr_buffer); - } + struct wlr_pixman_buffer *buffer = get_or_create_buffer(renderer, wlr_buffer); if (buffer == NULL) { return NULL; } From 2c1f23096ce24af8f79253bcd8ea21e66d71fc5f Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Fri, 3 Nov 2023 15:42:43 -0400 Subject: [PATCH 3/4] render/allocator: store shadow buffer preference in wlr_drm_dumb_allocator --- include/render/allocator/drm_dumb.h | 1 + render/allocator/drm_dumb.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/include/render/allocator/drm_dumb.h b/include/render/allocator/drm_dumb.h index 23c150bc3..6356f0305 100644 --- a/include/render/allocator/drm_dumb.h +++ b/include/render/allocator/drm_dumb.h @@ -25,6 +25,7 @@ struct wlr_drm_dumb_allocator { struct wlr_allocator base; struct wl_list buffers; // wlr_drm_dumb_buffer.link int drm_fd; + bool prefer_shadow; }; /** diff --git a/render/allocator/drm_dumb.c b/render/allocator/drm_dumb.c index 6de44f402..a5e270f74 100644 --- a/render/allocator/drm_dumb.c +++ b/render/allocator/drm_dumb.c @@ -97,6 +97,7 @@ static struct wlr_drm_dumb_buffer *create_buffer( .height = buffer->height, .format = format->format, .modifier = DRM_FORMAT_MOD_LINEAR, + .prefer_shadow = alloc->prefer_shadow, .n_planes = 1, .offset[0] = 0, .stride[0] = buffer->stride, @@ -216,6 +217,12 @@ struct wlr_allocator *wlr_drm_dumb_allocator_create(int drm_fd) { return NULL; } + uint64_t prefer_shadow; + if (drmGetCap(drm_fd, DRM_CAP_DUMB_PREFER_SHADOW, &prefer_shadow) < 0) { + wlr_log(WLR_ERROR, "Failed to get DRM capabilities"); + return NULL; + } + struct wlr_drm_dumb_allocator *alloc = calloc(1, sizeof(*alloc)); if (alloc == NULL) { return NULL; @@ -224,6 +231,7 @@ struct wlr_allocator *wlr_drm_dumb_allocator_create(int drm_fd) { WLR_BUFFER_CAP_DATA_PTR | WLR_BUFFER_CAP_DMABUF); alloc->drm_fd = drm_fd; + alloc->prefer_shadow = prefer_shadow; wl_list_init(&alloc->buffers); wlr_log(WLR_DEBUG, "Created DRM dumb allocator"); From 561e56cd7d75396804d43990eaf5973ae89bb1cf Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Fri, 3 Nov 2023 16:33:05 -0400 Subject: [PATCH 4/4] render/pixman: render on shadow image when prefered --- include/render/pixman.h | 1 + render/pixman/pass.c | 25 +++++++++++++------- render/pixman/renderer.c | 50 +++++++++++++++++++++++++++++----------- 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/include/render/pixman.h b/include/render/pixman.h index 77b37b43c..c5edca517 100644 --- a/include/render/pixman.h +++ b/include/render/pixman.h @@ -32,6 +32,7 @@ struct wlr_pixman_buffer { struct wl_list link; // wlr_pixman_renderer.buffers pixman_image_t *image; + pixman_image_t *shadow; struct wlr_addon addon; }; diff --git a/render/pixman/pass.c b/render/pixman/pass.c index 5fe73b053..68be6d805 100644 --- a/render/pixman/pass.c +++ b/render/pixman/pass.c @@ -18,9 +18,15 @@ static struct wlr_pixman_texture *get_texture(struct wlr_texture *wlr_texture) { static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { struct wlr_pixman_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_pixman_buffer *buffer = pass->buffer; - wlr_buffer_end_data_ptr_access(pass->buffer->buffer); - wlr_buffer_unlock(pass->buffer->buffer); + if (buffer->shadow) { + pixman_image_composite32(PIXMAN_OP_SRC, buffer->shadow, NULL, buffer->image, 0, 0, 0, + 0, 0, 0, buffer->buffer->width, buffer->buffer->height); + } + + wlr_buffer_end_data_ptr_access(buffer->buffer); + wlr_buffer_unlock(buffer->buffer); free(pass); return true; @@ -141,11 +147,13 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, pixman_op_t op = get_pixman_blending(options->blend_mode); - pixman_image_set_clip_region32(buffer->image, (pixman_region32_t *)options->clip); + pixman_image_t *target = buffer->shadow ? buffer->shadow : buffer->image; + + pixman_image_set_clip_region32(target, (pixman_region32_t *)options->clip); pixman_image_composite32(op, texture->image, mask, - buffer->image, src_box.x, src_box.y, 0, 0, dest_x, dest_y, + target, src_box.x, src_box.y, 0, 0, dest_x, dest_y, width, height); - pixman_image_set_clip_region32(buffer->image, NULL); + pixman_image_set_clip_region32(target, NULL); pixman_image_set_transform(texture->image, NULL); @@ -176,11 +184,12 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, }; pixman_image_t *fill = pixman_image_create_solid_fill(&color); + pixman_image_t *target = buffer->shadow ? buffer->shadow : buffer->image; - pixman_image_set_clip_region32(buffer->image, (pixman_region32_t *)options->clip); - pixman_image_composite32(op, fill, NULL, buffer->image, + pixman_image_set_clip_region32(target, (pixman_region32_t *)options->clip); + pixman_image_composite32(op, fill, NULL, target, 0, 0, 0, 0, box.x, box.y, box.width, box.height); - pixman_image_set_clip_region32(buffer->image, NULL); + pixman_image_set_clip_region32(target, NULL); pixman_image_unref(fill); } diff --git a/render/pixman/renderer.c b/render/pixman/renderer.c index feabe2005..2624672b4 100644 --- a/render/pixman/renderer.c +++ b/render/pixman/renderer.c @@ -83,10 +83,15 @@ static const struct wlr_texture_impl texture_impl = { .destroy = texture_destroy, }; + static void destroy_buffer(struct wlr_pixman_buffer *buffer) { wl_list_remove(&buffer->link); wlr_addon_finish(&buffer->addon); + if (buffer->shadow) { + pixman_image_unref(buffer->shadow); + } + pixman_image_unref(buffer->image); free(buffer); @@ -137,6 +142,15 @@ static struct wlr_pixman_buffer *get_or_create_buffer(struct wlr_pixman_renderer goto error_buffer; } + struct wlr_dmabuf_attributes dmabuf = {0}; + if (wlr_buffer_get_dmabuf(wlr_buffer, &dmabuf) && dmabuf.prefer_shadow) { + buffer->shadow = pixman_image_create_bits(format, wlr_buffer->width, wlr_buffer->height, + NULL, stride); + if (!buffer->shadow) { + wlr_log(WLR_ERROR, "Failed to allocate pixman shadow image"); + } + } + buffer->image = pixman_image_create_bits(format, wlr_buffer->width, wlr_buffer->height, data, stride); if (!buffer->image) { @@ -173,8 +187,13 @@ static bool pixman_begin(struct wlr_renderer *wlr_renderer, uint32_t width, static void pixman_end(struct wlr_renderer *wlr_renderer) { struct wlr_pixman_renderer *renderer = get_renderer(wlr_renderer); + struct wlr_pixman_buffer *buffer = renderer->current_buffer; + assert(buffer != NULL); - assert(renderer->current_buffer != NULL); + if (buffer->shadow) { + pixman_image_composite32(PIXMAN_OP_SRC, buffer->shadow, NULL, buffer->image, 0, 0, 0, + 0, 0, 0, renderer->width, renderer->height); + } wlr_buffer_end_data_ptr_access(renderer->current_buffer->buffer); } @@ -192,8 +211,9 @@ static void pixman_clear(struct wlr_renderer *wlr_renderer, }; pixman_image_t *fill = pixman_image_create_solid_fill(&colour); + pixman_image_t *target = buffer->shadow ? buffer->shadow : buffer->image; - pixman_image_composite32(PIXMAN_OP_SRC, fill, NULL, buffer->image, 0, 0, 0, + pixman_image_composite32(PIXMAN_OP_SRC, fill, NULL, target, 0, 0, 0, 0, 0, 0, renderer->width, renderer->height); pixman_image_unref(fill); @@ -204,14 +224,16 @@ static void pixman_scissor(struct wlr_renderer *wlr_renderer, struct wlr_pixman_renderer *renderer = get_renderer(wlr_renderer); struct wlr_pixman_buffer *buffer = renderer->current_buffer; + pixman_image_t *target = buffer->shadow ? buffer->shadow : buffer->image; + if (box != NULL) { struct pixman_region32 region = {0}; pixman_region32_init_rect(®ion, box->x, box->y, box->width, box->height); - pixman_image_set_clip_region32(buffer->image, ®ion); + pixman_image_set_clip_region32(target, ®ion); pixman_region32_fini(®ion); } else { - pixman_image_set_clip_region32(buffer->image, NULL); + pixman_image_set_clip_region32(target, NULL); } } @@ -262,9 +284,9 @@ static bool pixman_render_subtexture_with_matrix( pixman_image_set_transform(texture->image, &transform); // TODO clip properly with src_x and src_y - pixman_image_composite32(PIXMAN_OP_OVER, texture->image, mask, - buffer->image, 0, 0, 0, 0, 0, 0, renderer->width, - renderer->height); + pixman_image_t *target = buffer->shadow ? buffer->shadow : buffer->image; + pixman_image_composite32(PIXMAN_OP_OVER, texture->image, mask, target, + 0, 0, 0, 0, 0, 0, buffer->buffer->width, buffer->buffer->height); if (texture->buffer != NULL) { wlr_buffer_end_data_ptr_access(texture->buffer); @@ -320,7 +342,8 @@ static void pixman_render_quad_with_matrix(struct wlr_renderer *wlr_renderer, pixman_image_set_transform(image, &transform); - pixman_image_composite32(PIXMAN_OP_OVER, image, NULL, buffer->image, + pixman_image_t *target = buffer->shadow ? buffer->shadow : buffer->image; + pixman_image_composite32(PIXMAN_OP_OVER, image, NULL, target, 0, 0, 0, 0, 0, 0, renderer->width, renderer->height); pixman_image_unref(image); @@ -449,8 +472,7 @@ static uint32_t pixman_preferred_read_format( struct wlr_pixman_renderer *renderer = get_renderer(wlr_renderer); struct wlr_pixman_buffer *buffer = renderer->current_buffer; - pixman_format_code_t pixman_format = pixman_image_get_format( - buffer->image); + pixman_format_code_t pixman_format = pixman_image_get_format(buffer->image); return get_drm_format_from_pixman(pixman_format); } @@ -475,7 +497,8 @@ static bool pixman_read_pixels(struct wlr_renderer *wlr_renderer, pixman_image_t *dst = pixman_image_create_bits_no_clear(fmt, width, height, data, stride); - pixman_image_composite32(PIXMAN_OP_SRC, buffer->image, NULL, dst, + pixman_image_t *src = buffer->shadow ? buffer->shadow : buffer->image; + pixman_image_composite32(PIXMAN_OP_SRC, src, NULL, dst, src_x, src_y, 0, 0, dst_x, dst_y, width, height); pixman_image_unref(dst); @@ -553,6 +576,7 @@ pixman_image_t *wlr_pixman_texture_get_image(struct wlr_texture *wlr_texture) { pixman_image_t *wlr_pixman_renderer_get_current_image( struct wlr_renderer *wlr_renderer) { struct wlr_pixman_renderer *renderer = get_renderer(wlr_renderer); - assert(renderer->current_buffer); - return renderer->current_buffer->image; + struct wlr_pixman_buffer *buffer = renderer->current_buffer; + assert(buffer); + return buffer->shadow ? buffer->shadow : buffer->image; }