blob: bf73d0195d647937bf44da17291a886228555479 [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"
Pekka Paalanen90a5ffa2021-02-25 12:03:28 +020036#include "color.h"
Manuel Stoeckl8a7f1e22021-07-26 22:29:20 -040037#include "pixel-formats.h"
Jon Cruz867d50e2015-06-15 15:37:10 -070038#include "shared/helpers.h"
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030039
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020040#include <linux/input.h>
41
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030042struct pixman_output_state {
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +020043 void *shadow_buffer;
44 pixman_image_t *shadow_image;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030045 pixman_image_t *hw_buffer;
Pekka Paalanenacf50c32018-04-23 11:44:56 +020046 pixman_region32_t *hw_extra_damage;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030047};
48
49struct pixman_surface_state {
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030050 struct weston_surface *surface;
51
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030052 pixman_image_t *image;
53 struct weston_buffer_reference buffer_ref;
Alexandros Frantzis67629672018-10-19 12:14:11 +030054 struct weston_buffer_release_reference buffer_release_ref;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030055
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +010056 struct wl_listener buffer_destroy_listener;
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030057 struct wl_listener surface_destroy_listener;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030058 struct wl_listener renderer_destroy_listener;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030059};
60
61struct pixman_renderer {
62 struct weston_renderer base;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030063
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +020064 int repaint_debug;
65 pixman_image_t *debug_color;
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +030066 struct weston_binding *debug_binding;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +030067
68 struct wl_signal destroy_signal;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030069};
70
71static inline struct pixman_output_state *
72get_output_state(struct weston_output *output)
73{
74 return (struct pixman_output_state *)output->renderer_state;
75}
76
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030077static int
78pixman_renderer_create_surface(struct weston_surface *surface);
79
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030080static inline struct pixman_surface_state *
81get_surface_state(struct weston_surface *surface)
82{
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +030083 if (!surface->renderer_state)
84 pixman_renderer_create_surface(surface);
85
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +030086 return (struct pixman_surface_state *)surface->renderer_state;
87}
88
89static inline struct pixman_renderer *
90get_renderer(struct weston_compositor *ec)
91{
92 return (struct pixman_renderer *)ec->renderer;
93}
94
95static int
96pixman_renderer_read_pixels(struct weston_output *output,
97 pixman_format_code_t format, void *pixels,
98 uint32_t x, uint32_t y,
99 uint32_t width, uint32_t height)
100{
101 struct pixman_output_state *po = get_output_state(output);
102 pixman_image_t *out_buf;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300103
104 if (!po->hw_buffer) {
105 errno = ENODEV;
106 return -1;
107 }
108
109 out_buf = pixman_image_create_bits(format,
110 width,
111 height,
112 pixels,
113 (PIXMAN_FORMAT_BPP(format) / 8) * width);
114
Alexander Larsson97af7922013-05-29 12:01:33 +0200115 pixman_image_composite32(PIXMAN_OP_SRC,
116 po->hw_buffer, /* src */
117 NULL /* mask */,
118 out_buf, /* dest */
Stefan Agnerda2e5742019-06-16 23:28:15 +0200119 x, y, /* src_x, src_y */
Alexander Larsson97af7922013-05-29 12:01:33 +0200120 0, 0, /* mask_x, mask_y */
121 0, 0, /* dest_x, dest_y */
122 pixman_image_get_width (po->hw_buffer), /* width */
123 pixman_image_get_height (po->hw_buffer) /* height */);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300124
125 pixman_image_unref(out_buf);
126
127 return 0;
128}
129
Vasily Khoruzhickf4a457f2013-01-28 22:40:29 +0300130#define D2F(v) pixman_double_to_fixed((double)v)
131
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300132static void
Jason Ekstrand8870a232014-05-20 15:53:19 -0500133weston_matrix_to_pixman_transform(pixman_transform_t *pt,
134 const struct weston_matrix *wm)
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200135{
Jason Ekstrand8870a232014-05-20 15:53:19 -0500136 /* Pixman supports only 2D transform matrix, but Weston uses 3D, *
137 * so we're omitting Z coordinate here. */
138 pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
139 pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
140 pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
141 pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
142 pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
143 pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
144 pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
145 pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
146 pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
Pekka Paalanen0b4c5352014-03-14 14:38:17 +0200147}
148
149static void
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200150pixman_renderer_compute_transform(pixman_transform_t *transform_out,
151 struct weston_view *ev,
152 struct weston_output *output)
153{
154 struct weston_matrix matrix;
155
156 /* Set up the source transformation based on the surface
157 position, the output position/transform/scale and the client
158 specified buffer transform/scale */
Derek Foremana5855ad2015-03-24 11:36:16 -0500159 matrix = output->inverse_matrix;
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200160
161 if (ev->transform.enabled) {
162 weston_matrix_multiply(&matrix, &ev->transform.inverse);
163 } else {
164 weston_matrix_translate(&matrix,
165 -ev->geometry.x, -ev->geometry.y, 0);
166 }
167
168 weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
169
170 weston_matrix_to_pixman_transform(transform_out, &matrix);
171}
172
Pekka Paalanen23d4af52015-03-04 16:18:26 +0200173static bool
174view_transformation_is_translation(struct weston_view *view)
175{
176 if (!view->transform.enabled)
177 return true;
178
179 if (view->transform.matrix.type <= WESTON_MATRIX_TRANSFORM_TRANSLATE)
180 return true;
181
182 return false;
183}
184
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200185static void
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200186region_intersect_only_translation(pixman_region32_t *result_global,
187 pixman_region32_t *global,
188 pixman_region32_t *surf,
189 struct weston_view *view)
190{
191 float view_x, view_y;
192
193 assert(view_transformation_is_translation(view));
194
195 /* Convert from surface to global coordinates */
196 pixman_region32_copy(result_global, surf);
197 weston_view_to_global_float(view, 0, 0, &view_x, &view_y);
198 pixman_region32_translate(result_global, (int)view_x, (int)view_y);
199
200 pixman_region32_intersect(result_global, result_global, global);
201}
202
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200203static void
204composite_whole(pixman_op_t op,
205 pixman_image_t *src,
206 pixman_image_t *mask,
207 pixman_image_t *dest,
208 const pixman_transform_t *transform,
209 pixman_filter_t filter)
210{
211 int32_t dest_width;
212 int32_t dest_height;
213
214 dest_width = pixman_image_get_width(dest);
215 dest_height = pixman_image_get_height(dest);
216
217 pixman_image_set_transform(src, transform);
218 pixman_image_set_filter(src, filter, NULL, 0);
219
Pekka Paalanen9f53edd2020-03-11 15:21:04 +0200220 /* bilinear filtering needs the equivalent of OpenGL CLAMP_TO_EDGE */
221 if (filter == PIXMAN_FILTER_NEAREST)
222 pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
223 else
224 pixman_image_set_repeat(src, PIXMAN_REPEAT_PAD);
225
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200226 pixman_image_composite32(op, src, mask, dest,
227 0, 0, /* src_x, src_y */
228 0, 0, /* mask_x, mask_y */
229 0, 0, /* dest_x, dest_y */
230 dest_width, dest_height);
231}
232
233static void
234composite_clipped(pixman_image_t *src,
235 pixman_image_t *mask,
236 pixman_image_t *dest,
237 const pixman_transform_t *transform,
238 pixman_filter_t filter,
239 pixman_region32_t *src_clip)
240{
241 int n_box;
242 pixman_box32_t *boxes;
243 int32_t dest_width;
244 int32_t dest_height;
245 int src_stride;
246 int bitspp;
247 pixman_format_code_t src_format;
248 void *src_data;
249 int i;
250
Pekka Paalanen9f53edd2020-03-11 15:21:04 +0200251 /*
252 * Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200253 * a Pixman image produces (0,0,0,0) instead of discarding the
254 * fragment.
Pekka Paalanen9f53edd2020-03-11 15:21:04 +0200255 *
256 * Also repeat mode must be PIXMAN_REPEAT_NONE (the default) to
257 * actually sample (0,0,0,0). This may cause issues for clients that
258 * expect OpenGL CLAMP_TO_EDGE sampling behavior on their buffer.
259 * Using temporary 'boximg' it is not possible to apply CLAMP_TO_EDGE
260 * correctly with bilinear filter. Maybe trapezoid rendering could be
261 * the answer instead of source clip?
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200262 */
263
264 dest_width = pixman_image_get_width(dest);
265 dest_height = pixman_image_get_height(dest);
266 src_format = pixman_image_get_format(src);
267 src_stride = pixman_image_get_stride(src);
268 bitspp = PIXMAN_FORMAT_BPP(src_format);
269 src_data = pixman_image_get_data(src);
270
271 assert(src_format);
272
273 /* This would be massive overdraw, except when n_box is 1. */
274 boxes = pixman_region32_rectangles(src_clip, &n_box);
275 for (i = 0; i < n_box; i++) {
276 uint8_t *ptr = src_data;
277 pixman_image_t *boximg;
278 pixman_transform_t adj = *transform;
279
280 ptr += boxes[i].y1 * src_stride;
281 ptr += boxes[i].x1 * bitspp / 8;
282 boximg = pixman_image_create_bits_no_clear(src_format,
283 boxes[i].x2 - boxes[i].x1,
284 boxes[i].y2 - boxes[i].y1,
285 (uint32_t *)ptr, src_stride);
286
287 pixman_transform_translate(&adj, NULL,
288 pixman_int_to_fixed(-boxes[i].x1),
289 pixman_int_to_fixed(-boxes[i].y1));
290 pixman_image_set_transform(boximg, &adj);
291
292 pixman_image_set_filter(boximg, filter, NULL, 0);
293 pixman_image_composite32(PIXMAN_OP_OVER, boximg, mask, dest,
294 0, 0, /* src_x, src_y */
295 0, 0, /* mask_x, mask_y */
296 0, 0, /* dest_x, dest_y */
297 dest_width, dest_height);
298
299 pixman_image_unref(boximg);
300 }
301
302 if (n_box > 1) {
303 static bool warned = false;
304
305 if (!warned)
306 weston_log("Pixman-renderer warning: %dx overdraw\n",
307 n_box);
308 warned = true;
309 }
310}
311
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200312/** Paint an intersected region
313 *
314 * \param ev The view to be painted.
315 * \param output The output being painted.
316 * \param repaint_output The region to be painted in output coordinates.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200317 * \param source_clip The region of the source image to use, in source image
318 * coordinates. If NULL, use the whole source image.
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200319 * \param pixman_op Compositing operator, either SRC or OVER.
320 */
Pekka Paalanenf75b6bb2015-03-04 16:12:04 +0200321static void
Jason Ekstranda7af7042013-10-12 22:38:11 -0500322repaint_region(struct weston_view *ev, struct weston_output *output,
Pekka Paalanen11af0d92015-03-05 11:56:29 +0200323 pixman_region32_t *repaint_output,
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200324 pixman_region32_t *source_clip,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200325 pixman_op_t pixman_op)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300326{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200327 struct pixman_renderer *pr =
328 (struct pixman_renderer *) output->compositor->renderer;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500329 struct pixman_surface_state *ps = get_surface_state(ev->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300330 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200331 struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
Pekka Paalanen26ded942018-04-23 11:44:57 +0200332 pixman_image_t *target_image;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200333 pixman_transform_t transform;
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200334 pixman_filter_t filter;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200335 pixman_image_t *mask_image;
336 pixman_color_t mask = { 0, };
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300337
Pekka Paalanen26ded942018-04-23 11:44:57 +0200338 if (po->shadow_image)
339 target_image = po->shadow_image;
340 else
341 target_image = po->hw_buffer;
342
Dongjin Kimba89f002024-09-30 17:49:36 +0900343 /* Clip rendering to the damaged output region */
Pekka Paalanen26ded942018-04-23 11:44:57 +0200344 pixman_image_set_clip_region32(target_image, repaint_output);
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200345
Pekka Paalanen6ea523b2015-03-04 14:18:39 +0200346 pixman_renderer_compute_transform(&transform, ev, output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200347
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200348 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200349 filter = PIXMAN_FILTER_BILINEAR;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200350 else
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200351 filter = PIXMAN_FILTER_NEAREST;
Alexander Larsson1f206b42013-05-22 14:41:36 +0200352
Neil Robertse5051712013-11-13 15:44:06 +0000353 if (ps->buffer_ref.buffer)
354 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
355
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200356 if (ev->alpha < 1.0) {
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200357 mask.alpha = 0xffff * ev->alpha;
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200358 mask_image = pixman_image_create_solid_fill(&mask);
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200359 } else {
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200360 mask_image = NULL;
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200361 }
Manuel Bachmannb1fff412014-04-05 05:31:37 +0200362
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200363 if (source_clip)
Pekka Paalanen26ded942018-04-23 11:44:57 +0200364 composite_clipped(ps->image, mask_image, target_image,
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200365 &transform, filter, source_clip);
366 else
367 composite_whole(pixman_op, ps->image, mask_image,
Pekka Paalanen26ded942018-04-23 11:44:57 +0200368 target_image, &transform, filter);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200369
Manuel Bachmann9c4ab662014-04-07 11:58:45 +0200370 if (mask_image)
371 pixman_image_unref(mask_image);
372
Neil Robertse5051712013-11-13 15:44:06 +0000373 if (ps->buffer_ref.buffer)
374 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
375
Alexander Larsson1f206b42013-05-22 14:41:36 +0200376 if (pr->repaint_debug)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200377 pixman_image_composite32(PIXMAN_OP_OVER,
Alexander Larsson1f206b42013-05-22 14:41:36 +0200378 pr->debug_color, /* src */
379 NULL /* mask */,
Pekka Paalanen26ded942018-04-23 11:44:57 +0200380 target_image, /* dest */
Alexander Larsson1f206b42013-05-22 14:41:36 +0200381 0, 0, /* src_x, src_y */
382 0, 0, /* mask_x, mask_y */
383 0, 0, /* dest_x, dest_y */
Pekka Paalanen26ded942018-04-23 11:44:57 +0200384 pixman_image_get_width (target_image), /* width */
385 pixman_image_get_height (target_image) /* height */);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200386
Pekka Paalanen26ded942018-04-23 11:44:57 +0200387 pixman_image_set_clip_region32(target_image, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300388}
389
390static void
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200391draw_view_translated(struct weston_view *view, struct weston_output *output,
392 pixman_region32_t *repaint_global)
393{
394 struct weston_surface *surface = view->surface;
395 /* non-opaque region in surface coordinates: */
396 pixman_region32_t surface_blend;
397 /* region to be painted in output coordinates: */
398 pixman_region32_t repaint_output;
399
400 pixman_region32_init(&repaint_output);
401
402 /* Blended region is whole surface minus opaque region,
403 * unless surface alpha forces us to blend all.
404 */
405 pixman_region32_init_rect(&surface_blend, 0, 0,
406 surface->width, surface->height);
407
408 if (!(view->alpha < 1.0)) {
409 pixman_region32_subtract(&surface_blend, &surface_blend,
410 &surface->opaque);
411
412 if (pixman_region32_not_empty(&surface->opaque)) {
413 region_intersect_only_translation(&repaint_output,
414 repaint_global,
415 &surface->opaque,
416 view);
Pekka Paalanen06920792020-12-08 15:22:36 +0200417 weston_output_region_from_global(output,
418 &repaint_output);
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200419
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200420 repaint_region(view, output, &repaint_output, NULL,
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200421 PIXMAN_OP_SRC);
422 }
423 }
424
425 if (pixman_region32_not_empty(&surface_blend)) {
426 region_intersect_only_translation(&repaint_output,
427 repaint_global,
428 &surface_blend, view);
Pekka Paalanen06920792020-12-08 15:22:36 +0200429 weston_output_region_from_global(output, &repaint_output);
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200430
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_OVER);
433 }
434
435 pixman_region32_fini(&surface_blend);
436 pixman_region32_fini(&repaint_output);
437}
438
439static void
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200440draw_view_source_clipped(struct weston_view *view,
441 struct weston_output *output,
442 pixman_region32_t *repaint_global)
443{
444 struct weston_surface *surface = view->surface;
445 pixman_region32_t surf_region;
446 pixman_region32_t buffer_region;
447 pixman_region32_t repaint_output;
448
449 /* Do not bother separating the opaque region from non-opaque.
450 * Source clipping requires PIXMAN_OP_OVER in all cases, so painting
451 * opaque separately has no benefit.
452 */
453
454 pixman_region32_init_rect(&surf_region, 0, 0,
455 surface->width, surface->height);
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200456 if (view->geometry.scissor_enabled)
457 pixman_region32_intersect(&surf_region, &surf_region,
458 &view->geometry.scissor);
459
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200460 pixman_region32_init(&buffer_region);
461 weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
462
463 pixman_region32_init(&repaint_output);
464 pixman_region32_copy(&repaint_output, repaint_global);
Pekka Paalanen06920792020-12-08 15:22:36 +0200465 weston_output_region_from_global(output, &repaint_output);
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200466
467 repaint_region(view, output, &repaint_output, &buffer_region,
468 PIXMAN_OP_OVER);
469
470 pixman_region32_fini(&repaint_output);
471 pixman_region32_fini(&buffer_region);
472 pixman_region32_fini(&surf_region);
473}
474
475static void
Pekka Paalanen79885af2021-05-20 16:57:12 +0300476draw_paint_node(struct weston_paint_node *pnode,
477 pixman_region32_t *damage /* in global coordinates */)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300478{
Pekka Paalanen79885af2021-05-20 16:57:12 +0300479 struct pixman_surface_state *ps = get_surface_state(pnode->surface);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300480 /* repaint bounding region in global coordinates: */
481 pixman_region32_t repaint;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300482
Pekka Paalanen90a5ffa2021-02-25 12:03:28 +0200483 if (!pnode->surf_xform_valid)
484 return;
485
486 assert(pnode->surf_xform.transform == NULL);
487
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300488 /* No buffer attached */
489 if (!ps->image)
490 return;
491
492 pixman_region32_init(&repaint);
493 pixman_region32_intersect(&repaint,
Pekka Paalanen79885af2021-05-20 16:57:12 +0300494 &pnode->view->transform.boundingbox, damage);
495 pixman_region32_subtract(&repaint, &repaint, &pnode->view->clip);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300496
497 if (!pixman_region32_not_empty(&repaint))
498 goto out;
499
Pekka Paalanen79885af2021-05-20 16:57:12 +0300500 if (view_transformation_is_translation(pnode->view)) {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200501 /* The simple case: The surface regions opaque, non-opaque,
502 * etc. are convertible to global coordinate space.
503 * There is no need to use a source clip region.
504 * It is possible to paint opaque region as PIXMAN_OP_SRC.
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200505 * Also the boundingbox is accurate rather than an
506 * approximation.
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200507 */
Pekka Paalanen79885af2021-05-20 16:57:12 +0300508 draw_view_translated(pnode->view, pnode->output, &repaint);
Pekka Paalanenccf99ce2015-03-05 12:57:35 +0200509 } else {
Pekka Paalanend7ca6b02015-03-05 13:25:19 +0200510 /* The complex case: the view transformation does not allow
511 * converting opaque etc. regions into global coordinate space.
512 * Therefore we need source clipping to avoid sampling from
513 * unwanted source image areas, unless the source image is
514 * to be used whole. Source clipping does not work with
515 * PIXMAN_OP_SRC.
516 */
Pekka Paalanen79885af2021-05-20 16:57:12 +0300517 draw_view_source_clipped(pnode->view, pnode->output, &repaint);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300518 }
519
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300520out:
521 pixman_region32_fini(&repaint);
522}
523static void
524repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
525{
526 struct weston_compositor *compositor = output->compositor;
Pekka Paalanene02dbf62021-05-03 14:06:55 +0300527 struct weston_paint_node *pnode;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300528
Pekka Paalanene02dbf62021-05-03 14:06:55 +0300529 wl_list_for_each_reverse(pnode, &output->paint_node_z_order_list,
530 z_order_link) {
531 if (pnode->view->plane == &compositor->primary_plane)
Pekka Paalanen79885af2021-05-20 16:57:12 +0300532 draw_paint_node(pnode, damage);
Pekka Paalanene02dbf62021-05-03 14:06:55 +0300533 }
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300534}
535
536static void
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200537copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
538{
539 struct pixman_output_state *po = get_output_state(output);
Alexander Larsson1f206b42013-05-22 14:41:36 +0200540 pixman_region32_t output_region;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200541
Alexander Larsson1f206b42013-05-22 14:41:36 +0200542 pixman_region32_init(&output_region);
543 pixman_region32_copy(&output_region, region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200544
Pekka Paalanen06920792020-12-08 15:22:36 +0200545 weston_output_region_from_global(output, &output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200546
Alexander Larsson1f206b42013-05-22 14:41:36 +0200547 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
Ryo Munakata389d2052014-09-04 01:56:53 +0900548 pixman_region32_fini(&output_region);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200549
Alexander Larsson1f206b42013-05-22 14:41:36 +0200550 pixman_image_composite32(PIXMAN_OP_SRC,
551 po->shadow_image, /* src */
552 NULL /* mask */,
553 po->hw_buffer, /* dest */
554 0, 0, /* src_x, src_y */
555 0, 0, /* mask_x, mask_y */
556 0, 0, /* dest_x, dest_y */
557 pixman_image_get_width (po->hw_buffer), /* width */
558 pixman_image_get_height (po->hw_buffer) /* height */);
559
560 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200561}
562
563static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300564pixman_renderer_repaint_output(struct weston_output *output,
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200565 pixman_region32_t *output_damage)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300566{
567 struct pixman_output_state *po = get_output_state(output);
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200568 pixman_region32_t hw_damage;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300569
Pekka Paalanen1d2eee22021-02-25 12:03:28 +0200570 assert(output->from_blend_to_output_by_backend ||
571 output->from_blend_to_output == NULL);
572
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200573 if (!po->hw_buffer) {
574 po->hw_extra_damage = NULL;
Dongjin Kimba89f002024-09-30 17:49:36 +0900575 return;
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200576 }
577
578 pixman_region32_init(&hw_damage);
579 if (po->hw_extra_damage) {
580 pixman_region32_union(&hw_damage,
581 po->hw_extra_damage, output_damage);
582 po->hw_extra_damage = NULL;
583 } else {
584 pixman_region32_copy(&hw_damage, output_damage);
585 }
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300586
Pekka Paalanen26ded942018-04-23 11:44:57 +0200587 if (po->shadow_image) {
588 repaint_surfaces(output, output_damage);
589 copy_to_hw_buffer(output, &hw_damage);
590 } else {
591 repaint_surfaces(output, &hw_damage);
592 }
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200593 pixman_region32_fini(&hw_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300594
Stefan Agner0bb94472019-12-09 13:26:57 +0100595 wl_signal_emit(&output->frame_signal, output_damage);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300596
597 /* Actual flip should be done by caller */
598}
599
600static void
601pixman_renderer_flush_damage(struct weston_surface *surface)
602{
603 /* No-op for pixman renderer */
604}
605
606static void
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100607buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
608{
609 struct pixman_surface_state *ps;
610
611 ps = container_of(listener, struct pixman_surface_state,
612 buffer_destroy_listener);
613
614 if (ps->image) {
615 pixman_image_unref(ps->image);
616 ps->image = NULL;
617 }
618
619 ps->buffer_destroy_listener.notify = NULL;
620}
621
622static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500623pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300624{
625 struct pixman_surface_state *ps = get_surface_state(es);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500626 struct wl_shm_buffer *shm_buffer;
Manuel Stoeckl8a7f1e22021-07-26 22:29:20 -0400627 const struct pixel_format_info *pixel_info;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300628
629 weston_buffer_reference(&ps->buffer_ref, buffer);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300630 weston_buffer_release_reference(&ps->buffer_release_ref,
631 es->buffer_release_ref.buffer_release);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300632
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100633 if (ps->buffer_destroy_listener.notify) {
634 wl_list_remove(&ps->buffer_destroy_listener.link);
635 ps->buffer_destroy_listener.notify = NULL;
636 }
637
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300638 if (ps->image) {
639 pixman_image_unref(ps->image);
640 ps->image = NULL;
641 }
642
643 if (!buffer)
644 return;
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600645
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500646 shm_buffer = wl_shm_buffer_get(buffer->resource);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300647
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500648 if (! shm_buffer) {
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300649 weston_log("Pixman renderer supports only SHM buffers\n");
650 weston_buffer_reference(&ps->buffer_ref, NULL);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300651 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300652 return;
653 }
654
Manuel Stoeckl8a7f1e22021-07-26 22:29:20 -0400655 pixel_info = pixel_format_get_info_shm(wl_shm_buffer_get_format(shm_buffer));
656 if (!pixel_info || !pixman_format_supported_source(pixel_info->pixman_format)) {
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);
Emmanuel Gil Peyroteff793a2021-07-31 17:25:41 +0200661 weston_buffer_send_server_error(buffer,
Vasilis Liaskovitis486b4632018-10-10 16:14:55 +0200662 "disconnecting due to unhandled buffer type");
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300663 return;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300664 }
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500665
Manuel Stoeckl8a7f1e22021-07-26 22:29:20 -0400666 es->is_opaque = pixel_format_is_opaque(pixel_info);
667
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500668 buffer->shm_buffer = shm_buffer;
669 buffer->width = wl_shm_buffer_get_width(shm_buffer);
670 buffer->height = wl_shm_buffer_get_height(shm_buffer);
671
Manuel Stoeckl8a7f1e22021-07-26 22:29:20 -0400672 ps->image = pixman_image_create_bits(pixel_info->pixman_format,
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500673 buffer->width, buffer->height,
674 wl_shm_buffer_get_data(shm_buffer),
675 wl_shm_buffer_get_stride(shm_buffer));
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100676
677 ps->buffer_destroy_listener.notify =
678 buffer_state_handle_buffer_destroy;
679 wl_signal_add(&buffer->destroy_signal,
680 &ps->buffer_destroy_listener);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300681}
682
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300683static void
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300684pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300685{
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300686 wl_list_remove(&ps->surface_destroy_listener.link);
687 wl_list_remove(&ps->renderer_destroy_listener.link);
Lubomir Rintelddc2b1e2013-12-12 12:57:56 +0100688 if (ps->buffer_destroy_listener.notify) {
689 wl_list_remove(&ps->buffer_destroy_listener.link);
690 ps->buffer_destroy_listener.notify = NULL;
691 }
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300692
693 ps->surface->renderer_state = NULL;
694
695 if (ps->image) {
696 pixman_image_unref(ps->image);
697 ps->image = NULL;
698 }
699 weston_buffer_reference(&ps->buffer_ref, NULL);
Alexandros Frantzis67629672018-10-19 12:14:11 +0300700 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300701 free(ps);
702}
703
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300704static void
705surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
706{
707 struct pixman_surface_state *ps;
708
709 ps = container_of(listener, struct pixman_surface_state,
710 surface_destroy_listener);
711
712 pixman_renderer_surface_state_destroy(ps);
713}
714
715static void
716surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
717{
718 struct pixman_surface_state *ps;
719
720 ps = container_of(listener, struct pixman_surface_state,
721 renderer_destroy_listener);
722
723 pixman_renderer_surface_state_destroy(ps);
724}
725
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300726static int
727pixman_renderer_create_surface(struct weston_surface *surface)
728{
729 struct pixman_surface_state *ps;
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300730 struct pixman_renderer *pr = get_renderer(surface->compositor);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300731
Bryce Harringtonde16d892014-11-20 22:21:57 -0800732 ps = zalloc(sizeof *ps);
733 if (ps == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300734 return -1;
735
736 surface->renderer_state = ps;
737
Ander Conselvan de Oliveiraaa398ae2013-10-25 16:26:33 +0300738 ps->surface = surface;
739
740 ps->surface_destroy_listener.notify =
741 surface_state_handle_surface_destroy;
742 wl_signal_add(&surface->destroy_signal,
743 &ps->surface_destroy_listener);
744
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300745 ps->renderer_destroy_listener.notify =
746 surface_state_handle_renderer_destroy;
747 wl_signal_add(&pr->destroy_signal,
748 &ps->renderer_destroy_listener);
749
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300750 return 0;
751}
752
753static void
754pixman_renderer_surface_set_color(struct weston_surface *es,
755 float red, float green, float blue, float alpha)
756{
757 struct pixman_surface_state *ps = get_surface_state(es);
758 pixman_color_t color;
759
760 color.red = red * 0xffff;
761 color.green = green * 0xffff;
762 color.blue = blue * 0xffff;
763 color.alpha = alpha * 0xffff;
Jason Ekstrand52c476a2015-11-18 16:32:29 -0600764
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300765 if (ps->image) {
766 pixman_image_unref(ps->image);
767 ps->image = NULL;
768 }
769
770 ps->image = pixman_image_create_solid_fill(&color);
771}
772
773static void
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300774pixman_renderer_destroy(struct weston_compositor *ec)
775{
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300776 struct pixman_renderer *pr = get_renderer(ec);
777
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300778 wl_signal_emit(&pr->destroy_signal, pr);
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300779 weston_binding_destroy(pr->debug_binding);
780 free(pr);
781
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300782 ec->renderer = NULL;
783}
784
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200785static void
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200786pixman_renderer_surface_get_content_size(struct weston_surface *surface,
787 int *width, int *height)
788{
789 struct pixman_surface_state *ps = get_surface_state(surface);
790
791 if (ps->image) {
792 *width = pixman_image_get_width(ps->image);
793 *height = pixman_image_get_height(ps->image);
794 } else {
795 *width = 0;
796 *height = 0;
797 }
798}
799
800static int
801pixman_renderer_surface_copy_content(struct weston_surface *surface,
802 void *target, size_t size,
803 int src_x, int src_y,
804 int width, int height)
805{
806 const pixman_format_code_t format = PIXMAN_a8b8g8r8;
807 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
808 struct pixman_surface_state *ps = get_surface_state(surface);
809 pixman_image_t *out_buf;
810
811 if (!ps->image)
812 return -1;
813
814 out_buf = pixman_image_create_bits(format, width, height,
815 target, width * bytespp);
816
817 pixman_image_set_transform(ps->image, NULL);
818 pixman_image_composite32(PIXMAN_OP_SRC,
819 ps->image, /* src */
820 NULL, /* mask */
821 out_buf, /* dest */
822 src_x, src_y, /* src_x, src_y */
823 0, 0, /* mask_x, mask_y */
824 0, 0, /* dest_x, dest_y */
825 width, height);
826
827 pixman_image_unref(out_buf);
828
829 return 0;
830}
831
832static void
Alexandros Frantzis47e79c82017-11-16 18:20:57 +0200833debug_binding(struct weston_keyboard *keyboard, const struct timespec *time,
834 uint32_t key, void *data)
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200835{
836 struct weston_compositor *ec = data;
837 struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
838
839 pr->repaint_debug ^= 1;
840
841 if (pr->repaint_debug) {
842 pixman_color_t red = {
843 0x3fff, 0x0000, 0x0000, 0x3fff
844 };
845
846 pr->debug_color = pixman_image_create_solid_fill(&red);
847 } else {
848 pixman_image_unref(pr->debug_color);
849 weston_compositor_damage_all(ec);
850 }
851}
852
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300853WL_EXPORT int
854pixman_renderer_init(struct weston_compositor *ec)
855{
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200856 struct pixman_renderer *renderer;
Manuel Stoeckl8a7f1e22021-07-26 22:29:20 -0400857 const struct pixel_format_info *pixel_info, *info_argb8888, *info_xrgb8888;
858 unsigned int i, num_formats;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300859
Bryce Harringtonde16d892014-11-20 22:21:57 -0800860 renderer = zalloc(sizeof *renderer);
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300861 if (renderer == NULL)
862 return -1;
863
Philipp Brüschweilerf3e39f92013-03-08 20:35:39 +0100864 renderer->repaint_debug = 0;
865 renderer->debug_color = NULL;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200866 renderer->base.read_pixels = pixman_renderer_read_pixels;
867 renderer->base.repaint_output = pixman_renderer_repaint_output;
868 renderer->base.flush_damage = pixman_renderer_flush_damage;
869 renderer->base.attach = pixman_renderer_attach;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200870 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200871 renderer->base.destroy = pixman_renderer_destroy;
Pekka Paalanen6764bbe2015-02-11 12:29:56 +0200872 renderer->base.surface_get_content_size =
873 pixman_renderer_surface_get_content_size;
874 renderer->base.surface_copy_content =
875 pixman_renderer_surface_copy_content;
Ander Conselvan de Oliveira8792ef12013-01-25 15:13:00 +0200876 ec->renderer = &renderer->base;
Pekka Paalanen7bb65102013-05-22 18:03:04 +0300877 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
Pekka Paalanenc93782a2015-03-06 10:33:50 +0200878 ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300879
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +0300880 renderer->debug_binding =
881 weston_compositor_add_debug_binding(ec, KEY_R,
882 debug_binding, ec);
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200883
Manuel Stoeckl8a7f1e22021-07-26 22:29:20 -0400884 info_argb8888 = pixel_format_get_info_shm(WL_SHM_FORMAT_ARGB8888);
885 info_xrgb8888 = pixel_format_get_info_shm(WL_SHM_FORMAT_XRGB8888);
886
887 num_formats = pixel_format_get_info_count();
888 for (i = 0; i < num_formats; i++) {
889 pixel_info = pixel_format_get_info_by_index(i);
890 if (!pixman_format_supported_source(pixel_info->pixman_format))
891 continue;
892
893 /* skip formats which libwayland registers by default */
894 if (pixel_info == info_argb8888 || pixel_info == info_xrgb8888)
895 continue;
896
897 wl_display_add_shm_format(ec->wl_display, pixel_info->format);
898 }
Tomeu Vizoso1c1fc292013-08-06 20:05:56 +0200899
Ander Conselvan de Oliveiraadda00e2013-10-25 16:26:34 +0300900 wl_signal_init(&renderer->destroy_signal);
901
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300902 return 0;
903}
904
905WL_EXPORT void
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200906pixman_renderer_output_set_buffer(struct weston_output *output,
907 pixman_image_t *buffer)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300908{
909 struct pixman_output_state *po = get_output_state(output);
910
911 if (po->hw_buffer)
912 pixman_image_unref(po->hw_buffer);
913 po->hw_buffer = buffer;
914
915 if (po->hw_buffer) {
916 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
917 pixman_image_ref(po->hw_buffer);
918 }
919}
920
Pekka Paalanenacf50c32018-04-23 11:44:56 +0200921WL_EXPORT void
922pixman_renderer_output_set_hw_extra_damage(struct weston_output *output,
923 pixman_region32_t *extra_damage)
924{
925 struct pixman_output_state *po = get_output_state(output);
926
927 po->hw_extra_damage = extra_damage;
928}
929
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300930WL_EXPORT int
Daniel Stone61abf352020-03-06 12:46:30 +0000931pixman_renderer_output_create(struct weston_output *output,
932 const struct pixman_renderer_output_options *options)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300933{
Bryce Harringtonde16d892014-11-20 22:21:57 -0800934 struct pixman_output_state *po;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200935 int w, h;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300936
Bryce Harringtonde16d892014-11-20 22:21:57 -0800937 po = zalloc(sizeof *po);
938 if (po == NULL)
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300939 return -1;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200940
Daniel Stone61abf352020-03-06 12:46:30 +0000941 if (options->use_shadow) {
Pekka Paalanen26ded942018-04-23 11:44:57 +0200942 /* set shadow image transformation */
943 w = output->current_mode->width;
944 h = output->current_mode->height;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200945
Pekka Paalanen26ded942018-04-23 11:44:57 +0200946 po->shadow_buffer = malloc(w * h * 4);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200947
Pekka Paalanen26ded942018-04-23 11:44:57 +0200948 if (!po->shadow_buffer) {
949 free(po);
950 return -1;
951 }
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200952
Pekka Paalanen26ded942018-04-23 11:44:57 +0200953 po->shadow_image =
954 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
955 po->shadow_buffer, w * 4);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200956
Pekka Paalanen26ded942018-04-23 11:44:57 +0200957 if (!po->shadow_image) {
958 free(po->shadow_buffer);
959 free(po);
960 return -1;
961 }
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200962 }
963
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300964 output->renderer_state = po;
965
966 return 0;
967}
968
969WL_EXPORT void
970pixman_renderer_output_destroy(struct weston_output *output)
971{
972 struct pixman_output_state *po = get_output_state(output);
973
Pekka Paalanen26ded942018-04-23 11:44:57 +0200974 if (po->shadow_image)
975 pixman_image_unref(po->shadow_image);
Ander Conselvan de Oliveira23e72b82013-01-25 15:13:06 +0200976
977 if (po->hw_buffer)
978 pixman_image_unref(po->hw_buffer);
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200979
Arnaud Vrac8e3fe082014-08-25 20:56:52 +0200980 free(po->shadow_buffer);
981
982 po->shadow_buffer = NULL;
Ander Conselvan de Oliveira936effd2013-01-25 15:13:01 +0200983 po->shadow_image = NULL;
Vasily Khoruzhick71c2dd32013-01-07 20:39:49 +0300984 po->hw_buffer = NULL;
985
986 free(po);
987}