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; }