blob: cae89741183c710014fdb82f96b0af276caa8f51 [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;
Alexandros Frantzis67629672018-10-19 12:14:11 +030052 struct weston_buffer_release_reference buffer_release_ref;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030053
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +010054 struct wl_listener buffer_destroy_listener;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030055 struct wl_listener surface_destroy_listener;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030056 struct wl_listener renderer_destroy_listener;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030057};
58
59struct pixman_renderer {
60 struct weston_renderer base;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030061
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020062 int repaint_debug;
63 pixman_image_t *debug_color;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030064 struct weston_binding *debug_binding;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030065
66 struct wl_signal destroy_signal;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030067};
68
69static inline struct pixman_output_state *
70get_output_state(struct weston_output *output)
71{
72 return (struct pixman_output_state *)output->renderer_state;
73}
74
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030075static int
76pixman_renderer_create_surface(struct weston_surface *surface);
77
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030078static inline struct pixman_surface_state *
79get_surface_state(struct weston_surface *surface)
80{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030081 if (!surface->renderer_state)
82 pixman_renderer_create_surface(surface);
83
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030084 return (struct pixman_surface_state *)surface->renderer_state;
85}
86
87static inline struct pixman_renderer *
88get_renderer(struct weston_compositor *ec)
89{
90 return (struct pixman_renderer *)ec->renderer;
91}
92
93static int
94pixman_renderer_read_pixels(struct weston_output *output,
95 pixman_format_code_t format, void *pixels,
96 uint32_t x, uint32_t y,
97 uint32_t width, uint32_t height)
98{
99 struct pixman_output_state *po = get_output_state(output);
100 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 pixman_image_composite32(PIXMAN_OP_SRC,
114 po->hw_buffer, /* src */
115 NULL /* mask */,
116 out_buf, /* dest */
Stefan Agnerda2e5742019-06-16 23:28:15 +0200117 x, y, /* src_x, src_y */
Alexander Larsson97af7922013-05-29 12:01:33 +0200118 0, 0, /* mask_x, mask_y */
119 0, 0, /* dest_x, dest_y */
120 pixman_image_get_width (po->hw_buffer), /* width */
121 pixman_image_get_height (po->hw_buffer) /* height */);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300122
123 pixman_image_unref(out_buf);
124
125 return 0;
126}
127
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300128static void
Alexander Larsson1f206b42013-05-22 14:41:36 +0200129region_global_to_output(struct weston_output *output, pixman_region32_t *region)
130{
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600131 if (output->zoom.active) {
132 weston_matrix_transform_region(region, &output->matrix, region);
133 } else {
134 pixman_region32_translate(region, -output->x, -output->y);
135 weston_transformed_region(output->width, output->height,
136 output->transform,
137 output->current_scale,
138 region, region);
139 }
Vasily Khoruzhick031fc872013-01-29 14:58:14 +0300140}
141
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300142#define D2F(v) pixman_double_to_fixed((double)v)
143
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300144static void
Jason Ekstrand8870a232014-05-20 15:53:19 -0500145weston_matrix_to_pixman_transform(pixman_transform_t *pt,
146 const struct weston_matrix *wm)
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200147{
Jason Ekstrand8870a232014-05-20 15:53:19 -0500148 /* Pixman supports only 2D transform matrix, but Weston uses 3D, *
149 * so we're omitting Z coordinate here. */
150 pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
151 pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
152 pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
153 pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
154 pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
155 pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
156 pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
157 pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
158 pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200159}
160
161static void
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200162pixman_renderer_compute_transform(pixman_transform_t *transform_out,
163 struct weston_view *ev,
164 struct weston_output *output)
165{
166 struct weston_matrix matrix;
167
168 /* Set up the source transformation based on the surface
169 position, the output position/transform/scale and the client
170 specified buffer transform/scale */
Derek Foremana5855ad2015-03-24 11:36:16 -0500171 matrix = output->inverse_matrix;
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200172
173 if (ev->transform.enabled) {
174 weston_matrix_multiply(&matrix, &ev->transform.inverse);
175 } else {
176 weston_matrix_translate(&matrix,
177 -ev->geometry.x, -ev->geometry.y, 0);
178 }
179
180 weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
181
182 weston_matrix_to_pixman_transform(transform_out, &matrix);
183}
184
Pekka Paalanen23d4af52015-03-04 16:18:26 +0200185static bool
186view_transformation_is_translation(struct weston_view *view)
187{
188 if (!view->transform.enabled)
189 return true;
190
191 if (view->transform.matrix.type <= WESTON_MATRIX_TRANSFORM_TRANSLATE)
192 return true;
193
194 return false;
195}
196
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200197static void
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200198region_intersect_only_translation(pixman_region32_t *result_global,
199 pixman_region32_t *global,
200 pixman_region32_t *surf,
201 struct weston_view *view)
202{
203 float view_x, view_y;
204
205 assert(view_transformation_is_translation(view));
206
207 /* Convert from surface to global coordinates */
208 pixman_region32_copy(result_global, surf);
209 weston_view_to_global_float(view, 0, 0, &view_x, &view_y);
210 pixman_region32_translate(result_global, (int)view_x, (int)view_y);
211
212 pixman_region32_intersect(result_global, result_global, global);
213}
214
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200215static void
216composite_whole(pixman_op_t op,
217 pixman_image_t *src,
218 pixman_image_t *mask,
219 pixman_image_t *dest,
220 const pixman_transform_t *transform,
221 pixman_filter_t filter)
222{
223 int32_t dest_width;
224 int32_t dest_height;
225
226 dest_width = pixman_image_get_width(dest);
227 dest_height = pixman_image_get_height(dest);
228
229 pixman_image_set_transform(src, transform);
230 pixman_image_set_filter(src, filter, NULL, 0);
231
232 pixman_image_composite32(op, src, mask, dest,
233 0, 0, /* src_x, src_y */
234 0, 0, /* mask_x, mask_y */
235 0, 0, /* dest_x, dest_y */
236 dest_width, dest_height);
237}
238
239static void
240composite_clipped(pixman_image_t *src,
241 pixman_image_t *mask,
242 pixman_image_t *dest,
243 const pixman_transform_t *transform,
244 pixman_filter_t filter,
245 pixman_region32_t *src_clip)
246{
247 int n_box;
248 pixman_box32_t *boxes;
249 int32_t dest_width;
250 int32_t dest_height;
251 int src_stride;
252 int bitspp;
253 pixman_format_code_t src_format;
254 void *src_data;
255 int i;
256
257 /* Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
258 * a Pixman image produces (0,0,0,0) instead of discarding the
259 * fragment.
260 */
261
262 dest_width = pixman_image_get_width(dest);
263 dest_height = pixman_image_get_height(dest);
264 src_format = pixman_image_get_format(src);
265 src_stride = pixman_image_get_stride(src);
266 bitspp = PIXMAN_FORMAT_BPP(src_format);
267 src_data = pixman_image_get_data(src);
268
269 assert(src_format);
270
271 /* This would be massive overdraw, except when n_box is 1. */
272 boxes = pixman_region32_rectangles(src_clip, &n_box);
273 for (i = 0; i < n_box; i++) {
274 uint8_t *ptr = src_data;
275 pixman_image_t *boximg;
276 pixman_transform_t adj = *transform;
277
278 ptr += boxes[i].y1 * src_stride;
279 ptr += boxes[i].x1 * bitspp / 8;
280 boximg = pixman_image_create_bits_no_clear(src_format,
281 boxes[i].x2 - boxes[i].x1,
282 boxes[i].y2 - boxes[i].y1,
283 (uint32_t *)ptr, src_stride);
284
285 pixman_transform_translate(&adj, NULL,
286 pixman_int_to_fixed(-boxes[i].x1),
287 pixman_int_to_fixed(-boxes[i].y1));
288 pixman_image_set_transform(boximg, &adj);
289
290 pixman_image_set_filter(boximg, filter, NULL, 0);
291 pixman_image_composite32(PIXMAN_OP_OVER, boximg, mask, dest,
292 0, 0, /* src_x, src_y */
293 0, 0, /* mask_x, mask_y */
294 0, 0, /* dest_x, dest_y */
295 dest_width, dest_height);
296
297 pixman_image_unref(boximg);
298 }
299
300 if (n_box > 1) {
301 static bool warned = false;
302
303 if (!warned)
304 weston_log("Pixman-renderer warning: %dx overdraw\n",
305 n_box);
306 warned = true;
307 }
308}
309
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200310/** Paint an intersected region
311 *
312 * \param ev The view to be painted.
313 * \param output The output being painted.
314 * \param repaint_output The region to be painted in output coordinates.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200315 * \param source_clip The region of the source image to use, in source image
316 * coordinates. If NULL, use the whole source image.
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200317 * \param pixman_op Compositing operator, either SRC or OVER.
318 */
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200319static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500320repaint_region(struct weston_view *ev, struct weston_output *output,
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200321 pixman_region32_t *repaint_output,
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200322 pixman_region32_t *source_clip,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200323 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300324{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200325 struct pixman_renderer *pr =
326 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500327 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300328 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200329 struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
Pekka Paalanen26ded942018-04-23 11:44:57 +0200330 pixman_image_t *target_image;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200331 pixman_transform_t transform;
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200332 pixman_filter_t filter;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200333 pixman_image_t *mask_image;
334 pixman_color_t mask = { 0, };
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300335
Pekka Paalanen26ded942018-04-23 11:44:57 +0200336 if (po->shadow_image)
337 target_image = po->shadow_image;
338 else
339 target_image = po->hw_buffer;
340
341 /* Clip rendering to the damaged output region */
342 pixman_image_set_clip_region32(target_image, repaint_output);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200343
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200344 pixman_renderer_compute_transform(&transform, ev, output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200345
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200346 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200347 filter = PIXMAN_FILTER_BILINEAR;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200348 else
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200349 filter = PIXMAN_FILTER_NEAREST;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200350
Neil Robertse5051712013-11-13 15:44:06 +0000351 if (ps->buffer_ref.buffer)
352 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
353
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200354 if (ev->alpha < 1.0) {
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200355 mask.alpha = 0xffff * ev->alpha;
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200356 mask_image = pixman_image_create_solid_fill(&mask);
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200357 } else {
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200358 mask_image = NULL;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200359 }
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200360
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200361 if (source_clip)
Pekka Paalanen26ded942018-04-23 11:44:57 +0200362 composite_clipped(ps->image, mask_image, target_image,
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200363 &transform, filter, source_clip);
364 else
365 composite_whole(pixman_op, ps->image, mask_image,
Pekka Paalanen26ded942018-04-23 11:44:57 +0200366 target_image, &transform, filter);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200367
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200368 if (mask_image)
369 pixman_image_unref(mask_image);
370
Neil Robertse5051712013-11-13 15:44:06 +0000371 if (ps->buffer_ref.buffer)
372 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
373
Alexander Larsson1f206b42013-05-22 14:41:36 +0200374 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200375 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200376 pr->debug_color, /* src */
377 NULL /* mask */,
Pekka Paalanen26ded942018-04-23 11:44:57 +0200378 target_image, /* dest */
Alexander Larsson1f206b42013-05-22 14:41:36 +0200379 0, 0, /* src_x, src_y */
380 0, 0, /* mask_x, mask_y */
381 0, 0, /* dest_x, dest_y */
Pekka Paalanen26ded942018-04-23 11:44:57 +0200382 pixman_image_get_width (target_image), /* width */
383 pixman_image_get_height (target_image) /* height */);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200384
Pekka Paalanen26ded942018-04-23 11:44:57 +0200385 pixman_image_set_clip_region32(target_image, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300386}
387
388static void
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200389draw_view_translated(struct weston_view *view, struct weston_output *output,
390 pixman_region32_t *repaint_global)
391{
392 struct weston_surface *surface = view->surface;
393 /* non-opaque region in surface coordinates: */
394 pixman_region32_t surface_blend;
395 /* region to be painted in output coordinates: */
396 pixman_region32_t repaint_output;
397
398 pixman_region32_init(&repaint_output);
399
400 /* Blended region is whole surface minus opaque region,
401 * unless surface alpha forces us to blend all.
402 */
403 pixman_region32_init_rect(&surface_blend, 0, 0,
404 surface->width, surface->height);
405
406 if (!(view->alpha < 1.0)) {
407 pixman_region32_subtract(&surface_blend, &surface_blend,
408 &surface->opaque);
409
410 if (pixman_region32_not_empty(&surface->opaque)) {
411 region_intersect_only_translation(&repaint_output,
412 repaint_global,
413 &surface->opaque,
414 view);
415 region_global_to_output(output, &repaint_output);
416
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200417 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200418 PIXMAN_OP_SRC);
419 }
420 }
421
422 if (pixman_region32_not_empty(&surface_blend)) {
423 region_intersect_only_translation(&repaint_output,
424 repaint_global,
425 &surface_blend, view);
426 region_global_to_output(output, &repaint_output);
427
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200428 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200429 PIXMAN_OP_OVER);
430 }
431
432 pixman_region32_fini(&surface_blend);
433 pixman_region32_fini(&repaint_output);
434}
435
436static void
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200437draw_view_source_clipped(struct weston_view *view,
438 struct weston_output *output,
439 pixman_region32_t *repaint_global)
440{
441 struct weston_surface *surface = view->surface;
442 pixman_region32_t surf_region;
443 pixman_region32_t buffer_region;
444 pixman_region32_t repaint_output;
445
446 /* Do not bother separating the opaque region from non-opaque.
447 * Source clipping requires PIXMAN_OP_OVER in all cases, so painting
448 * opaque separately has no benefit.
449 */
450
451 pixman_region32_init_rect(&surf_region, 0, 0,
452 surface->width, surface->height);
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200453 if (view->geometry.scissor_enabled)
454 pixman_region32_intersect(&surf_region, &surf_region,
455 &view->geometry.scissor);
456
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200457 pixman_region32_init(&buffer_region);
458 weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
459
460 pixman_region32_init(&repaint_output);
461 pixman_region32_copy(&repaint_output, repaint_global);
462 region_global_to_output(output, &repaint_output);
463
464 repaint_region(view, output, &repaint_output, &buffer_region,
465 PIXMAN_OP_OVER);
466
467 pixman_region32_fini(&repaint_output);
468 pixman_region32_fini(&buffer_region);
469 pixman_region32_fini(&surf_region);
470}
471
472static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500473draw_view(struct weston_view *ev, struct weston_output *output,
474 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300475{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500476 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300477 /* repaint bounding region in global coordinates: */
478 pixman_region32_t repaint;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300479
480 /* No buffer attached */
481 if (!ps->image)
482 return;
483
484 pixman_region32_init(&repaint);
485 pixman_region32_intersect(&repaint,
Pekka Paalanen25c0ca52015-02-19 11:15:33 +0200486 &ev->transform.boundingbox, damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500487 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300488
489 if (!pixman_region32_not_empty(&repaint))
490 goto out;
491
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200492 if (view_transformation_is_translation(ev)) {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200493 /* The simple case: The surface regions opaque, non-opaque,
494 * etc. are convertible to global coordinate space.
495 * There is no need to use a source clip region.
496 * It is possible to paint opaque region as PIXMAN_OP_SRC.
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200497 * Also the boundingbox is accurate rather than an
498 * approximation.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200499 */
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200500 draw_view_translated(ev, output, &repaint);
501 } else {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200502 /* The complex case: the view transformation does not allow
503 * converting opaque etc. regions into global coordinate space.
504 * Therefore we need source clipping to avoid sampling from
505 * unwanted source image areas, unless the source image is
506 * to be used whole. Source clipping does not work with
507 * PIXMAN_OP_SRC.
508 */
509 draw_view_source_clipped(ev, output, &repaint);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300510 }
511
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300512out:
513 pixman_region32_fini(&repaint);
514}
515static void
516repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
517{
518 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500519 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300520
Jason Ekstranda7af7042013-10-12 22:38:11 -0500521 wl_list_for_each_reverse(view, &compositor->view_list, link)
522 if (view->plane == &compositor->primary_plane)
523 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300524}
525
526static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200527copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
528{
529 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200530 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200531
Alexander Larsson1f206b42013-05-22 14:41:36 +0200532 pixman_region32_init(&output_region);
533 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200534
Alexander Larsson1f206b42013-05-22 14:41:36 +0200535 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200536
Alexander Larsson1f206b42013-05-22 14:41:36 +0200537 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ryo Munakata389d2052014-09-04 01:56:53 +0900538 pixman_region32_fini(&output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200539
Alexander Larsson1f206b42013-05-22 14:41:36 +0200540 pixman_image_composite32(PIXMAN_OP_SRC,
541 po->shadow_image, /* src */
542 NULL /* mask */,
543 po->hw_buffer, /* dest */
544 0, 0, /* src_x, src_y */
545 0, 0, /* mask_x, mask_y */
546 0, 0, /* dest_x, dest_y */
547 pixman_image_get_width (po->hw_buffer), /* width */
548 pixman_image_get_height (po->hw_buffer) /* height */);
549
550 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200551}
552
553static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300554pixman_renderer_repaint_output(struct weston_output *output,
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200555 pixman_region32_t *output_damage)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300556{
557 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200558 pixman_region32_t hw_damage;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300559
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200560 if (!po->hw_buffer) {
561 po->hw_extra_damage = NULL;
562 return;
563 }
564
565 pixman_region32_init(&hw_damage);
566 if (po->hw_extra_damage) {
567 pixman_region32_union(&hw_damage,
568 po->hw_extra_damage, output_damage);
569 po->hw_extra_damage = NULL;
570 } else {
571 pixman_region32_copy(&hw_damage, output_damage);
572 }
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300573
Pekka Paalanen26ded942018-04-23 11:44:57 +0200574 if (po->shadow_image) {
575 repaint_surfaces(output, output_damage);
576 copy_to_hw_buffer(output, &hw_damage);
577 } else {
578 repaint_surfaces(output, &hw_damage);
579 }
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200580 pixman_region32_fini(&hw_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300581
Stefan Agner0bb94472019-12-09 13:26:57 +0100582 wl_signal_emit(&output->frame_signal, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300583
584 /* Actual flip should be done by caller */
585}
586
587static void
588pixman_renderer_flush_damage(struct weston_surface *surface)
589{
590 /* No-op for pixman renderer */
591}
592
593static void
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100594buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
595{
596 struct pixman_surface_state *ps;
597
598 ps = container_of(listener, struct pixman_surface_state,
599 buffer_destroy_listener);
600
601 if (ps->image) {
602 pixman_image_unref(ps->image);
603 ps->image = NULL;
604 }
605
606 ps->buffer_destroy_listener.notify = NULL;
607}
608
609static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500610pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300611{
612 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500613 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300614 pixman_format_code_t pixman_format;
615
616 weston_buffer_reference(&ps->buffer_ref, buffer);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300617 weston_buffer_release_reference(&ps->buffer_release_ref,
618 es->buffer_release_ref.buffer_release);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300619
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);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300638 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300639 return;
640 }
641
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500642 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300643 case WL_SHM_FORMAT_XRGB8888:
644 pixman_format = PIXMAN_x8r8g8b8;
Philipp Zabel195dade2018-09-03 19:44:59 +0200645 es->is_opaque = true;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300646 break;
647 case WL_SHM_FORMAT_ARGB8888:
648 pixman_format = PIXMAN_a8r8g8b8;
Philipp Zabel195dade2018-09-03 19:44:59 +0200649 es->is_opaque = false;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300650 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200651 case WL_SHM_FORMAT_RGB565:
652 pixman_format = PIXMAN_r5g6b5;
Philipp Zabel195dade2018-09-03 19:44:59 +0200653 es->is_opaque = true;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200654 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300655 default:
Vasilis Liaskovitis486b4632018-10-10 16:14:55 +0200656 weston_log("Unsupported SHM buffer format 0x%x\n",
657 wl_shm_buffer_get_format(shm_buffer));
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300658 weston_buffer_reference(&ps->buffer_ref, NULL);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300659 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
Vasilis Liaskovitis486b4632018-10-10 16:14:55 +0200660 weston_buffer_send_server_error(buffer,
661 "disconnecting due to unhandled buffer type");
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300662 return;
663 break;
664 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500665
666 buffer->shm_buffer = shm_buffer;
667 buffer->width = wl_shm_buffer_get_width(shm_buffer);
668 buffer->height = wl_shm_buffer_get_height(shm_buffer);
669
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300670 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500671 buffer->width, buffer->height,
672 wl_shm_buffer_get_data(shm_buffer),
673 wl_shm_buffer_get_stride(shm_buffer));
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100674
675 ps->buffer_destroy_listener.notify =
676 buffer_state_handle_buffer_destroy;
677 wl_signal_add(&buffer->destroy_signal,
678 &ps->buffer_destroy_listener);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300679}
680
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300681static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300682pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300683{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300684 wl_list_remove(&ps->surface_destroy_listener.link);
685 wl_list_remove(&ps->renderer_destroy_listener.link);
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100686 if (ps->buffer_destroy_listener.notify) {
687 wl_list_remove(&ps->buffer_destroy_listener.link);
688 ps->buffer_destroy_listener.notify = NULL;
689 }
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300690
691 ps->surface->renderer_state = NULL;
692
693 if (ps->image) {
694 pixman_image_unref(ps->image);
695 ps->image = NULL;
696 }
697 weston_buffer_reference(&ps->buffer_ref, NULL);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300698 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300699 free(ps);
700}
701
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300702static void
703surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
704{
705 struct pixman_surface_state *ps;
706
707 ps = container_of(listener, struct pixman_surface_state,
708 surface_destroy_listener);
709
710 pixman_renderer_surface_state_destroy(ps);
711}
712
713static void
714surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
715{
716 struct pixman_surface_state *ps;
717
718 ps = container_of(listener, struct pixman_surface_state,
719 renderer_destroy_listener);
720
721 pixman_renderer_surface_state_destroy(ps);
722}
723
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300724static int
725pixman_renderer_create_surface(struct weston_surface *surface)
726{
727 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300728 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300729
Bryce Harringtonde16d892014-11-20 22:21:57 -0800730 ps = zalloc(sizeof *ps);
731 if (ps == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300732 return -1;
733
734 surface->renderer_state = ps;
735
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300736 ps->surface = surface;
737
738 ps->surface_destroy_listener.notify =
739 surface_state_handle_surface_destroy;
740 wl_signal_add(&surface->destroy_signal,
741 &ps->surface_destroy_listener);
742
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300743 ps->renderer_destroy_listener.notify =
744 surface_state_handle_renderer_destroy;
745 wl_signal_add(&pr->destroy_signal,
746 &ps->renderer_destroy_listener);
747
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300748 return 0;
749}
750
751static void
752pixman_renderer_surface_set_color(struct weston_surface *es,
753 float red, float green, float blue, float alpha)
754{
755 struct pixman_surface_state *ps = get_surface_state(es);
756 pixman_color_t color;
757
758 color.red = red * 0xffff;
759 color.green = green * 0xffff;
760 color.blue = blue * 0xffff;
761 color.alpha = alpha * 0xffff;
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600762
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300763 if (ps->image) {
764 pixman_image_unref(ps->image);
765 ps->image = NULL;
766 }
767
768 ps->image = pixman_image_create_solid_fill(&color);
769}
770
771static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300772pixman_renderer_destroy(struct weston_compositor *ec)
773{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300774 struct pixman_renderer *pr = get_renderer(ec);
775
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300776 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300777 weston_binding_destroy(pr->debug_binding);
778 free(pr);
779
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300780 ec->renderer = NULL;
781}
782
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200783static void
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200784pixman_renderer_surface_get_content_size(struct weston_surface *surface,
785 int *width, int *height)
786{
787 struct pixman_surface_state *ps = get_surface_state(surface);
788
789 if (ps->image) {
790 *width = pixman_image_get_width(ps->image);
791 *height = pixman_image_get_height(ps->image);
792 } else {
793 *width = 0;
794 *height = 0;
795 }
796}
797
798static int
799pixman_renderer_surface_copy_content(struct weston_surface *surface,
800 void *target, size_t size,
801 int src_x, int src_y,
802 int width, int height)
803{
804 const pixman_format_code_t format = PIXMAN_a8b8g8r8;
805 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
806 struct pixman_surface_state *ps = get_surface_state(surface);
807 pixman_image_t *out_buf;
808
809 if (!ps->image)
810 return -1;
811
812 out_buf = pixman_image_create_bits(format, width, height,
813 target, width * bytespp);
814
815 pixman_image_set_transform(ps->image, NULL);
816 pixman_image_composite32(PIXMAN_OP_SRC,
817 ps->image, /* src */
818 NULL, /* mask */
819 out_buf, /* dest */
820 src_x, src_y, /* src_x, src_y */
821 0, 0, /* mask_x, mask_y */
822 0, 0, /* dest_x, dest_y */
823 width, height);
824
825 pixman_image_unref(out_buf);
826
827 return 0;
828}
829
830static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +0200831debug_binding(struct weston_keyboard *keyboard, const struct timespec *time,
832 uint32_t key, void *data)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200833{
834 struct weston_compositor *ec = data;
835 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
836
837 pr->repaint_debug ^= 1;
838
839 if (pr->repaint_debug) {
840 pixman_color_t red = {
841 0x3fff, 0x0000, 0x0000, 0x3fff
842 };
843
844 pr->debug_color = pixman_image_create_solid_fill(&red);
845 } else {
846 pixman_image_unref(pr->debug_color);
847 weston_compositor_damage_all(ec);
848 }
849}
850
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300851WL_EXPORT int
852pixman_renderer_init(struct weston_compositor *ec)
853{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200854 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300855
Bryce Harringtonde16d892014-11-20 22:21:57 -0800856 renderer = zalloc(sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300857 if (renderer == NULL)
858 return -1;
859
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100860 renderer->repaint_debug = 0;
861 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200862 renderer->base.read_pixels = pixman_renderer_read_pixels;
863 renderer->base.repaint_output = pixman_renderer_repaint_output;
864 renderer->base.flush_damage = pixman_renderer_flush_damage;
865 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200866 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200867 renderer->base.destroy = pixman_renderer_destroy;
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200868 renderer->base.surface_get_content_size =
869 pixman_renderer_surface_get_content_size;
870 renderer->base.surface_copy_content =
871 pixman_renderer_surface_copy_content;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200872 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300873 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200874 ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300875
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300876 renderer->debug_binding =
877 weston_compositor_add_debug_binding(ec, KEY_R,
878 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200879
880 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
881
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300882 wl_signal_init(&renderer->destroy_signal);
883
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300884 return 0;
885}
886
887WL_EXPORT void
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200888pixman_renderer_output_set_buffer(struct weston_output *output,
889 pixman_image_t *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300890{
891 struct pixman_output_state *po = get_output_state(output);
892
893 if (po->hw_buffer)
894 pixman_image_unref(po->hw_buffer);
895 po->hw_buffer = buffer;
896
897 if (po->hw_buffer) {
898 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
899 pixman_image_ref(po->hw_buffer);
900 }
901}
902
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200903WL_EXPORT void
904pixman_renderer_output_set_hw_extra_damage(struct weston_output *output,
905 pixman_region32_t *extra_damage)
906{
907 struct pixman_output_state *po = get_output_state(output);
908
909 po->hw_extra_damage = extra_damage;
910}
911
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300912WL_EXPORT int
Pekka Paalanen26ded942018-04-23 11:44:57 +0200913pixman_renderer_output_create(struct weston_output *output, uint32_t flags)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300914{
Bryce Harringtonde16d892014-11-20 22:21:57 -0800915 struct pixman_output_state *po;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200916 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300917
Bryce Harringtonde16d892014-11-20 22:21:57 -0800918 po = zalloc(sizeof *po);
919 if (po == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300920 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200921
Pekka Paalanen26ded942018-04-23 11:44:57 +0200922 if (flags & PIXMAN_RENDERER_OUTPUT_USE_SHADOW) {
923 /* set shadow image transformation */
924 w = output->current_mode->width;
925 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200926
Pekka Paalanen26ded942018-04-23 11:44:57 +0200927 po->shadow_buffer = malloc(w * h * 4);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200928
Pekka Paalanen26ded942018-04-23 11:44:57 +0200929 if (!po->shadow_buffer) {
930 free(po);
931 return -1;
932 }
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200933
Pekka Paalanen26ded942018-04-23 11:44:57 +0200934 po->shadow_image =
935 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
936 po->shadow_buffer, w * 4);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200937
Pekka Paalanen26ded942018-04-23 11:44:57 +0200938 if (!po->shadow_image) {
939 free(po->shadow_buffer);
940 free(po);
941 return -1;
942 }
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200943 }
944
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300945 output->renderer_state = po;
946
947 return 0;
948}
949
950WL_EXPORT void
951pixman_renderer_output_destroy(struct weston_output *output)
952{
953 struct pixman_output_state *po = get_output_state(output);
954
Pekka Paalanen26ded942018-04-23 11:44:57 +0200955 if (po->shadow_image)
956 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200957
958 if (po->hw_buffer)
959 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200960
Arnaud Vrac8e3fe082014-08-25 20:56:52 +0200961 free(po->shadow_buffer);
962
963 po->shadow_buffer = NULL;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200964 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300965 po->hw_buffer = NULL;
966
967 free(po);
968}