blob: 8cd650ca1b7f18ba8356873e079cd8bbed96cbe9 [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 Khoruzhickf4a457f2013-01-28 22:40:29 +0300128#define D2F(v) pixman_double_to_fixed((double)v)
129
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300130static void
Jason Ekstrand8870a232014-05-20 15:53:19 -0500131weston_matrix_to_pixman_transform(pixman_transform_t *pt,
132 const struct weston_matrix *wm)
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200133{
Jason Ekstrand8870a232014-05-20 15:53:19 -0500134 /* Pixman supports only 2D transform matrix, but Weston uses 3D, *
135 * so we're omitting Z coordinate here. */
136 pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
137 pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
138 pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
139 pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
140 pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
141 pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
142 pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
143 pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
144 pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200145}
146
147static void
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200148pixman_renderer_compute_transform(pixman_transform_t *transform_out,
149 struct weston_view *ev,
150 struct weston_output *output)
151{
152 struct weston_matrix matrix;
153
154 /* Set up the source transformation based on the surface
155 position, the output position/transform/scale and the client
156 specified buffer transform/scale */
Derek Foremana5855ad2015-03-24 11:36:16 -0500157 matrix = output->inverse_matrix;
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200158
159 if (ev->transform.enabled) {
160 weston_matrix_multiply(&matrix, &ev->transform.inverse);
161 } else {
162 weston_matrix_translate(&matrix,
163 -ev->geometry.x, -ev->geometry.y, 0);
164 }
165
166 weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
167
168 weston_matrix_to_pixman_transform(transform_out, &matrix);
169}
170
Pekka Paalanen23d4af52015-03-04 16:18:26 +0200171static bool
172view_transformation_is_translation(struct weston_view *view)
173{
174 if (!view->transform.enabled)
175 return true;
176
177 if (view->transform.matrix.type <= WESTON_MATRIX_TRANSFORM_TRANSLATE)
178 return true;
179
180 return false;
181}
182
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200183static void
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200184region_intersect_only_translation(pixman_region32_t *result_global,
185 pixman_region32_t *global,
186 pixman_region32_t *surf,
187 struct weston_view *view)
188{
189 float view_x, view_y;
190
191 assert(view_transformation_is_translation(view));
192
193 /* Convert from surface to global coordinates */
194 pixman_region32_copy(result_global, surf);
195 weston_view_to_global_float(view, 0, 0, &view_x, &view_y);
196 pixman_region32_translate(result_global, (int)view_x, (int)view_y);
197
198 pixman_region32_intersect(result_global, result_global, global);
199}
200
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200201static void
202composite_whole(pixman_op_t op,
203 pixman_image_t *src,
204 pixman_image_t *mask,
205 pixman_image_t *dest,
206 const pixman_transform_t *transform,
207 pixman_filter_t filter)
208{
209 int32_t dest_width;
210 int32_t dest_height;
211
212 dest_width = pixman_image_get_width(dest);
213 dest_height = pixman_image_get_height(dest);
214
215 pixman_image_set_transform(src, transform);
216 pixman_image_set_filter(src, filter, NULL, 0);
217
Pekka Paalanen9f53edd2020-03-11 15:21:04 +0200218 /* bilinear filtering needs the equivalent of OpenGL CLAMP_TO_EDGE */
219 if (filter == PIXMAN_FILTER_NEAREST)
220 pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
221 else
222 pixman_image_set_repeat(src, PIXMAN_REPEAT_PAD);
223
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200224 pixman_image_composite32(op, src, mask, dest,
225 0, 0, /* src_x, src_y */
226 0, 0, /* mask_x, mask_y */
227 0, 0, /* dest_x, dest_y */
228 dest_width, dest_height);
229}
230
231static void
232composite_clipped(pixman_image_t *src,
233 pixman_image_t *mask,
234 pixman_image_t *dest,
235 const pixman_transform_t *transform,
236 pixman_filter_t filter,
237 pixman_region32_t *src_clip)
238{
239 int n_box;
240 pixman_box32_t *boxes;
241 int32_t dest_width;
242 int32_t dest_height;
243 int src_stride;
244 int bitspp;
245 pixman_format_code_t src_format;
246 void *src_data;
247 int i;
248
Pekka Paalanen9f53edd2020-03-11 15:21:04 +0200249 /*
250 * Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200251 * a Pixman image produces (0,0,0,0) instead of discarding the
252 * fragment.
Pekka Paalanen9f53edd2020-03-11 15:21:04 +0200253 *
254 * Also repeat mode must be PIXMAN_REPEAT_NONE (the default) to
255 * actually sample (0,0,0,0). This may cause issues for clients that
256 * expect OpenGL CLAMP_TO_EDGE sampling behavior on their buffer.
257 * Using temporary 'boximg' it is not possible to apply CLAMP_TO_EDGE
258 * correctly with bilinear filter. Maybe trapezoid rendering could be
259 * the answer instead of source clip?
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200260 */
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);
Pekka Paalanen06920792020-12-08 15:22:36 +0200415 weston_output_region_from_global(output,
416 &repaint_output);
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200417
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200418 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200419 PIXMAN_OP_SRC);
420 }
421 }
422
423 if (pixman_region32_not_empty(&surface_blend)) {
424 region_intersect_only_translation(&repaint_output,
425 repaint_global,
426 &surface_blend, view);
Pekka Paalanen06920792020-12-08 15:22:36 +0200427 weston_output_region_from_global(output, &repaint_output);
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200428
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200429 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200430 PIXMAN_OP_OVER);
431 }
432
433 pixman_region32_fini(&surface_blend);
434 pixman_region32_fini(&repaint_output);
435}
436
437static void
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200438draw_view_source_clipped(struct weston_view *view,
439 struct weston_output *output,
440 pixman_region32_t *repaint_global)
441{
442 struct weston_surface *surface = view->surface;
443 pixman_region32_t surf_region;
444 pixman_region32_t buffer_region;
445 pixman_region32_t repaint_output;
446
447 /* Do not bother separating the opaque region from non-opaque.
448 * Source clipping requires PIXMAN_OP_OVER in all cases, so painting
449 * opaque separately has no benefit.
450 */
451
452 pixman_region32_init_rect(&surf_region, 0, 0,
453 surface->width, surface->height);
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200454 if (view->geometry.scissor_enabled)
455 pixman_region32_intersect(&surf_region, &surf_region,
456 &view->geometry.scissor);
457
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200458 pixman_region32_init(&buffer_region);
459 weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
460
461 pixman_region32_init(&repaint_output);
462 pixman_region32_copy(&repaint_output, repaint_global);
Pekka Paalanen06920792020-12-08 15:22:36 +0200463 weston_output_region_from_global(output, &repaint_output);
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200464
465 repaint_region(view, output, &repaint_output, &buffer_region,
466 PIXMAN_OP_OVER);
467
468 pixman_region32_fini(&repaint_output);
469 pixman_region32_fini(&buffer_region);
470 pixman_region32_fini(&surf_region);
471}
472
473static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500474draw_view(struct weston_view *ev, struct weston_output *output,
475 pixman_region32_t *damage) /* in global coordinates */
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300476{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500477 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300478 /* repaint bounding region in global coordinates: */
479 pixman_region32_t repaint;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300480
481 /* No buffer attached */
482 if (!ps->image)
483 return;
484
485 pixman_region32_init(&repaint);
486 pixman_region32_intersect(&repaint,
Pekka Paalanen25c0ca52015-02-19 11:15:33 +0200487 &ev->transform.boundingbox, damage);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500488 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300489
490 if (!pixman_region32_not_empty(&repaint))
491 goto out;
492
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200493 if (view_transformation_is_translation(ev)) {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200494 /* The simple case: The surface regions opaque, non-opaque,
495 * etc. are convertible to global coordinate space.
496 * There is no need to use a source clip region.
497 * It is possible to paint opaque region as PIXMAN_OP_SRC.
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200498 * Also the boundingbox is accurate rather than an
499 * approximation.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200500 */
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200501 draw_view_translated(ev, output, &repaint);
502 } else {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200503 /* The complex case: the view transformation does not allow
504 * converting opaque etc. regions into global coordinate space.
505 * Therefore we need source clipping to avoid sampling from
506 * unwanted source image areas, unless the source image is
507 * to be used whole. Source clipping does not work with
508 * PIXMAN_OP_SRC.
509 */
510 draw_view_source_clipped(ev, output, &repaint);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300511 }
512
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300513out:
514 pixman_region32_fini(&repaint);
515}
516static void
517repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
518{
519 struct weston_compositor *compositor = output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500520 struct weston_view *view;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300521
Jason Ekstranda7af7042013-10-12 22:38:11 -0500522 wl_list_for_each_reverse(view, &compositor->view_list, link)
523 if (view->plane == &compositor->primary_plane)
524 draw_view(view, output, damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300525}
526
527static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200528copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
529{
530 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200531 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200532
Alexander Larsson1f206b42013-05-22 14:41:36 +0200533 pixman_region32_init(&output_region);
534 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200535
Pekka Paalanen06920792020-12-08 15:22:36 +0200536 weston_output_region_from_global(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200537
Alexander Larsson1f206b42013-05-22 14:41:36 +0200538 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ryo Munakata389d2052014-09-04 01:56:53 +0900539 pixman_region32_fini(&output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200540
Alexander Larsson1f206b42013-05-22 14:41:36 +0200541 pixman_image_composite32(PIXMAN_OP_SRC,
542 po->shadow_image, /* src */
543 NULL /* mask */,
544 po->hw_buffer, /* dest */
545 0, 0, /* src_x, src_y */
546 0, 0, /* mask_x, mask_y */
547 0, 0, /* dest_x, dest_y */
548 pixman_image_get_width (po->hw_buffer), /* width */
549 pixman_image_get_height (po->hw_buffer) /* height */);
550
551 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200552}
553
554static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300555pixman_renderer_repaint_output(struct weston_output *output,
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200556 pixman_region32_t *output_damage)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300557{
558 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200559 pixman_region32_t hw_damage;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300560
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200561 if (!po->hw_buffer) {
562 po->hw_extra_damage = NULL;
563 return;
564 }
565
566 pixman_region32_init(&hw_damage);
567 if (po->hw_extra_damage) {
568 pixman_region32_union(&hw_damage,
569 po->hw_extra_damage, output_damage);
570 po->hw_extra_damage = NULL;
571 } else {
572 pixman_region32_copy(&hw_damage, output_damage);
573 }
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300574
Pekka Paalanen26ded942018-04-23 11:44:57 +0200575 if (po->shadow_image) {
576 repaint_surfaces(output, output_damage);
577 copy_to_hw_buffer(output, &hw_damage);
578 } else {
579 repaint_surfaces(output, &hw_damage);
580 }
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200581 pixman_region32_fini(&hw_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300582
Stefan Agner0bb94472019-12-09 13:26:57 +0100583 wl_signal_emit(&output->frame_signal, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300584
585 /* Actual flip should be done by caller */
586}
587
588static void
589pixman_renderer_flush_damage(struct weston_surface *surface)
590{
591 /* No-op for pixman renderer */
592}
593
594static void
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100595buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
596{
597 struct pixman_surface_state *ps;
598
599 ps = container_of(listener, struct pixman_surface_state,
600 buffer_destroy_listener);
601
602 if (ps->image) {
603 pixman_image_unref(ps->image);
604 ps->image = NULL;
605 }
606
607 ps->buffer_destroy_listener.notify = NULL;
608}
609
610static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500611pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300612{
613 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500614 struct wl_shm_buffer *shm_buffer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300615 pixman_format_code_t pixman_format;
616
617 weston_buffer_reference(&ps->buffer_ref, buffer);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300618 weston_buffer_release_reference(&ps->buffer_release_ref,
619 es->buffer_release_ref.buffer_release);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300620
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100621 if (ps->buffer_destroy_listener.notify) {
622 wl_list_remove(&ps->buffer_destroy_listener.link);
623 ps->buffer_destroy_listener.notify = NULL;
624 }
625
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300626 if (ps->image) {
627 pixman_image_unref(ps->image);
628 ps->image = NULL;
629 }
630
631 if (!buffer)
632 return;
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600633
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500634 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300635
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500636 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300637 weston_log("Pixman renderer supports only SHM buffers\n");
638 weston_buffer_reference(&ps->buffer_ref, NULL);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300639 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300640 return;
641 }
642
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500643 switch (wl_shm_buffer_get_format(shm_buffer)) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300644 case WL_SHM_FORMAT_XRGB8888:
645 pixman_format = PIXMAN_x8r8g8b8;
Philipp Zabel195dade2018-09-03 19:44:59 +0200646 es->is_opaque = true;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300647 break;
648 case WL_SHM_FORMAT_ARGB8888:
649 pixman_format = PIXMAN_a8r8g8b8;
Philipp Zabel195dade2018-09-03 19:44:59 +0200650 es->is_opaque = false;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300651 break;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200652 case WL_SHM_FORMAT_RGB565:
653 pixman_format = PIXMAN_r5g6b5;
Philipp Zabel195dade2018-09-03 19:44:59 +0200654 es->is_opaque = true;
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200655 break;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300656 default:
Vasilis Liaskovitis486b4632018-10-10 16:14:55 +0200657 weston_log("Unsupported SHM buffer format 0x%x\n",
658 wl_shm_buffer_get_format(shm_buffer));
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300659 weston_buffer_reference(&ps->buffer_ref, NULL);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300660 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
Vasilis Liaskovitis486b4632018-10-10 16:14:55 +0200661 weston_buffer_send_server_error(buffer,
662 "disconnecting due to unhandled buffer type");
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300663 return;
664 break;
665 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500666
667 buffer->shm_buffer = shm_buffer;
668 buffer->width = wl_shm_buffer_get_width(shm_buffer);
669 buffer->height = wl_shm_buffer_get_height(shm_buffer);
670
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300671 ps->image = pixman_image_create_bits(pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500672 buffer->width, buffer->height,
673 wl_shm_buffer_get_data(shm_buffer),
674 wl_shm_buffer_get_stride(shm_buffer));
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100675
676 ps->buffer_destroy_listener.notify =
677 buffer_state_handle_buffer_destroy;
678 wl_signal_add(&buffer->destroy_signal,
679 &ps->buffer_destroy_listener);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300680}
681
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300682static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300683pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300684{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300685 wl_list_remove(&ps->surface_destroy_listener.link);
686 wl_list_remove(&ps->renderer_destroy_listener.link);
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100687 if (ps->buffer_destroy_listener.notify) {
688 wl_list_remove(&ps->buffer_destroy_listener.link);
689 ps->buffer_destroy_listener.notify = NULL;
690 }
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300691
692 ps->surface->renderer_state = NULL;
693
694 if (ps->image) {
695 pixman_image_unref(ps->image);
696 ps->image = NULL;
697 }
698 weston_buffer_reference(&ps->buffer_ref, NULL);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300699 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300700 free(ps);
701}
702
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300703static void
704surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
705{
706 struct pixman_surface_state *ps;
707
708 ps = container_of(listener, struct pixman_surface_state,
709 surface_destroy_listener);
710
711 pixman_renderer_surface_state_destroy(ps);
712}
713
714static void
715surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
716{
717 struct pixman_surface_state *ps;
718
719 ps = container_of(listener, struct pixman_surface_state,
720 renderer_destroy_listener);
721
722 pixman_renderer_surface_state_destroy(ps);
723}
724
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300725static int
726pixman_renderer_create_surface(struct weston_surface *surface)
727{
728 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300729 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300730
Bryce Harringtonde16d892014-11-20 22:21:57 -0800731 ps = zalloc(sizeof *ps);
732 if (ps == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300733 return -1;
734
735 surface->renderer_state = ps;
736
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300737 ps->surface = surface;
738
739 ps->surface_destroy_listener.notify =
740 surface_state_handle_surface_destroy;
741 wl_signal_add(&surface->destroy_signal,
742 &ps->surface_destroy_listener);
743
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300744 ps->renderer_destroy_listener.notify =
745 surface_state_handle_renderer_destroy;
746 wl_signal_add(&pr->destroy_signal,
747 &ps->renderer_destroy_listener);
748
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300749 return 0;
750}
751
752static void
753pixman_renderer_surface_set_color(struct weston_surface *es,
754 float red, float green, float blue, float alpha)
755{
756 struct pixman_surface_state *ps = get_surface_state(es);
757 pixman_color_t color;
758
759 color.red = red * 0xffff;
760 color.green = green * 0xffff;
761 color.blue = blue * 0xffff;
762 color.alpha = alpha * 0xffff;
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600763
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300764 if (ps->image) {
765 pixman_image_unref(ps->image);
766 ps->image = NULL;
767 }
768
769 ps->image = pixman_image_create_solid_fill(&color);
770}
771
772static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300773pixman_renderer_destroy(struct weston_compositor *ec)
774{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300775 struct pixman_renderer *pr = get_renderer(ec);
776
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300777 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300778 weston_binding_destroy(pr->debug_binding);
779 free(pr);
780
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300781 ec->renderer = NULL;
782}
783
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200784static void
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200785pixman_renderer_surface_get_content_size(struct weston_surface *surface,
786 int *width, int *height)
787{
788 struct pixman_surface_state *ps = get_surface_state(surface);
789
790 if (ps->image) {
791 *width = pixman_image_get_width(ps->image);
792 *height = pixman_image_get_height(ps->image);
793 } else {
794 *width = 0;
795 *height = 0;
796 }
797}
798
799static int
800pixman_renderer_surface_copy_content(struct weston_surface *surface,
801 void *target, size_t size,
802 int src_x, int src_y,
803 int width, int height)
804{
805 const pixman_format_code_t format = PIXMAN_a8b8g8r8;
806 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
807 struct pixman_surface_state *ps = get_surface_state(surface);
808 pixman_image_t *out_buf;
809
810 if (!ps->image)
811 return -1;
812
813 out_buf = pixman_image_create_bits(format, width, height,
814 target, width * bytespp);
815
816 pixman_image_set_transform(ps->image, NULL);
817 pixman_image_composite32(PIXMAN_OP_SRC,
818 ps->image, /* src */
819 NULL, /* mask */
820 out_buf, /* dest */
821 src_x, src_y, /* src_x, src_y */
822 0, 0, /* mask_x, mask_y */
823 0, 0, /* dest_x, dest_y */
824 width, height);
825
826 pixman_image_unref(out_buf);
827
828 return 0;
829}
830
831static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +0200832debug_binding(struct weston_keyboard *keyboard, const struct timespec *time,
833 uint32_t key, void *data)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200834{
835 struct weston_compositor *ec = data;
836 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
837
838 pr->repaint_debug ^= 1;
839
840 if (pr->repaint_debug) {
841 pixman_color_t red = {
842 0x3fff, 0x0000, 0x0000, 0x3fff
843 };
844
845 pr->debug_color = pixman_image_create_solid_fill(&red);
846 } else {
847 pixman_image_unref(pr->debug_color);
848 weston_compositor_damage_all(ec);
849 }
850}
851
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300852WL_EXPORT int
853pixman_renderer_init(struct weston_compositor *ec)
854{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200855 struct pixman_renderer *renderer;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300856
Bryce Harringtonde16d892014-11-20 22:21:57 -0800857 renderer = zalloc(sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300858 if (renderer == NULL)
859 return -1;
860
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100861 renderer->repaint_debug = 0;
862 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200863 renderer->base.read_pixels = pixman_renderer_read_pixels;
864 renderer->base.repaint_output = pixman_renderer_repaint_output;
865 renderer->base.flush_damage = pixman_renderer_flush_damage;
866 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200867 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200868 renderer->base.destroy = pixman_renderer_destroy;
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200869 renderer->base.surface_get_content_size =
870 pixman_renderer_surface_get_content_size;
871 renderer->base.surface_copy_content =
872 pixman_renderer_surface_copy_content;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200873 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300874 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200875 ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300876
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300877 renderer->debug_binding =
878 weston_compositor_add_debug_binding(ec, KEY_R,
879 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200880
881 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
882
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300883 wl_signal_init(&renderer->destroy_signal);
884
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300885 return 0;
886}
887
888WL_EXPORT void
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200889pixman_renderer_output_set_buffer(struct weston_output *output,
890 pixman_image_t *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300891{
892 struct pixman_output_state *po = get_output_state(output);
893
894 if (po->hw_buffer)
895 pixman_image_unref(po->hw_buffer);
896 po->hw_buffer = buffer;
897
898 if (po->hw_buffer) {
899 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
900 pixman_image_ref(po->hw_buffer);
901 }
902}
903
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200904WL_EXPORT void
905pixman_renderer_output_set_hw_extra_damage(struct weston_output *output,
906 pixman_region32_t *extra_damage)
907{
908 struct pixman_output_state *po = get_output_state(output);
909
910 po->hw_extra_damage = extra_damage;
911}
912
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300913WL_EXPORT int
Daniel Stone61abf352020-03-06 12:46:30 +0000914pixman_renderer_output_create(struct weston_output *output,
915 const struct pixman_renderer_output_options *options)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300916{
Bryce Harringtonde16d892014-11-20 22:21:57 -0800917 struct pixman_output_state *po;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200918 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300919
Bryce Harringtonde16d892014-11-20 22:21:57 -0800920 po = zalloc(sizeof *po);
921 if (po == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300922 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200923
Daniel Stone61abf352020-03-06 12:46:30 +0000924 if (options->use_shadow) {
Pekka Paalanen26ded942018-04-23 11:44:57 +0200925 /* set shadow image transformation */
926 w = output->current_mode->width;
927 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200928
Pekka Paalanen26ded942018-04-23 11:44:57 +0200929 po->shadow_buffer = malloc(w * h * 4);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200930
Pekka Paalanen26ded942018-04-23 11:44:57 +0200931 if (!po->shadow_buffer) {
932 free(po);
933 return -1;
934 }
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200935
Pekka Paalanen26ded942018-04-23 11:44:57 +0200936 po->shadow_image =
937 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
938 po->shadow_buffer, w * 4);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200939
Pekka Paalanen26ded942018-04-23 11:44:57 +0200940 if (!po->shadow_image) {
941 free(po->shadow_buffer);
942 free(po);
943 return -1;
944 }
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200945 }
946
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300947 output->renderer_state = po;
948
949 return 0;
950}
951
952WL_EXPORT void
953pixman_renderer_output_destroy(struct weston_output *output)
954{
955 struct pixman_output_state *po = get_output_state(output);
956
Pekka Paalanen26ded942018-04-23 11:44:57 +0200957 if (po->shadow_image)
958 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200959
960 if (po->hw_buffer)
961 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200962
Arnaud Vrac8e3fe082014-08-25 20:56:52 +0200963 free(po->shadow_buffer);
964
965 po->shadow_buffer = NULL;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200966 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300967 po->hw_buffer = NULL;
968
969 free(po);
970}