blob: 59b1f0ff225156b35ac2cdbc56be676be1eee66d [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
Pekka Paalanen9f53edd2020-03-11 15:21:04 +0200232 /* bilinear filtering needs the equivalent of OpenGL CLAMP_TO_EDGE */
233 if (filter == PIXMAN_FILTER_NEAREST)
234 pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
235 else
236 pixman_image_set_repeat(src, PIXMAN_REPEAT_PAD);
237
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200238 pixman_image_composite32(op, src, mask, dest,
239 0, 0, /* src_x, src_y */
240 0, 0, /* mask_x, mask_y */
241 0, 0, /* dest_x, dest_y */
242 dest_width, dest_height);
243}
244
245static void
246composite_clipped(pixman_image_t *src,
247 pixman_image_t *mask,
248 pixman_image_t *dest,
249 const pixman_transform_t *transform,
250 pixman_filter_t filter,
251 pixman_region32_t *src_clip)
252{
253 int n_box;
254 pixman_box32_t *boxes;
255 int32_t dest_width;
256 int32_t dest_height;
257 int src_stride;
258 int bitspp;
259 pixman_format_code_t src_format;
260 void *src_data;
261 int i;
262
Pekka Paalanen9f53edd2020-03-11 15:21:04 +0200263 /*
264 * Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200265 * a Pixman image produces (0,0,0,0) instead of discarding the
266 * fragment.
Pekka Paalanen9f53edd2020-03-11 15:21:04 +0200267 *
268 * Also repeat mode must be PIXMAN_REPEAT_NONE (the default) to
269 * actually sample (0,0,0,0). This may cause issues for clients that
270 * expect OpenGL CLAMP_TO_EDGE sampling behavior on their buffer.
271 * Using temporary 'boximg' it is not possible to apply CLAMP_TO_EDGE
272 * correctly with bilinear filter. Maybe trapezoid rendering could be
273 * the answer instead of source clip?
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200274 */
275
276 dest_width = pixman_image_get_width(dest);
277 dest_height = pixman_image_get_height(dest);
278 src_format = pixman_image_get_format(src);
279 src_stride = pixman_image_get_stride(src);
280 bitspp = PIXMAN_FORMAT_BPP(src_format);
281 src_data = pixman_image_get_data(src);
282
283 assert(src_format);
284
285 /* This would be massive overdraw, except when n_box is 1. */
286 boxes = pixman_region32_rectangles(src_clip, &n_box);
287 for (i = 0; i < n_box; i++) {
288 uint8_t *ptr = src_data;
289 pixman_image_t *boximg;
290 pixman_transform_t adj = *transform;
291
292 ptr += boxes[i].y1 * src_stride;
293 ptr += boxes[i].x1 * bitspp / 8;
294 boximg = pixman_image_create_bits_no_clear(src_format,
295 boxes[i].x2 - boxes[i].x1,
296 boxes[i].y2 - boxes[i].y1,
297 (uint32_t *)ptr, src_stride);
298
299 pixman_transform_translate(&adj, NULL,
300 pixman_int_to_fixed(-boxes[i].x1),
301 pixman_int_to_fixed(-boxes[i].y1));
302 pixman_image_set_transform(boximg, &adj);
303
304 pixman_image_set_filter(boximg, filter, NULL, 0);
305 pixman_image_composite32(PIXMAN_OP_OVER, boximg, mask, dest,
306 0, 0, /* src_x, src_y */
307 0, 0, /* mask_x, mask_y */
308 0, 0, /* dest_x, dest_y */
309 dest_width, dest_height);
310
311 pixman_image_unref(boximg);
312 }
313
314 if (n_box > 1) {
315 static bool warned = false;
316
317 if (!warned)
318 weston_log("Pixman-renderer warning: %dx overdraw\n",
319 n_box);
320 warned = true;
321 }
322}
323
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200324/** Paint an intersected region
325 *
326 * \param ev The view to be painted.
327 * \param output The output being painted.
328 * \param repaint_output The region to be painted in output coordinates.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200329 * \param source_clip The region of the source image to use, in source image
330 * coordinates. If NULL, use the whole source image.
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200331 * \param pixman_op Compositing operator, either SRC or OVER.
332 */
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200333static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500334repaint_region(struct weston_view *ev, struct weston_output *output,
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200335 pixman_region32_t *repaint_output,
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200336 pixman_region32_t *source_clip,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200337 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300338{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200339 struct pixman_renderer *pr =
340 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500341 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300342 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200343 struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
Pekka Paalanen26ded942018-04-23 11:44:57 +0200344 pixman_image_t *target_image;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200345 pixman_transform_t transform;
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200346 pixman_filter_t filter;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200347 pixman_image_t *mask_image;
348 pixman_color_t mask = { 0, };
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300349
Pekka Paalanen26ded942018-04-23 11:44:57 +0200350 if (po->shadow_image)
351 target_image = po->shadow_image;
352 else
353 target_image = po->hw_buffer;
354
355 /* Clip rendering to the damaged output region */
356 pixman_image_set_clip_region32(target_image, repaint_output);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200357
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200358 pixman_renderer_compute_transform(&transform, ev, output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200359
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200360 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200361 filter = PIXMAN_FILTER_BILINEAR;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200362 else
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200363 filter = PIXMAN_FILTER_NEAREST;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200364
Neil Robertse5051712013-11-13 15:44:06 +0000365 if (ps->buffer_ref.buffer)
366 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
367
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200368 if (ev->alpha < 1.0) {
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200369 mask.alpha = 0xffff * ev->alpha;
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200370 mask_image = pixman_image_create_solid_fill(&mask);
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200371 } else {
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200372 mask_image = NULL;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200373 }
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200374
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200375 if (source_clip)
Pekka Paalanen26ded942018-04-23 11:44:57 +0200376 composite_clipped(ps->image, mask_image, target_image,
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200377 &transform, filter, source_clip);
378 else
379 composite_whole(pixman_op, ps->image, mask_image,
Pekka Paalanen26ded942018-04-23 11:44:57 +0200380 target_image, &transform, filter);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200381
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200382 if (mask_image)
383 pixman_image_unref(mask_image);
384
Neil Robertse5051712013-11-13 15:44:06 +0000385 if (ps->buffer_ref.buffer)
386 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
387
Alexander Larsson1f206b42013-05-22 14:41:36 +0200388 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200389 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200390 pr->debug_color, /* src */
391 NULL /* mask */,
Pekka Paalanen26ded942018-04-23 11:44:57 +0200392 target_image, /* dest */
Alexander Larsson1f206b42013-05-22 14:41:36 +0200393 0, 0, /* src_x, src_y */
394 0, 0, /* mask_x, mask_y */
395 0, 0, /* dest_x, dest_y */
Pekka Paalanen26ded942018-04-23 11:44:57 +0200396 pixman_image_get_width (target_image), /* width */
397 pixman_image_get_height (target_image) /* height */);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200398
Pekka Paalanen26ded942018-04-23 11:44:57 +0200399 pixman_image_set_clip_region32(target_image, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300400}
401
402static void
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200403draw_view_translated(struct weston_view *view, struct weston_output *output,
404 pixman_region32_t *repaint_global)
405{
406 struct weston_surface *surface = view->surface;
407 /* non-opaque region in surface coordinates: */
408 pixman_region32_t surface_blend;
409 /* region to be painted in output coordinates: */
410 pixman_region32_t repaint_output;
411
412 pixman_region32_init(&repaint_output);
413
414 /* Blended region is whole surface minus opaque region,
415 * unless surface alpha forces us to blend all.
416 */
417 pixman_region32_init_rect(&surface_blend, 0, 0,
418 surface->width, surface->height);
419
420 if (!(view->alpha < 1.0)) {
421 pixman_region32_subtract(&surface_blend, &surface_blend,
422 &surface->opaque);
423
424 if (pixman_region32_not_empty(&surface->opaque)) {
425 region_intersect_only_translation(&repaint_output,
426 repaint_global,
427 &surface->opaque,
428 view);
429 region_global_to_output(output, &repaint_output);
430
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200431 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200432 PIXMAN_OP_SRC);
433 }
434 }
435
436 if (pixman_region32_not_empty(&surface_blend)) {
437 region_intersect_only_translation(&repaint_output,
438 repaint_global,
439 &surface_blend, view);
440 region_global_to_output(output, &repaint_output);
441
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200442 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200443 PIXMAN_OP_OVER);
444 }
445
446 pixman_region32_fini(&surface_blend);
447 pixman_region32_fini(&repaint_output);
448}
449
450static void
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200451draw_view_source_clipped(struct weston_view *view,
452 struct weston_output *output,
453 pixman_region32_t *repaint_global)
454{
455 struct weston_surface *surface = view->surface;
456 pixman_region32_t surf_region;
457 pixman_region32_t buffer_region;
458 pixman_region32_t repaint_output;
459
460 /* Do not bother separating the opaque region from non-opaque.
461 * Source clipping requires PIXMAN_OP_OVER in all cases, so painting
462 * opaque separately has no benefit.
463 */
464
465 pixman_region32_init_rect(&surf_region, 0, 0,
466 surface->width, surface->height);
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200467 if (view->geometry.scissor_enabled)
468 pixman_region32_intersect(&surf_region, &surf_region,
469 &view->geometry.scissor);
470
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200471 pixman_region32_init(&buffer_region);
472 weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
473
474 pixman_region32_init(&repaint_output);
475 pixman_region32_copy(&repaint_output, repaint_global);
476 region_global_to_output(output, &repaint_output);
477
478 repaint_region(view, output, &repaint_output, &buffer_region,
479 PIXMAN_OP_OVER);
480
481 pixman_region32_fini(&repaint_output);
482 pixman_region32_fini(&buffer_region);
483 pixman_region32_fini(&surf_region);
484}
485
486static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500487draw_view(struct weston_view *ev, struct weston_output *output,
488 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300489{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500490 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300491 /* repaint bounding region in global coordinates: */
492 pixman_region32_t repaint;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300493
494 /* No buffer attached */
495 if (!ps->image)
496 return;
497
498 pixman_region32_init(&repaint);
499 pixman_region32_intersect(&repaint,
Pekka Paalanen25c0ca52015-02-19 11:15:33 +0200500 &ev->transform.boundingbox, damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500501 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300502
503 if (!pixman_region32_not_empty(&repaint))
504 goto out;
505
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200506 if (view_transformation_is_translation(ev)) {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200507 /* The simple case: The surface regions opaque, non-opaque,
508 * etc. are convertible to global coordinate space.
509 * There is no need to use a source clip region.
510 * It is possible to paint opaque region as PIXMAN_OP_SRC.
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200511 * Also the boundingbox is accurate rather than an
512 * approximation.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200513 */
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200514 draw_view_translated(ev, output, &repaint);
515 } else {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200516 /* The complex case: the view transformation does not allow
517 * converting opaque etc. regions into global coordinate space.
518 * Therefore we need source clipping to avoid sampling from
519 * unwanted source image areas, unless the source image is
520 * to be used whole. Source clipping does not work with
521 * PIXMAN_OP_SRC.
522 */
523 draw_view_source_clipped(ev, output, &repaint);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300524 }
525
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300526out:
527 pixman_region32_fini(&repaint);
528}
529static void
530repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
531{
532 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500533 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300534
Jason Ekstranda7af7042013-10-12 22:38:11 -0500535 wl_list_for_each_reverse(view, &compositor->view_list, link)
536 if (view->plane == &compositor->primary_plane)
537 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300538}
539
540static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200541copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
542{
543 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200544 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200545
Alexander Larsson1f206b42013-05-22 14:41:36 +0200546 pixman_region32_init(&output_region);
547 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200548
Alexander Larsson1f206b42013-05-22 14:41:36 +0200549 region_global_to_output(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200550
Alexander Larsson1f206b42013-05-22 14:41:36 +0200551 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ryo Munakata389d2052014-09-04 01:56:53 +0900552 pixman_region32_fini(&output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200553
Alexander Larsson1f206b42013-05-22 14:41:36 +0200554 pixman_image_composite32(PIXMAN_OP_SRC,
555 po->shadow_image, /* src */
556 NULL /* mask */,
557 po->hw_buffer, /* dest */
558 0, 0, /* src_x, src_y */
559 0, 0, /* mask_x, mask_y */
560 0, 0, /* dest_x, dest_y */
561 pixman_image_get_width (po->hw_buffer), /* width */
562 pixman_image_get_height (po->hw_buffer) /* height */);
563
564 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200565}
566
567static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300568pixman_renderer_repaint_output(struct weston_output *output,
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200569 pixman_region32_t *output_damage)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300570{
571 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200572 pixman_region32_t hw_damage;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300573
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200574 if (!po->hw_buffer) {
575 po->hw_extra_damage = NULL;
576 return;
577 }
578
579 pixman_region32_init(&hw_damage);
580 if (po->hw_extra_damage) {
581 pixman_region32_union(&hw_damage,
582 po->hw_extra_damage, output_damage);
583 po->hw_extra_damage = NULL;
584 } else {
585 pixman_region32_copy(&hw_damage, output_damage);
586 }
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300587
Pekka Paalanen26ded942018-04-23 11:44:57 +0200588 if (po->shadow_image) {
589 repaint_surfaces(output, output_damage);
590 copy_to_hw_buffer(output, &hw_damage);
591 } else {
592 repaint_surfaces(output, &hw_damage);
593 }
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200594 pixman_region32_fini(&hw_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300595
Stefan Agner0bb94472019-12-09 13:26:57 +0100596 wl_signal_emit(&output->frame_signal, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300597
598 /* Actual flip should be done by caller */
599}
600
601static void
602pixman_renderer_flush_damage(struct weston_surface *surface)
603{
604 /* No-op for pixman renderer */
605}
606
607static void
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100608buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
609{
610 struct pixman_surface_state *ps;
611
612 ps = container_of(listener, struct pixman_surface_state,
613 buffer_destroy_listener);
614
615 if (ps->image) {
616 pixman_image_unref(ps->image);
617 ps->image = NULL;
618 }
619
620 ps->buffer_destroy_listener.notify = NULL;
621}
622
623static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500624pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300625{
626 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500627 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300628 pixman_format_code_t pixman_format;
629
630 weston_buffer_reference(&ps->buffer_ref, buffer);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300631 weston_buffer_release_reference(&ps->buffer_release_ref,
632 es->buffer_release_ref.buffer_release);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300633
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100634 if (ps->buffer_destroy_listener.notify) {
635 wl_list_remove(&ps->buffer_destroy_listener.link);
636 ps->buffer_destroy_listener.notify = NULL;
637 }
638
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300639 if (ps->image) {
640 pixman_image_unref(ps->image);
641 ps->image = NULL;
642 }
643
644 if (!buffer)
645 return;
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600646
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500647 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300648
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500649 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300650 weston_log("Pixman renderer supports only SHM buffers\n");
651 weston_buffer_reference(&ps->buffer_ref, NULL);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300652 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300653 return;
654 }
655
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500656 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300657 case WL_SHM_FORMAT_XRGB8888:
658 pixman_format = PIXMAN_x8r8g8b8;
Philipp Zabel195dade2018-09-03 19:44:59 +0200659 es->is_opaque = true;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300660 break;
661 case WL_SHM_FORMAT_ARGB8888:
662 pixman_format = PIXMAN_a8r8g8b8;
Philipp Zabel195dade2018-09-03 19:44:59 +0200663 es->is_opaque = false;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300664 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200665 case WL_SHM_FORMAT_RGB565:
666 pixman_format = PIXMAN_r5g6b5;
Philipp Zabel195dade2018-09-03 19:44:59 +0200667 es->is_opaque = true;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200668 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300669 default:
Vasilis Liaskovitis486b4632018-10-10 16:14:55 +0200670 weston_log("Unsupported SHM buffer format 0x%x\n",
671 wl_shm_buffer_get_format(shm_buffer));
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300672 weston_buffer_reference(&ps->buffer_ref, NULL);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300673 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
Vasilis Liaskovitis486b4632018-10-10 16:14:55 +0200674 weston_buffer_send_server_error(buffer,
675 "disconnecting due to unhandled buffer type");
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300676 return;
677 break;
678 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500679
680 buffer->shm_buffer = shm_buffer;
681 buffer->width = wl_shm_buffer_get_width(shm_buffer);
682 buffer->height = wl_shm_buffer_get_height(shm_buffer);
683
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300684 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500685 buffer->width, buffer->height,
686 wl_shm_buffer_get_data(shm_buffer),
687 wl_shm_buffer_get_stride(shm_buffer));
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100688
689 ps->buffer_destroy_listener.notify =
690 buffer_state_handle_buffer_destroy;
691 wl_signal_add(&buffer->destroy_signal,
692 &ps->buffer_destroy_listener);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300693}
694
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300695static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300696pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300697{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300698 wl_list_remove(&ps->surface_destroy_listener.link);
699 wl_list_remove(&ps->renderer_destroy_listener.link);
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100700 if (ps->buffer_destroy_listener.notify) {
701 wl_list_remove(&ps->buffer_destroy_listener.link);
702 ps->buffer_destroy_listener.notify = NULL;
703 }
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300704
705 ps->surface->renderer_state = NULL;
706
707 if (ps->image) {
708 pixman_image_unref(ps->image);
709 ps->image = NULL;
710 }
711 weston_buffer_reference(&ps->buffer_ref, NULL);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300712 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300713 free(ps);
714}
715
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300716static void
717surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
718{
719 struct pixman_surface_state *ps;
720
721 ps = container_of(listener, struct pixman_surface_state,
722 surface_destroy_listener);
723
724 pixman_renderer_surface_state_destroy(ps);
725}
726
727static void
728surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
729{
730 struct pixman_surface_state *ps;
731
732 ps = container_of(listener, struct pixman_surface_state,
733 renderer_destroy_listener);
734
735 pixman_renderer_surface_state_destroy(ps);
736}
737
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300738static int
739pixman_renderer_create_surface(struct weston_surface *surface)
740{
741 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300742 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300743
Bryce Harringtonde16d892014-11-20 22:21:57 -0800744 ps = zalloc(sizeof *ps);
745 if (ps == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300746 return -1;
747
748 surface->renderer_state = ps;
749
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300750 ps->surface = surface;
751
752 ps->surface_destroy_listener.notify =
753 surface_state_handle_surface_destroy;
754 wl_signal_add(&surface->destroy_signal,
755 &ps->surface_destroy_listener);
756
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300757 ps->renderer_destroy_listener.notify =
758 surface_state_handle_renderer_destroy;
759 wl_signal_add(&pr->destroy_signal,
760 &ps->renderer_destroy_listener);
761
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300762 return 0;
763}
764
765static void
766pixman_renderer_surface_set_color(struct weston_surface *es,
767 float red, float green, float blue, float alpha)
768{
769 struct pixman_surface_state *ps = get_surface_state(es);
770 pixman_color_t color;
771
772 color.red = red * 0xffff;
773 color.green = green * 0xffff;
774 color.blue = blue * 0xffff;
775 color.alpha = alpha * 0xffff;
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600776
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300777 if (ps->image) {
778 pixman_image_unref(ps->image);
779 ps->image = NULL;
780 }
781
782 ps->image = pixman_image_create_solid_fill(&color);
783}
784
785static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300786pixman_renderer_destroy(struct weston_compositor *ec)
787{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300788 struct pixman_renderer *pr = get_renderer(ec);
789
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300790 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300791 weston_binding_destroy(pr->debug_binding);
792 free(pr);
793
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300794 ec->renderer = NULL;
795}
796
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200797static void
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200798pixman_renderer_surface_get_content_size(struct weston_surface *surface,
799 int *width, int *height)
800{
801 struct pixman_surface_state *ps = get_surface_state(surface);
802
803 if (ps->image) {
804 *width = pixman_image_get_width(ps->image);
805 *height = pixman_image_get_height(ps->image);
806 } else {
807 *width = 0;
808 *height = 0;
809 }
810}
811
812static int
813pixman_renderer_surface_copy_content(struct weston_surface *surface,
814 void *target, size_t size,
815 int src_x, int src_y,
816 int width, int height)
817{
818 const pixman_format_code_t format = PIXMAN_a8b8g8r8;
819 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
820 struct pixman_surface_state *ps = get_surface_state(surface);
821 pixman_image_t *out_buf;
822
823 if (!ps->image)
824 return -1;
825
826 out_buf = pixman_image_create_bits(format, width, height,
827 target, width * bytespp);
828
829 pixman_image_set_transform(ps->image, NULL);
830 pixman_image_composite32(PIXMAN_OP_SRC,
831 ps->image, /* src */
832 NULL, /* mask */
833 out_buf, /* dest */
834 src_x, src_y, /* src_x, src_y */
835 0, 0, /* mask_x, mask_y */
836 0, 0, /* dest_x, dest_y */
837 width, height);
838
839 pixman_image_unref(out_buf);
840
841 return 0;
842}
843
844static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +0200845debug_binding(struct weston_keyboard *keyboard, const struct timespec *time,
846 uint32_t key, void *data)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200847{
848 struct weston_compositor *ec = data;
849 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
850
851 pr->repaint_debug ^= 1;
852
853 if (pr->repaint_debug) {
854 pixman_color_t red = {
855 0x3fff, 0x0000, 0x0000, 0x3fff
856 };
857
858 pr->debug_color = pixman_image_create_solid_fill(&red);
859 } else {
860 pixman_image_unref(pr->debug_color);
861 weston_compositor_damage_all(ec);
862 }
863}
864
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300865WL_EXPORT int
866pixman_renderer_init(struct weston_compositor *ec)
867{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200868 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300869
Bryce Harringtonde16d892014-11-20 22:21:57 -0800870 renderer = zalloc(sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300871 if (renderer == NULL)
872 return -1;
873
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100874 renderer->repaint_debug = 0;
875 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200876 renderer->base.read_pixels = pixman_renderer_read_pixels;
877 renderer->base.repaint_output = pixman_renderer_repaint_output;
878 renderer->base.flush_damage = pixman_renderer_flush_damage;
879 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200880 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200881 renderer->base.destroy = pixman_renderer_destroy;
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200882 renderer->base.surface_get_content_size =
883 pixman_renderer_surface_get_content_size;
884 renderer->base.surface_copy_content =
885 pixman_renderer_surface_copy_content;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200886 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300887 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200888 ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300889
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300890 renderer->debug_binding =
891 weston_compositor_add_debug_binding(ec, KEY_R,
892 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200893
894 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
895
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300896 wl_signal_init(&renderer->destroy_signal);
897
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300898 return 0;
899}
900
901WL_EXPORT void
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200902pixman_renderer_output_set_buffer(struct weston_output *output,
903 pixman_image_t *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300904{
905 struct pixman_output_state *po = get_output_state(output);
906
907 if (po->hw_buffer)
908 pixman_image_unref(po->hw_buffer);
909 po->hw_buffer = buffer;
910
911 if (po->hw_buffer) {
912 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
913 pixman_image_ref(po->hw_buffer);
914 }
915}
916
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200917WL_EXPORT void
918pixman_renderer_output_set_hw_extra_damage(struct weston_output *output,
919 pixman_region32_t *extra_damage)
920{
921 struct pixman_output_state *po = get_output_state(output);
922
923 po->hw_extra_damage = extra_damage;
924}
925
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300926WL_EXPORT int
Daniel Stone61abf352020-03-06 12:46:30 +0000927pixman_renderer_output_create(struct weston_output *output,
928 const struct pixman_renderer_output_options *options)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300929{
Bryce Harringtonde16d892014-11-20 22:21:57 -0800930 struct pixman_output_state *po;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200931 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300932
Bryce Harringtonde16d892014-11-20 22:21:57 -0800933 po = zalloc(sizeof *po);
934 if (po == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300935 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200936
Daniel Stone61abf352020-03-06 12:46:30 +0000937 if (options->use_shadow) {
Pekka Paalanen26ded942018-04-23 11:44:57 +0200938 /* set shadow image transformation */
939 w = output->current_mode->width;
940 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200941
Pekka Paalanen26ded942018-04-23 11:44:57 +0200942 po->shadow_buffer = malloc(w * h * 4);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200943
Pekka Paalanen26ded942018-04-23 11:44:57 +0200944 if (!po->shadow_buffer) {
945 free(po);
946 return -1;
947 }
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200948
Pekka Paalanen26ded942018-04-23 11:44:57 +0200949 po->shadow_image =
950 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
951 po->shadow_buffer, w * 4);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200952
Pekka Paalanen26ded942018-04-23 11:44:57 +0200953 if (!po->shadow_image) {
954 free(po->shadow_buffer);
955 free(po);
956 return -1;
957 }
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200958 }
959
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300960 output->renderer_state = po;
961
962 return 0;
963}
964
965WL_EXPORT void
966pixman_renderer_output_destroy(struct weston_output *output)
967{
968 struct pixman_output_state *po = get_output_state(output);
969
Pekka Paalanen26ded942018-04-23 11:44:57 +0200970 if (po->shadow_image)
971 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200972
973 if (po->hw_buffer)
974 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200975
Arnaud Vrac8e3fe082014-08-25 20:56:52 +0200976 free(po->shadow_buffer);
977
978 po->shadow_buffer = NULL;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200979 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300980 po->hw_buffer = NULL;
981
982 free(po);
983}