blob: 692bbdeed0fffd3b568c46680d3f9e0634981bb7 [file] [log] [blame]
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +03001/*
2 * Copyright © 2012 Intel Corporation
3 * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
Pekka Paalanen6764bbe2015-02-11 12:29:56 +02004 * Copyright © 2015 Collabora, Ltd.
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +03005 *
6 * Permission to use, copy, modify, distribute, and sell this software and
7 * its documentation for any purpose is hereby granted without fee, provided
8 * that the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of the copyright holders not be used in
11 * advertising or publicity pertaining to distribution of the software
12 * without specific, written prior permission. The copyright holders make
13 * no representations about the suitability of this software for any
14 * purpose. It is provided "as is" without express or implied warranty.
15 *
16 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
20 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
21 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 */
24
Daniel Stonec228e232013-05-22 18:03:19 +030025#include "config.h"
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030026
27#include <errno.h>
28#include <stdlib.h>
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +020029#include <assert.h>
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030030
31#include "pixman-renderer.h"
32
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020033#include <linux/input.h>
34
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030035struct pixman_output_state {
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +020036 void *shadow_buffer;
37 pixman_image_t *shadow_image;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030038 pixman_image_t *hw_buffer;
39};
40
41struct pixman_surface_state {
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030042 struct weston_surface *surface;
43
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030044 pixman_image_t *image;
45 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030046
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +010047 struct wl_listener buffer_destroy_listener;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030048 struct wl_listener surface_destroy_listener;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030049 struct wl_listener renderer_destroy_listener;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030050};
51
52struct pixman_renderer {
53 struct weston_renderer base;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030054
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020055 int repaint_debug;
56 pixman_image_t *debug_color;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030057 struct weston_binding *debug_binding;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030058
59 struct wl_signal destroy_signal;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030060};
61
62static inline struct pixman_output_state *
63get_output_state(struct weston_output *output)
64{
65 return (struct pixman_output_state *)output->renderer_state;
66}
67
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030068static int
69pixman_renderer_create_surface(struct weston_surface *surface);
70
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030071static inline struct pixman_surface_state *
72get_surface_state(struct weston_surface *surface)
73{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030074 if (!surface->renderer_state)
75 pixman_renderer_create_surface(surface);
76
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030077 return (struct pixman_surface_state *)surface->renderer_state;
78}
79
80static inline struct pixman_renderer *
81get_renderer(struct weston_compositor *ec)
82{
83 return (struct pixman_renderer *)ec->renderer;
84}
85
86static int
87pixman_renderer_read_pixels(struct weston_output *output,
88 pixman_format_code_t format, void *pixels,
89 uint32_t x, uint32_t y,
90 uint32_t width, uint32_t height)
91{
92 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson97af7922013-05-29 12:01:33 +020093 pixman_transform_t transform;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030094 pixman_image_t *out_buf;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030095
96 if (!po->hw_buffer) {
97 errno = ENODEV;
98 return -1;
99 }
100
101 out_buf = pixman_image_create_bits(format,
102 width,
103 height,
104 pixels,
105 (PIXMAN_FORMAT_BPP(format) / 8) * width);
106
Alexander Larsson97af7922013-05-29 12:01:33 +0200107 /* Caller expects vflipped source image */
108 pixman_transform_init_translate(&transform,
109 pixman_int_to_fixed (x),
110 pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
111 pixman_transform_scale(&transform, NULL,
112 pixman_fixed_1,
113 pixman_fixed_minus_1);
114 pixman_image_set_transform(po->hw_buffer, &transform);
115
116 pixman_image_composite32(PIXMAN_OP_SRC,
117 po->hw_buffer, /* src */
118 NULL /* mask */,
119 out_buf, /* dest */
120 0, 0, /* src_x, src_y */
121 0, 0, /* mask_x, mask_y */
122 0, 0, /* dest_x, dest_y */
123 pixman_image_get_width (po->hw_buffer), /* width */
124 pixman_image_get_height (po->hw_buffer) /* height */);
125 pixman_image_set_transform(po->hw_buffer, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300126
127 pixman_image_unref(out_buf);
128
129 return 0;
130}
131
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300132static void
Alexander Larsson1f206b42013-05-22 14:41:36 +0200133region_global_to_output(struct weston_output *output, pixman_region32_t *region)
134{
135 pixman_region32_translate(region, -output->x, -output->y);
Jason Ekstrand33ff6362013-10-27 22:25:01 -0500136 weston_transformed_region(output->width, output->height,
137 output->transform, output->current_scale,
138 region, region);
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300139}
140
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300141#define D2F(v) pixman_double_to_fixed((double)v)
142
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300143static void
Jason Ekstrand8870a232014-05-20 15:53:19 -0500144weston_matrix_to_pixman_transform(pixman_transform_t *pt,
145 const struct weston_matrix *wm)
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200146{
Jason Ekstrand8870a232014-05-20 15:53:19 -0500147 /* Pixman supports only 2D transform matrix, but Weston uses 3D, *
148 * so we're omitting Z coordinate here. */
149 pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
150 pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
151 pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
152 pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
153 pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
154 pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
155 pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
156 pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
157 pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200158}
159
160static void
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200161pixman_renderer_compute_transform(pixman_transform_t *transform_out,
162 struct weston_view *ev,
163 struct weston_output *output)
164{
165 struct weston_matrix matrix;
166
167 /* Set up the source transformation based on the surface
168 position, the output position/transform/scale and the client
169 specified buffer transform/scale */
170 weston_matrix_invert(&matrix, &output->matrix);
171
172 if (ev->transform.enabled) {
173 weston_matrix_multiply(&matrix, &ev->transform.inverse);
174 } else {
175 weston_matrix_translate(&matrix,
176 -ev->geometry.x, -ev->geometry.y, 0);
177 }
178
179 weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
180
181 weston_matrix_to_pixman_transform(transform_out, &matrix);
182}
183
Pekka Paalanen23d4af52015-03-04 16:18:26 +0200184static bool
185view_transformation_is_translation(struct weston_view *view)
186{
187 if (!view->transform.enabled)
188 return true;
189
190 if (view->transform.matrix.type <= WESTON_MATRIX_TRANSFORM_TRANSLATE)
191 return true;
192
193 return false;
194}
195
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200196static void
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200197region_intersect_only_translation(pixman_region32_t *result_global,
198 pixman_region32_t *global,
199 pixman_region32_t *surf,
200 struct weston_view *view)
201{
202 float view_x, view_y;
203
204 assert(view_transformation_is_translation(view));
205
206 /* Convert from surface to global coordinates */
207 pixman_region32_copy(result_global, surf);
208 weston_view_to_global_float(view, 0, 0, &view_x, &view_y);
209 pixman_region32_translate(result_global, (int)view_x, (int)view_y);
210
211 pixman_region32_intersect(result_global, result_global, global);
212}
213
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200214/** Paint an intersected region
215 *
216 * \param ev The view to be painted.
217 * \param output The output being painted.
218 * \param repaint_output The region to be painted in output coordinates.
219 * \param pixman_op Compositing operator, either SRC or OVER.
220 */
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200221static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500222repaint_region(struct weston_view *ev, struct weston_output *output,
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200223 pixman_region32_t *repaint_output,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200224 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300225{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200226 struct pixman_renderer *pr =
227 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500228 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300229 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200230 struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200231 pixman_transform_t transform;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200232 pixman_image_t *mask_image;
233 pixman_color_t mask = { 0, };
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300234
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200235 /* Clip rendering to the damaged output region */
236 pixman_image_set_clip_region32(po->shadow_image, repaint_output);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200237
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200238 pixman_renderer_compute_transform(&transform, ev, output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200239 pixman_image_set_transform(ps->image, &transform);
240
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200241 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
Alexander Larsson1f206b42013-05-22 14:41:36 +0200242 pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
243 else
244 pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);
245
Neil Robertse5051712013-11-13 15:44:06 +0000246 if (ps->buffer_ref.buffer)
247 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
248
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200249 if (ev->alpha < 1.0) {
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200250 mask.alpha = 0xffff * ev->alpha;
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200251 mask_image = pixman_image_create_solid_fill(&mask);
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200252 } else {
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200253 mask_image = NULL;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200254 }
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200255
Alexander Larsson1f206b42013-05-22 14:41:36 +0200256 pixman_image_composite32(pixman_op,
257 ps->image, /* src */
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200258 mask_image, /* mask */
Alexander Larsson1f206b42013-05-22 14:41:36 +0200259 po->shadow_image, /* dest */
260 0, 0, /* src_x, src_y */
261 0, 0, /* mask_x, mask_y */
262 0, 0, /* dest_x, dest_y */
263 pixman_image_get_width (po->shadow_image), /* width */
264 pixman_image_get_height (po->shadow_image) /* height */);
265
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200266 if (mask_image)
267 pixman_image_unref(mask_image);
268
Neil Robertse5051712013-11-13 15:44:06 +0000269 if (ps->buffer_ref.buffer)
270 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
271
Alexander Larsson1f206b42013-05-22 14:41:36 +0200272 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200273 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200274 pr->debug_color, /* src */
275 NULL /* mask */,
276 po->shadow_image, /* dest */
277 0, 0, /* src_x, src_y */
278 0, 0, /* mask_x, mask_y */
279 0, 0, /* dest_x, dest_y */
280 pixman_image_get_width (po->shadow_image), /* width */
281 pixman_image_get_height (po->shadow_image) /* height */);
282
283 pixman_image_set_clip_region32 (po->shadow_image, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300284}
285
286static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500287draw_view(struct weston_view *ev, struct weston_output *output,
288 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300289{
Derek Foreman66951b72014-09-01 10:33:28 -0500290 static int zoom_logged = 0;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500291 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300292 /* repaint bounding region in global coordinates: */
293 pixman_region32_t repaint;
294 /* non-opaque region in surface coordinates: */
295 pixman_region32_t surface_blend;
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200296 pixman_region32_t repaint_output;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300297
298 /* No buffer attached */
299 if (!ps->image)
300 return;
301
302 pixman_region32_init(&repaint);
303 pixman_region32_intersect(&repaint,
Pekka Paalanen25c0ca52015-02-19 11:15:33 +0200304 &ev->transform.boundingbox, damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500305 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300306
307 if (!pixman_region32_not_empty(&repaint))
308 goto out;
309
Derek Foreman66951b72014-09-01 10:33:28 -0500310 if (output->zoom.active && !zoom_logged) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300311 weston_log("pixman renderer does not support zoom\n");
Derek Foreman66951b72014-09-01 10:33:28 -0500312 zoom_logged = 1;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300313 }
314
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300315 /* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
Pekka Paalanen23d4af52015-03-04 16:18:26 +0200316 if (ev->alpha != 1.0 || !view_transformation_is_translation(ev)) {
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200317 region_global_to_output(output, &repaint);
318 repaint_region(ev, output, &repaint, PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300319 } else {
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200320 pixman_region32_init(&repaint_output);
321
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300322 /* blended region is whole surface minus opaque region: */
323 pixman_region32_init_rect(&surface_blend, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600324 ev->surface->width, ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500325 pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300326
Jason Ekstranda7af7042013-10-12 22:38:11 -0500327 if (pixman_region32_not_empty(&ev->surface->opaque)) {
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200328 region_intersect_only_translation(&repaint_output,
329 &repaint,
330 &ev->surface->opaque,
331 ev);
332 region_global_to_output(output, &repaint_output);
333 repaint_region(ev, output, &repaint_output,
334 PIXMAN_OP_SRC);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300335 }
336
337 if (pixman_region32_not_empty(&surface_blend)) {
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200338 region_intersect_only_translation(&repaint_output,
339 &repaint,
340 &surface_blend,
341 ev);
342 region_global_to_output(output, &repaint_output);
343 repaint_region(ev, output, &repaint_output,
344 PIXMAN_OP_OVER);
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300345 }
346 pixman_region32_fini(&surface_blend);
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200347 pixman_region32_fini(&repaint_output);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300348 }
349
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300350
351out:
352 pixman_region32_fini(&repaint);
353}
354static void
355repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
356{
357 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500358 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300359
Jason Ekstranda7af7042013-10-12 22:38:11 -0500360 wl_list_for_each_reverse(view, &compositor->view_list, link)
361 if (view->plane == &compositor->primary_plane)
362 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300363}
364
365static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200366copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
367{
368 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200369 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200370
Alexander Larsson1f206b42013-05-22 14:41:36 +0200371 pixman_region32_init(&output_region);
372 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200373
Alexander Larsson1f206b42013-05-22 14:41:36 +0200374 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200375
Alexander Larsson1f206b42013-05-22 14:41:36 +0200376 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ryo Munakata389d2052014-09-04 01:56:53 +0900377 pixman_region32_fini(&output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200378
Alexander Larsson1f206b42013-05-22 14:41:36 +0200379 pixman_image_composite32(PIXMAN_OP_SRC,
380 po->shadow_image, /* src */
381 NULL /* mask */,
382 po->hw_buffer, /* dest */
383 0, 0, /* src_x, src_y */
384 0, 0, /* mask_x, mask_y */
385 0, 0, /* dest_x, dest_y */
386 pixman_image_get_width (po->hw_buffer), /* width */
387 pixman_image_get_height (po->hw_buffer) /* height */);
388
389 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200390}
391
392static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300393pixman_renderer_repaint_output(struct weston_output *output,
394 pixman_region32_t *output_damage)
395{
396 struct pixman_output_state *po = get_output_state(output);
397
398 if (!po->hw_buffer)
399 return;
400
401 repaint_surfaces(output, output_damage);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200402 copy_to_hw_buffer(output, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300403
404 pixman_region32_copy(&output->previous_damage, output_damage);
405 wl_signal_emit(&output->frame_signal, output);
406
407 /* Actual flip should be done by caller */
408}
409
410static void
411pixman_renderer_flush_damage(struct weston_surface *surface)
412{
413 /* No-op for pixman renderer */
414}
415
416static void
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100417buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
418{
419 struct pixman_surface_state *ps;
420
421 ps = container_of(listener, struct pixman_surface_state,
422 buffer_destroy_listener);
423
424 if (ps->image) {
425 pixman_image_unref(ps->image);
426 ps->image = NULL;
427 }
428
429 ps->buffer_destroy_listener.notify = NULL;
430}
431
432static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500433pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300434{
435 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500436 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300437 pixman_format_code_t pixman_format;
438
439 weston_buffer_reference(&ps->buffer_ref, buffer);
440
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100441 if (ps->buffer_destroy_listener.notify) {
442 wl_list_remove(&ps->buffer_destroy_listener.link);
443 ps->buffer_destroy_listener.notify = NULL;
444 }
445
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300446 if (ps->image) {
447 pixman_image_unref(ps->image);
448 ps->image = NULL;
449 }
450
451 if (!buffer)
452 return;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500453
454 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300455
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500456 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300457 weston_log("Pixman renderer supports only SHM buffers\n");
458 weston_buffer_reference(&ps->buffer_ref, NULL);
459 return;
460 }
461
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500462 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300463 case WL_SHM_FORMAT_XRGB8888:
464 pixman_format = PIXMAN_x8r8g8b8;
465 break;
466 case WL_SHM_FORMAT_ARGB8888:
467 pixman_format = PIXMAN_a8r8g8b8;
468 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200469 case WL_SHM_FORMAT_RGB565:
470 pixman_format = PIXMAN_r5g6b5;
471 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300472 default:
473 weston_log("Unsupported SHM buffer format\n");
474 weston_buffer_reference(&ps->buffer_ref, NULL);
475 return;
476 break;
477 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500478
479 buffer->shm_buffer = shm_buffer;
480 buffer->width = wl_shm_buffer_get_width(shm_buffer);
481 buffer->height = wl_shm_buffer_get_height(shm_buffer);
482
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300483 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500484 buffer->width, buffer->height,
485 wl_shm_buffer_get_data(shm_buffer),
486 wl_shm_buffer_get_stride(shm_buffer));
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100487
488 ps->buffer_destroy_listener.notify =
489 buffer_state_handle_buffer_destroy;
490 wl_signal_add(&buffer->destroy_signal,
491 &ps->buffer_destroy_listener);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300492}
493
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300494static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300495pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300496{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300497 wl_list_remove(&ps->surface_destroy_listener.link);
498 wl_list_remove(&ps->renderer_destroy_listener.link);
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100499 if (ps->buffer_destroy_listener.notify) {
500 wl_list_remove(&ps->buffer_destroy_listener.link);
501 ps->buffer_destroy_listener.notify = NULL;
502 }
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300503
504 ps->surface->renderer_state = NULL;
505
506 if (ps->image) {
507 pixman_image_unref(ps->image);
508 ps->image = NULL;
509 }
510 weston_buffer_reference(&ps->buffer_ref, NULL);
511 free(ps);
512}
513
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300514static void
515surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
516{
517 struct pixman_surface_state *ps;
518
519 ps = container_of(listener, struct pixman_surface_state,
520 surface_destroy_listener);
521
522 pixman_renderer_surface_state_destroy(ps);
523}
524
525static void
526surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
527{
528 struct pixman_surface_state *ps;
529
530 ps = container_of(listener, struct pixman_surface_state,
531 renderer_destroy_listener);
532
533 pixman_renderer_surface_state_destroy(ps);
534}
535
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300536static int
537pixman_renderer_create_surface(struct weston_surface *surface)
538{
539 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300540 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300541
Bryce Harringtonde16d892014-11-20 22:21:57 -0800542 ps = zalloc(sizeof *ps);
543 if (ps == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300544 return -1;
545
546 surface->renderer_state = ps;
547
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300548 ps->surface = surface;
549
550 ps->surface_destroy_listener.notify =
551 surface_state_handle_surface_destroy;
552 wl_signal_add(&surface->destroy_signal,
553 &ps->surface_destroy_listener);
554
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300555 ps->renderer_destroy_listener.notify =
556 surface_state_handle_renderer_destroy;
557 wl_signal_add(&pr->destroy_signal,
558 &ps->renderer_destroy_listener);
559
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300560 return 0;
561}
562
563static void
564pixman_renderer_surface_set_color(struct weston_surface *es,
565 float red, float green, float blue, float alpha)
566{
567 struct pixman_surface_state *ps = get_surface_state(es);
568 pixman_color_t color;
569
570 color.red = red * 0xffff;
571 color.green = green * 0xffff;
572 color.blue = blue * 0xffff;
573 color.alpha = alpha * 0xffff;
574
575 if (ps->image) {
576 pixman_image_unref(ps->image);
577 ps->image = NULL;
578 }
579
580 ps->image = pixman_image_create_solid_fill(&color);
581}
582
583static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300584pixman_renderer_destroy(struct weston_compositor *ec)
585{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300586 struct pixman_renderer *pr = get_renderer(ec);
587
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300588 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300589 weston_binding_destroy(pr->debug_binding);
590 free(pr);
591
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300592 ec->renderer = NULL;
593}
594
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200595static void
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200596pixman_renderer_surface_get_content_size(struct weston_surface *surface,
597 int *width, int *height)
598{
599 struct pixman_surface_state *ps = get_surface_state(surface);
600
601 if (ps->image) {
602 *width = pixman_image_get_width(ps->image);
603 *height = pixman_image_get_height(ps->image);
604 } else {
605 *width = 0;
606 *height = 0;
607 }
608}
609
610static int
611pixman_renderer_surface_copy_content(struct weston_surface *surface,
612 void *target, size_t size,
613 int src_x, int src_y,
614 int width, int height)
615{
616 const pixman_format_code_t format = PIXMAN_a8b8g8r8;
617 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
618 struct pixman_surface_state *ps = get_surface_state(surface);
619 pixman_image_t *out_buf;
620
621 if (!ps->image)
622 return -1;
623
624 out_buf = pixman_image_create_bits(format, width, height,
625 target, width * bytespp);
626
627 pixman_image_set_transform(ps->image, NULL);
628 pixman_image_composite32(PIXMAN_OP_SRC,
629 ps->image, /* src */
630 NULL, /* mask */
631 out_buf, /* dest */
632 src_x, src_y, /* src_x, src_y */
633 0, 0, /* mask_x, mask_y */
634 0, 0, /* dest_x, dest_y */
635 width, height);
636
637 pixman_image_unref(out_buf);
638
639 return 0;
640}
641
642static void
Kristian Høgsberge3148752013-05-06 23:19:49 -0400643debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200644 void *data)
645{
646 struct weston_compositor *ec = data;
647 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
648
649 pr->repaint_debug ^= 1;
650
651 if (pr->repaint_debug) {
652 pixman_color_t red = {
653 0x3fff, 0x0000, 0x0000, 0x3fff
654 };
655
656 pr->debug_color = pixman_image_create_solid_fill(&red);
657 } else {
658 pixman_image_unref(pr->debug_color);
659 weston_compositor_damage_all(ec);
660 }
661}
662
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300663WL_EXPORT int
664pixman_renderer_init(struct weston_compositor *ec)
665{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200666 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300667
Bryce Harringtonde16d892014-11-20 22:21:57 -0800668 renderer = zalloc(sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300669 if (renderer == NULL)
670 return -1;
671
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100672 renderer->repaint_debug = 0;
673 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200674 renderer->base.read_pixels = pixman_renderer_read_pixels;
675 renderer->base.repaint_output = pixman_renderer_repaint_output;
676 renderer->base.flush_damage = pixman_renderer_flush_damage;
677 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200678 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200679 renderer->base.destroy = pixman_renderer_destroy;
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200680 renderer->base.surface_get_content_size =
681 pixman_renderer_surface_get_content_size;
682 renderer->base.surface_copy_content =
683 pixman_renderer_surface_copy_content;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200684 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300685 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300686 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300687
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300688 renderer->debug_binding =
689 weston_compositor_add_debug_binding(ec, KEY_R,
690 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200691
692 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
693
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300694 wl_signal_init(&renderer->destroy_signal);
695
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300696 return 0;
697}
698
699WL_EXPORT void
700pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
701{
702 struct pixman_output_state *po = get_output_state(output);
703
704 if (po->hw_buffer)
705 pixman_image_unref(po->hw_buffer);
706 po->hw_buffer = buffer;
707
708 if (po->hw_buffer) {
709 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
710 pixman_image_ref(po->hw_buffer);
711 }
712}
713
714WL_EXPORT int
715pixman_renderer_output_create(struct weston_output *output)
716{
Bryce Harringtonde16d892014-11-20 22:21:57 -0800717 struct pixman_output_state *po;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200718 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300719
Bryce Harringtonde16d892014-11-20 22:21:57 -0800720 po = zalloc(sizeof *po);
721 if (po == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300722 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200723
724 /* set shadow image transformation */
Hardeningff39efa2013-09-18 23:56:35 +0200725 w = output->current_mode->width;
726 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200727
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200728 po->shadow_buffer = malloc(w * h * 4);
729
730 if (!po->shadow_buffer) {
731 free(po);
732 return -1;
733 }
734
735 po->shadow_image =
736 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
737 po->shadow_buffer, w * 4);
738
739 if (!po->shadow_image) {
740 free(po->shadow_buffer);
741 free(po);
742 return -1;
743 }
744
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300745 output->renderer_state = po;
746
747 return 0;
748}
749
750WL_EXPORT void
751pixman_renderer_output_destroy(struct weston_output *output)
752{
753 struct pixman_output_state *po = get_output_state(output);
754
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200755 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200756
757 if (po->hw_buffer)
758 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200759
Arnaud Vrac8e3fe082014-08-25 20:56:52 +0200760 free(po->shadow_buffer);
761
762 po->shadow_buffer = NULL;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200763 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300764 po->hw_buffer = NULL;
765
766 free(po);
767}