예제 #1
0
static int
pixman_renderer_surface_copy_content(struct weston_surface *surface,
				     void *target, size_t size,
				     int src_x, int src_y,
				     int width, int height)
{
	const pixman_format_code_t format = PIXMAN_a8b8g8r8;
	const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
	struct pixman_surface_state *ps = get_surface_state(surface);
	pixman_image_t *out_buf;

	if (!ps->image)
		return -1;

	out_buf = pixman_image_create_bits(format, width, height,
					   target, width * bytespp);

	pixman_image_set_transform(ps->image, NULL);
	pixman_image_composite32(PIXMAN_OP_SRC,
				 ps->image,    /* src */
				 NULL,         /* mask */
				 out_buf,      /* dest */
				 src_x, src_y, /* src_x, src_y */
				 0, 0,         /* mask_x, mask_y */
				 0, 0,         /* dest_x, dest_y */
				 width, height);

	pixman_image_unref(out_buf);

	return 0;
}
예제 #2
0
static void
pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
{
	struct pixman_surface_state *ps = get_surface_state(es);
	struct wl_shm_buffer *shm_buffer;
	pixman_format_code_t pixman_format;

	weston_buffer_reference(&ps->buffer_ref, buffer);

	if (ps->image) {
		pixman_image_unref(ps->image);
		ps->image = NULL;
	}

	if (!buffer)
		return;
	
	shm_buffer = wl_shm_buffer_get(buffer->resource);

	if (! shm_buffer) {
		weston_log("Pixman renderer supports only SHM buffers\n");
		weston_buffer_reference(&ps->buffer_ref, NULL);
		return;
	}

	switch (wl_shm_buffer_get_format(shm_buffer)) {
	case WL_SHM_FORMAT_XRGB8888:
		pixman_format = PIXMAN_x8r8g8b8;
		break;
	case WL_SHM_FORMAT_ARGB8888:
		pixman_format = PIXMAN_a8r8g8b8;
		break;
	case WL_SHM_FORMAT_RGB565:
		pixman_format = PIXMAN_r5g6b5;
		break;
	default:
		weston_log("Unsupported SHM buffer format\n");
		weston_buffer_reference(&ps->buffer_ref, NULL);
		return;
	break;
	}

	buffer->shm_buffer = shm_buffer;
	buffer->width = wl_shm_buffer_get_width(shm_buffer);
	buffer->height = wl_shm_buffer_get_height(shm_buffer);

	ps->image = pixman_image_create_bits(pixman_format,
		buffer->width, buffer->height,
		wl_shm_buffer_get_data(shm_buffer),
		wl_shm_buffer_get_stride(shm_buffer));
}
예제 #3
0
static void
draw_view(struct weston_view *ev, struct weston_output *output,
	  pixman_region32_t *damage) /* in global coordinates */
{
	struct pixman_surface_state *ps = get_surface_state(ev->surface);
	/* repaint bounding region in global coordinates: */
	pixman_region32_t repaint;
	/* non-opaque region in surface coordinates: */
	pixman_region32_t surface_blend;

	/* No buffer attached */
	if (!ps->image)
		return;

	pixman_region32_init(&repaint);
	pixman_region32_intersect(&repaint,
				  &ev->transform.boundingbox, damage);
	pixman_region32_subtract(&repaint, &repaint, &ev->clip);

	if (!pixman_region32_not_empty(&repaint))
		goto out;

	if (output->zoom.active) {
		weston_log("pixman renderer does not support zoom\n");
		goto out;
	}

	/* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
	if (ev->transform.enabled &&
	    ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE) {
		repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER);
	} else {
		/* blended region is whole surface minus opaque region: */
		pixman_region32_init_rect(&surface_blend, 0, 0,
					  ev->surface->width, ev->surface->height);
		pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);

		if (pixman_region32_not_empty(&ev->surface->opaque)) {
			repaint_region(ev, output, &repaint, &ev->surface->opaque, PIXMAN_OP_SRC);
		}

		if (pixman_region32_not_empty(&surface_blend)) {
			repaint_region(ev, output, &repaint, &surface_blend, PIXMAN_OP_OVER);
		}
		pixman_region32_fini(&surface_blend);
	}


