blob: cf43b15d2ef2ac5f37424f32804bb95d5663f7cb [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>
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030031#include <stdint.h>
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030032#include <stdlib.h>
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +020033#include <assert.h>
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030034
35#include "pixman-renderer.h"
Jon Cruz867d50e2015-06-15 15:37:10 -070036#include "shared/helpers.h"
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030037
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020038#include <linux/input.h>
39
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030040struct pixman_output_state {
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +020041 void *shadow_buffer;
42 pixman_image_t *shadow_image;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030043 pixman_image_t *hw_buffer;
Pekka Paalanenacf50c32018-04-23 11:44:56 +020044 pixman_region32_t *hw_extra_damage;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030045};
46
47struct pixman_surface_state {
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030048 struct weston_surface *surface;
49
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030050 pixman_image_t *image;
51 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030052
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +010053 struct wl_listener buffer_destroy_listener;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030054 struct wl_listener surface_destroy_listener;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030055 struct wl_listener renderer_destroy_listener;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030056};
57
58struct pixman_renderer {
59 struct weston_renderer base;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030060
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020061 int repaint_debug;
62 pixman_image_t *debug_color;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030063 struct weston_binding *debug_binding;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030064
65 struct wl_signal destroy_signal;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030066};
67
68static inline struct pixman_output_state *
69get_output_state(struct weston_output *output)
70{
71 return (struct pixman_output_state *)output->renderer_state;
72}
73
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030074static int
75pixman_renderer_create_surface(struct weston_surface *surface);
76
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030077static inline struct pixman_surface_state *
78get_surface_state(struct weston_surface *surface)
79{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030080 if (!surface->renderer_state)
81 pixman_renderer_create_surface(surface);
82
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030083 return (struct pixman_surface_state *)surface->renderer_state;
84}
85
86static inline struct pixman_renderer *
87get_renderer(struct weston_compositor *ec)
88{
89 return (struct pixman_renderer *)ec->renderer;
90}
91
92static int
93pixman_renderer_read_pixels(struct weston_output *output,
94 pixman_format_code_t format, void *pixels,
95 uint32_t x, uint32_t y,
96 uint32_t width, uint32_t height)
97{
98 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson97af7922013-05-29 12:01:33 +020099 pixman_transform_t transform;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300100 pixman_image_t *out_buf;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300101
102 if (!po->hw_buffer) {
103 errno = ENODEV;
104 return -1;
105 }
106
107 out_buf = pixman_image_create_bits(format,
108 width,
109 height,
110 pixels,
111 (PIXMAN_FORMAT_BPP(format) / 8) * width);
112
Alexander Larsson97af7922013-05-29 12:01:33 +0200113 /* Caller expects vflipped source image */
114 pixman_transform_init_translate(&transform,
115 pixman_int_to_fixed (x),
116 pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
117 pixman_transform_scale(&transform, NULL,
118 pixman_fixed_1,
119 pixman_fixed_minus_1);
120 pixman_image_set_transform(po->hw_buffer, &transform);
121
122 pixman_image_composite32(PIXMAN_OP_SRC,
123 po->hw_buffer, /* src */
124 NULL /* mask */,
125 out_buf, /* dest */
126 0, 0, /* src_x, src_y */
127 0, 0, /* mask_x, mask_y */
128 0, 0, /* dest_x, dest_y */
129 pixman_image_get_width (po->hw_buffer), /* width */
130 pixman_image_get_height (po->hw_buffer) /* height */);
131 pixman_image_set_transform(po->hw_buffer, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300132
133 pixman_image_unref(out_buf);
134
135 return 0;
136}
137
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300138static void
Alexander Larsson1f206b42013-05-22 14:41:36 +0200139region_global_to_output(struct weston_output *output, pixman_region32_t *region)
140{
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600141 if (output->zoom.active) {
142 weston_matrix_transform_region(region, &output->matrix, region);
143 } else {
144 pixman_region32_translate(region, -output->x, -output->y);
145 weston_transformed_region(output->width, output->height,
146 output->transform,
147 output->current_scale,
148 region, region);
149 }
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300150}
151
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300152#define D2F(v) pixman_double_to_fixed((double)v)
153
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300154static void
Jason Ekstrand8870a232014-05-20 15:53:19 -0500155weston_matrix_to_pixman_transform(pixman_transform_t *pt,
156 const struct weston_matrix *wm)
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200157{
Jason Ekstrand8870a232014-05-20 15:53:19 -0500158 /* Pixman supports only 2D transform matrix, but Weston uses 3D, *
159 * so we're omitting Z coordinate here. */
160 pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
161 pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
162 pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
163 pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
164 pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
165 pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
166 pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
167 pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
168 pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200169}
170
171static void
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200172pixman_renderer_compute_transform(pixman_transform_t *transform_out,
173 struct weston_view *ev,
174 struct weston_output *output)
175{
176 struct weston_matrix matrix;
177
178 /* Set up the source transformation based on the surface
179 position, the output position/transform/scale and the client
180 specified buffer transform/scale */
Derek Foremana5855ad2015-03-24 11:36:16 -0500181 matrix = output->inverse_matrix;
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200182
183 if (ev->transform.enabled) {
184 weston_matrix_multiply(&matrix, &ev->transform.inverse);
185 } else {
186 weston_matrix_translate(&matrix,
187 -ev->geometry.x, -ev->geometry.y, 0);
188 }
189
190 weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
191
192 weston_matrix_to_pixman_transform(transform_out, &matrix);
193}
194
Pekka Paalanen23d4af52015-03-04 16:18:26 +0200195static bool
196view_transformation_is_translation(struct weston_view *view)
197{
198 if (!view->transform.enabled)
199 return true;
200
201 if (view->transform.matrix.type <= WESTON_MATRIX_TRANSFORM_TRANSLATE)
202 return true;
203
204 return false;
205}
206
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200207static void
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200208region_intersect_only_translation(pixman_region32_t *result_global,
209 pixman_region32_t *global,
210 pixman_region32_t *surf,
211 struct weston_view *view)
212{
213 float view_x, view_y;
214
215 assert(view_transformation_is_translation(view));
216
217 /* Convert from surface to global coordinates */
218 pixman_region32_copy(result_global, surf);
219 weston_view_to_global_float(view, 0, 0, &view_x, &view_y);
220 pixman_region32_translate(result_global, (int)view_x, (int)view_y);
221
222 pixman_region32_intersect(result_global, result_global, global);
223}
224
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200225static void
226composite_whole(pixman_op_t op,
227 pixman_image_t *src,
228 pixman_image_t *mask,
229 pixman_image_t *dest,
230 const pixman_transform_t *transform,
231 pixman_filter_t filter)
232{
233 int32_t dest_width;
234 int32_t dest_height;
235
236 dest_width = pixman_image_get_width(dest);
237 dest_height = pixman_image_get_height(dest);
238
239 pixman_image_set_transform(src, transform);
240 pixman_image_set_filter(src, filter, NULL, 0);
241
242 pixman_image_composite32(op, src, mask, dest,
243 0, 0, /* src_x, src_y */
244 0, 0, /* mask_x, mask_y */
245 0, 0, /* dest_x, dest_y */
246 dest_width, dest_height);
247}
248
249static void
250composite_clipped(pixman_image_t *src,
251 pixman_image_t *mask,
252 pixman_image_t *dest,
253 const pixman_transform_t *transform,
254 pixman_filter_t filter,
255 pixman_region32_t *src_clip)
256{
257 int n_box;
258 pixman_box32_t *boxes;
259 int32_t dest_width;
260 int32_t dest_height;
261 int src_stride;
262 int bitspp;
263 pixman_format_code_t src_format;
264 void *src_data;
265 int i;
266
267 /* Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
268 * a Pixman image produces (0,0,0,0) instead of discarding the
269 * fragment.
270 */
271
272 dest_width = pixman_image_get_width(dest);
273 dest_height = pixman_image_get_height(dest);
274 src_format = pixman_image_get_format(src);
275 src_stride = pixman_image_get_stride(src);
276 bitspp = PIXMAN_FORMAT_BPP(src_format);
277 src_data = pixman_image_get_data(src);
278
279 assert(src_format);
280
281 /* This would be massive overdraw, except when n_box is 1. */
282 boxes = pixman_region32_rectangles(src_clip, &n_box);
283 for (i = 0; i < n_box; i++) {
284 uint8_t *ptr = src_data;
285 pixman_image_t *boximg;
286 pixman_transform_t adj = *transform;
287
288 ptr += boxes[i].y1 * src_stride;
289 ptr += boxes[i].x1 * bitspp / 8;
290 boximg = pixman_image_create_bits_no_clear(src_format,
291 boxes[i].x2 - boxes[i].x1,
292 boxes[i].y2 - boxes[i].y1,
293 (uint32_t *)ptr, src_stride);
294
295 pixman_transform_translate(&adj, NULL,
296 pixman_int_to_fixed(-boxes[i].x1),
297 pixman_int_to_fixed(-boxes[i].y1));
298 pixman_image_set_transform(boximg, &adj);
299
300 pixman_image_set_filter(boximg, filter, NULL, 0);
301 pixman_image_composite32(PIXMAN_OP_OVER, boximg, mask, dest,
302 0, 0, /* src_x, src_y */
303 0, 0, /* mask_x, mask_y */
304 0, 0, /* dest_x, dest_y */
305 dest_width, dest_height);
306
307 pixman_image_unref(boximg);
308 }
309
310 if (n_box > 1) {
311 static bool warned = false;
312
313 if (!warned)
314 weston_log("Pixman-renderer warning: %dx overdraw\n",
315 n_box);
316 warned = true;
317 }
318}
319
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200320/** Paint an intersected region
321 *
322 * \param ev The view to be painted.
323 * \param output The output being painted.
324 * \param repaint_output The region to be painted in output coordinates.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200325 * \param source_clip The region of the source image to use, in source image
326 * coordinates. If NULL, use the whole source image.
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200327 * \param pixman_op Compositing operator, either SRC or OVER.
328 */
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200329static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500330repaint_region(struct weston_view *ev, struct weston_output *output,
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200331 pixman_region32_t *repaint_output,
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200332 pixman_region32_t *source_clip,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200333 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300334{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200335 struct pixman_renderer *pr =
336 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500337 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300338 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200339 struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200340 pixman_transform_t transform;
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200341 pixman_filter_t filter;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200342 pixman_image_t *mask_image;
343 pixman_color_t mask = { 0, };
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300344
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200345 /* Clip rendering to the damaged output region */
346 pixman_image_set_clip_region32(po->shadow_image, repaint_output);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200347
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200348 pixman_renderer_compute_transform(&transform, ev, output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200349
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200350 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200351 filter = PIXMAN_FILTER_BILINEAR;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200352 else
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200353 filter = PIXMAN_FILTER_NEAREST;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200354
Neil Robertse5051712013-11-13 15:44:06 +0000355 if (ps->buffer_ref.buffer)
356 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
357
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200358 if (ev->alpha < 1.0) {
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200359 mask.alpha = 0xffff * ev->alpha;
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200360 mask_image = pixman_image_create_solid_fill(&mask);
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200361 } else {
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200362 mask_image = NULL;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200363 }
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200364
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200365 if (source_clip)
366 composite_clipped(ps->image, mask_image, po->shadow_image,
367 &transform, filter, source_clip);
368 else
369 composite_whole(pixman_op, ps->image, mask_image,
370 po->shadow_image, &transform, filter);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200371
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200372 if (mask_image)
373 pixman_image_unref(mask_image);
374
Neil Robertse5051712013-11-13 15:44:06 +0000375 if (ps->buffer_ref.buffer)
376 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
377
Alexander Larsson1f206b42013-05-22 14:41:36 +0200378 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200379 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200380 pr->debug_color, /* src */
381 NULL /* mask */,
382 po->shadow_image, /* 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->shadow_image), /* width */
387 pixman_image_get_height (po->shadow_image) /* height */);
388
389 pixman_image_set_clip_region32 (po->shadow_image, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300390}
391
392static void
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200393draw_view_translated(struct weston_view *view, struct weston_output *output,
394 pixman_region32_t *repaint_global)
395{
396 struct weston_surface *surface = view->surface;
397 /* non-opaque region in surface coordinates: */
398 pixman_region32_t surface_blend;
399 /* region to be painted in output coordinates: */
400 pixman_region32_t repaint_output;
401
402 pixman_region32_init(&repaint_output);
403
404 /* Blended region is whole surface minus opaque region,
405 * unless surface alpha forces us to blend all.
406 */
407 pixman_region32_init_rect(&surface_blend, 0, 0,
408 surface->width, surface->height);
409
410 if (!(view->alpha < 1.0)) {
411 pixman_region32_subtract(&surface_blend, &surface_blend,
412 &surface->opaque);
413
414 if (pixman_region32_not_empty(&surface->opaque)) {
415 region_intersect_only_translation(&repaint_output,
416 repaint_global,
417 &surface->opaque,
418 view);
419 region_global_to_output(output, &repaint_output);
420
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200421 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200422 PIXMAN_OP_SRC);
423 }
424 }
425
426 if (pixman_region32_not_empty(&surface_blend)) {
427 region_intersect_only_translation(&repaint_output,
428 repaint_global,
429 &surface_blend, view);
430 region_global_to_output(output, &repaint_output);
431
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200432 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200433 PIXMAN_OP_OVER);
434 }
435
436 pixman_region32_fini(&surface_blend);
437 pixman_region32_fini(&repaint_output);
438}
439
440static void
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200441draw_view_source_clipped(struct weston_view *view,
442 struct weston_output *output,
443 pixman_region32_t *repaint_global)
444{
445 struct weston_surface *surface = view->surface;
446 pixman_region32_t surf_region;
447 pixman_region32_t buffer_region;
448 pixman_region32_t repaint_output;
449
450 /* Do not bother separating the opaque region from non-opaque.
451 * Source clipping requires PIXMAN_OP_OVER in all cases, so painting
452 * opaque separately has no benefit.
453 */
454
455 pixman_region32_init_rect(&surf_region, 0, 0,
456 surface->width, surface->height);
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200457 if (view->geometry.scissor_enabled)
458 pixman_region32_intersect(&surf_region, &surf_region,
459 &view->geometry.scissor);
460
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200461 pixman_region32_init(&buffer_region);
462 weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
463
464 pixman_region32_init(&repaint_output);
465 pixman_region32_copy(&repaint_output, repaint_global);
466 region_global_to_output(output, &repaint_output);
467
468 repaint_region(view, output, &repaint_output, &buffer_region,
469 PIXMAN_OP_OVER);
470
471 pixman_region32_fini(&repaint_output);
472 pixman_region32_fini(&buffer_region);
473 pixman_region32_fini(&surf_region);
474}
475
476static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500477draw_view(struct weston_view *ev, struct weston_output *output,
478 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300479{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500480 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300481 /* repaint bounding region in global coordinates: */
482 pixman_region32_t repaint;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300483
484 /* No buffer attached */
485 if (!ps->image)
486 return;
487
488 pixman_region32_init(&repaint);
489 pixman_region32_intersect(&repaint,
Pekka Paalanen25c0ca52015-02-19 11:15:33 +0200490 &ev->transform.boundingbox, damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500491 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300492
493 if (!pixman_region32_not_empty(&repaint))
494 goto out;
495
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200496 if (view_transformation_is_translation(ev)) {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200497 /* The simple case: The surface regions opaque, non-opaque,
498 * etc. are convertible to global coordinate space.
499 * There is no need to use a source clip region.
500 * It is possible to paint opaque region as PIXMAN_OP_SRC.
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200501 * Also the boundingbox is accurate rather than an
502 * approximation.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200503 */
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200504 draw_view_translated(ev, output, &repaint);
505 } else {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200506 /* The complex case: the view transformation does not allow
507 * converting opaque etc. regions into global coordinate space.
508 * Therefore we need source clipping to avoid sampling from
509 * unwanted source image areas, unless the source image is
510 * to be used whole. Source clipping does not work with
511 * PIXMAN_OP_SRC.
512 */
513 draw_view_source_clipped(ev, output, &repaint);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300514 }
515
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300516out:
517 pixman_region32_fini(&repaint);
518}
519static void
520repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
521{
522 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500523 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300524
Jason Ekstranda7af7042013-10-12 22:38:11 -0500525 wl_list_for_each_reverse(view, &compositor->view_list, link)
526 if (view->plane == &compositor->primary_plane)
527 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300528}
529
530static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200531copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
532{
533 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200534 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200535
Alexander Larsson1f206b42013-05-22 14:41:36 +0200536 pixman_region32_init(&output_region);
537 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200538
Alexander Larsson1f206b42013-05-22 14:41:36 +0200539 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200540
Alexander Larsson1f206b42013-05-22 14:41:36 +0200541 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ryo Munakata389d2052014-09-04 01:56:53 +0900542 pixman_region32_fini(&output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200543
Alexander Larsson1f206b42013-05-22 14:41:36 +0200544 pixman_image_composite32(PIXMAN_OP_SRC,
545 po->shadow_image, /* src */
546 NULL /* mask */,
547 po->hw_buffer, /* dest */
548 0, 0, /* src_x, src_y */
549 0, 0, /* mask_x, mask_y */
550 0, 0, /* dest_x, dest_y */
551 pixman_image_get_width (po->hw_buffer), /* width */
552 pixman_image_get_height (po->hw_buffer) /* height */);
553
554 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200555}
556
557static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300558pixman_renderer_repaint_output(struct weston_output *output,
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200559 pixman_region32_t *output_damage)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300560{
561 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200562 pixman_region32_t hw_damage;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300563
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200564 if (!po->hw_buffer) {
565 po->hw_extra_damage = NULL;
566 return;
567 }
568
569 pixman_region32_init(&hw_damage);
570 if (po->hw_extra_damage) {
571 pixman_region32_union(&hw_damage,
572 po->hw_extra_damage, output_damage);
573 po->hw_extra_damage = NULL;
574 } else {
575 pixman_region32_copy(&hw_damage, output_damage);
576 }
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300577
578 repaint_surfaces(output, output_damage);
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200579
580 copy_to_hw_buffer(output, &hw_damage);
581 pixman_region32_fini(&hw_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300582
583 pixman_region32_copy(&output->previous_damage, output_damage);
584 wl_signal_emit(&output->frame_signal, output);
585
586 /* Actual flip should be done by caller */
587}
588
589static void
590pixman_renderer_flush_damage(struct weston_surface *surface)
591{
592 /* No-op for pixman renderer */
593}
594
595static void
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100596buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
597{
598 struct pixman_surface_state *ps;
599
600 ps = container_of(listener, struct pixman_surface_state,
601 buffer_destroy_listener);
602
603 if (ps->image) {
604 pixman_image_unref(ps->image);
605 ps->image = NULL;
606 }
607
608 ps->buffer_destroy_listener.notify = NULL;
609}
610
611static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500612pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300613{
614 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500615 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300616 pixman_format_code_t pixman_format;
617
618 weston_buffer_reference(&ps->buffer_ref, buffer);
619
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100620 if (ps->buffer_destroy_listener.notify) {
621 wl_list_remove(&ps->buffer_destroy_listener.link);
622 ps->buffer_destroy_listener.notify = NULL;
623 }
624
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300625 if (ps->image) {
626 pixman_image_unref(ps->image);
627 ps->image = NULL;
628 }
629
630 if (!buffer)
631 return;
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600632
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500633 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300634
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500635 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300636 weston_log("Pixman renderer supports only SHM buffers\n");
637 weston_buffer_reference(&ps->buffer_ref, NULL);
638 return;
639 }
640
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500641 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300642 case WL_SHM_FORMAT_XRGB8888:
643 pixman_format = PIXMAN_x8r8g8b8;
644 break;
645 case WL_SHM_FORMAT_ARGB8888:
646 pixman_format = PIXMAN_a8r8g8b8;
647 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200648 case WL_SHM_FORMAT_RGB565:
649 pixman_format = PIXMAN_r5g6b5;
650 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300651 default:
652 weston_log("Unsupported SHM buffer format\n");
653 weston_buffer_reference(&ps->buffer_ref, NULL);
654 return;
655 break;
656 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500657
658 buffer->shm_buffer = shm_buffer;
659 buffer->width = wl_shm_buffer_get_width(shm_buffer);
660 buffer->height = wl_shm_buffer_get_height(shm_buffer);
661
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300662 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500663 buffer->width, buffer->height,
664 wl_shm_buffer_get_data(shm_buffer),
665 wl_shm_buffer_get_stride(shm_buffer));
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100666
667 ps->buffer_destroy_listener.notify =
668 buffer_state_handle_buffer_destroy;
669 wl_signal_add(&buffer->destroy_signal,
670 &ps->buffer_destroy_listener);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300671}
672
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300673static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300674pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300675{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300676 wl_list_remove(&ps->surface_destroy_listener.link);
677 wl_list_remove(&ps->renderer_destroy_listener.link);
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100678 if (ps->buffer_destroy_listener.notify) {
679 wl_list_remove(&ps->buffer_destroy_listener.link);
680 ps->buffer_destroy_listener.notify = NULL;
681 }
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300682
683 ps->surface->renderer_state = NULL;
684
685 if (ps->image) {
686 pixman_image_unref(ps->image);
687 ps->image = NULL;
688 }
689 weston_buffer_reference(&ps->buffer_ref, NULL);
690 free(ps);
691}
692
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300693static void
694surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
695{
696 struct pixman_surface_state *ps;
697
698 ps = container_of(listener, struct pixman_surface_state,
699 surface_destroy_listener);
700
701 pixman_renderer_surface_state_destroy(ps);
702}
703
704static void
705surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
706{
707 struct pixman_surface_state *ps;
708
709 ps = container_of(listener, struct pixman_surface_state,
710 renderer_destroy_listener);
711
712 pixman_renderer_surface_state_destroy(ps);
713}
714
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300715static int
716pixman_renderer_create_surface(struct weston_surface *surface)
717{
718 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300719 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300720
Bryce Harringtonde16d892014-11-20 22:21:57 -0800721 ps = zalloc(sizeof *ps);
722 if (ps == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300723 return -1;
724
725 surface->renderer_state = ps;
726
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300727 ps->surface = surface;
728
729 ps->surface_destroy_listener.notify =
730 surface_state_handle_surface_destroy;
731 wl_signal_add(&surface->destroy_signal,
732 &ps->surface_destroy_listener);
733
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300734 ps->renderer_destroy_listener.notify =
735 surface_state_handle_renderer_destroy;
736 wl_signal_add(&pr->destroy_signal,
737 &ps->renderer_destroy_listener);
738
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300739 return 0;
740}
741
742static void
743pixman_renderer_surface_set_color(struct weston_surface *es,
744 float red, float green, float blue, float alpha)
745{
746 struct pixman_surface_state *ps = get_surface_state(es);
747 pixman_color_t color;
748
749 color.red = red * 0xffff;
750 color.green = green * 0xffff;
751 color.blue = blue * 0xffff;
752 color.alpha = alpha * 0xffff;
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600753
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300754 if (ps->image) {
755 pixman_image_unref(ps->image);
756 ps->image = NULL;
757 }
758
759 ps->image = pixman_image_create_solid_fill(&color);
760}
761
762static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300763pixman_renderer_destroy(struct weston_compositor *ec)
764{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300765 struct pixman_renderer *pr = get_renderer(ec);
766
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300767 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300768 weston_binding_destroy(pr->debug_binding);
769 free(pr);
770
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300771 ec->renderer = NULL;
772}
773
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200774static void
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200775pixman_renderer_surface_get_content_size(struct weston_surface *surface,
776 int *width, int *height)
777{
778 struct pixman_surface_state *ps = get_surface_state(surface);
779
780 if (ps->image) {
781 *width = pixman_image_get_width(ps->image);
782 *height = pixman_image_get_height(ps->image);
783 } else {
784 *width = 0;
785 *height = 0;
786 }
787}
788
789static int
790pixman_renderer_surface_copy_content(struct weston_surface *surface,
791 void *target, size_t size,
792 int src_x, int src_y,
793 int width, int height)
794{
795 const pixman_format_code_t format = PIXMAN_a8b8g8r8;
796 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
797 struct pixman_surface_state *ps = get_surface_state(surface);
798 pixman_image_t *out_buf;
799
800 if (!ps->image)
801 return -1;
802
803 out_buf = pixman_image_create_bits(format, width, height,
804 target, width * bytespp);
805
806 pixman_image_set_transform(ps->image, NULL);
807 pixman_image_composite32(PIXMAN_OP_SRC,
808 ps->image, /* src */
809 NULL, /* mask */
810 out_buf, /* dest */
811 src_x, src_y, /* src_x, src_y */
812 0, 0, /* mask_x, mask_y */
813 0, 0, /* dest_x, dest_y */
814 width, height);
815
816 pixman_image_unref(out_buf);
817
818 return 0;
819}
820
821static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +0200822debug_binding(struct weston_keyboard *keyboard, const struct timespec *time,
823 uint32_t key, void *data)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200824{
825 struct weston_compositor *ec = data;
826 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
827
828 pr->repaint_debug ^= 1;
829
830 if (pr->repaint_debug) {
831 pixman_color_t red = {
832 0x3fff, 0x0000, 0x0000, 0x3fff
833 };
834
835 pr->debug_color = pixman_image_create_solid_fill(&red);
836 } else {
837 pixman_image_unref(pr->debug_color);
838 weston_compositor_damage_all(ec);
839 }
840}
841
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300842WL_EXPORT int
843pixman_renderer_init(struct weston_compositor *ec)
844{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200845 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300846
Bryce Harringtonde16d892014-11-20 22:21:57 -0800847 renderer = zalloc(sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300848 if (renderer == NULL)
849 return -1;
850
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100851 renderer->repaint_debug = 0;
852 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200853 renderer->base.read_pixels = pixman_renderer_read_pixels;
854 renderer->base.repaint_output = pixman_renderer_repaint_output;
855 renderer->base.flush_damage = pixman_renderer_flush_damage;
856 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200857 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200858 renderer->base.destroy = pixman_renderer_destroy;
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200859 renderer->base.surface_get_content_size =
860 pixman_renderer_surface_get_content_size;
861 renderer->base.surface_copy_content =
862 pixman_renderer_surface_copy_content;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200863 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300864 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanen4fc5dd02013-05-22 18:03:05 +0300865 ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200866 ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300867
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300868 renderer->debug_binding =
869 weston_compositor_add_debug_binding(ec, KEY_R,
870 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200871
872 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
873
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300874 wl_signal_init(&renderer->destroy_signal);
875
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300876 return 0;
877}
878
879WL_EXPORT void
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200880pixman_renderer_output_set_buffer(struct weston_output *output,
881 pixman_image_t *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300882{
883 struct pixman_output_state *po = get_output_state(output);
884
885 if (po->hw_buffer)
886 pixman_image_unref(po->hw_buffer);
887 po->hw_buffer = buffer;
888
889 if (po->hw_buffer) {
890 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
891 pixman_image_ref(po->hw_buffer);
892 }
893}
894
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200895WL_EXPORT void
896pixman_renderer_output_set_hw_extra_damage(struct weston_output *output,
897 pixman_region32_t *extra_damage)
898{
899 struct pixman_output_state *po = get_output_state(output);
900
901 po->hw_extra_damage = extra_damage;
902}
903
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300904WL_EXPORT int
905pixman_renderer_output_create(struct weston_output *output)
906{
Bryce Harringtonde16d892014-11-20 22:21:57 -0800907 struct pixman_output_state *po;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200908 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300909
Bryce Harringtonde16d892014-11-20 22:21:57 -0800910 po = zalloc(sizeof *po);
911 if (po == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300912 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200913
914 /* set shadow image transformation */
Hardeningff39efa2013-09-18 23:56:35 +0200915 w = output->current_mode->width;
916 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200917
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200918 po->shadow_buffer = malloc(w * h * 4);
919
920 if (!po->shadow_buffer) {
921 free(po);
922 return -1;
923 }
924
925 po->shadow_image =
926 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
927 po->shadow_buffer, w * 4);
928
929 if (!po->shadow_image) {
930 free(po->shadow_buffer);
931 free(po);
932 return -1;
933 }
934
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300935 output->renderer_state = po;
936
937 return 0;
938}
939
940WL_EXPORT void
941pixman_renderer_output_destroy(struct weston_output *output)
942{
943 struct pixman_output_state *po = get_output_state(output);
944
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200945 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200946
947 if (po->hw_buffer)
948 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200949
Arnaud Vrac8e3fe082014-08-25 20:56:52 +0200950 free(po->shadow_buffer);
951
952 po->shadow_buffer = NULL;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200953 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300954 po->hw_buffer = NULL;
955
956 free(po);
957}