blob: b71982992f12f8f15e1083e3487aa86dd2cef4c0 [file] [log] [blame]
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +03001/*
2 * Copyright © 2012 Intel Corporation
3 * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
Daniel Stonec228e232013-05-22 18:03:19 +030024#include "config.h"
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030025
26#include <errno.h>
27#include <stdlib.h>
28
29#include "pixman-renderer.h"
30
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020031#include <linux/input.h>
32
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030033struct pixman_output_state {
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +020034 void *shadow_buffer;
35 pixman_image_t *shadow_image;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030036 pixman_image_t *hw_buffer;
37};
38
39struct pixman_surface_state {
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030040 struct weston_surface *surface;
41
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030042 pixman_image_t *image;
43 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030044
45 struct wl_listener surface_destroy_listener;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030046 struct wl_listener renderer_destroy_listener;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030047};
48
49struct pixman_renderer {
50 struct weston_renderer base;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030051
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020052 int repaint_debug;
53 pixman_image_t *debug_color;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030054 struct weston_binding *debug_binding;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030055
56 struct wl_signal destroy_signal;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030057};
58
59static inline struct pixman_output_state *
60get_output_state(struct weston_output *output)
61{
62 return (struct pixman_output_state *)output->renderer_state;
63}
64
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030065static int
66pixman_renderer_create_surface(struct weston_surface *surface);
67
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030068static inline struct pixman_surface_state *
69get_surface_state(struct weston_surface *surface)
70{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030071 if (!surface->renderer_state)
72 pixman_renderer_create_surface(surface);
73
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030074 return (struct pixman_surface_state *)surface->renderer_state;
75}
76
77static inline struct pixman_renderer *
78get_renderer(struct weston_compositor *ec)
79{
80 return (struct pixman_renderer *)ec->renderer;
81}
82
83static int
84pixman_renderer_read_pixels(struct weston_output *output,
85 pixman_format_code_t format, void *pixels,
86 uint32_t x, uint32_t y,
87 uint32_t width, uint32_t height)
88{
89 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson97af7922013-05-29 12:01:33 +020090 pixman_transform_t transform;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030091 pixman_image_t *out_buf;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030092
93 if (!po->hw_buffer) {
94 errno = ENODEV;
95 return -1;
96 }
97
98 out_buf = pixman_image_create_bits(format,
99 width,
100 height,
101 pixels,
102 (PIXMAN_FORMAT_BPP(format) / 8) * width);
103
Alexander Larsson97af7922013-05-29 12:01:33 +0200104 /* Caller expects vflipped source image */
105 pixman_transform_init_translate(&transform,
106 pixman_int_to_fixed (x),
107 pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
108 pixman_transform_scale(&transform, NULL,
109 pixman_fixed_1,
110 pixman_fixed_minus_1);
111 pixman_image_set_transform(po->hw_buffer, &transform);
112
113 pixman_image_composite32(PIXMAN_OP_SRC,
114 po->hw_buffer, /* src */
115 NULL /* mask */,
116 out_buf, /* dest */
117 0, 0, /* src_x, src_y */
118 0, 0, /* mask_x, mask_y */
119 0, 0, /* dest_x, dest_y */
120 pixman_image_get_width (po->hw_buffer), /* width */
121 pixman_image_get_height (po->hw_buffer) /* height */);
122 pixman_image_set_transform(po->hw_buffer, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300123
124 pixman_image_unref(out_buf);
125
126 return 0;
127}
128
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300129static void
Alexander Larsson1f206b42013-05-22 14:41:36 +0200130region_global_to_output(struct weston_output *output, pixman_region32_t *region)
131{
132 pixman_region32_translate(region, -output->x, -output->y);
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500133 weston_transformed_region(output->width, output->height,
134 output->transform, output->current_scale,
135 region, region);
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300136}
137
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300138#define D2F(v) pixman_double_to_fixed((double)v)
139
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300140static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500141repaint_region(struct weston_view *ev, struct weston_output *output,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200142 pixman_region32_t *region, pixman_region32_t *surf_region,
143 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300144{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200145 struct pixman_renderer *pr =
146 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500147 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300148 struct pixman_output_state *po = get_output_state(output);
149 pixman_region32_t final_region;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500150 float view_x, view_y;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200151 pixman_transform_t transform;
152 pixman_fixed_t fw, fh;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300153
154 /* The final region to be painted is the intersection of
155 * 'region' and 'surf_region'. However, 'region' is in the global
156 * coordinates, and 'surf_region' is in the surface-local
157 * coordinates
158 */
159 pixman_region32_init(&final_region);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200160 if (surf_region) {
161 pixman_region32_copy(&final_region, surf_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300162
Alexander Larsson1f206b42013-05-22 14:41:36 +0200163 /* Convert from surface to global coordinates */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500164 if (!ev->transform.enabled) {
165 pixman_region32_translate(&final_region, ev->geometry.x, ev->geometry.y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200166 } else {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500167 weston_view_to_global_float(ev, 0, 0, &view_x, &view_y);
168 pixman_region32_translate(&final_region, (int)view_x, (int)view_y);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200169 }
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300170
Alexander Larsson1f206b42013-05-22 14:41:36 +0200171 /* We need to paint the intersection */
172 pixman_region32_intersect(&final_region, &final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300173 } else {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200174 /* If there is no surface region, just use the global region */
175 pixman_region32_copy(&final_region, region);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300176 }
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300177
Alexander Larsson1f206b42013-05-22 14:41:36 +0200178 /* Convert from global to output coord */
179 region_global_to_output(output, &final_region);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300180
Alexander Larsson1f206b42013-05-22 14:41:36 +0200181 /* And clip to it */
182 pixman_image_set_clip_region32 (po->shadow_image, &final_region);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200183
Alexander Larsson1f206b42013-05-22 14:41:36 +0200184 /* Set up the source transformation based on the surface
Alexander Larsson4ea95522013-05-22 14:41:37 +0200185 position, the output position/transform/scale and the client
186 specified buffer transform/scale */
Alexander Larsson1f206b42013-05-22 14:41:36 +0200187 pixman_transform_init_identity(&transform);
Alexander Larsson4ea95522013-05-22 14:41:37 +0200188 pixman_transform_scale(&transform, NULL,
Hardeningff39efa2013-09-18 23:56:35 +0200189 pixman_double_to_fixed ((double)1.0/output->current_scale),
190 pixman_double_to_fixed ((double)1.0/output->current_scale));
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200191
Alexander Larsson1f206b42013-05-22 14:41:36 +0200192 fw = pixman_int_to_fixed(output->width);
193 fh = pixman_int_to_fixed(output->height);
194 switch (output->transform) {
195 default:
196 case WL_OUTPUT_TRANSFORM_NORMAL:
197 case WL_OUTPUT_TRANSFORM_FLIPPED:
198 break;
199 case WL_OUTPUT_TRANSFORM_90:
200 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
201 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
202 pixman_transform_translate(&transform, NULL, 0, fh);
203 break;
204 case WL_OUTPUT_TRANSFORM_180:
205 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
206 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
207 pixman_transform_translate(&transform, NULL, fw, fh);
208 break;
209 case WL_OUTPUT_TRANSFORM_270:
210 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
211 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
212 pixman_transform_translate(&transform, NULL, fw, 0);
213 break;
214 }
215
216 switch (output->transform) {
217 case WL_OUTPUT_TRANSFORM_FLIPPED:
218 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
219 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
220 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
221 pixman_transform_scale(&transform, NULL,
222 pixman_int_to_fixed (-1),
223 pixman_int_to_fixed (1));
224 pixman_transform_translate(&transform, NULL, fw, 0);
225 break;
226 }
227
228 pixman_transform_translate(&transform, NULL,
229 pixman_double_to_fixed (output->x),
230 pixman_double_to_fixed (output->y));
231
Jason Ekstranda7af7042013-10-12 22:38:11 -0500232 if (ev->transform.enabled) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200233 /* Pixman supports only 2D transform matrix, but Weston uses 3D,
234 * so we're omitting Z coordinate here
235 */
236 pixman_transform_t surface_transform = {{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500237 { D2F(ev->transform.matrix.d[0]),
238 D2F(ev->transform.matrix.d[4]),
239 D2F(ev->transform.matrix.d[12]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200240 },
Jason Ekstranda7af7042013-10-12 22:38:11 -0500241 { D2F(ev->transform.matrix.d[1]),
242 D2F(ev->transform.matrix.d[5]),
243 D2F(ev->transform.matrix.d[13]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200244 },
Jason Ekstranda7af7042013-10-12 22:38:11 -0500245 { D2F(ev->transform.matrix.d[3]),
246 D2F(ev->transform.matrix.d[7]),
247 D2F(ev->transform.matrix.d[15]),
Alexander Larsson1f206b42013-05-22 14:41:36 +0200248 }
249 }};
250
251 pixman_transform_invert(&surface_transform, &surface_transform);
252 pixman_transform_multiply (&transform, &surface_transform, &transform);
253 } else {
254 pixman_transform_translate(&transform, NULL,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500255 pixman_double_to_fixed ((double)-ev->geometry.x),
256 pixman_double_to_fixed ((double)-ev->geometry.y));
Alexander Larsson1f206b42013-05-22 14:41:36 +0200257 }
258
259
Jason Ekstranda7af7042013-10-12 22:38:11 -0500260 fw = pixman_int_to_fixed(ev->geometry.width);
261 fh = pixman_int_to_fixed(ev->geometry.height);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200262
Jason Ekstranda7af7042013-10-12 22:38:11 -0500263 switch (ev->surface->buffer_transform) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200264 case WL_OUTPUT_TRANSFORM_FLIPPED:
265 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
266 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
267 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
268 pixman_transform_scale(&transform, NULL,
269 pixman_int_to_fixed (-1),
270 pixman_int_to_fixed (1));
271 pixman_transform_translate(&transform, NULL, fw, 0);
272 break;
273 }
274
Jason Ekstranda7af7042013-10-12 22:38:11 -0500275 switch (ev->surface->buffer_transform) {
Alexander Larsson1f206b42013-05-22 14:41:36 +0200276 default:
277 case WL_OUTPUT_TRANSFORM_NORMAL:
278 case WL_OUTPUT_TRANSFORM_FLIPPED:
279 break;
280 case WL_OUTPUT_TRANSFORM_90:
281 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
282 pixman_transform_rotate(&transform, NULL, 0, pixman_fixed_1);
283 pixman_transform_translate(&transform, NULL, fh, 0);
284 break;
285 case WL_OUTPUT_TRANSFORM_180:
286 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
287 pixman_transform_rotate(&transform, NULL, -pixman_fixed_1, 0);
288 pixman_transform_translate(&transform, NULL, fw, fh);
289 break;
290 case WL_OUTPUT_TRANSFORM_270:
291 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
292 pixman_transform_rotate(&transform, NULL, 0, -pixman_fixed_1);
293 pixman_transform_translate(&transform, NULL, 0, fw);
294 break;
295 }
296
Alexander Larsson4ea95522013-05-22 14:41:37 +0200297 pixman_transform_scale(&transform, NULL,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500298 pixman_double_to_fixed ((double)ev->surface->buffer_scale),
299 pixman_double_to_fixed ((double)ev->surface->buffer_scale));
Alexander Larsson4ea95522013-05-22 14:41:37 +0200300
Alexander Larsson1f206b42013-05-22 14:41:36 +0200301 pixman_image_set_transform(ps->image, &transform);
302
Jason Ekstranda7af7042013-10-12 22:38:11 -0500303 if (ev->transform.enabled || output->current_scale != ev->surface->buffer_scale)
Alexander Larsson1f206b42013-05-22 14:41:36 +0200304 pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
305 else
306 pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);
307
Neil Robertse5051712013-11-13 15:44:06 +0000308 if (ps->buffer_ref.buffer)
309 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
310
Alexander Larsson1f206b42013-05-22 14:41:36 +0200311 pixman_image_composite32(pixman_op,
312 ps->image, /* src */
313 NULL /* mask */,
314 po->shadow_image, /* dest */
315 0, 0, /* src_x, src_y */
316 0, 0, /* mask_x, mask_y */
317 0, 0, /* dest_x, dest_y */
318 pixman_image_get_width (po->shadow_image), /* width */
319 pixman_image_get_height (po->shadow_image) /* height */);
320
Neil Robertse5051712013-11-13 15:44:06 +0000321 if (ps->buffer_ref.buffer)
322 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
323
Alexander Larsson1f206b42013-05-22 14:41:36 +0200324 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200325 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200326 pr->debug_color, /* src */
327 NULL /* mask */,
328 po->shadow_image, /* dest */
329 0, 0, /* src_x, src_y */
330 0, 0, /* mask_x, mask_y */
331 0, 0, /* dest_x, dest_y */
332 pixman_image_get_width (po->shadow_image), /* width */
333 pixman_image_get_height (po->shadow_image) /* height */);
334
335 pixman_image_set_clip_region32 (po->shadow_image, NULL);
336
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300337 pixman_region32_fini(&final_region);
338}
339
340static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500341draw_view(struct weston_view *ev, struct weston_output *output,
342 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300343{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500344 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300345 /* repaint bounding region in global coordinates: */
346 pixman_region32_t repaint;
347 /* non-opaque region in surface coordinates: */
348 pixman_region32_t surface_blend;
349
350 /* No buffer attached */
351 if (!ps->image)
352 return;
353
354 pixman_region32_init(&repaint);
355 pixman_region32_intersect(&repaint,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500356 &ev->transform.boundingbox, damage);
357 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300358
359 if (!pixman_region32_not_empty(&repaint))
360 goto out;
361
362 if (output->zoom.active) {
363 weston_log("pixman renderer does not support zoom\n");
364 goto out;
365 }
366
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300367 /* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
Jason Ekstranda7af7042013-10-12 22:38:11 -0500368 if (ev->transform.enabled &&
369 ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE) {
370 repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300371 } else {
372 /* blended region is whole surface minus opaque region: */
373 pixman_region32_init_rect(&surface_blend, 0, 0,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500374 ev->geometry.width, ev->geometry.height);
375 pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300376
Jason Ekstranda7af7042013-10-12 22:38:11 -0500377 if (pixman_region32_not_empty(&ev->surface->opaque)) {
378 repaint_region(ev, output, &repaint, &ev->surface->opaque, PIXMAN_OP_SRC);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300379 }
380
381 if (pixman_region32_not_empty(&surface_blend)) {
Jason Ekstranda7af7042013-10-12 22:38:11 -0500382 repaint_region(ev, output, &repaint, &surface_blend, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300383 }
384 pixman_region32_fini(&surface_blend);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300385 }
386
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300387
388out:
389 pixman_region32_fini(&repaint);
390}
391static void
392repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
393{
394 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500395 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300396
Jason Ekstranda7af7042013-10-12 22:38:11 -0500397 wl_list_for_each_reverse(view, &compositor->view_list, link)
398 if (view->plane == &compositor->primary_plane)
399 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300400}
401
402static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200403copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
404{
405 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200406 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200407
Alexander Larsson1f206b42013-05-22 14:41:36 +0200408 pixman_region32_init(&output_region);
409 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200410
Alexander Larsson1f206b42013-05-22 14:41:36 +0200411 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200412
Alexander Larsson1f206b42013-05-22 14:41:36 +0200413 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200414
Alexander Larsson1f206b42013-05-22 14:41:36 +0200415 pixman_image_composite32(PIXMAN_OP_SRC,
416 po->shadow_image, /* src */
417 NULL /* mask */,
418 po->hw_buffer, /* dest */
419 0, 0, /* src_x, src_y */
420 0, 0, /* mask_x, mask_y */
421 0, 0, /* dest_x, dest_y */
422 pixman_image_get_width (po->hw_buffer), /* width */
423 pixman_image_get_height (po->hw_buffer) /* height */);
424
425 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200426}
427
428static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300429pixman_renderer_repaint_output(struct weston_output *output,
430 pixman_region32_t *output_damage)
431{
432 struct pixman_output_state *po = get_output_state(output);
433
434 if (!po->hw_buffer)
435 return;
436
437 repaint_surfaces(output, output_damage);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200438 copy_to_hw_buffer(output, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300439
440 pixman_region32_copy(&output->previous_damage, output_damage);
441 wl_signal_emit(&output->frame_signal, output);
442
443 /* Actual flip should be done by caller */
444}
445
446static void
447pixman_renderer_flush_damage(struct weston_surface *surface)
448{
449 /* No-op for pixman renderer */
450}
451
452static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500453pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300454{
455 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500456 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300457 pixman_format_code_t pixman_format;
458
459 weston_buffer_reference(&ps->buffer_ref, buffer);
460
461 if (ps->image) {
462 pixman_image_unref(ps->image);
463 ps->image = NULL;
464 }
465
466 if (!buffer)
467 return;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500468
469 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300470
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500471 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300472 weston_log("Pixman renderer supports only SHM buffers\n");
473 weston_buffer_reference(&ps->buffer_ref, NULL);
474 return;
475 }
476
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500477 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300478 case WL_SHM_FORMAT_XRGB8888:
479 pixman_format = PIXMAN_x8r8g8b8;
480 break;
481 case WL_SHM_FORMAT_ARGB8888:
482 pixman_format = PIXMAN_a8r8g8b8;
483 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200484 case WL_SHM_FORMAT_RGB565:
485 pixman_format = PIXMAN_r5g6b5;
486 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300487 default:
488 weston_log("Unsupported SHM buffer format\n");
489 weston_buffer_reference(&ps->buffer_ref, NULL);
490 return;
491 break;
492 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500493
494 buffer->shm_buffer = shm_buffer;
495 buffer->width = wl_shm_buffer_get_width(shm_buffer);
496 buffer->height = wl_shm_buffer_get_height(shm_buffer);
497
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300498 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500499 buffer->width, buffer->height,
500 wl_shm_buffer_get_data(shm_buffer),
501 wl_shm_buffer_get_stride(shm_buffer));
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300502}
503
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300504static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300505pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300506{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300507 wl_list_remove(&ps->surface_destroy_listener.link);
508 wl_list_remove(&ps->renderer_destroy_listener.link);
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300509
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300510
511 ps->surface->renderer_state = NULL;
512
513 if (ps->image) {
514 pixman_image_unref(ps->image);
515 ps->image = NULL;
516 }
517 weston_buffer_reference(&ps->buffer_ref, NULL);
518 free(ps);
519}
520
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300521static void
522surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
523{
524 struct pixman_surface_state *ps;
525
526 ps = container_of(listener, struct pixman_surface_state,
527 surface_destroy_listener);
528
529 pixman_renderer_surface_state_destroy(ps);
530}
531
532static void
533surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
534{
535 struct pixman_surface_state *ps;
536
537 ps = container_of(listener, struct pixman_surface_state,
538 renderer_destroy_listener);
539
540 pixman_renderer_surface_state_destroy(ps);
541}
542
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300543static int
544pixman_renderer_create_surface(struct weston_surface *surface)
545{
546 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300547 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300548
549 ps = calloc(1, sizeof *ps);
550 if (!ps)
551 return -1;
552
553 surface->renderer_state = ps;
554
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300555 ps->surface = surface;
556
557 ps->surface_destroy_listener.notify =
558 surface_state_handle_surface_destroy;
559 wl_signal_add(&surface->destroy_signal,
560 &ps->surface_destroy_listener);
561
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300562 ps->renderer_destroy_listener.notify =
563 surface_state_handle_renderer_destroy;
564 wl_signal_add(&pr->destroy_signal,
565 &ps->renderer_destroy_listener);
566
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300567 return 0;
568}
569
570static void
571pixman_renderer_surface_set_color(struct weston_surface *es,
572 float red, float green, float blue, float alpha)
573{
574 struct pixman_surface_state *ps = get_surface_state(es);
575 pixman_color_t color;
576
577 color.red = red * 0xffff;
578 color.green = green * 0xffff;
579 color.blue = blue * 0xffff;
580 color.alpha = alpha * 0xffff;
581
582 if (ps->image) {
583 pixman_image_unref(ps->image);
584 ps->image = NULL;
585 }
586
587 ps->image = pixman_image_create_solid_fill(&color);
588}
589
590static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300591pixman_renderer_destroy(struct weston_compositor *ec)
592{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300593 struct pixman_renderer *pr = get_renderer(ec);
594
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300595 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300596 weston_binding_destroy(pr->debug_binding);
597 free(pr);
598
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300599 ec->renderer = NULL;
600}
601
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200602static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400603debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200604 void *data)
605{
606 struct weston_compositor *ec = data;
607 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
608
609 pr->repaint_debug ^= 1;
610
611 if (pr->repaint_debug) {
612 pixman_color_t red = {
613 0x3fff, 0x0000, 0x0000, 0x3fff
614 };
615
616 pr->debug_color = pixman_image_create_solid_fill(&red);
617 } else {
618 pixman_image_unref(pr->debug_color);
619 weston_compositor_damage_all(ec);
620 }
621}
622
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300623WL_EXPORT int
624pixman_renderer_init(struct weston_compositor *ec)
625{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200626 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300627
Ander Conselvan de Oliveirac68b1082013-10-25 16:26:31 +0300628 renderer = calloc(1, sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300629 if (renderer == NULL)
630 return -1;
631
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100632 renderer->repaint_debug = 0;
633 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200634 renderer->base.read_pixels = pixman_renderer_read_pixels;
635 renderer->base.repaint_output = pixman_renderer_repaint_output;
636 renderer->base.flush_damage = pixman_renderer_flush_damage;
637 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200638 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200639 renderer->base.destroy = pixman_renderer_destroy;
640 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300641 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300642 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300643
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300644 renderer->debug_binding =
645 weston_compositor_add_debug_binding(ec, KEY_R,
646 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200647
648 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
649
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300650 wl_signal_init(&renderer->destroy_signal);
651
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300652 return 0;
653}
654
655WL_EXPORT void
656pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
657{
658 struct pixman_output_state *po = get_output_state(output);
659
660 if (po->hw_buffer)
661 pixman_image_unref(po->hw_buffer);
662 po->hw_buffer = buffer;
663
664 if (po->hw_buffer) {
665 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
666 pixman_image_ref(po->hw_buffer);
667 }
668}
669
670WL_EXPORT int
671pixman_renderer_output_create(struct weston_output *output)
672{
673 struct pixman_output_state *po = calloc(1, sizeof *po);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200674 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300675
676 if (!po)
677 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200678
679 /* set shadow image transformation */
Hardeningff39efa2013-09-18 23:56:35 +0200680 w = output->current_mode->width;
681 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200682
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200683 po->shadow_buffer = malloc(w * h * 4);
684
685 if (!po->shadow_buffer) {
686 free(po);
687 return -1;
688 }
689
690 po->shadow_image =
691 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
692 po->shadow_buffer, w * 4);
693
694 if (!po->shadow_image) {
695 free(po->shadow_buffer);
696 free(po);
697 return -1;
698 }
699
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300700 output->renderer_state = po;
701
702 return 0;
703}
704
705WL_EXPORT void
706pixman_renderer_output_destroy(struct weston_output *output)
707{
708 struct pixman_output_state *po = get_output_state(output);
709
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200710 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200711
712 if (po->hw_buffer)
713 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200714
715 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300716 po->hw_buffer = NULL;
717
718 free(po);
719}