out:
	pixman_region32_fini(&repaint);
}
예제 #4
0
static void
pixman_renderer_surface_get_content_size(struct weston_surface *surface,
					 int *width, int *height)
{
	struct pixman_surface_state *ps = get_surface_state(surface);

	if (ps->image) {
		*width = pixman_image_get_width(ps->image);
		*height = pixman_image_get_height(ps->image);
	} else {
		*width = 0;
		*height = 0;
	}
}
예제 #5
0
static void
draw_view(struct weston_view *ev, struct weston_output *output,
	  pixman_region32_t *damage) /* in global coordinates */
{
	static int zoom_logged = 0;
	struct pixman_surface_state *ps = get_surface_state(ev->surface);
	/* repaint bounding region in global coordinates: */
	pixman_region32_t repaint;

	/* No buffer attached */
	if (!ps->image)
		return;

	pixman_region32_init(&repaint);
	pixman_region32_intersect(&repaint,
				  &ev->transform.boundingbox, damage);
	pixman_region32_subtract(&repaint, &repaint, &ev->clip);

	if (!pixman_region32_not_empty(&repaint))
		goto out;

	if (output->zoom.active && !zoom_logged) {
		weston_log("pixman renderer does not support zoom\n");
		zoom_logged = 1;
	}

	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.
		 * Also the boundingbox is accurate rather than an
		 * approximation.
		 */
		draw_view_translated(ev, output, &repaint);
	} else {
		/* 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:
	pixman_region32_fini(&repaint);
}
예제 #6
0
static void
pixman_renderer_surface_set_color(struct weston_surface *es,
		 float red, float green, float blue, float alpha)
{
	struct pixman_surface_state *ps = get_surface_state(es);
	pixman_color_t color;

	color.red = red * 0xffff;
	color.green = green * 0xffff;
	color.blue = blue * 0xffff;
	color.alpha = alpha * 0xffff;
	
	if (ps->image) {
		pixman_image_unref(ps->image);
		ps->image = NULL;
	}

	ps->image = pixman_image_create_solid_fill(&color);
}
예제 #7
0
static void
repaint_region(struct weston_view *ev, struct weston_output *output,
	       pixman_region32_t *region, pixman_region32_t *surf_region,
	       pixman_op_t pixman_op)
{
	struct pixman_renderer *pr =
		(struct pixman_renderer *) output->compositor->renderer;
	struct pixman_surface_state *ps = get_surface_state(ev->surface);
	struct pixman_output_state *po = get_output_state(output);
	pixman_region32_t final_region;
	float view_x, view_y;
	pixman_transform_t transform;
	pixman_fixed_t fw, fh;

	/* The final region to be painted is the intersection of
	 * 'region' and 'surf_region'. However, 'region' is in the global
	 * coordinates, and 'surf_region' is in the surface-local
	 * coordinates
	 */
	pixman_region32_init(&final_region);
	if (surf_region) {
		pixman_region32_copy(&final_region, surf_region);

		/* Convert from surface to global coordinates */
		if (!ev->transform.enabled) {
			pixman_region32_translate(&final_region, ev->geometry.x, ev->geometry.y);
		} else {
			weston_view_to_global_float(ev, 0, 0, &view_x, &view_y);
			pixman_region32_translate(&final_region, (int)view_x, (int)view_y);
		}

		/* We need to paint the intersection */
		pixman_region32_intersect(&final_region, &final_region, region);
	} else {
		/* If there is no surface region, just use the global region */
		pixman_region32_copy(&final_region, region);
	}

	/* Convert from global to output coord */
	region_global_to_output(output, &final_region);

	/* And clip to it */
	pixman_image_set_clip_region32 (po->shadow_image, &final_region);

	/* Set up the source transformation based on the surface
	   position, the output position/transform/scale and the client
	   specified buffer transform/scale */
	pixman_transform_init_identity(&transform);
	pixman_transform_scale(&transform, NULL,
			       pixman_double_to_fixed ((double)1.0/output->current_scale),
			       pixman_double_to_fixed ((double)1.0/output->current_scale));

	fw = pixman_int_to_fixed(output->width);
	fh = pixman_int_to_fixed(output->height);
	switch (output->transform) {
	default:
	case WL_OUTPUT_TRANSFORM_NORMAL:
	case WL_OUTPUT_TRANSFORM_FLIPPED:
		break;
	case WL_OUTPUT_TRANSFORM_90:
	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
		pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
		pixman_transform_translate(&transform, NULL, 0, fh);
		break;
	case WL_OUTPUT_TRANSFORM_180:
	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
		pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
		pixman_transform_translate(&transform, NULL, fw, fh);
		break;
	case WL_OUTPUT_TRANSFORM_270:
	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
		pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
		pixman_transform_translate(&transform, NULL, fw, 0);
		break;
	}

	switch (output->transform) {
	case WL_OUTPUT_TRANSFORM_FLIPPED:
	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
		pixman_transform_scale(&transform, NULL,
				       pixman_int_to_fixed (-1),
				       pixman_int_to_fixed (1));
		pixman_transform_translate(&transform, NULL, fw, 0);
		break;
	}

        pixman_transform_translate(&transform, NULL,
				   pixman_double_to_fixed (output->x),
				   pixman_double_to_fixed (output->y));

	if (ev->transform.enabled) {
		/* Pixman supports only 2D transform matrix, but Weston uses 3D,
		 * so we're omitting Z coordinate here
		 */
		pixman_transform_t surface_transform = {{
				{ D2F(ev->transform.matrix.d[0]),
				  D2F(ev->transform.matrix.d[4]),
				  D2F(ev->transform.matrix.d[12]),
				},
				{ D2F(ev->transform.matrix.d[1]),
				  D2F(ev->transform.matrix.d[5]),
				  D2F(ev->transform.matrix.d[13]),
				},
				{ D2F(ev->transform.matrix.d[3]),
				  D2F(ev->transform.matrix.d[7]),
				  D2F(ev->transform.matrix.d[15]),
				}
			}};

		pixman_transform_invert(&surface_transform, &surface_transform);
		pixman_transform_multiply (&transform, &surface_transform, &transform);
	} else {
		pixman_transform_translate(&transform, NULL,
					   pixman_double_to_fixed ((double)-ev->geometry.x),
					   pixman_double_to_fixed ((double)-ev->geometry.y));
	}

	if (ev->surface->buffer_viewport.scaler_set) {
		double scaler_x, scaler_y, scaler_width, scaler_height;
		double ratio_x, ratio_y;

		scaler_x = wl_fixed_to_double(ev->surface->buffer_viewport.src_x);
		scaler_y = wl_fixed_to_double(ev->surface->buffer_viewport.src_y);
		scaler_width = wl_fixed_to_double(ev->surface->buffer_viewport.src_width);
		scaler_height = wl_fixed_to_double(ev->surface->buffer_viewport.src_height);

		ratio_x = scaler_width / ev->surface->buffer_viewport.dst_width;
		ratio_y = scaler_height / ev->surface->buffer_viewport.dst_height;

		pixman_transform_scale(&transform, NULL,
				       pixman_double_to_fixed(ratio_x),
				       pixman_double_to_fixed(ratio_y));
		pixman_transform_translate(&transform, NULL, pixman_double_to_fixed(scaler_x),
							     pixman_double_to_fixed(scaler_y));
	}

	pixman_transform_scale(&transform, NULL,
			       pixman_double_to_fixed(ev->surface->buffer_viewport.scale),
			       pixman_double_to_fixed(ev->surface->buffer_viewport.scale));

	fw = pixman_int_to_fixed(pixman_image_get_width(ps->image));
	fh = pixman_int_to_fixed(pixman_image_get_height(ps->image));

	switch (ev->surface->buffer_viewport.transform) {
	case WL_OUTPUT_TRANSFORM_FLIPPED:
	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
		pixman_transform_scale(&transform, NULL,
				       pixman_int_to_fixed (-1),
				       pixman_int_to_fixed (1));
		pixman_transform_translate(&transform, NULL, fw, 0);
		break;
	}

	switch (ev->surface->buffer_viewport.transform) {
	default:
	case WL_OUTPUT_TRANSFORM_NORMAL:
	case WL_OUTPUT_TRANSFORM_FLIPPED:
		break;
	case WL_OUTPUT_TRANSFORM_90:
	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
		pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
		pixman_transform_translate(&transform, NULL, fh, 0);
		break;
	case WL_OUTPUT_TRANSFORM_180:
	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
		pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
		pixman_transform_translate(&transform, NULL, fw, fh);
		break;
	case WL_OUTPUT_TRANSFORM_270:
	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
		pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
		pixman_transform_translate(&transform, NULL, 0, fw);
		break;
	}

	pixman_image_set_transform(ps->image, &transform);

	if (ev->transform.enabled || output->current_scale != ev->surface->buffer_viewport.scale)
		pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
	else
		pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);

	if (ps->buffer_ref.buffer)
		wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);

	pixman_image_composite32(pixman_op,
				 ps->image, /* src */
				 NULL /* 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 (ps->buffer_ref.buffer)
		wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);

	if (pr->repaint_debug)
		pixman_image_composite32(PIXMAN_OP_OVER,
					 pr->debug_color, /* src */
					 NULL /* 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 */);

	pixman_image_set_clip_region32 (po->shadow_image, NULL);

	pixman_region32_fini(&final_region);
}
예제 #8
0
/** Paint an intersected region
 *
 * \param ev The view to be painted.
 * \param output The output being painted.
 * \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.
 * \param pixman_op Compositing operator, either SRC or OVER.
 */
static void
repaint_region(struct weston_view *ev, struct weston_output *output,
	       pixman_region32_t *repaint_output,
	       pixman_region32_t *source_clip,
	       pixman_op_t pixman_op)
{
	struct pixman_renderer *pr =
		(struct pixman_renderer *) output->compositor->renderer;
	struct pixman_surface_state *ps = get_surface_state(ev->surface);
	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, };

	/* Clip rendering to the damaged output region */
	pixman_image_set_clip_region32(po->shadow_image, repaint_output);

	pixman_renderer_compute_transform(&transform, ev, output);

	if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
		filter = PIXMAN_FILTER_BILINEAR;
	else
		filter = PIXMAN_FILTER_NEAREST;

	if (ps->buffer_ref.buffer)
		wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);

	if (ev->alpha < 1.0) {
		mask.alpha = 0xffff * ev->alpha;
		mask_image = pixman_image_create_solid_fill(&mask);
	} else {
		mask_image = NULL;
	}

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

	if (ps->buffer_ref.buffer)
		wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);

	if (pr->repaint_debug)
		pixman_image_composite32(PIXMAN_OP_OVER,
					 pr->debug_color, /* src */
					 NULL /* 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 */);

	pixman_image_set_clip_region32 (po->shadow_image, NULL);
}