1 /*
2 * Copyright © 2012 Intel Corporation
3 * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
4 * Copyright © 2015 Collabora, Ltd.
5 *
6 * 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:
13 *
14 * 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.
26 */
27
28 #include "config.h"
29
30 #include <errno.h>
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <assert.h>
34
35 #include "pixman-renderer.h"
36 #include "pixman-renderer-protected.h"
37 #include "shared/helpers.h"
38
39 #include <linux/input.h>
40
41 #include "tde-render-part.h"
42
43 static int
44 pixman_renderer_create_surface(struct weston_surface *surface);
45
46 struct pixman_output_state *
get_output_state(struct weston_output * output)47 get_output_state(struct weston_output *output)
48 {
49 return (struct pixman_output_state *)output->renderer_state;
50 }
51
52 static int
53 pixman_renderer_create_surface(struct weston_surface *surface);
54
55 struct pixman_surface_state *
get_surface_state(struct weston_surface * surface)56 get_surface_state(struct weston_surface *surface)
57 {
58 if (!surface->renderer_state)
59 pixman_renderer_create_surface(surface);
60
61 return (struct pixman_surface_state *)surface->renderer_state;
62 }
63
64 struct pixman_renderer *
get_renderer(struct weston_compositor * ec)65 get_renderer(struct weston_compositor *ec)
66 {
67 return (struct pixman_renderer *)ec->renderer;
68 }
69
70 static int
pixman_renderer_read_pixels(struct weston_output * output,pixman_format_code_t format,void * pixels,uint32_t x,uint32_t y,uint32_t width,uint32_t height)71 pixman_renderer_read_pixels(struct weston_output *output,
72 pixman_format_code_t format, void *pixels,
73 uint32_t x, uint32_t y,
74 uint32_t width, uint32_t height)
75 {
76 struct pixman_output_state *po = get_output_state(output);
77 pixman_image_t *out_buf;
78
79 if (!po->hw_buffer) {
80 errno = ENODEV;
81 return -1;
82 }
83
84 out_buf = pixman_image_create_bits(format,
85 width,
86 height,
87 pixels,
88 (PIXMAN_FORMAT_BPP(format) / 8) * width);
89
90 pixman_image_composite32(PIXMAN_OP_SRC,
91 po->hw_buffer, /* src */
92 NULL /* mask */,
93 out_buf, /* dest */
94 x, y, /* src_x, src_y */
95 0, 0, /* mask_x, mask_y */
96 0, 0, /* dest_x, dest_y */
97 pixman_image_get_width (po->hw_buffer), /* width */
98 pixman_image_get_height (po->hw_buffer) /* height */);
99
100 pixman_image_unref(out_buf);
101
102 return 0;
103 }
104
105 static void
region_global_to_output(struct weston_output * output,pixman_region32_t * region)106 region_global_to_output(struct weston_output *output, pixman_region32_t *region)
107 {
108 if (output->zoom.active) {
109 weston_matrix_transform_region(region, &output->matrix, region);
110 } else {
111 pixman_region32_translate(region, -output->x, -output->y);
112 weston_transformed_region(output->width, output->height,
113 output->transform,
114 output->current_scale,
115 region, region);
116 }
117 }
118
119 #define D2F(v) pixman_double_to_fixed((double)v)
120
121 static void
weston_matrix_to_pixman_transform(pixman_transform_t * pt,const struct weston_matrix * wm)122 weston_matrix_to_pixman_transform(pixman_transform_t *pt,
123 const struct weston_matrix *wm)
124 {
125 /* Pixman supports only 2D transform matrix, but Weston uses 3D, *
126 * so we're omitting Z coordinate here. */
127 pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
128 pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
129 pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
130 pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
131 pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
132 pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
133 pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
134 pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
135 pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
136 }
137
138 static void
pixman_renderer_compute_transform(pixman_transform_t * transform_out,struct weston_view * ev,struct weston_output * output)139 pixman_renderer_compute_transform(pixman_transform_t *transform_out,
140 struct weston_view *ev,
141 struct weston_output *output)
142 {
143 struct weston_matrix matrix;
144
145 /* Set up the source transformation based on the surface
146 position, the output position/transform/scale and the client
147 specified buffer transform/scale */
148 matrix = output->inverse_matrix;
149
150 if (ev->transform.enabled) {
151 weston_matrix_multiply(&matrix, &ev->transform.inverse);
152 } else {
153 weston_matrix_translate(&matrix,
154 -ev->geometry.x, -ev->geometry.y, 0);
155 }
156
157 weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
158
159 weston_matrix_to_pixman_transform(transform_out, &matrix);
160 }
161
162 static bool
view_transformation_is_translation(struct weston_view * view)163 view_transformation_is_translation(struct weston_view *view)
164 {
165 if (!view->transform.enabled)
166 return true;
167
168 if (view->transform.matrix.type <= WESTON_MATRIX_TRANSFORM_TRANSLATE)
169 return true;
170
171 return false;
172 }
173
174 static void
region_intersect_only_translation(pixman_region32_t * result_global,pixman_region32_t * global,pixman_region32_t * surf,struct weston_view * view)175 region_intersect_only_translation(pixman_region32_t *result_global,
176 pixman_region32_t *global,
177 pixman_region32_t *surf,
178 struct weston_view *view)
179 {
180 float view_x, view_y;
181
182 assert(view_transformation_is_translation(view));
183
184 /* Convert from surface to global coordinates */
185 pixman_region32_copy(result_global, surf);
186 weston_view_to_global_float(view, 0, 0, &view_x, &view_y);
187 pixman_region32_translate(result_global, (int)view_x, (int)view_y);
188
189 pixman_region32_intersect(result_global, result_global, global);
190 }
191
192 static void
composite_whole(pixman_op_t op,pixman_image_t * src,pixman_image_t * mask,pixman_image_t * dest,const pixman_transform_t * transform,pixman_filter_t filter)193 composite_whole(pixman_op_t op,
194 pixman_image_t *src,
195 pixman_image_t *mask,
196 pixman_image_t *dest,
197 const pixman_transform_t *transform,
198 pixman_filter_t filter)
199 {
200 int32_t dest_width;
201 int32_t dest_height;
202
203 dest_width = pixman_image_get_width(dest);
204 dest_height = pixman_image_get_height(dest);
205
206 pixman_image_set_transform(src, transform);
207 pixman_image_set_filter(src, filter, NULL, 0);
208
209 /* bilinear filtering needs the equivalent of OpenGL CLAMP_TO_EDGE */
210 if (filter == PIXMAN_FILTER_NEAREST)
211 pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
212 else
213 pixman_image_set_repeat(src, PIXMAN_REPEAT_PAD);
214
215 pixman_image_composite32(op, src, mask, dest,
216 0, 0, /* src_x, src_y */
217 0, 0, /* mask_x, mask_y */
218 0, 0, /* dest_x, dest_y */
219 dest_width, dest_height);
220 }
221
222 static void
composite_clipped(pixman_image_t * src,pixman_image_t * mask,pixman_image_t * dest,const pixman_transform_t * transform,pixman_filter_t filter,pixman_region32_t * src_clip)223 composite_clipped(pixman_image_t *src,
224 pixman_image_t *mask,
225 pixman_image_t *dest,
226 const pixman_transform_t *transform,
227 pixman_filter_t filter,
228 pixman_region32_t *src_clip)
229 {
230 int n_box;
231 pixman_box32_t *boxes;
232 int32_t dest_width;
233 int32_t dest_height;
234 int src_stride;
235 int bitspp;
236 pixman_format_code_t src_format;
237 void *src_data;
238 int i;
239
240 /*
241 * Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
242 * a Pixman image produces (0,0,0,0) instead of discarding the
243 * fragment.
244 *
245 * Also repeat mode must be PIXMAN_REPEAT_NONE (the default) to
246 * actually sample (0,0,0,0). This may cause issues for clients that
247 * expect OpenGL CLAMP_TO_EDGE sampling behavior on their buffer.
248 * Using temporary 'boximg' it is not possible to apply CLAMP_TO_EDGE
249 * correctly with bilinear filter. Maybe trapezoid rendering could be
250 * the answer instead of source clip?
251 */
252
253 dest_width = pixman_image_get_width(dest);
254 dest_height = pixman_image_get_height(dest);
255 src_format = pixman_image_get_format(src);
256 src_stride = pixman_image_get_stride(src);
257 bitspp = PIXMAN_FORMAT_BPP(src_format);
258 src_data = pixman_image_get_data(src);
259
260 assert(src_format);
261
262 /* This would be massive overdraw, except when n_box is 1. */
263 boxes = pixman_region32_rectangles(src_clip, &n_box);
264 for (i = 0; i < n_box; i++) {
265 uint8_t *ptr = src_data;
266 pixman_image_t *boximg;
267 pixman_transform_t adj = *transform;
268
269 ptr += boxes[i].y1 * src_stride;
270 ptr += boxes[i].x1 * bitspp / 8;
271 boximg = pixman_image_create_bits_no_clear(src_format,
272 boxes[i].x2 - boxes[i].x1,
273 boxes[i].y2 - boxes[i].y1,
274 (uint32_t *)ptr, src_stride);
275
276 pixman_transform_translate(&adj, NULL,
277 pixman_int_to_fixed(-boxes[i].x1),
278 pixman_int_to_fixed(-boxes[i].y1));
279 pixman_image_set_transform(boximg, &adj);
280
281 pixman_image_set_filter(boximg, filter, NULL, 0);
282 pixman_image_composite32(PIXMAN_OP_OVER, boximg, mask, dest,
283 0, 0, /* src_x, src_y */
284 0, 0, /* mask_x, mask_y */
285 0, 0, /* dest_x, dest_y */
286 dest_width, dest_height);
287
288 pixman_image_unref(boximg);
289 }
290
291 if (n_box > 1) {
292 static bool warned = false;
293
294 if (!warned)
295 weston_log("Pixman-renderer warning: %dx overdraw\n",
296 n_box);
297 warned = true;
298 }
299 }
300
301 /** Paint an intersected region
302 *
303 * \param ev The view to be painted.
304 * \param output The output being painted.
305 * \param repaint_output The region to be painted in output coordinates.
306 * \param source_clip The region of the source image to use, in source image
307 * coordinates. If NULL, use the whole source image.
308 * \param pixman_op Compositing operator, either SRC or OVER.
309 */
310 static void
repaint_region(struct weston_view * ev,struct weston_output * output,pixman_region32_t * repaint_output,pixman_region32_t * source_clip,pixman_op_t pixman_op)311 repaint_region(struct weston_view *ev, struct weston_output *output,
312 pixman_region32_t *repaint_output,
313 pixman_region32_t *source_clip,
314 pixman_op_t pixman_op)
315 {
316 struct pixman_renderer *pr =
317 (struct pixman_renderer *) output->compositor->renderer;
318 struct pixman_surface_state *ps = get_surface_state(ev->surface);
319 struct pixman_output_state *po = get_output_state(output);
320 struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
321 pixman_image_t *target_image;
322 pixman_transform_t transform;
323 pixman_filter_t filter;
324 pixman_image_t *mask_image;
325 pixman_color_t mask = { 0, };
326
327 if (po->shadow_image)
328 target_image = po->shadow_image;
329 else
330 target_image = po->hw_buffer;
331
332 /* Clip rendering to the damaged output region */
333 pixman_image_set_clip_region32(target_image, repaint_output);
334
335 pixman_renderer_compute_transform(&transform, ev, output);
336
337 if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
338 filter = PIXMAN_FILTER_BILINEAR;
339 else
340 filter = PIXMAN_FILTER_NEAREST;
341
342 if (ps->buffer_ref.buffer && ps->buffer_ref.buffer->shm_buffer)
343 wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
344
345 if (ev->alpha < 1.0) {
346 mask.alpha = 0xffff * ev->alpha;
347 mask_image = pixman_image_create_solid_fill(&mask);
348 } else {
349 mask_image = NULL;
350 }
351
352 if (source_clip)
353 composite_clipped(ps->image, mask_image, target_image,
354 &transform, filter, source_clip);
355 else
356 composite_whole(pixman_op, ps->image, mask_image,
357 target_image, &transform, filter);
358
359 if (mask_image)
360 pixman_image_unref(mask_image);
361
362 if (ps->buffer_ref.buffer && ps->buffer_ref.buffer->shm_buffer)
363 wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
364
365 if (pr->repaint_debug)
366 pixman_image_composite32(PIXMAN_OP_OVER,
367 pr->debug_color, /* src */
368 NULL /* mask */,
369 target_image, /* dest */
370 0, 0, /* src_x, src_y */
371 0, 0, /* mask_x, mask_y */
372 0, 0, /* dest_x, dest_y */
373 pixman_image_get_width (target_image), /* width */
374 pixman_image_get_height (target_image) /* height */);
375
376 pixman_image_set_clip_region32(target_image, NULL);
377 }
378
379 static void
draw_view_translated(struct weston_view * view,struct weston_output * output,pixman_region32_t * repaint_global)380 draw_view_translated(struct weston_view *view, struct weston_output *output,
381 pixman_region32_t *repaint_global)
382 {
383 struct weston_surface *surface = view->surface;
384 /* non-opaque region in surface coordinates: */
385 pixman_region32_t surface_blend;
386 /* region to be painted in output coordinates: */
387 pixman_region32_t repaint_output;
388
389 pixman_region32_init(&repaint_output);
390
391 /* Blended region is whole surface minus opaque region,
392 * unless surface alpha forces us to blend all.
393 */
394 pixman_region32_init_rect(&surface_blend, 0, 0,
395 surface->width, surface->height);
396
397 if (!(view->alpha < 1.0)) {
398 pixman_region32_subtract(&surface_blend, &surface_blend,
399 &surface->opaque);
400
401 if (pixman_region32_not_empty(&surface->opaque)) {
402 region_intersect_only_translation(&repaint_output,
403 repaint_global,
404 &surface->opaque,
405 view);
406 region_global_to_output(output, &repaint_output);
407
408 repaint_region(view, output, &repaint_output, NULL,
409 PIXMAN_OP_SRC);
410 }
411 }
412
413 if (pixman_region32_not_empty(&surface_blend)) {
414 region_intersect_only_translation(&repaint_output,
415 repaint_global,
416 &surface_blend, view);
417 region_global_to_output(output, &repaint_output);
418
419 // OHOS TDE
420 if (tde_repaint_region_hook(view, output, &surface_blend, &repaint_output) != 0) {
421 repaint_region(view, output, &repaint_output, NULL,
422 PIXMAN_OP_OVER);
423 }
424 }
425
426 pixman_region32_fini(&surface_blend);
427 pixman_region32_fini(&repaint_output);
428 }
429
430 static void
draw_view_source_clipped(struct weston_view * view,struct weston_output * output,pixman_region32_t * repaint_global)431 draw_view_source_clipped(struct weston_view *view,
432 struct weston_output *output,
433 pixman_region32_t *repaint_global)
434 {
435 struct weston_surface *surface = view->surface;
436 pixman_region32_t surf_region;
437 pixman_region32_t buffer_region;
438 pixman_region32_t repaint_output;
439
440 /* Do not bother separating the opaque region from non-opaque.
441 * Source clipping requires PIXMAN_OP_OVER in all cases, so painting
442 * opaque separately has no benefit.
443 */
444
445 pixman_region32_init_rect(&surf_region, 0, 0,
446 surface->width, surface->height);
447 if (view->geometry.scissor_enabled)
448 pixman_region32_intersect(&surf_region, &surf_region,
449 &view->geometry.scissor);
450
451 pixman_region32_init(&buffer_region);
452 weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
453
454 pixman_region32_init(&repaint_output);
455 pixman_region32_copy(&repaint_output, repaint_global);
456 region_global_to_output(output, &repaint_output);
457
458 // OHOS TDE
459 if (tde_repaint_region_hook(view, output, &buffer_region, &repaint_output) != 0) {
460 repaint_region(view, output, &repaint_output, &buffer_region,
461 PIXMAN_OP_OVER);
462 }
463
464 pixman_region32_fini(&repaint_output);
465 pixman_region32_fini(&buffer_region);
466 pixman_region32_fini(&surf_region);
467 }
468
469 static void
draw_view(struct weston_view * ev,struct weston_output * output,pixman_region32_t * damage)470 draw_view(struct weston_view *ev, struct weston_output *output,
471 pixman_region32_t *damage) /* in global coordinates */
472 {
473 struct pixman_surface_state *ps = get_surface_state(ev->surface);
474 /* repaint bounding region in global coordinates: */
475 pixman_region32_t repaint;
476
477 /* No buffer attached */
478 if (!ps->image)
479 return;
480
481 pixman_region32_init(&repaint);
482 pixman_region32_intersect(&repaint,
483 &ev->transform.boundingbox, damage);
484 pixman_region32_subtract(&repaint, &repaint, &ev->clip);
485
486 if (!pixman_region32_not_empty(&repaint))
487 goto out;
488
489 if (view_transformation_is_translation(ev)) {
490 /* The simple case: The surface regions opaque, non-opaque,
491 * etc. are convertible to global coordinate space.
492 * There is no need to use a source clip region.
493 * It is possible to paint opaque region as PIXMAN_OP_SRC.
494 * Also the boundingbox is accurate rather than an
495 * approximation.
496 */
497 draw_view_translated(ev, output, &repaint);
498 } else {
499 /* The complex case: the view transformation does not allow
500 * converting opaque etc. regions into global coordinate space.
501 * Therefore we need source clipping to avoid sampling from
502 * unwanted source image areas, unless the source image is
503 * to be used whole. Source clipping does not work with
504 * PIXMAN_OP_SRC.
505 */
506 draw_view_source_clipped(ev, output, &repaint);
507 }
508
509 out:
510 pixman_region32_fini(&repaint);
511 }
512 static void
repaint_surfaces(struct weston_output * output,pixman_region32_t * damage)513 repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
514 {
515 struct weston_compositor *compositor = output->compositor;
516 struct weston_view *view;
517
518 wl_list_for_each_reverse(view, &compositor->view_list, link)
519 if (view->plane == &compositor->primary_plane)
520 draw_view(view, output, damage);
521 }
522
523 static void
copy_to_hw_buffer(struct weston_output * output,pixman_region32_t * region)524 copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
525 {
526 struct pixman_output_state *po = get_output_state(output);
527 pixman_region32_t output_region;
528
529 pixman_region32_init(&output_region);
530 pixman_region32_copy(&output_region, region);
531
532 region_global_to_output(output, &output_region);
533
534 pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
535 pixman_region32_fini(&output_region);
536
537 pixman_image_composite32(PIXMAN_OP_SRC,
538 po->shadow_image, /* src */
539 NULL /* mask */,
540 po->hw_buffer, /* dest */
541 0, 0, /* src_x, src_y */
542 0, 0, /* mask_x, mask_y */
543 0, 0, /* dest_x, dest_y */
544 pixman_image_get_width (po->hw_buffer), /* width */
545 pixman_image_get_height (po->hw_buffer) /* height */);
546
547 pixman_image_set_clip_region32 (po->hw_buffer, NULL);
548 }
549
550 static void
pixman_renderer_repaint_output(struct weston_output * output,pixman_region32_t * output_damage)551 pixman_renderer_repaint_output(struct weston_output *output,
552 pixman_region32_t *output_damage)
553 {
554 struct pixman_output_state *po = get_output_state(output);
555 // OHOS TDE
556 tde_output_state_init_hook(po);
557 pixman_region32_t hw_damage;
558
559 if (!po->hw_buffer) {
560 po->hw_extra_damage = NULL;
561 return;
562 }
563
564 pixman_region32_init(&hw_damage);
565 if (po->hw_extra_damage) {
566 pixman_region32_union(&hw_damage,
567 po->hw_extra_damage, output_damage);
568 po->hw_extra_damage = NULL;
569 } else {
570 pixman_region32_copy(&hw_damage, output_damage);
571 }
572
573 if (po->shadow_image) {
574 repaint_surfaces(output, output_damage);
575 copy_to_hw_buffer(output, &hw_damage);
576 } else {
577 repaint_surfaces(output, &hw_damage);
578 }
579 pixman_region32_fini(&hw_damage);
580
581 wl_signal_emit(&output->frame_signal, output_damage);
582
583 /* Actual flip should be done by caller */
584 }
585
586 static void
pixman_renderer_flush_damage(struct weston_surface * surface)587 pixman_renderer_flush_damage(struct weston_surface *surface)
588 {
589 /* No-op for pixman renderer */
590 }
591
592 static void
buffer_state_handle_buffer_destroy(struct wl_listener * listener,void * data)593 buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
594 {
595 struct pixman_surface_state *ps;
596
597 ps = container_of(listener, struct pixman_surface_state,
598 buffer_destroy_listener);
599
600 if (ps->image) {
601 tde_unref_image_hook(ps);
602 pixman_image_unref(ps->image);
603 ps->image = NULL;
604 }
605
606 ps->buffer_destroy_listener.notify = NULL;
607 }
608
609 static void
pixman_renderer_attach(struct weston_surface * es,struct weston_buffer * buffer)610 pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
611 {
612 // OHOS TDE
613 if (tde_render_attach_hook(es, buffer) == 0) {
614 return;
615 }
616
617 struct pixman_surface_state *ps = get_surface_state(es);
618 struct wl_shm_buffer *shm_buffer;
619 pixman_format_code_t pixman_format;
620
621 weston_buffer_reference(&ps->buffer_ref, buffer);
622 weston_buffer_release_reference(&ps->buffer_release_ref,
623 es->buffer_release_ref.buffer_release);
624
625 if (ps->buffer_destroy_listener.notify) {
626 wl_list_remove(&ps->buffer_destroy_listener.link);
627 ps->buffer_destroy_listener.notify = NULL;
628 }
629
630 if (ps->image) {
631 pixman_image_unref(ps->image);
632 ps->image = NULL;
633 }
634
635 if (!buffer)
636 return;
637
638 shm_buffer = wl_shm_buffer_get(buffer->resource);
639
640 if (! shm_buffer) {
641 weston_log("Pixman renderer supports only SHM buffers\n");
642 weston_buffer_reference(&ps->buffer_ref, NULL);
643 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
644 return;
645 }
646
647 switch (wl_shm_buffer_get_format(shm_buffer)) {
648 case WL_SHM_FORMAT_XRGB8888:
649 pixman_format = PIXMAN_x8r8g8b8;
650 es->is_opaque = true;
651 break;
652 case WL_SHM_FORMAT_ARGB8888:
653 pixman_format = PIXMAN_a8r8g8b8;
654 es->is_opaque = false;
655 break;
656 case WL_SHM_FORMAT_RGB565:
657 pixman_format = PIXMAN_r5g6b5;
658 es->is_opaque = true;
659 break;
660 default:
661 weston_log("Unsupported SHM buffer format 0x%x\n",
662 wl_shm_buffer_get_format(shm_buffer));
663 weston_buffer_reference(&ps->buffer_ref, NULL);
664 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
665 weston_buffer_send_server_error(buffer,
666 "disconnecting due to unhandled buffer type");
667 return;
668 break;
669 }
670
671 buffer->shm_buffer = shm_buffer;
672 buffer->width = wl_shm_buffer_get_width(shm_buffer);
673 buffer->height = wl_shm_buffer_get_height(shm_buffer);
674
675 ps->image = pixman_image_create_bits(pixman_format,
676 buffer->width, buffer->height,
677 wl_shm_buffer_get_data(shm_buffer),
678 wl_shm_buffer_get_stride(shm_buffer));
679
680 ps->buffer_destroy_listener.notify =
681 buffer_state_handle_buffer_destroy;
682 wl_signal_add(&buffer->destroy_signal,
683 &ps->buffer_destroy_listener);
684 }
685
686 static void
pixman_renderer_surface_state_destroy(struct pixman_surface_state * ps)687 pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
688 {
689 wl_list_remove(&ps->surface_destroy_listener.link);
690 wl_list_remove(&ps->renderer_destroy_listener.link);
691 if (ps->buffer_destroy_listener.notify) {
692 wl_list_remove(&ps->buffer_destroy_listener.link);
693 ps->buffer_destroy_listener.notify = NULL;
694 }
695
696 ps->surface->renderer_state = NULL;
697
698 if (ps->image) {
699 tde_unref_image_hook(ps);
700 pixman_image_unref(ps->image);
701 ps->image = NULL;
702 }
703 weston_buffer_reference(&ps->buffer_ref, NULL);
704 weston_buffer_release_reference(&ps->buffer_release_ref, NULL);
705 tde_surface_state_free_hook(ps);
706 free(ps);
707 }
708
709 static void
surface_state_handle_surface_destroy(struct wl_listener * listener,void * data)710 surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
711 {
712 struct pixman_surface_state *ps;
713
714 ps = container_of(listener, struct pixman_surface_state,
715 surface_destroy_listener);
716
717 pixman_renderer_surface_state_destroy(ps);
718 }
719
720 static void
surface_state_handle_renderer_destroy(struct wl_listener * listener,void * data)721 surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
722 {
723 struct pixman_surface_state *ps;
724
725 ps = container_of(listener, struct pixman_surface_state,
726 renderer_destroy_listener);
727
728 pixman_renderer_surface_state_destroy(ps);
729 }
730
731 int
pixman_renderer_create_surface(struct weston_surface * surface)732 pixman_renderer_create_surface(struct weston_surface *surface)
733 {
734 struct pixman_surface_state *ps;
735 struct pixman_renderer *pr = get_renderer(surface->compositor);
736
737 ps = zalloc(sizeof *ps);
738 if (ps == NULL)
739 return -1;
740
741 tde_surface_state_alloc_hook(ps);
742
743 surface->renderer_state = ps;
744
745 ps->surface = surface;
746
747 ps->surface_destroy_listener.notify =
748 surface_state_handle_surface_destroy;
749 wl_signal_add(&surface->destroy_signal,
750 &ps->surface_destroy_listener);
751
752 ps->renderer_destroy_listener.notify =
753 surface_state_handle_renderer_destroy;
754 wl_signal_add(&pr->destroy_signal,
755 &ps->renderer_destroy_listener);
756
757 return 0;
758 }
759
760 static void
pixman_renderer_surface_set_color(struct weston_surface * es,float red,float green,float blue,float alpha)761 pixman_renderer_surface_set_color(struct weston_surface *es,
762 float red, float green, float blue, float alpha)
763 {
764 struct pixman_surface_state *ps = get_surface_state(es);
765 pixman_color_t color;
766
767 color.red = red * 0xffff;
768 color.green = green * 0xffff;
769 color.blue = blue * 0xffff;
770 color.alpha = alpha * 0xffff;
771
772 if (ps->image) {
773 tde_unref_image_hook(ps);
774 pixman_image_unref(ps->image);
775 ps->image = NULL;
776 }
777
778 ps->image = pixman_image_create_solid_fill(&color);
779 }
780
781 static void
pixman_renderer_destroy(struct weston_compositor * ec)782 pixman_renderer_destroy(struct weston_compositor *ec)
783 {
784 struct pixman_renderer *pr = get_renderer(ec);
785
786 wl_signal_emit(&pr->destroy_signal, pr);
787
788 // OHOS remove debugger
789 if (pr->debug_binding != NULL)
790 weston_binding_destroy(pr->debug_binding);
791
792 // OHOS TDE
793 tde_renderer_free_hook(pr);
794 free(pr);
795
796 ec->renderer = NULL;
797 }
798
799 static void
pixman_renderer_surface_get_content_size(struct weston_surface * surface,int * width,int * height)800 pixman_renderer_surface_get_content_size(struct weston_surface *surface,
801 int *width, int *height)
802 {
803 struct pixman_surface_state *ps = get_surface_state(surface);
804
805 if (ps->image) {
806 *width = pixman_image_get_width(ps->image);
807 *height = pixman_image_get_height(ps->image);
808 } else {
809 *width = 0;
810 *height = 0;
811 }
812 }
813
814 static int
pixman_renderer_surface_copy_content(struct weston_surface * surface,void * target,size_t size,int src_x,int src_y,int width,int height)815 pixman_renderer_surface_copy_content(struct weston_surface *surface,
816 void *target, size_t size,
817 int src_x, int src_y,
818 int width, int height)
819 {
820 const pixman_format_code_t format = PIXMAN_a8b8g8r8;
821 const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
822 struct pixman_surface_state *ps = get_surface_state(surface);
823 pixman_image_t *out_buf;
824
825 if (!ps->image)
826 return -1;
827
828 out_buf = pixman_image_create_bits(format, width, height,
829 target, width * bytespp);
830
831 pixman_image_set_transform(ps->image, NULL);
832 pixman_image_composite32(PIXMAN_OP_SRC,
833 ps->image, /* src */
834 NULL, /* mask */
835 out_buf, /* dest */
836 src_x, src_y, /* src_x, src_y */
837 0, 0, /* mask_x, mask_y */
838 0, 0, /* dest_x, dest_y */
839 width, height);
840
841 pixman_image_unref(out_buf);
842
843 return 0;
844 }
845
846 // OHOS debugger
847 //static void
848 //debug_binding(struct weston_keyboard *keyboard, const struct timespec *time,
849 // uint32_t key, void *data)
850 //{
851 // struct weston_compositor *ec = data;
852 // struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
853 //
854 // pr->repaint_debug ^= 1;
855 //
856 // if (pr->repaint_debug) {
857 // pixman_color_t red = {
858 // 0x3fff, 0x0000, 0x0000, 0x3fff
859 // };
860 //
861 // pr->debug_color = pixman_image_create_solid_fill(&red);
862 // } else {
863 // pixman_image_unref(pr->debug_color);
864 // weston_compositor_damage_all(ec);
865 // }
866 //}
867
868 static bool pixman_renderer_import_dmabuf(struct weston_compositor *ec, struct linux_dmabuf_buffer *dmabuf);
869 static void pixman_renderer_query_dmabuf_formats(struct weston_compositor *wc, int **formats, int *num_formats);
870 static void pixman_renderer_query_dmabuf_modifiers(struct weston_compositor *wc, int format, uint64_t **modifiers, int *num_modifiers);
871
872 WL_EXPORT int
pixman_renderer_init(struct weston_compositor * ec)873 pixman_renderer_init(struct weston_compositor *ec)
874 {
875 struct pixman_renderer *renderer;
876
877 renderer = zalloc(sizeof *renderer);
878 if (renderer == NULL)
879 return -1;
880
881 // OHOS TDE
882 tde_renderer_alloc_hook(renderer, ec);
883
884 renderer->repaint_debug = 0;
885 renderer->debug_color = NULL;
886 renderer->base.read_pixels = pixman_renderer_read_pixels;
887 renderer->base.repaint_output = pixman_renderer_repaint_output;
888 renderer->base.flush_damage = pixman_renderer_flush_damage;
889 renderer->base.attach = pixman_renderer_attach;
890 renderer->base.surface_set_color = pixman_renderer_surface_set_color;
891 renderer->base.destroy = pixman_renderer_destroy;
892 renderer->base.surface_get_content_size =
893 pixman_renderer_surface_get_content_size;
894 renderer->base.surface_copy_content =
895 pixman_renderer_surface_copy_content;
896 ec->renderer = &renderer->base;
897 ec->capabilities |= WESTON_CAP_ROTATION_ANY;
898 ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
899
900 // OHOS remove debugger
901 //renderer->debug_binding =
902 // weston_compositor_add_debug_binding(ec, KEY_R,
903 // debug_binding, ec);
904
905 wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
906
907 wl_signal_init(&renderer->destroy_signal);
908
909 return 0;
910 }
911
912 WL_EXPORT void
pixman_renderer_output_set_buffer(struct weston_output * output,pixman_image_t * buffer)913 pixman_renderer_output_set_buffer(struct weston_output *output,
914 pixman_image_t *buffer)
915 {
916 struct pixman_output_state *po = get_output_state(output);
917
918 if (po->hw_buffer)
919 pixman_image_unref(po->hw_buffer);
920 po->hw_buffer = buffer;
921
922 if (po->hw_buffer) {
923 output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
924 pixman_image_ref(po->hw_buffer);
925 }
926 }
927
928 WL_EXPORT void
pixman_renderer_output_set_hw_extra_damage(struct weston_output * output,pixman_region32_t * extra_damage)929 pixman_renderer_output_set_hw_extra_damage(struct weston_output *output,
930 pixman_region32_t *extra_damage)
931 {
932 struct pixman_output_state *po = get_output_state(output);
933
934 po->hw_extra_damage = extra_damage;
935 }
936
937 WL_EXPORT int
pixman_renderer_output_create(struct weston_output * output,const struct pixman_renderer_output_options * options)938 pixman_renderer_output_create(struct weston_output *output,
939 const struct pixman_renderer_output_options *options)
940 {
941 struct pixman_output_state *po;
942 int w, h;
943
944 po = zalloc(sizeof *po);
945 if (po == NULL)
946 return -1;
947
948 // OHOS TDE
949 tde_output_state_alloc_hook(po);
950
951 if (options->use_shadow) {
952 /* set shadow image transformation */
953 w = output->current_mode->width;
954 h = output->current_mode->height;
955
956 po->shadow_buffer = malloc(w * h * 4);
957
958 if (!po->shadow_buffer) {
959 tde_output_state_free_hook(po);
960 free(po);
961 return -1;
962 }
963
964 po->shadow_image =
965 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
966 po->shadow_buffer, w * 4);
967
968 if (!po->shadow_image) {
969 free(po->shadow_buffer);
970 tde_output_state_free_hook(po);
971 free(po);
972 return -1;
973 }
974 }
975
976 output->renderer_state = po;
977
978 return 0;
979 }
980
981 WL_EXPORT void
pixman_renderer_output_destroy(struct weston_output * output)982 pixman_renderer_output_destroy(struct weston_output *output)
983 {
984 struct pixman_output_state *po = get_output_state(output);
985
986 if (po->shadow_image)
987 pixman_image_unref(po->shadow_image);
988
989 if (po->hw_buffer)
990 pixman_image_unref(po->hw_buffer);
991
992 free(po->shadow_buffer);
993
994 po->shadow_buffer = NULL;
995 po->shadow_image = NULL;
996 po->hw_buffer = NULL;
997
998 tde_output_state_free_hook(po);
999 free(po);
1000 }
1001