[PATCH weston 7/8] pixman-renderer: implement source clipping
Derek Foreman
derekf at osg.samsung.com
Fri Mar 6 11:53:46 PST 2015
On 06/03/15 05:04 AM, Pekka Paalanen wrote:
> From: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
>
> Implement a way to do composition clipping with a region32 given in
> source image space.
>
> Pixman does not directly support this kind of operation at all. If you
> pixman_image_set_clip_region32() on a source image, it will be ignored
> unless you also
> pixman_image_set_source_clipping(image, 1);
> pixman_image_set_has_client_clip(image, 1);
> but then it takes the region from source image and still uses it in the
> destination coordinate space. For reference:
> http://lists.freedesktop.org/archives/pixman/2015-March/003501.html
> That is actually the intended behaviour in Pixman.
>
> This patch implements source clipping by taking each rectangle of the
> source clip region, wrapping that sub-rect of the source image in a new
> pixman_image_t, and compositing it separately. This might be very heavy as
> we are painting the whole damage the number of rectangles times, but
> practically always the number of rectangles is one.
>
> An alternative solution would be to use mask images of type PIXMAN_a1,
> render the source clip region in it, and set the transformation. You'd
> probably also want to cache those images. And because we use the mask to
> apply view->alpha, you'd have to use PIXMAN_a8 in those cases.
>
> Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
> ---
> src/pixman-renderer.c | 166 +++++++++++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 150 insertions(+), 16 deletions(-)
>
> diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c
> index fc7613c..d3f1342 100644
> --- a/src/pixman-renderer.c
> +++ b/src/pixman-renderer.c
> @@ -26,6 +26,7 @@
>
> #include <errno.h>
> #include <stdlib.h>
> +#include <assert.h>
>
> #include "pixman-renderer.h"
>
> @@ -326,6 +327,101 @@ region_intersect_only_translation(pixman_region32_t *result_global,
> pixman_region32_intersect(result_global, result_global, global);
> }
>
> +static void
> +composite_whole(pixman_op_t op,
> + pixman_image_t *src,
> + pixman_image_t *mask,
> + pixman_image_t *dest,
> + const pixman_transform_t *transform,
> + pixman_filter_t filter)
> +{
> + int32_t dest_width;
> + int32_t dest_height;
> +
> + dest_width = pixman_image_get_width(dest);
> + dest_height = pixman_image_get_height(dest);
> +
> + pixman_image_set_transform(src, transform);
> + pixman_image_set_filter(src, filter, NULL, 0);
> +
> + pixman_image_composite32(op, src, mask, dest,
> + 0, 0, /* src_x, src_y */
> + 0, 0, /* mask_x, mask_y */
> + 0, 0, /* dest_x, dest_y */
> + dest_width, dest_height);
> +}
> +
> +static void
> +composite_clipped(pixman_image_t *src,
> + pixman_image_t *mask,
> + pixman_image_t *dest,
> + const pixman_transform_t *transform,
> + pixman_filter_t filter,
> + pixman_region32_t *src_clip)
> +{
> + int n_box;
> + pixman_box32_t *boxes;
> + int32_t dest_width;
> + int32_t dest_height;
> + int src_stride;
> + int bitspp;
> + pixman_format_code_t src_format;
> + void *src_data;
> + int i;
> +
> + /* Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
> + * a Pixman image produces (0,0,0,0) instead of discarding the
> + * fragment.
> + */
> +
> + dest_width = pixman_image_get_width(dest);
> + dest_height = pixman_image_get_height(dest);
> + src_format = pixman_image_get_format(src);
> + src_stride = pixman_image_get_stride(src);
> + bitspp = PIXMAN_FORMAT_BPP(src_format);
> + src_data = pixman_image_get_data(src);
> +
> + assert(src_format);
> +
> + /* This would be massive overdraw, except n_box is 1. */
except WHEN n_box is 1? comment seems to declare that n_box is 1, so
why the for loop?
> + boxes = pixman_region32_rectangles(src_clip, &n_box);
> + for (i = 0; i < n_box; i++) {
> + uint8_t *ptr = src_data;
> + pixman_image_t *boximg;
> + pixman_transform_t adj = *transform;
> +
> + ptr += boxes[i].y1 * src_stride;
> + ptr += boxes[i].x1 * bitspp / 8;
> + boximg = pixman_image_create_bits_no_clear(src_format,
> + boxes[i].x2 - boxes[i].x1,
> + boxes[i].y2 - boxes[i].y1,
> + (uint32_t *)ptr, src_stride);
> +
> + pixman_transform_translate(&adj, NULL,
> + pixman_int_to_fixed(-boxes[i].x1),
> + pixman_int_to_fixed(-boxes[i].y1));
> + pixman_image_set_transform(boximg, &adj);
> +
> + pixman_image_set_filter(boximg, filter, NULL, 0);
> + pixman_image_composite32(PIXMAN_OP_OVER, boximg, mask, dest,
> + 0, 0, /* src_x, src_y */
> + 0, 0, /* mask_x, mask_y */
> + 0, 0, /* dest_x, dest_y */
> + dest_width, dest_height);
> +
> + pixman_image_unref(boximg);
> + }
> +
> + if (n_box > 1) {
> + static bool warned = false;
> +
> + if (!warned)
> + weston_log("Pixman-renderer warning: %dx overdraw\n",
> + n_box);
> + warned = true;
> + }
> +}
> +
> /** Paint an intersected region
> *
> * \param ev The view to be painted.
> @@ -333,7 +429,6 @@ region_intersect_only_translation(pixman_region32_t *result_global,
> * \param repaint_output The region to be painted in output coordinates.
> * \param source_clip The region of the source image to use, in source image
> * coordinates. If NULL, use the whole source image.
> - * XXX: UNIMPLEMENTED
> * \param pixman_op Compositing operator, either SRC or OVER.
> */
> static void
> @@ -347,6 +442,7 @@ repaint_region(struct weston_view *ev, struct weston_output *output,
> struct pixman_output_state *po = get_output_state(output);
> struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
> pixman_transform_t transform;
> + pixman_filter_t filter;
> pixman_image_t *mask_image;
> pixman_color_t mask = { 0, };
>
> @@ -354,12 +450,11 @@ repaint_region(struct weston_view *ev, struct weston_output *output,
> pixman_image_set_clip_region32(po->shadow_image, repaint_output);
>
> pixman_renderer_compute_transform(&transform, ev, output);
> - pixman_image_set_transform(ps->image, &transform);
>
> if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
> - pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
> + filter = PIXMAN_FILTER_BILINEAR;
> else
> - pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);
> + filter = PIXMAN_FILTER_NEAREST;
>
> if (ps->buffer_ref.buffer)
> wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
> @@ -371,15 +466,12 @@ repaint_region(struct weston_view *ev, struct weston_output *output,
> mask_image = NULL;
> }
>
> - pixman_image_composite32(pixman_op,
> - ps->image, /* src */
> - mask_image, /* mask */
> - po->shadow_image, /* dest */
> - 0, 0, /* src_x, src_y */
> - 0, 0, /* mask_x, mask_y */
> - 0, 0, /* dest_x, dest_y */
> - pixman_image_get_width (po->shadow_image), /* width */
> - pixman_image_get_height (po->shadow_image) /* height */);
> + if (source_clip)
> + composite_clipped(ps->image, mask_image, po->shadow_image,
> + &transform, filter, source_clip);
> + else
> + composite_whole(pixman_op, ps->image, mask_image,
> + po->shadow_image, &transform, filter);
>
> if (mask_image)
> pixman_image_unref(mask_image);
> @@ -450,6 +542,38 @@ draw_view_translated(struct weston_view *view, struct weston_output *output,
> }
>
> static void
> +draw_view_source_clipped(struct weston_view *view,
> + struct weston_output *output,
> + pixman_region32_t *repaint_global)
> +{
> + struct weston_surface *surface = view->surface;
> + pixman_region32_t surf_region;
> + pixman_region32_t buffer_region;
> + pixman_region32_t repaint_output;
> +
> + /* Do not bother separating the opaque region from non-opaque.
> + * Source clipping requires PIXMAN_OP_OVER in all cases, so painting
> + * opaque separately has no benefit.
> + */
> +
> + pixman_region32_init_rect(&surf_region, 0, 0,
> + surface->width, surface->height);
> + pixman_region32_init(&buffer_region);
> + weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
> +
> + pixman_region32_init(&repaint_output);
> + pixman_region32_copy(&repaint_output, repaint_global);
> + region_global_to_output(output, &repaint_output);
> +
> + repaint_region(view, output, &repaint_output, &buffer_region,
> + PIXMAN_OP_OVER);
> +
> + pixman_region32_fini(&repaint_output);
> + pixman_region32_fini(&buffer_region);
> + pixman_region32_fini(&surf_region);
> +}
> +
> +static void
> draw_view(struct weston_view *ev, struct weston_output *output,
> pixman_region32_t *damage) /* in global coordinates */
> {
> @@ -475,12 +599,22 @@ draw_view(struct weston_view *ev, struct weston_output *output,
> zoom_logged = 1;
> }
>
> - /* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
I guess this patch doesn't do what the removed commend suggested - is
that comment still valid?
> if (view_transformation_is_translation(ev)) {
> + /* The simple case: The surface regions opaque, non-opaque,
> + * etc. are convertible to global coordinate space.
> + * There is no need to use a source clip region.
> + * It is possible to paint opaque region as PIXMAN_OP_SRC.
> + */
> draw_view_translated(ev, output, &repaint);
> } else {
> - region_global_to_output(output, &repaint);
> - repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER);
> + /* The complex case: the view transformation does not allow
> + * converting opaque etc. regions into global coordinate space.
> + * Therefore we need source clipping to avoid sampling from
> + * unwanted source image areas, unless the source image is
> + * to be used whole. Source clipping does not work with
> + * PIXMAN_OP_SRC.
> + */
> + draw_view_source_clipped(ev, output, &repaint);
> }
>
> out:
>
More information about the wayland-devel
mailing list