blob: 793a33d0734ff077a5f50a942b37333cc3bacd64 [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 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07006 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030013 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070014 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030026 */
27
Daniel Stonec228e232013-05-22 18:03:19 +030028#include "config.h"
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030029
30#include <errno.h>
31#include <stdlib.h>
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +020032#include <assert.h>
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030033
34#include "pixman-renderer.h"
Jon Cruz867d50e2015-06-15 15:37:10 -070035#include "shared/helpers.h"
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030036
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020037#include <linux/input.h>
38
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030039struct pixman_output_state {
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +020040 void *shadow_buffer;
41 pixman_image_t *shadow_image;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030042 pixman_image_t *hw_buffer;
43};
44
45struct pixman_surface_state {
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030046 struct weston_surface *surface;
47
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030048 pixman_image_t *image;
49 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030050
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +010051 struct wl_listener buffer_destroy_listener;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030052 struct wl_listener surface_destroy_listener;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030053 struct wl_listener renderer_destroy_listener;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030054};
55
56struct pixman_renderer {
57 struct weston_renderer base;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030058
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020059 int repaint_debug;
60 pixman_image_t *debug_color;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030061 struct weston_binding *debug_binding;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030062
63 struct wl_signal destroy_signal;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030064};
65
66static inline struct pixman_output_state *
67get_output_state(struct weston_output *output)
68{
69 return (struct pixman_output_state *)output->renderer_state;
70}
71
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030072static int
73pixman_renderer_create_surface(struct weston_surface *surface);
74
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030075static inline struct pixman_surface_state *
76get_surface_state(struct weston_surface *surface)
77{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030078 if (!surface->renderer_state)
79 pixman_renderer_create_surface(surface);
80
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030081 return (struct pixman_surface_state *)surface->renderer_state;
82}
83
84static inline struct pixman_renderer *
85get_renderer(struct weston_compositor *ec)
86{
87 return (struct pixman_renderer *)ec->renderer;
88}
89
90static int
91pixman_renderer_read_pixels(struct weston_output *output,
92 pixman_format_code_t format, void *pixels,
93 uint32_t x, uint32_t y,
94 uint32_t width, uint32_t height)
95{
96 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson97af7922013-05-29 12:01:33 +020097 pixman_transform_t transform;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030098 pixman_image_t *out_buf;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030099
100 if (!po->hw_buffer) {
101 errno = ENODEV;
102 return -1;
103 }
104
105 out_buf = pixman_image_create_bits(format,
106 width,
107 height,
108 pixels,
109 (PIXMAN_FORMAT_BPP(format) / 8) * width);
110
Alexander Larsson97af7922013-05-29 12:01:33 +0200111 /* Caller expects vflipped source image */
112 pixman_transform_init_translate(&transform,
113 pixman_int_to_fixed (x),
114 pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
115 pixman_transform_scale(&transform, NULL,
116 pixman_fixed_1,
117 pixman_fixed_minus_1);
118 pixman_image_set_transform(po->hw_buffer, &transform);
119
120 pixman_image_composite32(PIXMAN_OP_SRC,
121 po->hw_buffer, /* src */
122 NULL /* mask */,
123 out_buf, /* dest */
124 0, 0, /* src_x, src_y */
125 0, 0, /* mask_x, mask_y */
126 0, 0, /* dest_x, dest_y */
127 pixman_image_get_width (po->hw_buffer), /* width */
128 pixman_image_get_height (po->hw_buffer) /* height */);
129 pixman_image_set_transform(po->hw_buffer, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300130
131 pixman_image_unref(out_buf);
132
133 return 0;
134}
135
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600136/*
137 * Warning: This function does not work for projective, affine, or matrices
138 * that encode arbitrary rotations. Only 90-degree step rotations are
139 * supported.
140 *
141 * Luckily it is only used for output matrices, so it is fine here.
142 */
143static void
144weston_matrix_transform_region(pixman_region32_t *dest,
145 struct weston_matrix *matrix,
146 pixman_region32_t *src)
147{
148 pixman_box32_t *src_rects, *dest_rects;
149 int nrects, i;
150
151 src_rects = pixman_region32_rectangles(src, &nrects);
152 dest_rects = malloc(nrects * sizeof(*dest_rects));
153 if (!dest_rects)
154 return;
155
156 for (i = 0; i < nrects; i++) {
157 struct weston_vector vec1 = {{
158 src_rects[i].x1, src_rects[i].y1, 0, 1
159 }};
160 weston_matrix_transform(matrix, &vec1);
161 vec1.f[0] /= vec1.f[3];
162 vec1.f[1] /= vec1.f[3];
163
164 struct weston_vector vec2 = {{
165 src_rects[i].x2, src_rects[i].y2, 0, 1
166 }};
167 weston_matrix_transform(matrix, &vec2);
168 vec2.f[0] /= vec2.f[3];
169 vec2.f[1] /= vec2.f[3];
170
171 if (vec1.f[0] < vec2.f[0]) {
172 dest_rects[i].x1 = floor(vec1.f[0]);
173 dest_rects[i].x2 = ceil(vec2.f[0]);
174 } else {
175 dest_rects[i].x1 = floor(vec2.f[0]);
176 dest_rects[i].x2 = ceil(vec1.f[0]);
177 }
178
179
180 if (vec1.f[1] < vec2.f[1]) {
181 dest_rects[i].y1 = floor(vec1.f[1]);
182 dest_rects[i].y2 = ceil(vec2.f[1]);
183 } else {
184 dest_rects[i].y1 = floor(vec2.f[1]);
185 dest_rects[i].y2 = ceil(vec1.f[1]);
186 }
187 }
188
189 pixman_region32_clear(dest);
190 pixman_region32_init_rects(dest, dest_rects, nrects);
191 free(dest_rects);
192}
193
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300194static void
Alexander Larsson1f206b42013-05-22 14:41:36 +0200195region_global_to_output(struct weston_output *output, pixman_region32_t *region)
196{
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600197 if (output->zoom.active) {
198 weston_matrix_transform_region(region, &output->matrix, region);
199 } else {
200 pixman_region32_translate(region, -output->x, -output->y);
201 weston_transformed_region(output->width, output->height,
202 output->transform,
203 output->current_scale,
204 region, region);
205 }
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300206}
207
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300208#define D2F(v) pixman_double_to_fixed((double)v)
209
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300210static void
Jason Ekstrand8870a232014-05-20 15:53:19 -0500211weston_matrix_to_pixman_transform(pixman_transform_t *pt,
212 const struct weston_matrix *wm)
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200213{
Jason Ekstrand8870a232014-05-20 15:53:19 -0500214 /* Pixman supports only 2D transform matrix, but Weston uses 3D, *
215 * so we're omitting Z coordinate here. */
216 pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
217 pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
218 pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
219 pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
220 pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
221 pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
222 pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
223 pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
224 pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200225}
226
227static void
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200228pixman_renderer_compute_transform(pixman_transform_t *transform_out,
229 struct weston_view *ev,
230 struct weston_output *output)
231{
232 struct weston_matrix matrix;
233
234 /* Set up the source transformation based on the surface
235 position, the output position/transform/scale and the client
236 specified buffer transform/scale */
Derek Foremana5855ad2015-03-24 11:36:16 -0500237 matrix = output->inverse_matrix;
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200238
239 if (ev->transform.enabled) {
240 weston_matrix_multiply(&matrix, &ev->transform.inverse);
241 } else {
242 weston_matrix_translate(&matrix,
243 -ev->geometry.x, -ev->geometry.y, 0);
244 }
245
246 weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
247
248 weston_matrix_to_pixman_transform(transform_out, &matrix);
249}
250
Pekka Paalanen23d4af52015-03-04 16:18:26 +0200251static bool
252view_transformation_is_translation(struct weston_view *view)
253{
254 if (!view->transform.enabled)
255 return true;
256
257 if (view->transform.matrix.type <= WESTON_MATRIX_TRANSFORM_TRANSLATE)
258 return true;
259
260 return false;
261}
262
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200263static void
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200264region_intersect_only_translation(pixman_region32_t *result_global,
265 pixman_region32_t *global,
266 pixman_region32_t *surf,
267 struct weston_view *view)
268{
269 float view_x, view_y;
270
271 assert(view_transformation_is_translation(view));
272
273 /* Convert from surface to global coordinates */
274 pixman_region32_copy(result_global, surf);
275 weston_view_to_global_float(view, 0, 0, &view_x, &view_y);
276 pixman_region32_translate(result_global, (int)view_x, (int)view_y);
277
278 pixman_region32_intersect(result_global, result_global, global);
279}
280
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200281static void
282composite_whole(pixman_op_t op,
283 pixman_image_t *src,
284 pixman_image_t *mask,
285 pixman_image_t *dest,
286 const pixman_transform_t *transform,
287 pixman_filter_t filter)
288{
289 int32_t dest_width;
290 int32_t dest_height;
291
292 dest_width = pixman_image_get_width(dest);
293 dest_height = pixman_image_get_height(dest);
294
295 pixman_image_set_transform(src, transform);
296 pixman_image_set_filter(src, filter, NULL, 0);
297
298 pixman_image_composite32(op, src, mask, dest,
299 0, 0, /* src_x, src_y */
300 0, 0, /* mask_x, mask_y */
301 0, 0, /* dest_x, dest_y */
302 dest_width, dest_height);
303}
304
305static void
306composite_clipped(pixman_image_t *src,
307 pixman_image_t *mask,
308 pixman_image_t *dest,
309 const pixman_transform_t *transform,
310 pixman_filter_t filter,
311 pixman_region32_t *src_clip)
312{
313 int n_box;
314 pixman_box32_t *boxes;
315 int32_t dest_width;
316 int32_t dest_height;
317 int src_stride;
318 int bitspp;
319 pixman_format_code_t src_format;
320 void *src_data;
321 int i;
322
323 /* Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
324 * a Pixman image produces (0,0,0,0) instead of discarding the
325 * fragment.
326 */
327
328 dest_width = pixman_image_get_width(dest);
329 dest_height = pixman_image_get_height(dest);
330 src_format = pixman_image_get_format(src);
331 src_stride = pixman_image_get_stride(src);
332 bitspp = PIXMAN_FORMAT_BPP(src_format);
333 src_data = pixman_image_get_data(src);
334
335 assert(src_format);
336
337 /* This would be massive overdraw, except when n_box is 1. */
338 boxes = pixman_region32_rectangles(src_clip, &n_box);
339 for (i = 0; i < n_box; i++) {
340 uint8_t *ptr = src_data;
341 pixman_image_t *boximg;
342 pixman_transform_t adj = *transform;
343
344 ptr += boxes[i].y1 * src_stride;
345 ptr += boxes[i].x1 * bitspp / 8;
346 boximg = pixman_image_create_bits_no_clear(src_format,
347 boxes[i].x2 - boxes[i].x1,
348 boxes[i].y2 - boxes[i].y1,
349 (uint32_t *)ptr, src_stride);
350
351 pixman_transform_translate(&adj, NULL,
352 pixman_int_to_fixed(-boxes[i].x1),
353 pixman_int_to_fixed(-boxes[i].y1));
354 pixman_image_set_transform(boximg, &adj);
355
356 pixman_image_set_filter(boximg, filter, NULL, 0);
357 pixman_image_composite32(PIXMAN_OP_OVER, boximg, mask, dest,
358 0, 0, /* src_x, src_y */
359 0, 0, /* mask_x, mask_y */
360 0, 0, /* dest_x, dest_y */
361 dest_width, dest_height);
362
363 pixman_image_unref(boximg);
364 }
365
366 if (n_box > 1) {
367 static bool warned = false;
368
369 if (!warned)
370 weston_log("Pixman-renderer warning: %dx overdraw\n",
371 n_box);
372 warned = true;
373 }
374}
375
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200376/** Paint an intersected region
377 *
378 * \param ev The view to be painted.
379 * \param output The output being painted.
380 * \param repaint_output The region to be painted in output coordinates.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200381 * \param source_clip The region of the source image to use, in source image
382 * coordinates. If NULL, use the whole source image.
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200383 * \param pixman_op Compositing operator, either SRC or OVER.
384 */
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200385static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500386repaint_region(struct weston_view *ev, struct weston_output *output,
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200387 pixman_region32_t *repaint_output,
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200388 pixman_region32_t *source_clip,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200389 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300390{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200391 struct pixman_renderer *pr =
392 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500393 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300394 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200395 struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200396 pixman_transform_t transform;
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200397 pixman_filter_t filter;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200398 pixman_image_t *mask_image;
399 pixman_color_t mask = { 0, };
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300400
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200401 /* Clip rendering to the damaged output region */
402 pixman_image_set_clip_region32(po->shadow_image, repaint_output);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200403
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200404 pixman_renderer_compute_transform(&transform, ev, output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200405
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200406 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200407 filter = PIXMAN_FILTER_BILINEAR;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200408 else
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200409 filter = PIXMAN_FILTER_NEAREST;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200410
Neil Robertse5051712013-11-13 15:44:06 +0000411 if (ps->buffer_ref.buffer)
412 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
413
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200414 if (ev->alpha < 1.0) {
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200415 mask.alpha = 0xffff * ev->alpha;
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200416 mask_image = pixman_image_create_solid_fill(&mask);
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200417 } else {
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200418 mask_image = NULL;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200419 }
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200420
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200421 if (source_clip)
422 composite_clipped(ps->image, mask_image, po->shadow_image,
423 &transform, filter, source_clip);
424 else
425 composite_whole(pixman_op, ps->image, mask_image,
426 po->shadow_image, &transform, filter);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200427
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200428 if (mask_image)
429 pixman_image_unref(mask_image);
430
Neil Robertse5051712013-11-13 15:44:06 +0000431 if (ps->buffer_ref.buffer)
432 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
433
Alexander Larsson1f206b42013-05-22 14:41:36 +0200434 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200435 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200436 pr->debug_color, /* src */
437 NULL /* mask */,
438 po->shadow_image, /* dest */
439 0, 0, /* src_x, src_y */
440 0, 0, /* mask_x, mask_y */
441 0, 0, /* dest_x, dest_y */
442 pixman_image_get_width (po->shadow_image), /* width */
443 pixman_image_get_height (po->shadow_image) /* height */);
444
445 pixman_image_set_clip_region32 (po->shadow_image, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300446}
447
448static void
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200449draw_view_translated(struct weston_view *view, struct weston_output *output,
450 pixman_region32_t *repaint_global)
451{
452 struct weston_surface *surface = view->surface;
453 /* non-opaque region in surface coordinates: */
454 pixman_region32_t surface_blend;
455 /* region to be painted in output coordinates: */
456 pixman_region32_t repaint_output;
457
458 pixman_region32_init(&repaint_output);
459
460 /* Blended region is whole surface minus opaque region,
461 * unless surface alpha forces us to blend all.
462 */
463 pixman_region32_init_rect(&surface_blend, 0, 0,
464 surface->width, surface->height);
465
466 if (!(view->alpha < 1.0)) {
467 pixman_region32_subtract(&surface_blend, &surface_blend,
468 &surface->opaque);
469
470 if (pixman_region32_not_empty(&surface->opaque)) {
471 region_intersect_only_translation(&repaint_output,
472 repaint_global,
473 &surface->opaque,
474 view);
475 region_global_to_output(output, &repaint_output);
476
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200477 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200478 PIXMAN_OP_SRC);
479 }
480 }
481
482 if (pixman_region32_not_empty(&surface_blend)) {
483 region_intersect_only_translation(&repaint_output,
484 repaint_global,
485 &surface_blend, view);
486 region_global_to_output(output, &repaint_output);
487
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200488 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200489 PIXMAN_OP_OVER);
490 }
491
492 pixman_region32_fini(&surface_blend);
493 pixman_region32_fini(&repaint_output);
494}
495
496static void
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200497draw_view_source_clipped(struct weston_view *view,
498 struct weston_output *output,
499 pixman_region32_t *repaint_global)
500{
501 struct weston_surface *surface = view->surface;
502 pixman_region32_t surf_region;
503 pixman_region32_t buffer_region;
504 pixman_region32_t repaint_output;
505
506 /* Do not bother separating the opaque region from non-opaque.
507 * Source clipping requires PIXMAN_OP_OVER in all cases, so painting
508 * opaque separately has no benefit.
509 */
510
511 pixman_region32_init_rect(&surf_region, 0, 0,
512 surface->width, surface->height);
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200513 if (view->geometry.scissor_enabled)
514 pixman_region32_intersect(&surf_region, &surf_region,
515 &view->geometry.scissor);
516
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200517 pixman_region32_init(&buffer_region);
518 weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
519
520 pixman_region32_init(&repaint_output);
521 pixman_region32_copy(&repaint_output, repaint_global);
522 region_global_to_output(output, &repaint_output);
523
524 repaint_region(view, output, &repaint_output, &buffer_region,
525 PIXMAN_OP_OVER);
526
527 pixman_region32_fini(&repaint_output);
528 pixman_region32_fini(&buffer_region);
529 pixman_region32_fini(&surf_region);
530}
531
532static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500533draw_view(struct weston_view *ev, struct weston_output *output,
534 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300535{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500536 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300537 /* repaint bounding region in global coordinates: */
538 pixman_region32_t repaint;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300539
540 /* No buffer attached */
541 if (!ps->image)
542 return;
543
544 pixman_region32_init(&repaint);
545 pixman_region32_intersect(&repaint,
Pekka Paalanen25c0ca52015-02-19 11:15:33 +0200546 &ev->transform.boundingbox, damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500547 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300548
549 if (!pixman_region32_not_empty(&repaint))
550 goto out;
551
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200552 if (view_transformation_is_translation(ev)) {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200553 /* The simple case: The surface regions opaque, non-opaque,
554 * etc. are convertible to global coordinate space.
555 * There is no need to use a source clip region.
556 * It is possible to paint opaque region as PIXMAN_OP_SRC.
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200557 * Also the boundingbox is accurate rather than an
558 * approximation.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200559 */
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200560 draw_view_translated(ev, output, &repaint);
561 } else {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200562 /* The complex case: the view transformation does not allow
563 * converting opaque etc. regions into global coordinate space.
564 * Therefore we need source clipping to avoid sampling from
565 * unwanted source image areas, unless the source image is
566 * to be used whole. Source clipping does not work with
567 * PIXMAN_OP_SRC.
568 */
569 draw_view_source_clipped(ev, output, &repaint);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300570 }
571
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300572out:
573 pixman_region32_fini(&repaint);
574}
575static void
576repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
577{
578 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500579 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300580
Jason Ekstranda7af7042013-10-12 22:38:11 -0500581 wl_list_for_each_reverse(view, &compositor->view_list, link)
582 if (view->plane == &compositor->primary_plane)
583 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300584}
585
586static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200587copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
588{
589 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200590 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200591
Alexander Larsson1f206b42013-05-22 14:41:36 +0200592 pixman_region32_init(&output_region);
593 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200594
Alexander Larsson1f206b42013-05-22 14:41:36 +0200595 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200596
Alexander Larsson1f206b42013-05-22 14:41:36 +0200597 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ryo Munakata389d2052014-09-04 01:56:53 +0900598 pixman_region32_fini(&output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200599
Alexander Larsson1f206b42013-05-22 14:41:36 +0200600 pixman_image_composite32(PIXMAN_OP_SRC,
601 po->shadow_image, /* src */
602 NULL /* mask */,
603 po->hw_buffer, /* dest */
604 0, 0, /* src_x, src_y */
605 0, 0, /* mask_x, mask_y */
606 0, 0, /* dest_x, dest_y */
607 pixman_image_get_width (po->hw_buffer), /* width */
608 pixman_image_get_height (po->hw_buffer) /* height */);
609
610 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200611}
612
613static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300614pixman_renderer_repaint_output(struct weston_output *output,
615 pixman_region32_t *output_damage)
616{
617 struct pixman_output_state *po = get_output_state(output);
618
619 if (!po->hw_buffer)
620 return;
621
622 repaint_surfaces(output, output_damage);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200623 copy_to_hw_buffer(output, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300624
625 pixman_region32_copy(&output->previous_damage, output_damage);
626 wl_signal_emit(&output->frame_signal, output);
627
628 /* Actual flip should be done by caller */
629}
630
631static void
632pixman_renderer_flush_damage(struct weston_surface *surface)
633{
634 /* No-op for pixman renderer */
635}
636
637static void
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100638buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
639{
640 struct pixman_surface_state *ps;
641
642 ps = container_of(listener, struct pixman_surface_state,
643 buffer_destroy_listener);
644
645 if (ps->image) {
646 pixman_image_unref(ps->image);
647 ps->image = NULL;
648 }
649
650 ps->buffer_destroy_listener.notify = NULL;
651}
652
653static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500654pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300655{
656 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500657 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300658 pixman_format_code_t pixman_format;
659
660 weston_buffer_reference(&ps->buffer_ref, buffer);
661
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100662 if (ps->buffer_destroy_listener.notify) {
663 wl_list_remove(&ps->buffer_destroy_listener.link);
664 ps->buffer_destroy_listener.notify = NULL;
665 }
666
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300667 if (ps->image) {
668 pixman_image_unref(ps->image);
669 ps->image = NULL;
670 }
671
672 if (!buffer)
673 return;
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600674
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500675 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300676
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500677 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300678 weston_log("Pixman renderer supports only SHM buffers\n");
679 weston_buffer_reference(&ps->buffer_ref, NULL);
680 return;
681 }
682
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500683 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300684 case WL_SHM_FORMAT_XRGB8888:
685 pixman_format = PIXMAN_x8r8g8b8;
686 break;
687 case WL_SHM_FORMAT_ARGB8888:
688 pixman_format = PIXMAN_a8r8g8b8;
689 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200690 case WL_SHM_FORMAT_RGB565:
691 pixman_format = PIXMAN_r5g6b5;
692 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300693 default:
694 weston_log("Unsupported SHM buffer format\n");
695 weston_buffer_reference(&ps->buffer_ref, NULL);
696 return;
697 break;
698 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500699
700 buffer->shm_buffer = shm_buffer;
701 buffer->width = wl_shm_buffer_get_width(shm_buffer);
702 buffer->height = wl_shm_buffer_get_height(shm_buffer);
703
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300704 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500705 buffer->width, buffer->height,
706 wl_shm_buffer_get_data(shm_buffer),
707 wl_shm_buffer_get_stride(shm_buffer));
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100708
709 ps->buffer_destroy_listener.notify =
710 buffer_state_handle_buffer_destroy;
711 wl_signal_add(&buffer->destroy_signal,
712 &ps->buffer_destroy_listener);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300713}
714
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300715static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300716pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300717{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300718 wl_list_remove(&ps->surface_destroy_listener.link);
719 wl_list_remove(&ps->renderer_destroy_listener.link);
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100720 if (ps->buffer_destroy_listener.notify) {
721 wl_list_remove(&ps->buffer_destroy_listener.link);
722 ps->buffer_destroy_listener.notify = NULL;
723 }
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300724
725 ps->surface->renderer_state = NULL;
726
727 if (ps->image) {
728 pixman_image_unref(ps->image);
729 ps->image = NULL;
730 }
731 weston_buffer_reference(&ps->buffer_ref, NULL);
732 free(ps);
733}
734
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300735static void
736surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
737{
738 struct pixman_surface_state *ps;
739
740 ps = container_of(listener, struct pixman_surface_state,
741 surface_destroy_listener);
742
743 pixman_renderer_surface_state_destroy(ps);
744}
745
746static void
747surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
748{
749 struct pixman_surface_state *ps;
750
751 ps = container_of(listener, struct pixman_surface_state,
752 renderer_destroy_listener);
753
754 pixman_renderer_surface_state_destroy(ps);
755}
756
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300757static int
758pixman_renderer_create_surface(struct weston_surface *surface)
759{
760 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300761 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300762
Bryce Harringtonde16d892014-11-20 22:21:57 -0800763 ps = zalloc(sizeof *ps);
764 if (ps == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300765 return -1;
766
767 surface->renderer_state = ps;
768
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300769 ps->surface = surface;
770
771 ps->surface_destroy_listener.notify =
772 surface_state_handle_surface_destroy;
773 wl_signal_add(&surface->destroy_signal,
774 &ps->surface_destroy_listener);
775
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300776 ps->renderer_destroy_listener.notify =
777 surface_state_handle_renderer_destroy;
778 wl_signal_add(&pr->destroy_signal,
779 &ps->renderer_destroy_listener);
780
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300781 return 0;
782}
783
784static void
785pixman_renderer_surface_set_color(struct weston_surface *es,
786 float red, float green, float blue, float alpha)
787{
788 struct pixman_surface_state *ps = get_surface_state(es);
789 pixman_color_t color;
790
791 color.red = red * 0xffff;
792 color.green = green * 0xffff;
793 color.blue = blue * 0xffff;
794 color.alpha = alpha * 0xffff;
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600795
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300796 if (ps->image) {
797 pixman_image_unref(ps->image);
798 ps->image = NULL;
799 }
800
801 ps->image = pixman_image_create_solid_fill(&color);
802}
803
804static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300805pixman_renderer_destroy(struct weston_compositor *ec)
806{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300807 struct pixman_renderer *pr = get_renderer(ec);
808
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300809 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300810 weston_binding_destroy(pr->debug_binding);
811 free(pr);
812
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300813 ec->renderer = NULL;
814}
815
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200816static void
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200817pixman_renderer_surface_get_content_size(struct weston_surface *surface,
818 int *width, int *height)
819{
820 struct pixman_surface_state *ps = get_surface_state(surface);
821
822 if (ps->image) {
823 *width = pixman_image_get_width(ps->image);
824 *height = pixman_image_get_height(ps->image);
825 } else {
826 *width = 0;
827 *height = 0;
828 }
829}
830
831static int
832pixman_renderer_surface_copy_content(struct weston_surface *surface,
833 void *target, size_t size,
834 int src_x, int src_y,
835 int width, int height)
836{
837 const pixman_format_code_t format = PIXMAN_a8b8g8r8;
838 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
839 struct pixman_surface_state *ps = get_surface_state(surface);
840 pixman_image_t *out_buf;
841
842 if (!ps->image)
843 return -1;
844
845 out_buf = pixman_image_create_bits(format, width, height,
846 target, width * bytespp);
847
848 pixman_image_set_transform(ps->image, NULL);
849 pixman_image_composite32(PIXMAN_OP_SRC,
850 ps->image, /* src */
851 NULL, /* mask */
852 out_buf, /* dest */
853 src_x, src_y, /* src_x, src_y */
854 0, 0, /* mask_x, mask_y */
855 0, 0, /* dest_x, dest_y */
856 width, height);
857
858 pixman_image_unref(out_buf);
859
860 return 0;
861}
862
863static void
Derek Foreman8ae2db52015-07-15 13:00:36 -0500864debug_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200865 void *data)
866{
867 struct weston_compositor *ec = data;
868 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
869
870 pr->repaint_debug ^= 1;
871
872 if (pr->repaint_debug) {
873 pixman_color_t red = {
874 0x3fff, 0x0000, 0x0000, 0x3fff
875 };
876
877 pr->debug_color = pixman_image_create_solid_fill(&red);
878 } else {
879 pixman_image_unref(pr->debug_color);
880 weston_compositor_damage_all(ec);
881 }
882}
883
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300884WL_EXPORT int
885pixman_renderer_init(struct weston_compositor *ec)
886{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200887 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300888
Bryce Harringtonde16d892014-11-20 22:21:57 -0800889 renderer = zalloc(sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300890 if (renderer == NULL)
891 return -1;
892
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100893 renderer->repaint_debug = 0;
894 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200895 renderer->base.read_pixels = pixman_renderer_read_pixels;
896 renderer->base.repaint_output = pixman_renderer_repaint_output;
897 renderer->base.flush_damage = pixman_renderer_flush_damage;
898 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200899 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200900 renderer->base.destroy = pixman_renderer_destroy;
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200901 renderer->base.surface_get_content_size =
902 pixman_renderer_surface_get_content_size;
903 renderer->base.surface_copy_content =
904 pixman_renderer_surface_copy_content;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200905 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300906 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300907 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200908 ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300909
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300910 renderer->debug_binding =
911 weston_compositor_add_debug_binding(ec, KEY_R,
912 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200913
914 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
915
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300916 wl_signal_init(&renderer->destroy_signal);
917
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300918 return 0;
919}
920
921WL_EXPORT void
922pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
923{
924 struct pixman_output_state *po = get_output_state(output);
925
926 if (po->hw_buffer)
927 pixman_image_unref(po->hw_buffer);
928 po->hw_buffer = buffer;
929
930 if (po->hw_buffer) {
931 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
932 pixman_image_ref(po->hw_buffer);
933 }
934}
935
936WL_EXPORT int
937pixman_renderer_output_create(struct weston_output *output)
938{
Bryce Harringtonde16d892014-11-20 22:21:57 -0800939 struct pixman_output_state *po;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200940 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300941
Bryce Harringtonde16d892014-11-20 22:21:57 -0800942 po = zalloc(sizeof *po);
943 if (po == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300944 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200945
946 /* set shadow image transformation */
Hardeningff39efa2013-09-18 23:56:35 +0200947 w = output->current_mode->width;
948 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200949
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200950 po->shadow_buffer = malloc(w * h * 4);
951
952 if (!po->shadow_buffer) {
953 free(po);
954 return -1;
955 }
956
957 po->shadow_image =
958 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
959 po->shadow_buffer, w * 4);
960
961 if (!po->shadow_image) {
962 free(po->shadow_buffer);
963 free(po);
964 return -1;
965 }
966
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300967 output->renderer_state = po;
968
969 return 0;
970}
971
972WL_EXPORT void
973pixman_renderer_output_destroy(struct weston_output *output)
974{
975 struct pixman_output_state *po = get_output_state(output);
976
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200977 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200978
979 if (po->hw_buffer)
980 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200981
Arnaud Vrac8e3fe082014-08-25 20:56:52 +0200982 free(po->shadow_buffer);
983
984 po->shadow_buffer = NULL;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200985 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300986 po->hw_buffer = NULL;
987
988 free(po);
989}