1 /*
2 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
4 * Copyright © 2017, 2018 Collabora, Ltd.
5 * Copyright © 2017, 2018 General Electric Company
6 * Copyright (c) 2018 DisplayLink (UK) Ltd.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining
9 * a copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial
18 * portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 */
29
30 #include "config.h"
31
32 #include <errno.h>
33 #include <stdint.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36 #include <string.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <linux/input.h>
40 #include <linux/vt.h>
41 #include <assert.h>
42 #include <sys/mman.h>
43 #include <time.h>
44
45 #include <xf86drm.h>
46 #include <xf86drmMode.h>
47 #include <drm_fourcc.h>
48
49 #include <libudev.h>
50
51 #include <vsync_module_c.h> // OHOS vsync module
52
53 #include <libweston/libweston.h>
54 #include <libweston/backend-drm.h>
55 #include <libweston/weston-log.h>
56 #include "drm-internal.h"
57 #include "shared/helpers.h"
58 #include "shared/timespec-util.h"
59 #include "shared/string-helpers.h"
60 #include "pixman-renderer.h"
61 #include "pixel-formats.h"
62 #include "libbacklight.h"
63 #include "libinput-seat.h"
64 #include "launcher-util.h"
65 #include "vaapi-recorder.h"
66 #include "presentation-time-server-protocol.h"
67 #include "linux-dmabuf.h"
68 #include "linux-dmabuf-unstable-v1-server-protocol.h"
69 #include "linux-explicit-synchronization.h"
70 #include "wayland_drm_auth_server.h" // OHOS drm auth
71
72 #include "libweston/trace.h"
73 DEFINE_LOG_LABEL("DrmBackend");
74
75 static const char default_seat[] = "seat0";
76
77 static void
drm_backend_create_faked_zpos(struct drm_backend * b)78 drm_backend_create_faked_zpos(struct drm_backend *b)
79 {
80 struct drm_plane *plane;
81 uint64_t zpos = 0ULL;
82 uint64_t zpos_min_primary;
83 uint64_t zpos_min_overlay;
84 uint64_t zpos_min_cursor;
85
86 zpos_min_primary = zpos;
87 wl_list_for_each(plane, &b->plane_list, link) {
88 /* if the property is there, bail out sooner */
89 if (plane->props[WDRM_PLANE_ZPOS].prop_id != 0)
90 return;
91
92 if (plane->type != WDRM_PLANE_TYPE_PRIMARY)
93 continue;
94 zpos++;
95 }
96
97 zpos_min_overlay = zpos;
98 wl_list_for_each(plane, &b->plane_list, link) {
99 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
100 continue;
101 zpos++;
102 }
103
104 zpos_min_cursor = zpos;
105 wl_list_for_each(plane, &b->plane_list, link) {
106 if (plane->type != WDRM_PLANE_TYPE_CURSOR)
107 continue;
108 zpos++;
109 }
110
111 drm_debug(b, "[drm-backend] zpos property not found. "
112 "Using invented immutable zpos values:\n");
113 /* assume that invented zpos values are immutable */
114 wl_list_for_each(plane, &b->plane_list, link) {
115 if (plane->type == WDRM_PLANE_TYPE_PRIMARY) {
116 plane->zpos_min = zpos_min_primary;
117 plane->zpos_max = zpos_min_primary;
118 } else if (plane->type == WDRM_PLANE_TYPE_OVERLAY) {
119 plane->zpos_min = zpos_min_overlay;
120 plane->zpos_max = zpos_min_overlay;
121 } else if (plane->type == WDRM_PLANE_TYPE_CURSOR) {
122 plane->zpos_min = zpos_min_cursor;
123 plane->zpos_max = zpos_min_cursor;
124 }
125 drm_debug(b, "\t[plane] %s plane %d, zpos_min %"PRIu64", "
126 "zpos_max %"PRIu64"\n",
127 drm_output_get_plane_type_name(plane),
128 plane->plane_id, plane->zpos_min, plane->zpos_max);
129 }
130 }
131
132 static void
wl_array_remove_uint32(struct wl_array * array,uint32_t elm)133 wl_array_remove_uint32(struct wl_array *array, uint32_t elm)
134 {
135 uint32_t *pos, *end;
136
137 end = (uint32_t *) ((char *) array->data + array->size);
138
139 wl_array_for_each(pos, array) {
140 if (*pos != elm)
141 continue;
142
143 array->size -= sizeof(*pos);
144 if (pos + 1 == end)
145 break;
146
147 memmove(pos, pos + 1, (char *) end - (char *) (pos + 1));
148 break;
149 }
150 }
151
152 static int
pageflip_timeout(void * data)153 pageflip_timeout(void *data) {
154 /*
155 * Our timer just went off, that means we're not receiving drm
156 * page flip events anymore for that output. Let's gracefully exit
157 * weston with a return value so devs can debug what's going on.
158 */
159 struct drm_output *output = data;
160 struct weston_compositor *compositor = output->base.compositor;
161
162 weston_log("Pageflip timeout reached on output %s, your "
163 "driver is probably buggy! Exiting.\n",
164 output->base.name);
165 weston_compositor_exit_with_code(compositor, EXIT_FAILURE);
166
167 return 0;
168 }
169
170 /* Creates the pageflip timer. Note that it isn't armed by default */
171 static int
drm_output_pageflip_timer_create(struct drm_output * output)172 drm_output_pageflip_timer_create(struct drm_output *output)
173 {
174 struct wl_event_loop *loop = NULL;
175 struct weston_compositor *ec = output->base.compositor;
176
177 loop = wl_display_get_event_loop(ec->wl_display);
178 assert(loop);
179 output->pageflip_timer = wl_event_loop_add_timer(loop,
180 pageflip_timeout,
181 output);
182
183 if (output->pageflip_timer == NULL) {
184 weston_log("creating drm pageflip timer failed: %s\n",
185 strerror(errno));
186 return -1;
187 }
188
189 return 0;
190 }
191
192 static void
193 drm_output_destroy(struct weston_output *output_base);
194
195 /**
196 * Returns true if the plane can be used on the given output for its current
197 * repaint cycle.
198 */
199 bool
drm_plane_is_available(struct drm_plane * plane,struct drm_output * output)200 drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
201 {
202 assert(plane->state_cur);
203
204 if (output->virtual)
205 return false;
206
207 /* The plane still has a request not yet completed by the kernel. */
208 if (!plane->state_cur->complete)
209 return false;
210
211 /* The plane is still active on another output. */
212 if (plane->state_cur->output && plane->state_cur->output != output)
213 return false;
214
215 /* Check whether the plane can be used with this CRTC; possible_crtcs
216 * is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
217 return !!(plane->possible_crtcs & (1 << output->pipe));
218 }
219
220 struct drm_output *
drm_output_find_by_crtc(struct drm_backend * b,uint32_t crtc_id)221 drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id)
222 {
223 struct drm_output *output;
224
225 wl_list_for_each(output, &b->compositor->output_list, base.link) {
226 if (output->crtc_id == crtc_id)
227 return output;
228 }
229
230 return NULL;
231 }
232
233 struct drm_head *
drm_head_find_by_connector(struct drm_backend * backend,uint32_t connector_id)234 drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id)
235 {
236 struct weston_head *base;
237 struct drm_head *head;
238
239 wl_list_for_each(base,
240 &backend->compositor->head_list, compositor_link) {
241 head = to_drm_head(base);
242 if (head->connector_id == connector_id)
243 return head;
244 }
245
246 return NULL;
247 }
248
249 /**
250 * Get output state to disable output
251 *
252 * Returns a pointer to an output_state object which can be used to disable
253 * an output (e.g. DPMS off).
254 *
255 * @param pending_state The pending state object owning this update
256 * @param output The output to disable
257 * @returns A drm_output_state to disable the output
258 */
259 static struct drm_output_state *
drm_output_get_disable_state(struct drm_pending_state * pending_state,struct drm_output * output)260 drm_output_get_disable_state(struct drm_pending_state *pending_state,
261 struct drm_output *output)
262 {
263 struct drm_output_state *output_state;
264
265 output_state = drm_output_state_duplicate(output->state_cur,
266 pending_state,
267 DRM_OUTPUT_STATE_CLEAR_PLANES);
268 output_state->dpms = WESTON_DPMS_OFF;
269
270 output_state->protection = WESTON_HDCP_DISABLE;
271
272 return output_state;
273 }
274
275
276 /**
277 * Mark a drm_output_state (the output's last state) as complete. This handles
278 * any post-completion actions such as updating the repaint timer, disabling the
279 * output, and finally freeing the state.
280 */
281 void
drm_output_update_complete(struct drm_output * output,uint32_t flags,unsigned int sec,unsigned int usec)282 drm_output_update_complete(struct drm_output *output, uint32_t flags,
283 unsigned int sec, unsigned int usec)
284 {
285 struct drm_backend *b = to_drm_backend(output->base.compositor);
286 struct drm_plane_state *ps;
287 struct timespec ts;
288
289 /* Stop the pageflip timer instead of rearming it here */
290 if (output->pageflip_timer)
291 wl_event_source_timer_update(output->pageflip_timer, 0);
292
293 wl_list_for_each(ps, &output->state_cur->plane_list, link)
294 ps->complete = true;
295
296 drm_output_state_free(output->state_last);
297 output->state_last = NULL;
298
299 if (output->destroy_pending) {
300 output->destroy_pending = false;
301 output->disable_pending = false;
302 output->dpms_off_pending = false;
303 drm_output_destroy(&output->base);
304 return;
305 } else if (output->disable_pending) {
306 output->disable_pending = false;
307 output->dpms_off_pending = false;
308 weston_output_disable(&output->base);
309 return;
310 } else if (output->dpms_off_pending) {
311 struct drm_pending_state *pending = drm_pending_state_alloc(b);
312 output->dpms_off_pending = false;
313 drm_output_get_disable_state(pending, output);
314 drm_pending_state_apply_sync(pending);
315 }
316 if (output->state_cur->dpms == WESTON_DPMS_OFF &&
317 output->base.repaint_status != REPAINT_AWAITING_COMPLETION) {
318 /* DPMS can happen to us either in the middle of a repaint
319 * cycle (when we have painted fresh content, only to throw it
320 * away for DPMS off), or at any other random point. If the
321 * latter is true, then we cannot go through finish_frame,
322 * because the repaint machinery does not expect this. */
323 return;
324 }
325
326 ts.tv_sec = sec;
327 ts.tv_nsec = usec * 1000;
328 LOG_PASS();
329 weston_output_finish_frame(&output->base, &ts, flags);
330
331 /* We can't call this from frame_notify, because the output's
332 * repaint needed flag is cleared just after that */
333 if (output->recorder)
334 weston_output_schedule_repaint(&output->base);
335 }
336
337 static struct drm_fb *
drm_output_render_pixman(struct drm_output_state * state,pixman_region32_t * damage)338 drm_output_render_pixman(struct drm_output_state *state,
339 pixman_region32_t *damage)
340 {
341 struct drm_output *output = state->output;
342 struct weston_compositor *ec = output->base.compositor;
343
344 output->current_image ^= 1;
345
346 pixman_renderer_output_set_buffer(&output->base,
347 output->image[output->current_image]);
348 pixman_renderer_output_set_hw_extra_damage(&output->base,
349 &output->previous_damage);
350
351 ec->renderer->repaint_output(&output->base, damage);
352
353 pixman_region32_copy(&output->previous_damage, damage);
354
355 return drm_fb_ref(output->dumb[output->current_image]);
356 }
357
358 void
drm_output_render(struct drm_output_state * state,pixman_region32_t * damage)359 drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
360 {
361 struct drm_output *output = state->output;
362 struct weston_compositor *c = output->base.compositor;
363 struct drm_plane_state *scanout_state;
364 struct drm_plane *scanout_plane = output->scanout_plane;
365 struct drm_property_info *damage_info =
366 &scanout_plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
367 struct drm_backend *b = to_drm_backend(c);
368 struct drm_fb *fb;
369 pixman_region32_t scanout_damage;
370 pixman_box32_t *rects;
371 int n_rects;
372
373 /* If we already have a client buffer promoted to scanout, then we don't
374 * want to render. */
375 scanout_state = drm_output_state_get_plane(state,
376 output->scanout_plane);
377 if (scanout_state->fb)
378 return;
379
380 /*
381 * If we don't have any damage on the primary plane, and we already
382 * have a renderer buffer active, we can reuse it; else we pass
383 * the damaged region into the renderer to re-render the affected
384 * area.
385 */
386 if (!pixman_region32_not_empty(damage) &&
387 scanout_plane->state_cur->fb &&
388 (scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
389 scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB)) {
390 fb = drm_fb_ref(scanout_plane->state_cur->fb);
391 } else if (b->use_pixman) {
392 fb = drm_output_render_pixman(state, damage);
393 } else {
394 fb = drm_output_render_gl(state, damage);
395 }
396
397 if (!fb) {
398 drm_plane_state_put_back(scanout_state);
399 return;
400 }
401
402 scanout_state->fb = fb;
403 scanout_state->output = output;
404
405 scanout_state->src_x = 0;
406 scanout_state->src_y = 0;
407 scanout_state->src_w = fb->width << 16;
408 scanout_state->src_h = fb->height << 16;
409
410 scanout_state->dest_x = 0;
411 scanout_state->dest_y = 0;
412 scanout_state->dest_w = output->base.current_mode->width;
413 scanout_state->dest_h = output->base.current_mode->height;
414
415 pixman_region32_subtract(&c->primary_plane.damage,
416 &c->primary_plane.damage, damage);
417
418 /* Don't bother calculating plane damage if the plane doesn't support it */
419 if (damage_info->prop_id == 0)
420 return;
421
422 pixman_region32_init(&scanout_damage);
423 pixman_region32_copy(&scanout_damage, damage);
424
425 if (output->base.zoom.active) {
426 weston_matrix_transform_region(&scanout_damage,
427 &output->base.matrix,
428 &scanout_damage);
429 } else {
430 pixman_region32_translate(&scanout_damage,
431 -output->base.x, -output->base.y);
432 weston_transformed_region(output->base.width,
433 output->base.height,
434 output->base.transform,
435 output->base.current_scale,
436 &scanout_damage,
437 &scanout_damage);
438 }
439
440 assert(scanout_state->damage_blob_id == 0);
441
442 rects = pixman_region32_rectangles(&scanout_damage, &n_rects);
443
444 /*
445 * If this function fails, the blob id should still be 0.
446 * This tells the kernel there is no damage information, which means
447 * that it will consider the whole plane damaged. While this may
448 * affect efficiency, it should still produce correct results.
449 */
450 drmModeCreatePropertyBlob(b->drm.fd, rects,
451 sizeof(*rects) * n_rects,
452 &scanout_state->damage_blob_id);
453
454 pixman_region32_fini(&scanout_damage);
455 }
456
457 static int
drm_output_repaint(struct weston_output * output_base,pixman_region32_t * damage,void * repaint_data)458 drm_output_repaint(struct weston_output *output_base,
459 pixman_region32_t *damage,
460 void *repaint_data)
461 {
462 struct drm_pending_state *pending_state = repaint_data;
463 struct drm_output *output = to_drm_output(output_base);
464 struct drm_output_state *state = NULL;
465 struct drm_plane_state *scanout_state;
466
467 assert(!output->virtual);
468
469 if (output->disable_pending || output->destroy_pending)
470 goto err;
471
472 assert(!output->state_last);
473
474 /* If planes have been disabled in the core, we might not have
475 * hit assign_planes at all, so might not have valid output state
476 * here. */
477 state = drm_pending_state_get_output(pending_state, output);
478 if (!state)
479 state = drm_output_state_duplicate(output->state_cur,
480 pending_state,
481 DRM_OUTPUT_STATE_CLEAR_PLANES);
482 state->dpms = WESTON_DPMS_ON;
483
484 if (output_base->allow_protection)
485 state->protection = output_base->desired_protection;
486 else
487 state->protection = WESTON_HDCP_DISABLE;
488
489 drm_output_render(state, damage);
490 scanout_state = drm_output_state_get_plane(state,
491 output->scanout_plane);
492 if (!scanout_state || !scanout_state->fb)
493 goto err;
494
495 return 0;
496
497 err:
498 drm_output_state_free(state);
499 return -1;
500 }
501
502 /* Determine the type of vblank synchronization to use for the output.
503 *
504 * The pipe parameter indicates which CRTC is in use. Knowing this, we
505 * can determine which vblank sequence type to use for it. Traditional
506 * cards had only two CRTCs, with CRTC 0 using no special flags, and
507 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
508 * parameter indicates this.
509 *
510 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
511 * 0-31. If this is non-zero it indicates we're dealing with a
512 * multi-gpu situation and we need to calculate the vblank sync
513 * using DRM_BLANK_HIGH_CRTC_MASK.
514 */
515 static unsigned int
drm_waitvblank_pipe(struct drm_output * output)516 drm_waitvblank_pipe(struct drm_output *output)
517 {
518 if (output->pipe > 1)
519 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
520 DRM_VBLANK_HIGH_CRTC_MASK;
521 else if (output->pipe > 0)
522 return DRM_VBLANK_SECONDARY;
523 else
524 return 0;
525 }
526
527 static int
drm_output_start_repaint_loop(struct weston_output * output_base)528 drm_output_start_repaint_loop(struct weston_output *output_base)
529 {
530 struct drm_output *output = to_drm_output(output_base);
531 struct drm_pending_state *pending_state;
532 struct drm_plane *scanout_plane = output->scanout_plane;
533 struct drm_backend *backend =
534 to_drm_backend(output_base->compositor);
535 struct timespec ts, tnow;
536 struct timespec vbl2now;
537 int64_t refresh_nsec;
538 int ret;
539 drmVBlank vbl = {
540 .request.type = DRM_VBLANK_RELATIVE,
541 .request.sequence = 0,
542 .request.signal = 0,
543 };
544
545 if (output->disable_pending || output->destroy_pending)
546 return 0;
547
548 if (!output->scanout_plane->state_cur->fb) {
549 /* We can't page flip if there's no mode set */
550 goto finish_frame;
551 }
552
553 /* Need to smash all state in from scratch; current timings might not
554 * be what we want, page flip might not work, etc.
555 */
556 if (backend->state_invalid)
557 goto finish_frame;
558
559 assert(scanout_plane->state_cur->output == output);
560
561 /* Try to get current msc and timestamp via instant query */
562 vbl.request.type |= drm_waitvblank_pipe(output);
563 ret = drmWaitVBlank(backend->drm.fd, &vbl);
564
565 /* Error ret or zero timestamp means failure to get valid timestamp */
566 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
567 ts.tv_sec = vbl.reply.tval_sec;
568 ts.tv_nsec = vbl.reply.tval_usec * 1000;
569
570 /* Valid timestamp for most recent vblank - not stale?
571 * Stale ts could happen on Linux 3.17+, so make sure it
572 * is not older than 1 refresh duration since now.
573 */
574 weston_compositor_read_presentation_clock(backend->compositor,
575 &tnow);
576 timespec_sub(&vbl2now, &tnow, &ts);
577 refresh_nsec =
578 millihz_to_nsec(output->base.current_mode->refresh);
579 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
580 drm_output_update_msc(output, vbl.reply.sequence);
581 LOG_PASS();
582 weston_output_finish_frame(output_base, &ts,
583 WP_PRESENTATION_FEEDBACK_INVALID);
584 return 0;
585 }
586 }
587
588 /* Immediate query didn't provide valid timestamp.
589 * Use pageflip fallback.
590 */
591
592 assert(!output->page_flip_pending);
593 assert(!output->state_last);
594
595 pending_state = drm_pending_state_alloc(backend);
596 drm_output_state_duplicate(output->state_cur, pending_state,
597 DRM_OUTPUT_STATE_PRESERVE_PLANES);
598
599 ret = drm_pending_state_apply(pending_state);
600 if (ret != 0) {
601 weston_log("applying repaint-start state failed: %s\n",
602 strerror(errno));
603 if (ret == -EACCES)
604 return -1;
605 goto finish_frame;
606 }
607
608 return 0;
609
610 finish_frame:
611 /* if we cannot page-flip, immediately finish frame */
612 LOG_PASS();
613 weston_output_finish_frame(output_base, NULL,
614 WP_PRESENTATION_FEEDBACK_INVALID);
615 return 0;
616 }
617
618 /**
619 * Begin a new repaint cycle
620 *
621 * Called by the core compositor at the beginning of a repaint cycle. Creates
622 * a new pending_state structure to own any output state created by individual
623 * output repaint functions until the repaint is flushed or cancelled.
624 */
625 static void *
drm_repaint_begin(struct weston_compositor * compositor)626 drm_repaint_begin(struct weston_compositor *compositor)
627 {
628 struct drm_backend *b = to_drm_backend(compositor);
629 struct drm_pending_state *ret;
630
631 ret = drm_pending_state_alloc(b);
632 b->repaint_data = ret;
633
634 // OHOS remove logger
635 // if (weston_log_scope_is_enabled(b->debug)) {
636 // char *dbg = weston_compositor_print_scene_graph(compositor);
637 // drm_debug(b, "[repaint] Beginning repaint; pending_state %p\n",
638 // ret);
639 // drm_debug(b, "%s", dbg);
640 // free(dbg);
641 // }
642
643 return ret;
644 }
645
646 /**
647 * Flush a repaint set
648 *
649 * Called by the core compositor when a repaint cycle has been completed
650 * and should be flushed. Frees the pending state, transitioning ownership
651 * of the output state from the pending state, to the update itself. When
652 * the update completes (see drm_output_update_complete), the output
653 * state will be freed.
654 */
655 static int
drm_repaint_flush(struct weston_compositor * compositor,void * repaint_data)656 drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
657 {
658 struct drm_backend *b = to_drm_backend(compositor);
659 struct drm_pending_state *pending_state = repaint_data;
660 int ret;
661
662 ret = drm_pending_state_apply(pending_state);
663 if (ret != 0)
664 weston_log("repaint-flush failed: %s\n", strerror(errno));
665
666 drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state);
667 b->repaint_data = NULL;
668
669 return (ret == -EACCES) ? -1 : 0;
670 }
671
672 /**
673 * Cancel a repaint set
674 *
675 * Called by the core compositor when a repaint has finished, so the data
676 * held across the repaint cycle should be discarded.
677 */
678 static void
drm_repaint_cancel(struct weston_compositor * compositor,void * repaint_data)679 drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
680 {
681 struct drm_backend *b = to_drm_backend(compositor);
682 struct drm_pending_state *pending_state = repaint_data;
683
684 drm_pending_state_free(pending_state);
685 drm_debug(b, "[repaint] cancel pending_state %p\n", pending_state);
686 b->repaint_data = NULL;
687 }
688
689 static int
690 drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
691 static void
692 drm_output_fini_pixman(struct drm_output *output);
693
694 static int
drm_output_switch_mode(struct weston_output * output_base,struct weston_mode * mode)695 drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
696 {
697 struct drm_output *output = to_drm_output(output_base);
698 struct drm_backend *b = to_drm_backend(output_base->compositor);
699 struct drm_mode *drm_mode = drm_output_choose_mode(output, mode);
700
701 if (!drm_mode) {
702 weston_log("%s: invalid resolution %dx%d\n",
703 output_base->name, mode->width, mode->height);
704 return -1;
705 }
706
707 if (&drm_mode->base == output->base.current_mode)
708 return 0;
709
710 output->base.current_mode->flags = 0;
711
712 output->base.current_mode = &drm_mode->base;
713 output->base.current_mode->flags =
714 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
715
716 /* XXX: This drops our current buffer too early, before we've started
717 * displaying it. Ideally this should be much more atomic and
718 * integrated with a full repaint cycle, rather than doing a
719 * sledgehammer modeswitch first, and only later showing new
720 * content.
721 */
722 b->state_invalid = true;
723
724 if (b->use_pixman) {
725 drm_output_fini_pixman(output);
726 if (drm_output_init_pixman(output, b) < 0) {
727 weston_log("failed to init output pixman state with "
728 "new mode\n");
729 return -1;
730 }
731 } else {
732 drm_output_fini_egl(output);
733 if (drm_output_init_egl(output, b) < 0) {
734 weston_log("failed to init output egl state with "
735 "new mode");
736 return -1;
737 }
738 }
739
740 return 0;
741 }
742
743 static int
init_pixman(struct drm_backend * b)744 init_pixman(struct drm_backend *b)
745 {
746 return pixman_renderer_init(b->compositor);
747 }
748
749 /**
750 * Create a drm_plane for a hardware plane
751 *
752 * Creates one drm_plane structure for a hardware plane, and initialises its
753 * properties and formats.
754 *
755 * In the absence of universal plane support, where KMS does not explicitly
756 * expose the primary and cursor planes to userspace, this may also create
757 * an 'internal' plane for internal management.
758 *
759 * This function does not add the plane to the list of usable planes in Weston
760 * itself; the caller is responsible for this.
761 *
762 * Call drm_plane_destroy to clean up the plane.
763 *
764 * @sa drm_output_find_special_plane
765 * @param b DRM compositor backend
766 * @param kplane DRM plane to create, or NULL if creating internal plane
767 * @param output Output to create internal plane for, or NULL
768 * @param type Type to use when creating internal plane, or invalid
769 * @param format Format to use for internal planes, or 0
770 */
771 static struct drm_plane *
drm_plane_create(struct drm_backend * b,const drmModePlane * kplane,struct drm_output * output,enum wdrm_plane_type type,uint32_t format)772 drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
773 struct drm_output *output, enum wdrm_plane_type type,
774 uint32_t format)
775 {
776 struct drm_plane *plane;
777 drmModeObjectProperties *props;
778 uint64_t *zpos_range_values;
779 uint32_t num_formats = (kplane) ? kplane->count_formats : 1;
780
781 plane = zalloc(sizeof(*plane) +
782 (sizeof(plane->formats[0]) * num_formats));
783 if (!plane) {
784 weston_log("%s: out of memory\n", __func__);
785 return NULL;
786 }
787
788 plane->backend = b;
789 plane->count_formats = num_formats;
790 plane->state_cur = drm_plane_state_alloc(NULL, plane);
791 plane->state_cur->complete = true;
792
793 if (kplane) {
794 plane->possible_crtcs = kplane->possible_crtcs;
795 plane->plane_id = kplane->plane_id;
796
797 props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
798 DRM_MODE_OBJECT_PLANE);
799 if (!props) {
800 weston_log("couldn't get plane properties\n");
801 goto err;
802 }
803 drm_property_info_populate(b, plane_props, plane->props,
804 WDRM_PLANE__COUNT, props);
805 plane->type =
806 drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
807 props,
808 WDRM_PLANE_TYPE__COUNT);
809
810 zpos_range_values =
811 drm_property_get_range_values(&plane->props[WDRM_PLANE_ZPOS],
812 props);
813
814 if (zpos_range_values) {
815 plane->zpos_min = zpos_range_values[0];
816 plane->zpos_max = zpos_range_values[1];
817 } else {
818 plane->zpos_min = DRM_PLANE_ZPOS_INVALID_PLANE;
819 plane->zpos_max = DRM_PLANE_ZPOS_INVALID_PLANE;
820 }
821
822 if (drm_plane_populate_formats(plane, kplane, props,
823 b->fb_modifiers) < 0) {
824 drmModeFreeObjectProperties(props);
825 goto err;
826 }
827
828 drmModeFreeObjectProperties(props);
829 }
830 else {
831 plane->possible_crtcs = (1 << output->pipe);
832 plane->plane_id = 0;
833
834 // OHOS fix
835 if (!b->use_tde) {
836 plane->plane_id = 1;
837 }
838 weston_log("plane->plane_id: %{public}d", plane->plane_id);
839
840 plane->count_formats = 1;
841 plane->formats[0].format = format;
842 plane->type = type;
843 plane->zpos_max = DRM_PLANE_ZPOS_INVALID_PLANE;
844 plane->zpos_min = DRM_PLANE_ZPOS_INVALID_PLANE;
845 }
846
847 if (plane->type == WDRM_PLANE_TYPE__COUNT)
848 goto err_props;
849
850 /* With universal planes, everything is a DRM plane; without
851 * universal planes, the only DRM planes are overlay planes.
852 * Everything else is a fake plane. */
853 if (b->universal_planes) {
854 assert(kplane);
855 } else {
856 if (kplane)
857 assert(plane->type == WDRM_PLANE_TYPE_OVERLAY);
858 else
859 assert(plane->type != WDRM_PLANE_TYPE_OVERLAY &&
860 output);
861 }
862
863 weston_plane_init(&plane->base, b->compositor, 0, 0);
864 wl_list_insert(&b->plane_list, &plane->link);
865
866 return plane;
867
868 err_props:
869 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
870 err:
871 drm_plane_state_free(plane->state_cur, true);
872 free(plane);
873 return NULL;
874 }
875
876 /**
877 * Find, or create, a special-purpose plane
878 *
879 * Primary and cursor planes are a special case, in that before universal
880 * planes, they are driven by non-plane API calls. Without universal plane
881 * support, the only way to configure a primary plane is via drmModeSetCrtc,
882 * and the only way to configure a cursor plane is drmModeSetCursor2.
883 *
884 * Although they may actually be regular planes in the hardware, without
885 * universal plane support, these planes are not actually exposed to
886 * userspace in the regular plane list.
887 *
888 * However, for ease of internal tracking, we want to manage all planes
889 * through the same drm_plane structures. Therefore, when we are running
890 * without universal plane support, we create fake drm_plane structures
891 * to track these planes.
892 *
893 * @param b DRM backend
894 * @param output Output to use for plane
895 * @param type Type of plane
896 */
897 static struct drm_plane *
drm_output_find_special_plane(struct drm_backend * b,struct drm_output * output,enum wdrm_plane_type type)898 drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
899 enum wdrm_plane_type type)
900 {
901 struct drm_plane *plane;
902
903 if (!b->universal_planes) {
904 uint32_t format;
905
906 switch (type) {
907 case WDRM_PLANE_TYPE_CURSOR:
908 format = DRM_FORMAT_ARGB8888;
909 break;
910 case WDRM_PLANE_TYPE_PRIMARY:
911 /* We don't know what formats the primary plane supports
912 * before universal planes, so we just assume that the
913 * GBM format works; however, this isn't set until after
914 * the output is created. */
915 format = 0;
916 break;
917 default:
918 assert(!"invalid type in drm_output_find_special_plane");
919 break;
920 }
921
922 return drm_plane_create(b, NULL, output, type, format);
923 }
924
925 wl_list_for_each(plane, &b->plane_list, link) {
926 struct drm_output *tmp;
927 bool found_elsewhere = false;
928
929 if (plane->type != type)
930 continue;
931 if (!drm_plane_is_available(plane, output))
932 continue;
933
934 /* On some platforms, primary/cursor planes can roam
935 * between different CRTCs, so make sure we don't claim the
936 * same plane for two outputs. */
937 wl_list_for_each(tmp, &b->compositor->output_list,
938 base.link) {
939 if (tmp->cursor_plane == plane ||
940 tmp->scanout_plane == plane) {
941 found_elsewhere = true;
942 break;
943 }
944 }
945
946 if (found_elsewhere)
947 continue;
948
949 plane->possible_crtcs = (1 << output->pipe);
950 return plane;
951 }
952
953 return NULL;
954 }
955
956 /**
957 * Destroy one DRM plane
958 *
959 * Destroy a DRM plane, removing it from screen and releasing its retained
960 * buffers in the process. The counterpart to drm_plane_create.
961 *
962 * @param plane Plane to deallocate (will be freed)
963 */
964 static void
drm_plane_destroy(struct drm_plane * plane)965 drm_plane_destroy(struct drm_plane *plane)
966 {
967 if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
968 drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
969 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
970 drm_plane_state_free(plane->state_cur, true);
971 drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
972 weston_plane_release(&plane->base);
973 wl_list_remove(&plane->link);
974 free(plane);
975 }
976
977 /**
978 * Initialise sprites (overlay planes)
979 *
980 * Walk the list of provided DRM planes, and add overlay planes.
981 *
982 * Call destroy_sprites to free these planes.
983 *
984 * @param b DRM compositor backend
985 */
986 static void
create_sprites(struct drm_backend * b)987 create_sprites(struct drm_backend *b)
988 {
989 drmModePlaneRes *kplane_res;
990 drmModePlane *kplane;
991 struct drm_plane *drm_plane;
992 uint32_t i;
993 kplane_res = drmModeGetPlaneResources(b->drm.fd);
994 if (!kplane_res) {
995 weston_log("failed to get plane resources: %s\n",
996 strerror(errno));
997 return;
998 }
999
1000 for (i = 0; i < kplane_res->count_planes; i++) {
1001 kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i]);
1002 if (!kplane)
1003 continue;
1004
1005 drm_plane = drm_plane_create(b, kplane, NULL,
1006 WDRM_PLANE_TYPE__COUNT, 0);
1007 drmModeFreePlane(kplane);
1008 if (!drm_plane)
1009 continue;
1010
1011 if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
1012 weston_compositor_stack_plane(b->compositor,
1013 &drm_plane->base,
1014 &b->compositor->primary_plane);
1015 }
1016
1017 drmModeFreePlaneResources(kplane_res);
1018 }
1019
1020 /**
1021 * Clean up sprites (overlay planes)
1022 *
1023 * The counterpart to create_sprites.
1024 *
1025 * @param b DRM compositor backend
1026 */
1027 static void
destroy_sprites(struct drm_backend * b)1028 destroy_sprites(struct drm_backend *b)
1029 {
1030 struct drm_plane *plane, *next;
1031
1032 wl_list_for_each_safe(plane, next, &b->plane_list, link)
1033 drm_plane_destroy(plane);
1034 }
1035
1036 /* returns a value between 0-255 range, where higher is brighter */
1037 static uint32_t
drm_get_backlight(struct drm_head * head)1038 drm_get_backlight(struct drm_head *head)
1039 {
1040 long brightness, max_brightness, norm;
1041
1042 brightness = backlight_get_brightness(head->backlight);
1043 max_brightness = backlight_get_max_brightness(head->backlight);
1044
1045 /* convert it on a scale of 0 to 255 */
1046 norm = (brightness * 255)/(max_brightness);
1047
1048 return (uint32_t) norm;
1049 }
1050
1051 /* values accepted are between 0-255 range */
1052 static void
drm_set_backlight(struct weston_output * output_base,uint32_t value)1053 drm_set_backlight(struct weston_output *output_base, uint32_t value)
1054 {
1055 struct drm_output *output = to_drm_output(output_base);
1056 struct drm_head *head;
1057 long max_brightness, new_brightness;
1058
1059 if (value > 255)
1060 return;
1061
1062 wl_list_for_each(head, &output->base.head_list, base.output_link) {
1063 if (!head->backlight)
1064 return;
1065
1066 max_brightness = backlight_get_max_brightness(head->backlight);
1067
1068 /* get denormalized value */
1069 new_brightness = (value * max_brightness) / 255;
1070
1071 backlight_set_brightness(head->backlight, new_brightness);
1072 }
1073 }
1074
1075 static void
drm_output_init_backlight(struct drm_output * output)1076 drm_output_init_backlight(struct drm_output *output)
1077 {
1078 struct weston_head *base;
1079 struct drm_head *head;
1080
1081 output->base.set_backlight = NULL;
1082
1083 wl_list_for_each(base, &output->base.head_list, output_link) {
1084 head = to_drm_head(base);
1085
1086 if (head->backlight) {
1087 weston_log("Initialized backlight for head '%s', device %s\n",
1088 head->base.name, head->backlight->path);
1089
1090 if (!output->base.set_backlight) {
1091 output->base.set_backlight = drm_set_backlight;
1092 output->base.backlight_current =
1093 drm_get_backlight(head);
1094 }
1095 }
1096 }
1097 }
1098
1099 /**
1100 * Power output on or off
1101 *
1102 * The DPMS/power level of an output is used to switch it on or off. This
1103 * is DRM's hook for doing so, which can called either as part of repaint,
1104 * or independently of the repaint loop.
1105 *
1106 * If we are called as part of repaint, we simply set the relevant bit in
1107 * state and return.
1108 *
1109 * This function is never called on a virtual output.
1110 */
1111 static void
drm_set_dpms(struct weston_output * output_base,enum dpms_enum level)1112 drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1113 {
1114 struct drm_output *output = to_drm_output(output_base);
1115 struct drm_backend *b = to_drm_backend(output_base->compositor);
1116 struct drm_pending_state *pending_state = b->repaint_data;
1117 struct drm_output_state *state;
1118 int ret;
1119
1120 assert(!output->virtual);
1121
1122 if (output->state_cur->dpms == level)
1123 return;
1124
1125 /* If we're being called during the repaint loop, then this is
1126 * simple: discard any previously-generated state, and create a new
1127 * state where we disable everything. When we come to flush, this
1128 * will be applied.
1129 *
1130 * However, we need to be careful: we can be called whilst another
1131 * output is in its repaint cycle (pending_state exists), but our
1132 * output still has an incomplete state application outstanding.
1133 * In that case, we need to wait until that completes. */
1134 if (pending_state && !output->state_last) {
1135 /* The repaint loop already sets DPMS on; we don't need to
1136 * explicitly set it on here, as it will already happen
1137 * whilst applying the repaint state. */
1138 if (level == WESTON_DPMS_ON)
1139 return;
1140
1141 state = drm_pending_state_get_output(pending_state, output);
1142 if (state)
1143 drm_output_state_free(state);
1144 state = drm_output_get_disable_state(pending_state, output);
1145 return;
1146 }
1147
1148 /* As we throw everything away when disabling, just send us back through
1149 * a repaint cycle. */
1150 if (level == WESTON_DPMS_ON) {
1151 if (output->dpms_off_pending)
1152 output->dpms_off_pending = false;
1153 weston_output_schedule_repaint(output_base);
1154 return;
1155 }
1156
1157 /* If we've already got a request in the pipeline, then we need to
1158 * park our DPMS request until that request has quiesced. */
1159 if (output->state_last) {
1160 output->dpms_off_pending = true;
1161 return;
1162 }
1163
1164 pending_state = drm_pending_state_alloc(b);
1165 drm_output_get_disable_state(pending_state, output);
1166 ret = drm_pending_state_apply_sync(pending_state);
1167 if (ret != 0)
1168 weston_log("drm_set_dpms: couldn't disable output?\n");
1169 }
1170
1171 static const char * const connector_type_names[] = {
1172 [DRM_MODE_CONNECTOR_Unknown] = "Unknown",
1173 [DRM_MODE_CONNECTOR_VGA] = "VGA",
1174 [DRM_MODE_CONNECTOR_DVII] = "DVI-I",
1175 [DRM_MODE_CONNECTOR_DVID] = "DVI-D",
1176 [DRM_MODE_CONNECTOR_DVIA] = "DVI-A",
1177 [DRM_MODE_CONNECTOR_Composite] = "Composite",
1178 [DRM_MODE_CONNECTOR_SVIDEO] = "SVIDEO",
1179 [DRM_MODE_CONNECTOR_LVDS] = "LVDS",
1180 [DRM_MODE_CONNECTOR_Component] = "Component",
1181 [DRM_MODE_CONNECTOR_9PinDIN] = "DIN",
1182 [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
1183 [DRM_MODE_CONNECTOR_HDMIA] = "HDMI-A",
1184 [DRM_MODE_CONNECTOR_HDMIB] = "HDMI-B",
1185 [DRM_MODE_CONNECTOR_TV] = "TV",
1186 [DRM_MODE_CONNECTOR_eDP] = "eDP",
1187 [DRM_MODE_CONNECTOR_VIRTUAL] = "Virtual",
1188 [DRM_MODE_CONNECTOR_DSI] = "DSI",
1189 [DRM_MODE_CONNECTOR_DPI] = "DPI",
1190 };
1191
1192 /** Create a name given a DRM connector
1193 *
1194 * \param con The DRM connector whose type and id form the name.
1195 * \return A newly allocate string, or NULL on error. Must be free()'d
1196 * after use.
1197 *
1198 * The name does not identify the DRM display device.
1199 */
1200 static char *
make_connector_name(const drmModeConnector * con)1201 make_connector_name(const drmModeConnector *con)
1202 {
1203 char *name;
1204 const char *type_name = NULL;
1205 int ret;
1206
1207 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
1208 type_name = connector_type_names[con->connector_type];
1209
1210 if (!type_name)
1211 type_name = "UNNAMED";
1212
1213 ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
1214 if (ret < 0)
1215 return NULL;
1216
1217 return name;
1218 }
1219
1220 static int
drm_output_init_pixman(struct drm_output * output,struct drm_backend * b)1221 drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
1222 {
1223 int w = output->base.current_mode->width;
1224 int h = output->base.current_mode->height;
1225 uint32_t format = output->gbm_format;
1226 uint32_t pixman_format;
1227 unsigned int i;
1228 b->use_pixman_shadow = false; // OHOS
1229 const struct pixman_renderer_output_options options = {
1230 .use_shadow = b->use_pixman_shadow,
1231 };
1232
1233 switch (format) {
1234 case DRM_FORMAT_XRGB8888:
1235 pixman_format = PIXMAN_x8r8g8b8;
1236 break;
1237 case DRM_FORMAT_RGB565:
1238 pixman_format = PIXMAN_r5g6b5;
1239 break;
1240 default:
1241 weston_log("Unsupported pixman format 0x%x\n", format);
1242 return -1;
1243 }
1244
1245 /* FIXME error checking */
1246 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1247 output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
1248 if (!output->dumb[i])
1249 goto err;
1250
1251 output->image[i] =
1252 pixman_image_create_bits(pixman_format, w, h,
1253 output->dumb[i]->map,
1254 output->dumb[i]->strides[0]);
1255 if (!output->image[i])
1256 goto err;
1257 }
1258
1259 if (pixman_renderer_output_create(&output->base, &options) < 0)
1260 goto err;
1261
1262 weston_log("DRM: output %s %s shadow framebuffer.\n", output->base.name,
1263 b->use_pixman_shadow ? "uses" : "does not use");
1264
1265 pixman_region32_init_rect(&output->previous_damage,
1266 output->base.x, output->base.y, output->base.width, output->base.height);
1267
1268 return 0;
1269
1270 err:
1271 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1272 if (output->dumb[i])
1273 drm_fb_unref(output->dumb[i]);
1274 if (output->image[i])
1275 pixman_image_unref(output->image[i]);
1276
1277 output->dumb[i] = NULL;
1278 output->image[i] = NULL;
1279 }
1280
1281 return -1;
1282 }
1283
1284 static void
drm_output_fini_pixman(struct drm_output * output)1285 drm_output_fini_pixman(struct drm_output *output)
1286 {
1287 struct drm_backend *b = to_drm_backend(output->base.compositor);
1288 unsigned int i;
1289
1290 /* Destroying the Pixman surface will destroy all our buffers,
1291 * regardless of refcount. Ensure we destroy them here. */
1292 if (!b->shutting_down &&
1293 output->scanout_plane->state_cur->fb &&
1294 output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
1295 drm_plane_reset_state(output->scanout_plane);
1296 }
1297
1298 pixman_renderer_output_destroy(&output->base);
1299 pixman_region32_fini(&output->previous_damage);
1300
1301 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1302 pixman_image_unref(output->image[i]);
1303 drm_fb_unref(output->dumb[i]);
1304 output->dumb[i] = NULL;
1305 output->image[i] = NULL;
1306 }
1307 }
1308
1309 static void
setup_output_seat_constraint(struct drm_backend * b,struct weston_output * output,const char * s)1310 setup_output_seat_constraint(struct drm_backend *b,
1311 struct weston_output *output,
1312 const char *s)
1313 {
1314 if (strcmp(s, "") != 0) {
1315 struct weston_pointer *pointer;
1316 struct udev_seat *seat;
1317
1318 seat = udev_seat_get_named(&b->input, s);
1319 if (!seat)
1320 return;
1321
1322 seat->base.output = output;
1323
1324 pointer = weston_seat_get_pointer(&seat->base);
1325 if (pointer)
1326 weston_pointer_clamp(pointer,
1327 &pointer->x,
1328 &pointer->y);
1329 }
1330 }
1331
1332 static int
drm_output_attach_head(struct weston_output * output_base,struct weston_head * head_base)1333 drm_output_attach_head(struct weston_output *output_base,
1334 struct weston_head *head_base)
1335 {
1336 struct drm_backend *b = to_drm_backend(output_base->compositor);
1337
1338 if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS)
1339 return -1;
1340
1341 if (!output_base->enabled)
1342 return 0;
1343
1344 /* XXX: ensure the configuration will work.
1345 * This is actually impossible without major infrastructure
1346 * work. */
1347
1348 /* Need to go through modeset to add connectors. */
1349 /* XXX: Ideally we'd do this per-output, not globally. */
1350 /* XXX: Doing it globally, what guarantees another output's update
1351 * will not clear the flag before this output is updated?
1352 */
1353 b->state_invalid = true;
1354
1355 weston_output_schedule_repaint(output_base);
1356
1357 return 0;
1358 }
1359
1360 static void
drm_output_detach_head(struct weston_output * output_base,struct weston_head * head_base)1361 drm_output_detach_head(struct weston_output *output_base,
1362 struct weston_head *head_base)
1363 {
1364 struct drm_backend *b = to_drm_backend(output_base->compositor);
1365
1366 if (!output_base->enabled)
1367 return;
1368
1369 /* Need to go through modeset to drop connectors that should no longer
1370 * be driven. */
1371 /* XXX: Ideally we'd do this per-output, not globally. */
1372 b->state_invalid = true;
1373
1374 weston_output_schedule_repaint(output_base);
1375 }
1376
1377 int
parse_gbm_format(const char * s,uint32_t default_value,uint32_t * gbm_format)1378 parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
1379 {
1380 const struct pixel_format_info *pinfo;
1381
1382 if (s == NULL) {
1383 *gbm_format = default_value;
1384
1385 return 0;
1386 }
1387
1388 pinfo = pixel_format_get_info_by_drm_name(s);
1389 if (!pinfo) {
1390 weston_log("fatal: unrecognized pixel format: %s\n", s);
1391
1392 return -1;
1393 }
1394
1395 /* GBM formats and DRM formats are identical. */
1396 *gbm_format = pinfo->format;
1397
1398 return 0;
1399 }
1400
1401 static int
drm_head_read_current_setup(struct drm_head * head,struct drm_backend * backend)1402 drm_head_read_current_setup(struct drm_head *head, struct drm_backend *backend)
1403 {
1404 int drm_fd = backend->drm.fd;
1405 drmModeEncoder *encoder;
1406 drmModeCrtc *crtc;
1407
1408 /* Get the current mode on the crtc that's currently driving
1409 * this connector. */
1410 encoder = drmModeGetEncoder(drm_fd, head->connector->encoder_id);
1411 if (encoder != NULL) {
1412 head->inherited_crtc_id = encoder->crtc_id;
1413
1414 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
1415 drmModeFreeEncoder(encoder);
1416
1417 if (crtc == NULL)
1418 return -1;
1419 if (crtc->mode_valid)
1420 head->inherited_mode = crtc->mode;
1421 drmModeFreeCrtc(crtc);
1422 }
1423
1424 return 0;
1425 }
1426
1427 static void
drm_output_set_gbm_format(struct weston_output * base,const char * gbm_format)1428 drm_output_set_gbm_format(struct weston_output *base,
1429 const char *gbm_format)
1430 {
1431 struct drm_output *output = to_drm_output(base);
1432 struct drm_backend *b = to_drm_backend(base->compositor);
1433
1434 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
1435 output->gbm_format = b->gbm_format;
1436 }
1437
1438 static void
drm_output_set_seat(struct weston_output * base,const char * seat)1439 drm_output_set_seat(struct weston_output *base,
1440 const char *seat)
1441 {
1442 struct drm_output *output = to_drm_output(base);
1443 struct drm_backend *b = to_drm_backend(base->compositor);
1444
1445 setup_output_seat_constraint(b, &output->base,
1446 seat ? seat : "");
1447 }
1448
1449 static int
drm_output_init_gamma_size(struct drm_output * output)1450 drm_output_init_gamma_size(struct drm_output *output)
1451 {
1452 struct drm_backend *backend = to_drm_backend(output->base.compositor);
1453 drmModeCrtc *crtc;
1454
1455 assert(output->base.compositor);
1456 assert(output->crtc_id != 0);
1457 crtc = drmModeGetCrtc(backend->drm.fd, output->crtc_id);
1458 if (!crtc)
1459 return -1;
1460
1461 output->base.gamma_size = crtc->gamma_size;
1462
1463 drmModeFreeCrtc(crtc);
1464
1465 return 0;
1466 }
1467
1468 static uint32_t
drm_head_get_possible_crtcs_mask(struct drm_head * head)1469 drm_head_get_possible_crtcs_mask(struct drm_head *head)
1470 {
1471 uint32_t possible_crtcs = 0;
1472 drmModeEncoder *encoder;
1473 int i;
1474
1475 for (i = 0; i < head->connector->count_encoders; i++) {
1476 encoder = drmModeGetEncoder(head->backend->drm.fd,
1477 head->connector->encoders[i]);
1478 if (!encoder)
1479 continue;
1480
1481 possible_crtcs |= encoder->possible_crtcs;
1482 drmModeFreeEncoder(encoder);
1483 }
1484
1485 return possible_crtcs;
1486 }
1487
1488 static int
drm_crtc_get_index(drmModeRes * resources,uint32_t crtc_id)1489 drm_crtc_get_index(drmModeRes *resources, uint32_t crtc_id)
1490 {
1491 int i;
1492
1493 for (i = 0; i < resources->count_crtcs; i++) {
1494 if (resources->crtcs[i] == crtc_id)
1495 return i;
1496 }
1497
1498 assert(0 && "unknown crtc id");
1499 return -1;
1500 }
1501
1502 /** Pick a CRTC that might be able to drive all attached connectors
1503 *
1504 * @param output The output whose attached heads to include.
1505 * @param resources The DRM KMS resources.
1506 * @return CRTC index, or -1 on failure or not found.
1507 */
1508 static int
drm_output_pick_crtc(struct drm_output * output,drmModeRes * resources)1509 drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources)
1510 {
1511 struct drm_backend *backend;
1512 struct weston_head *base;
1513 struct drm_head *head;
1514 uint32_t possible_crtcs = 0xffffffff;
1515 int existing_crtc[32];
1516 unsigned j, n = 0;
1517 uint32_t crtc_id;
1518 int best_crtc_index = -1;
1519 int fallback_crtc_index = -1;
1520 int i;
1521 bool match;
1522
1523 backend = to_drm_backend(output->base.compositor);
1524
1525 /* This algorithm ignores drmModeEncoder::possible_clones restriction,
1526 * because it is more often set wrong than not in the kernel. */
1527
1528 /* Accumulate a mask of possible crtcs and find existing routings. */
1529 wl_list_for_each(base, &output->base.head_list, output_link) {
1530 head = to_drm_head(base);
1531
1532 possible_crtcs &= drm_head_get_possible_crtcs_mask(head);
1533
1534 crtc_id = head->inherited_crtc_id;
1535 if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc))
1536 existing_crtc[n++] = drm_crtc_get_index(resources,
1537 crtc_id);
1538 }
1539
1540 /* Find a crtc that could drive each connector individually at least,
1541 * and prefer existing routings. */
1542 for (i = 0; i < resources->count_crtcs; i++) {
1543 crtc_id = resources->crtcs[i];
1544
1545 /* Could the crtc not drive each connector? */
1546 if (!(possible_crtcs & (1 << i)))
1547 continue;
1548
1549 /* Is the crtc already in use? */
1550 if (drm_output_find_by_crtc(backend, crtc_id))
1551 continue;
1552
1553 /* Try to preserve the existing CRTC -> connector routing;
1554 * it makes initialisation faster, and also since we have a
1555 * very dumb picking algorithm, may preserve a better
1556 * choice. */
1557 for (j = 0; j < n; j++) {
1558 if (existing_crtc[j] == i)
1559 return i;
1560 }
1561
1562 /* Check if any other head had existing routing to this CRTC.
1563 * If they did, this is not the best CRTC as it might be needed
1564 * for another output we haven't enabled yet. */
1565 match = false;
1566 wl_list_for_each(base, &backend->compositor->head_list,
1567 compositor_link) {
1568 head = to_drm_head(base);
1569
1570 if (head->base.output == &output->base)
1571 continue;
1572
1573 if (weston_head_is_enabled(&head->base))
1574 continue;
1575
1576 if (head->inherited_crtc_id == crtc_id) {
1577 match = true;
1578 break;
1579 }
1580 }
1581 if (!match)
1582 best_crtc_index = i;
1583
1584 fallback_crtc_index = i;
1585 }
1586
1587 if (best_crtc_index != -1)
1588 return best_crtc_index;
1589
1590 if (fallback_crtc_index != -1)
1591 return fallback_crtc_index;
1592
1593 /* Likely possible_crtcs was empty due to asking for clones,
1594 * but since the DRM documentation says the kernel lies, let's
1595 * pick one crtc anyway. Trial and error is the only way to
1596 * be sure if something doesn't work. */
1597
1598 /* First pick any existing assignment. */
1599 for (j = 0; j < n; j++) {
1600 crtc_id = resources->crtcs[existing_crtc[j]];
1601 if (!drm_output_find_by_crtc(backend, crtc_id))
1602 return existing_crtc[j];
1603 }
1604
1605 /* Otherwise pick any available crtc. */
1606 for (i = 0; i < resources->count_crtcs; i++) {
1607 crtc_id = resources->crtcs[i];
1608
1609 if (!drm_output_find_by_crtc(backend, crtc_id))
1610 return i;
1611 }
1612
1613 return -1;
1614 }
1615
1616 /** Allocate a CRTC for the output
1617 *
1618 * @param output The output with no allocated CRTC.
1619 * @param resources DRM KMS resources.
1620 * @return 0 on success, -1 on failure.
1621 *
1622 * Finds a free CRTC that might drive the attached connectors, reserves the CRTC
1623 * for the output, and loads the CRTC properties.
1624 *
1625 * Populates the cursor and scanout planes.
1626 *
1627 * On failure, the output remains without a CRTC.
1628 */
1629 static int
drm_output_init_crtc(struct drm_output * output,drmModeRes * resources)1630 drm_output_init_crtc(struct drm_output *output, drmModeRes *resources)
1631 {
1632 struct drm_backend *b = to_drm_backend(output->base.compositor);
1633 drmModeObjectPropertiesPtr props;
1634 int i;
1635
1636 assert(output->crtc_id == 0);
1637
1638 i = drm_output_pick_crtc(output, resources);
1639 if (i < 0) {
1640 weston_log("Output '%s': No available CRTCs.\n",
1641 output->base.name);
1642 return -1;
1643 }
1644
1645 output->crtc_id = resources->crtcs[i];
1646 output->pipe = i;
1647
1648 props = drmModeObjectGetProperties(b->drm.fd, output->crtc_id,
1649 DRM_MODE_OBJECT_CRTC);
1650 if (!props) {
1651 weston_log("failed to get CRTC properties\n");
1652 goto err_crtc;
1653 }
1654 drm_property_info_populate(b, crtc_props, output->props_crtc,
1655 WDRM_CRTC__COUNT, props);
1656 drmModeFreeObjectProperties(props);
1657
1658 output->scanout_plane =
1659 drm_output_find_special_plane(b, output,
1660 WDRM_PLANE_TYPE_PRIMARY);
1661 if (!output->scanout_plane) {
1662 weston_log("Failed to find primary plane for output %s\n",
1663 output->base.name);
1664 goto err_crtc;
1665 }
1666
1667 /* Without universal planes, we can't discover which formats are
1668 * supported by the primary plane; we just hope that the GBM format
1669 * works. */
1670 if (!b->universal_planes)
1671 output->scanout_plane->formats[0].format = output->gbm_format;
1672
1673 /* Failing to find a cursor plane is not fatal, as we'll fall back
1674 * to software cursor. */
1675 output->cursor_plane =
1676 drm_output_find_special_plane(b, output,
1677 WDRM_PLANE_TYPE_CURSOR);
1678
1679 wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
1680
1681 return 0;
1682
1683 err_crtc:
1684 output->crtc_id = 0;
1685 output->pipe = 0;
1686
1687 return -1;
1688 }
1689
1690 /** Free the CRTC from the output
1691 *
1692 * @param output The output whose CRTC to deallocate.
1693 *
1694 * The CRTC reserved for the given output becomes free to use again.
1695 */
1696 static void
drm_output_fini_crtc(struct drm_output * output)1697 drm_output_fini_crtc(struct drm_output *output)
1698 {
1699 struct drm_backend *b = to_drm_backend(output->base.compositor);
1700 uint32_t *unused;
1701
1702 /* If the compositor is already shutting down, the planes have already
1703 * been destroyed. */
1704 if (!b->shutting_down) {
1705 if (!b->universal_planes) {
1706 /* Without universal planes, our special planes are
1707 * pseudo-planes allocated at output creation, freed at
1708 * output destruction, and not usable by other outputs.
1709 */
1710 if (output->cursor_plane)
1711 drm_plane_destroy(output->cursor_plane);
1712 if (output->scanout_plane)
1713 drm_plane_destroy(output->scanout_plane);
1714 } else {
1715 /* With universal planes, the 'special' planes are
1716 * allocated at startup, freed at shutdown, and live on
1717 * the plane list in between. We want the planes to
1718 * continue to exist and be freed up for other outputs.
1719 */
1720 if (output->cursor_plane)
1721 drm_plane_reset_state(output->cursor_plane);
1722 if (output->scanout_plane)
1723 drm_plane_reset_state(output->scanout_plane);
1724 }
1725 }
1726
1727 drm_property_info_free(output->props_crtc, WDRM_CRTC__COUNT);
1728
1729 assert(output->crtc_id != 0);
1730
1731 unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
1732 *unused = output->crtc_id;
1733
1734 /* Force resetting unused CRTCs */
1735 b->state_invalid = true;
1736
1737 output->crtc_id = 0;
1738 output->cursor_plane = NULL;
1739 output->scanout_plane = NULL;
1740 }
1741
1742 static int
drm_output_enable(struct weston_output * base)1743 drm_output_enable(struct weston_output *base)
1744 {
1745 struct drm_output *output = to_drm_output(base);
1746 struct drm_backend *b = to_drm_backend(base->compositor);
1747 drmModeRes *resources;
1748 int ret;
1749
1750 assert(!output->virtual);
1751
1752 resources = drmModeGetResources(b->drm.fd);
1753 if (!resources) {
1754 weston_log("drmModeGetResources failed\n");
1755 return -1;
1756 }
1757 ret = drm_output_init_crtc(output, resources);
1758 drmModeFreeResources(resources);
1759 if (ret < 0)
1760 return -1;
1761
1762 if (drm_output_init_gamma_size(output) < 0)
1763 goto err;
1764
1765 if (b->pageflip_timeout)
1766 drm_output_pageflip_timer_create(output);
1767
1768 if (b->use_pixman) {
1769 if (drm_output_init_pixman(output, b) < 0) {
1770 weston_log("Failed to init output pixman state\n");
1771 goto err;
1772 }
1773 } else if (drm_output_init_egl(output, b) < 0) {
1774 weston_log("Failed to init output gl state\n");
1775 goto err;
1776 }
1777
1778 drm_output_init_backlight(output);
1779
1780 output->base.start_repaint_loop = drm_output_start_repaint_loop;
1781 output->base.repaint = drm_output_repaint;
1782 output->base.assign_planes = drm_assign_planes;
1783 output->base.set_dpms = drm_set_dpms;
1784 output->base.switch_mode = drm_output_switch_mode;
1785 output->base.set_gamma = drm_output_set_gamma;
1786
1787 if (output->cursor_plane)
1788 weston_compositor_stack_plane(b->compositor,
1789 &output->cursor_plane->base,
1790 NULL);
1791 else
1792 b->cursors_are_broken = true;
1793
1794 weston_compositor_stack_plane(b->compositor,
1795 &output->scanout_plane->base,
1796 &b->compositor->primary_plane);
1797
1798 weston_log("Output %s (crtc %d) video modes:\n",
1799 output->base.name, output->crtc_id);
1800 drm_output_print_modes(output);
1801
1802 return 0;
1803
1804 err:
1805 drm_output_fini_crtc(output);
1806
1807 return -1;
1808 }
1809
1810 static void
drm_output_deinit(struct weston_output * base)1811 drm_output_deinit(struct weston_output *base)
1812 {
1813 struct drm_output *output = to_drm_output(base);
1814 struct drm_backend *b = to_drm_backend(base->compositor);
1815
1816 if (b->use_pixman)
1817 drm_output_fini_pixman(output);
1818 else
1819 drm_output_fini_egl(output);
1820
1821 /* Since our planes are no longer in use anywhere, remove their base
1822 * weston_plane's link from the plane stacking list, unless we're
1823 * shutting down, in which case the plane has already been
1824 * destroyed. */
1825 if (!b->shutting_down) {
1826 wl_list_remove(&output->scanout_plane->base.link);
1827 wl_list_init(&output->scanout_plane->base.link);
1828
1829 if (output->cursor_plane) {
1830 wl_list_remove(&output->cursor_plane->base.link);
1831 wl_list_init(&output->cursor_plane->base.link);
1832 /* Turn off hardware cursor */
1833 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
1834 }
1835 }
1836
1837 drm_output_fini_crtc(output);
1838 }
1839
1840 static void
1841 drm_head_destroy(struct drm_head *head);
1842
1843 static void
drm_output_destroy(struct weston_output * base)1844 drm_output_destroy(struct weston_output *base)
1845 {
1846 struct drm_output *output = to_drm_output(base);
1847 struct drm_backend *b = to_drm_backend(base->compositor);
1848
1849 assert(!output->virtual);
1850
1851 if (output->page_flip_pending || output->atomic_complete_pending) {
1852 output->destroy_pending = true;
1853 weston_log("destroy output while page flip pending\n");
1854 return;
1855 }
1856
1857 if (output->base.enabled)
1858 drm_output_deinit(&output->base);
1859
1860 drm_mode_list_destroy(b, &output->base.mode_list);
1861
1862 if (output->pageflip_timer)
1863 wl_event_source_remove(output->pageflip_timer);
1864
1865 weston_output_release(&output->base);
1866
1867 assert(!output->state_last);
1868 drm_output_state_free(output->state_cur);
1869
1870 free(output);
1871 }
1872
1873 static int
drm_output_disable(struct weston_output * base)1874 drm_output_disable(struct weston_output *base)
1875 {
1876 struct drm_output *output = to_drm_output(base);
1877
1878 assert(!output->virtual);
1879
1880 if (output->page_flip_pending || output->atomic_complete_pending) {
1881 output->disable_pending = true;
1882 return -1;
1883 }
1884
1885 weston_log("Disabling output %s\n", output->base.name);
1886
1887 if (output->base.enabled)
1888 drm_output_deinit(&output->base);
1889
1890 output->disable_pending = false;
1891
1892 return 0;
1893 }
1894
1895 /**
1896 * Update the list of unused connectors and CRTCs
1897 *
1898 * This keeps the unused_crtc arrays up to date.
1899 *
1900 * @param b Weston backend structure
1901 * @param resources DRM resources for this device
1902 */
1903 static void
drm_backend_update_unused_outputs(struct drm_backend * b,drmModeRes * resources)1904 drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources)
1905 {
1906 int i;
1907
1908 wl_array_release(&b->unused_crtcs);
1909 wl_array_init(&b->unused_crtcs);
1910
1911 for (i = 0; i < resources->count_crtcs; i++) {
1912 struct drm_output *output;
1913 uint32_t *crtc_id;
1914
1915 output = drm_output_find_by_crtc(b, resources->crtcs[i]);
1916 if (output && output->base.enabled)
1917 continue;
1918
1919 crtc_id = wl_array_add(&b->unused_crtcs, sizeof(*crtc_id));
1920 *crtc_id = resources->crtcs[i];
1921 }
1922 }
1923
1924 /*
1925 * This function converts the protection status from drm values to
1926 * weston_hdcp_protection status. The drm values as read from the connector
1927 * properties "Content Protection" and "HDCP Content Type" need to be converted
1928 * to appropriate weston values, that can be sent to a client application.
1929 */
1930 static int
get_weston_protection_from_drm(enum wdrm_content_protection_state protection,enum wdrm_hdcp_content_type type,enum weston_hdcp_protection * weston_protection)1931 get_weston_protection_from_drm(enum wdrm_content_protection_state protection,
1932 enum wdrm_hdcp_content_type type,
1933 enum weston_hdcp_protection *weston_protection)
1934
1935 {
1936 if (protection >= WDRM_CONTENT_PROTECTION__COUNT)
1937 return -1;
1938 if (protection == WDRM_CONTENT_PROTECTION_DESIRED ||
1939 protection == WDRM_CONTENT_PROTECTION_UNDESIRED) {
1940 *weston_protection = WESTON_HDCP_DISABLE;
1941 return 0;
1942 }
1943 if (type >= WDRM_HDCP_CONTENT_TYPE__COUNT)
1944 return -1;
1945 if (type == WDRM_HDCP_CONTENT_TYPE0) {
1946 *weston_protection = WESTON_HDCP_ENABLE_TYPE_0;
1947 return 0;
1948 }
1949 if (type == WDRM_HDCP_CONTENT_TYPE1) {
1950 *weston_protection = WESTON_HDCP_ENABLE_TYPE_1;
1951 return 0;
1952 }
1953 return -1;
1954 }
1955
1956 /**
1957 * Get current content-protection status for a given head.
1958 *
1959 * @param head drm_head, whose protection is to be retrieved
1960 * @param props drm property object of the connector, related to the head
1961 * @return protection status in case of success, -1 otherwise
1962 */
1963 static enum weston_hdcp_protection
drm_head_get_current_protection(struct drm_head * head,drmModeObjectProperties * props)1964 drm_head_get_current_protection(struct drm_head *head,
1965 drmModeObjectProperties *props)
1966 {
1967 struct drm_property_info *info;
1968 enum wdrm_content_protection_state protection;
1969 enum wdrm_hdcp_content_type type;
1970 enum weston_hdcp_protection weston_hdcp = WESTON_HDCP_DISABLE;
1971
1972 info = &head->props_conn[WDRM_CONNECTOR_CONTENT_PROTECTION];
1973 protection = drm_property_get_value(info, props,
1974 WDRM_CONTENT_PROTECTION__COUNT);
1975
1976 if (protection == WDRM_CONTENT_PROTECTION__COUNT)
1977 return WESTON_HDCP_DISABLE;
1978
1979 info = &head->props_conn[WDRM_CONNECTOR_HDCP_CONTENT_TYPE];
1980 type = drm_property_get_value(info, props,
1981 WDRM_HDCP_CONTENT_TYPE__COUNT);
1982
1983 /*
1984 * In case of platforms supporting HDCP1.4, only property
1985 * 'Content Protection' is exposed and not the 'HDCP Content Type'
1986 * for such cases HDCP Type 0 should be considered as the content-type.
1987 */
1988
1989 if (type == WDRM_HDCP_CONTENT_TYPE__COUNT)
1990 type = WDRM_HDCP_CONTENT_TYPE0;
1991
1992 if (get_weston_protection_from_drm(protection, type,
1993 &weston_hdcp) == -1) {
1994 weston_log("Invalid drm protection:%d type:%d, for head:%s connector-id:%d\n",
1995 protection, type, head->base.name,
1996 head->connector_id);
1997 return WESTON_HDCP_DISABLE;
1998 }
1999
2000 return weston_hdcp;
2001 }
2002
2003 /** Replace connector data and monitor information
2004 *
2005 * @param head The head to update.
2006 * @param connector The connector data to be owned by the head, must match
2007 * the head's connector ID.
2008 * @return 0 on success, -1 on failure.
2009 *
2010 * Takes ownership of @c connector on success, not on failure.
2011 *
2012 * May schedule a heads changed call.
2013 */
2014 static int
drm_head_assign_connector_info(struct drm_head * head,drmModeConnector * connector)2015 drm_head_assign_connector_info(struct drm_head *head,
2016 drmModeConnector *connector)
2017 {
2018 drmModeObjectProperties *props;
2019
2020 assert(connector);
2021 assert(head->connector_id == connector->connector_id);
2022
2023 props = drmModeObjectGetProperties(head->backend->drm.fd,
2024 head->connector_id,
2025 DRM_MODE_OBJECT_CONNECTOR);
2026 if (!props) {
2027 weston_log("Error: failed to get connector '%s' properties\n",
2028 head->base.name);
2029 return -1;
2030 }
2031
2032 if (head->connector)
2033 drmModeFreeConnector(head->connector);
2034 head->connector = connector;
2035
2036 drm_property_info_populate(head->backend, connector_props,
2037 head->props_conn,
2038 WDRM_CONNECTOR__COUNT, props);
2039 update_head_from_connector(head, props);
2040
2041 weston_head_set_content_protection_status(&head->base,
2042 drm_head_get_current_protection(head, props));
2043 drmModeFreeObjectProperties(props);
2044
2045 return 0;
2046 }
2047
2048 static void
drm_head_log_info(struct drm_head * head,const char * msg)2049 drm_head_log_info(struct drm_head *head, const char *msg)
2050 {
2051 if (head->base.connected) {
2052 weston_log("DRM: head '%s' %s, connector %d is connected, "
2053 "EDID make '%s', model '%s', serial '%s'\n",
2054 head->base.name, msg, head->connector_id,
2055 head->base.make, head->base.model,
2056 head->base.serial_number ?: "");
2057 } else {
2058 weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
2059 head->base.name, msg, head->connector_id);
2060 }
2061 }
2062
2063 /** Update connector and monitor information
2064 *
2065 * @param head The head to update.
2066 *
2067 * Re-reads the DRM property lists for the connector and updates monitor
2068 * information and connection status. This may schedule a heads changed call
2069 * to the user.
2070 */
2071 static void
drm_head_update_info(struct drm_head * head)2072 drm_head_update_info(struct drm_head *head)
2073 {
2074 drmModeConnector *connector;
2075
2076 connector = drmModeGetConnector(head->backend->drm.fd,
2077 head->connector_id);
2078 if (!connector) {
2079 weston_log("DRM: getting connector info for '%s' failed.\n",
2080 head->base.name);
2081 return;
2082 }
2083
2084 if (drm_head_assign_connector_info(head, connector) < 0)
2085 drmModeFreeConnector(connector);
2086
2087 if (head->base.device_changed)
2088 drm_head_log_info(head, "updated");
2089 }
2090
2091 /**
2092 * Create a Weston head for a connector
2093 *
2094 * Given a DRM connector, create a matching drm_head structure and add it
2095 * to Weston's head list.
2096 *
2097 * @param backend Weston backend structure
2098 * @param connector_id DRM connector ID for the head
2099 * @param drm_device udev device pointer
2100 * @returns The new head, or NULL on failure.
2101 */
2102 static struct drm_head *
drm_head_create(struct drm_backend * backend,uint32_t connector_id,struct udev_device * drm_device)2103 drm_head_create(struct drm_backend *backend, uint32_t connector_id,
2104 struct udev_device *drm_device)
2105 {
2106 struct drm_head *head;
2107 drmModeConnector *connector;
2108 char *name;
2109
2110 head = zalloc(sizeof *head);
2111 if (!head)
2112 return NULL;
2113
2114 connector = drmModeGetConnector(backend->drm.fd, connector_id);
2115 if (!connector)
2116 goto err_alloc;
2117
2118 name = make_connector_name(connector);
2119 if (!name)
2120 goto err_alloc;
2121
2122 weston_head_init(&head->base, name);
2123 free(name);
2124
2125 head->connector_id = connector_id;
2126 head->backend = backend;
2127
2128 head->backlight = backlight_init(drm_device, connector->connector_type);
2129
2130 if (drm_head_assign_connector_info(head, connector) < 0)
2131 goto err_init;
2132
2133 if (head->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
2134 head->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
2135 weston_head_set_internal(&head->base);
2136
2137 if (drm_head_read_current_setup(head, backend) < 0) {
2138 weston_log("Failed to retrieve current mode from connector %d.\n",
2139 head->connector_id);
2140 /* Not fatal. */
2141 }
2142
2143 weston_compositor_add_head(backend->compositor, &head->base);
2144 drm_head_log_info(head, "found");
2145
2146 return head;
2147
2148 err_init:
2149 weston_head_release(&head->base);
2150
2151 err_alloc:
2152 if (connector)
2153 drmModeFreeConnector(connector);
2154
2155 free(head);
2156
2157 return NULL;
2158 }
2159
2160 static void
drm_head_destroy(struct drm_head * head)2161 drm_head_destroy(struct drm_head *head)
2162 {
2163 weston_head_release(&head->base);
2164
2165 drm_property_info_free(head->props_conn, WDRM_CONNECTOR__COUNT);
2166 drmModeFreeConnector(head->connector);
2167
2168 if (head->backlight)
2169 backlight_destroy(head->backlight);
2170
2171 free(head);
2172 }
2173
2174 /**
2175 * Create a Weston output structure
2176 *
2177 * Create an "empty" drm_output. This is the implementation of
2178 * weston_backend::create_output.
2179 *
2180 * Creating an output is usually followed by drm_output_attach_head()
2181 * and drm_output_enable() to make use of it.
2182 *
2183 * @param compositor The compositor instance.
2184 * @param name Name for the new output.
2185 * @returns The output, or NULL on failure.
2186 */
2187 static struct weston_output *
drm_output_create(struct weston_compositor * compositor,const char * name)2188 drm_output_create(struct weston_compositor *compositor, const char *name)
2189 {
2190 struct drm_backend *b = to_drm_backend(compositor);
2191 struct drm_output *output;
2192
2193 output = zalloc(sizeof *output);
2194 if (output == NULL)
2195 return NULL;
2196
2197 output->backend = b;
2198 #ifdef BUILD_DRM_GBM
2199 output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
2200 #endif
2201
2202 weston_output_init(&output->base, compositor, name);
2203
2204 output->base.enable = drm_output_enable;
2205 output->base.destroy = drm_output_destroy;
2206 output->base.disable = drm_output_disable;
2207 output->base.attach_head = drm_output_attach_head;
2208 output->base.detach_head = drm_output_detach_head;
2209
2210 output->destroy_pending = false;
2211 output->disable_pending = false;
2212
2213 output->state_cur = drm_output_state_alloc(output, NULL);
2214
2215 weston_compositor_add_pending_output(&output->base, b->compositor);
2216
2217 return &output->base;
2218 }
2219
2220 static int
drm_backend_create_heads(struct drm_backend * b,struct udev_device * drm_device)2221 drm_backend_create_heads(struct drm_backend *b, struct udev_device *drm_device)
2222 {
2223 struct drm_head *head;
2224 drmModeRes *resources;
2225 int i;
2226
2227 resources = drmModeGetResources(b->drm.fd);
2228 if (!resources) {
2229 weston_log("drmModeGetResources failed\n");
2230 return -1;
2231 }
2232
2233 b->min_width = resources->min_width;
2234 b->max_width = resources->max_width;
2235 b->min_height = resources->min_height;
2236 b->max_height = resources->max_height;
2237
2238 for (i = 0; i < resources->count_connectors; i++) {
2239 uint32_t connector_id = resources->connectors[i];
2240
2241 head = drm_head_create(b, connector_id, drm_device);
2242 if (!head) {
2243 weston_log("DRM: failed to create head for connector %d.\n",
2244 connector_id);
2245 }
2246 }
2247
2248 drm_backend_update_unused_outputs(b, resources);
2249
2250 drmModeFreeResources(resources);
2251
2252 return 0;
2253 }
2254
2255 static void
drm_backend_update_heads(struct drm_backend * b,struct udev_device * drm_device)2256 drm_backend_update_heads(struct drm_backend *b, struct udev_device *drm_device)
2257 {
2258 drmModeRes *resources;
2259 struct weston_head *base, *next;
2260 struct drm_head *head;
2261 int i;
2262
2263 resources = drmModeGetResources(b->drm.fd);
2264 if (!resources) {
2265 weston_log("drmModeGetResources failed\n");
2266 return;
2267 }
2268
2269 /* collect new connectors that have appeared, e.g. MST */
2270 for (i = 0; i < resources->count_connectors; i++) {
2271 uint32_t connector_id = resources->connectors[i];
2272
2273 head = drm_head_find_by_connector(b, connector_id);
2274 if (head) {
2275 drm_head_update_info(head);
2276 } else {
2277 head = drm_head_create(b, connector_id, drm_device);
2278 if (!head)
2279 weston_log("DRM: failed to create head for hot-added connector %d.\n",
2280 connector_id);
2281 }
2282 }
2283
2284 /* Remove connectors that have disappeared. */
2285 wl_list_for_each_safe(base, next,
2286 &b->compositor->head_list, compositor_link) {
2287 bool removed = true;
2288
2289 head = to_drm_head(base);
2290
2291 for (i = 0; i < resources->count_connectors; i++) {
2292 if (resources->connectors[i] == head->connector_id) {
2293 removed = false;
2294 break;
2295 }
2296 }
2297
2298 if (!removed)
2299 continue;
2300
2301 weston_log("DRM: head '%s' (connector %d) disappeared.\n",
2302 head->base.name, head->connector_id);
2303 drm_head_destroy(head);
2304 }
2305
2306 drm_backend_update_unused_outputs(b, resources);
2307
2308 drmModeFreeResources(resources);
2309 }
2310
2311 static enum wdrm_connector_property
drm_head_find_property_by_id(struct drm_head * head,uint32_t property_id)2312 drm_head_find_property_by_id(struct drm_head *head, uint32_t property_id)
2313 {
2314 int i;
2315 enum wdrm_connector_property prop = WDRM_CONNECTOR__COUNT;
2316
2317 if (!head || !property_id)
2318 return WDRM_CONNECTOR__COUNT;
2319
2320 for (i = 0; i < WDRM_CONNECTOR__COUNT; i++)
2321 if (head->props_conn[i].prop_id == property_id) {
2322 prop = (enum wdrm_connector_property) i;
2323 break;
2324 }
2325 return prop;
2326 }
2327
2328 static void
drm_backend_update_conn_props(struct drm_backend * b,uint32_t connector_id,uint32_t property_id)2329 drm_backend_update_conn_props(struct drm_backend *b,
2330 uint32_t connector_id,
2331 uint32_t property_id)
2332 {
2333 struct drm_head *head;
2334 enum wdrm_connector_property conn_prop;
2335 drmModeObjectProperties *props;
2336
2337 head = drm_head_find_by_connector(b, connector_id);
2338 if (!head) {
2339 weston_log("DRM: failed to find head for connector id: %d.\n",
2340 connector_id);
2341 return;
2342 }
2343
2344 conn_prop = drm_head_find_property_by_id(head, property_id);
2345 if (conn_prop >= WDRM_CONNECTOR__COUNT)
2346 return;
2347
2348 props = drmModeObjectGetProperties(b->drm.fd,
2349 connector_id,
2350 DRM_MODE_OBJECT_CONNECTOR);
2351 if (!props) {
2352 weston_log("Error: failed to get connector '%s' properties\n",
2353 head->base.name);
2354 return;
2355 }
2356 if (conn_prop == WDRM_CONNECTOR_CONTENT_PROTECTION) {
2357 weston_head_set_content_protection_status(&head->base,
2358 drm_head_get_current_protection(head, props));
2359 }
2360 drmModeFreeObjectProperties(props);
2361 }
2362
2363 static int
udev_event_is_hotplug(struct drm_backend * b,struct udev_device * device)2364 udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
2365 {
2366 const char *sysnum;
2367 const char *val;
2368
2369 sysnum = udev_device_get_sysnum(device);
2370 if (!sysnum || atoi(sysnum) != b->drm.id)
2371 return 0;
2372
2373 val = udev_device_get_property_value(device, "HOTPLUG");
2374 if (!val)
2375 return 0;
2376
2377 return strcmp(val, "1") == 0;
2378 }
2379
2380 static int
udev_event_is_conn_prop_change(struct drm_backend * b,struct udev_device * device,uint32_t * connector_id,uint32_t * property_id)2381 udev_event_is_conn_prop_change(struct drm_backend *b,
2382 struct udev_device *device,
2383 uint32_t *connector_id,
2384 uint32_t *property_id)
2385
2386 {
2387 const char *val;
2388 int id;
2389
2390 val = udev_device_get_property_value(device, "CONNECTOR");
2391 if (!val || !safe_strtoint(val, &id))
2392 return 0;
2393 else
2394 *connector_id = id;
2395
2396 val = udev_device_get_property_value(device, "PROPERTY");
2397 if (!val || !safe_strtoint(val, &id))
2398 return 0;
2399 else
2400 *property_id = id;
2401
2402 return 1;
2403 }
2404
2405 static int
udev_drm_event(int fd,uint32_t mask,void * data)2406 udev_drm_event(int fd, uint32_t mask, void *data)
2407 {
2408 struct drm_backend *b = data;
2409 struct udev_device *event;
2410 uint32_t conn_id, prop_id;
2411
2412 event = udev_monitor_receive_device(b->udev_monitor);
2413
2414 if (udev_event_is_hotplug(b, event)) {
2415 if (udev_event_is_conn_prop_change(b, event, &conn_id, &prop_id))
2416 drm_backend_update_conn_props(b, conn_id, prop_id);
2417 else
2418 drm_backend_update_heads(b, event);
2419 }
2420
2421 udev_device_unref(event);
2422
2423 return 1;
2424 }
2425
2426 static void
drm_destroy(struct weston_compositor * ec)2427 drm_destroy(struct weston_compositor *ec)
2428 {
2429 struct drm_backend *b = to_drm_backend(ec);
2430 struct weston_head *base, *next;
2431
2432 udev_input_destroy(&b->input);
2433
2434 wl_event_source_remove(b->udev_drm_source);
2435 wl_event_source_remove(b->drm_source);
2436
2437 b->shutting_down = true;
2438
2439 destroy_sprites(b);
2440
2441 // OHOS remove logger
2442 // weston_log_scope_destroy(b->debug);
2443 b->debug = NULL;
2444 weston_compositor_shutdown(ec);
2445
2446 wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
2447 drm_head_destroy(to_drm_head(base));
2448
2449 #ifdef BUILD_DRM_GBM
2450 if (b->gbm)
2451 gbm_device_destroy(b->gbm);
2452 #endif
2453
2454 udev_monitor_unref(b->udev_monitor);
2455 udev_unref(b->udev);
2456
2457 weston_launcher_destroy(ec->launcher);
2458
2459 wl_array_release(&b->unused_crtcs);
2460
2461 DeInitWaylandDrmAuthService(); // OHOS drm auth
2462
2463 // OHOS vsync module
2464 b->vsync_thread_running = false;
2465 pthread_join(b->vsync_thread, NULL);
2466 VsyncModuleStop();
2467
2468 close(b->drm.fd);
2469 free(b->drm.filename);
2470 free(b);
2471 }
2472
2473 static void
session_notify(struct wl_listener * listener,void * data)2474 session_notify(struct wl_listener *listener, void *data)
2475 {
2476 struct weston_compositor *compositor = data;
2477 struct drm_backend *b = to_drm_backend(compositor);
2478 struct drm_plane *plane;
2479 struct drm_output *output;
2480
2481 if (compositor->session_active) {
2482 weston_log("activating session\n");
2483 weston_compositor_wake(compositor);
2484 weston_compositor_damage_all(compositor);
2485 b->state_invalid = true;
2486 udev_input_enable(&b->input);
2487 } else {
2488 weston_log("deactivating session\n");
2489 udev_input_disable(&b->input);
2490
2491 weston_compositor_offscreen(compositor);
2492
2493 /* If we have a repaint scheduled (either from a
2494 * pending pageflip or the idle handler), make sure we
2495 * cancel that so we don't try to pageflip when we're
2496 * vt switched away. The OFFSCREEN state will prevent
2497 * further attempts at repainting. When we switch
2498 * back, we schedule a repaint, which will process
2499 * pending frame callbacks. */
2500
2501 wl_list_for_each(output, &compositor->output_list, base.link) {
2502 output->base.repaint_needed = false;
2503 if (output->cursor_plane)
2504 drmModeSetCursor(b->drm.fd, output->crtc_id,
2505 0, 0, 0);
2506 }
2507
2508 output = container_of(compositor->output_list.next,
2509 struct drm_output, base.link);
2510
2511 wl_list_for_each(plane, &b->plane_list, link) {
2512 if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
2513 continue;
2514
2515 drmModeSetPlane(b->drm.fd,
2516 plane->plane_id,
2517 output->crtc_id, 0, 0,
2518 0, 0, 0, 0, 0, 0, 0, 0);
2519 }
2520 }
2521 }
2522
2523
2524 /**
2525 * Handle KMS GPU being added/removed
2526 *
2527 * If the device being added/removed is the KMS device, we activate/deactivate
2528 * the compositor session.
2529 *
2530 * @param compositor The compositor instance.
2531 * @param device The device being added/removed.
2532 * @param added Whether the device is being added (or removed)
2533 */
2534 static void
drm_device_changed(struct weston_compositor * compositor,dev_t device,bool added)2535 drm_device_changed(struct weston_compositor *compositor,
2536 dev_t device, bool added)
2537 {
2538 struct drm_backend *b = to_drm_backend(compositor);
2539
2540 if (b->drm.fd < 0 || b->drm.devnum != device ||
2541 compositor->session_active == added)
2542 return;
2543
2544 compositor->session_active = added;
2545 wl_signal_emit(&compositor->session_signal, compositor);
2546 }
2547
2548 /**
2549 * Determines whether or not a device is capable of modesetting. If successful,
2550 * sets b->drm.fd and b->drm.filename to the opened device.
2551 */
2552 static bool
drm_device_is_kms(struct drm_backend * b,struct udev_device * device)2553 drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
2554 {
2555 const char *filename = udev_device_get_devnode(device);
2556 const char *sysnum = udev_device_get_sysnum(device);
2557 dev_t devnum = udev_device_get_devnum(device);
2558 drmModeRes *res;
2559 int id = -1, fd;
2560
2561 if (!filename)
2562 return false;
2563
2564 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR | O_CLOEXEC); // OHOS
2565 if (fd < 0)
2566 return false;
2567
2568 res = drmModeGetResources(fd);
2569 if (!res)
2570 goto out_fd;
2571
2572 if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
2573 res->count_encoders <= 0)
2574 goto out_res;
2575
2576 if (sysnum)
2577 id = atoi(sysnum);
2578 if (!sysnum || id < 0) {
2579 weston_log("couldn't get sysnum for device %s\n", filename);
2580 goto out_res;
2581 }
2582
2583 /* We can be called successfully on multiple devices; if we have,
2584 * clean up old entries. */
2585 if (b->drm.fd >= 0)
2586 weston_launcher_close(b->compositor->launcher, b->drm.fd);
2587 free(b->drm.filename);
2588
2589 b->drm.fd = fd;
2590 b->drm.id = id;
2591 b->drm.filename = strdup(filename);
2592 b->drm.devnum = devnum;
2593
2594 drmModeFreeResources(res);
2595
2596 return true;
2597
2598 out_res:
2599 drmModeFreeResources(res);
2600 out_fd:
2601 weston_launcher_close(b->compositor->launcher, fd);
2602 return false;
2603 }
2604
2605 /*
2606 * Find primary GPU
2607 * Some systems may have multiple DRM devices attached to a single seat. This
2608 * function loops over all devices and tries to find a PCI device with the
2609 * boot_vga sysfs attribute set to 1.
2610 * If no such device is found, the first DRM device reported by udev is used.
2611 * Devices are also vetted to make sure they are are capable of modesetting,
2612 * rather than pure render nodes (GPU with no display), or pure
2613 * memory-allocation devices (VGEM).
2614 */
2615 static struct udev_device*
find_primary_gpu(struct drm_backend * b,const char * seat)2616 find_primary_gpu(struct drm_backend *b, const char *seat)
2617 {
2618 struct udev_enumerate *e;
2619 struct udev_list_entry *entry;
2620 const char *path, *device_seat, *id;
2621 struct udev_device *device, *drm_device, *pci;
2622
2623 e = udev_enumerate_new(b->udev);
2624 udev_enumerate_add_match_subsystem(e, "drm");
2625 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2626
2627 udev_enumerate_scan_devices(e);
2628 drm_device = NULL;
2629 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2630 bool is_boot_vga = false;
2631
2632 path = udev_list_entry_get_name(entry);
2633 device = udev_device_new_from_syspath(b->udev, path);
2634 if (!device)
2635 continue;
2636 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2637 if (!device_seat)
2638 device_seat = default_seat;
2639 if (strcmp(device_seat, seat)) {
2640 udev_device_unref(device);
2641 continue;
2642 }
2643
2644 pci = udev_device_get_parent_with_subsystem_devtype(device,
2645 "pci", NULL);
2646 if (pci) {
2647 id = udev_device_get_sysattr_value(pci, "boot_vga");
2648 if (id && !strcmp(id, "1"))
2649 is_boot_vga = true;
2650 }
2651
2652 /* If we already have a modesetting-capable device, and this
2653 * device isn't our boot-VGA device, we aren't going to use
2654 * it. */
2655 if (!is_boot_vga && drm_device) {
2656 udev_device_unref(device);
2657 continue;
2658 }
2659
2660 /* Make sure this device is actually capable of modesetting;
2661 * if this call succeeds, b->drm.{fd,filename} will be set,
2662 * and any old values freed. */
2663 if (!drm_device_is_kms(b, device)) {
2664 udev_device_unref(device);
2665 continue;
2666 }
2667
2668 /* There can only be one boot_vga device, and we try to use it
2669 * at all costs. */
2670 if (is_boot_vga) {
2671 if (drm_device)
2672 udev_device_unref(drm_device);
2673 drm_device = device;
2674 break;
2675 }
2676
2677 /* Per the (!is_boot_vga && drm_device) test above, we only
2678 * trump existing saved devices with boot-VGA devices, so if
2679 * we end up here, this must be the first device we've seen. */
2680 assert(!drm_device);
2681 drm_device = device;
2682 }
2683
2684 /* If we're returning a device to use, we must have an open FD for
2685 * it. */
2686 assert(!!drm_device == (b->drm.fd >= 0));
2687
2688 udev_enumerate_unref(e);
2689 return drm_device;
2690 }
2691
2692 static struct udev_device *
open_specific_drm_device(struct drm_backend * b,const char * name)2693 open_specific_drm_device(struct drm_backend *b, const char *name)
2694 {
2695 struct udev_device *device;
2696
2697 device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
2698 if (!device) {
2699 weston_log("ERROR: could not open DRM device '%s'\n", name);
2700 return NULL;
2701 }
2702
2703 if (!drm_device_is_kms(b, device)) {
2704 udev_device_unref(device);
2705 weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
2706 return NULL;
2707 }
2708
2709 /* If we're returning a device to use, we must have an open FD for
2710 * it. */
2711 assert(b->drm.fd >= 0);
2712
2713 return device;
2714 }
2715
2716 static void
planes_binding(struct weston_keyboard * keyboard,const struct timespec * time,uint32_t key,void * data)2717 planes_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2718 uint32_t key, void *data)
2719 {
2720 struct drm_backend *b = data;
2721
2722 switch (key) {
2723 case KEY_C:
2724 b->cursors_are_broken ^= true;
2725 break;
2726 case KEY_V:
2727 /* We don't support overlay-plane usage with legacy KMS. */
2728 if (b->atomic_modeset)
2729 b->sprites_are_broken ^= true;
2730 break;
2731 default:
2732 break;
2733 }
2734 }
2735
2736 #ifdef BUILD_VAAPI_RECORDER
2737 static void
recorder_destroy(struct drm_output * output)2738 recorder_destroy(struct drm_output *output)
2739 {
2740 vaapi_recorder_destroy(output->recorder);
2741 output->recorder = NULL;
2742
2743 weston_output_disable_planes_decr(&output->base);
2744
2745 wl_list_remove(&output->recorder_frame_listener.link);
2746 weston_log("[libva recorder] done\n");
2747 }
2748
2749 static void
recorder_frame_notify(struct wl_listener * listener,void * data)2750 recorder_frame_notify(struct wl_listener *listener, void *data)
2751 {
2752 struct drm_output *output;
2753 struct drm_backend *b;
2754 int fd, ret;
2755
2756 output = container_of(listener, struct drm_output,
2757 recorder_frame_listener);
2758 b = to_drm_backend(output->base.compositor);
2759
2760 if (!output->recorder)
2761 return;
2762
2763 ret = drmPrimeHandleToFD(b->drm.fd,
2764 output->scanout_plane->state_cur->fb->handles[0],
2765 DRM_CLOEXEC, &fd);
2766 if (ret) {
2767 weston_log("[libva recorder] "
2768 "failed to create prime fd for front buffer\n");
2769 return;
2770 }
2771
2772 ret = vaapi_recorder_frame(output->recorder, fd,
2773 output->scanout_plane->state_cur->fb->strides[0]);
2774 if (ret < 0) {
2775 weston_log("[libva recorder] aborted: %s\n", strerror(errno));
2776 recorder_destroy(output);
2777 }
2778 }
2779
2780 static void *
create_recorder(struct drm_backend * b,int width,int height,const char * filename)2781 create_recorder(struct drm_backend *b, int width, int height,
2782 const char *filename)
2783 {
2784 int fd;
2785 drm_magic_t magic;
2786
2787 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
2788 if (fd < 0)
2789 return NULL;
2790
2791 drmGetMagic(fd, &magic);
2792 drmAuthMagic(b->drm.fd, magic);
2793
2794 return vaapi_recorder_create(fd, width, height, filename);
2795 }
2796
2797 static void
recorder_binding(struct weston_keyboard * keyboard,const struct timespec * time,uint32_t key,void * data)2798 recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2799 uint32_t key, void *data)
2800 {
2801 struct drm_backend *b = data;
2802 struct drm_output *output;
2803 int width, height;
2804
2805 output = container_of(b->compositor->output_list.next,
2806 struct drm_output, base.link);
2807
2808 if (!output->recorder) {
2809 if (output->gbm_format != DRM_FORMAT_XRGB8888) {
2810 weston_log("failed to start vaapi recorder: "
2811 "output format not supported\n");
2812 return;
2813 }
2814
2815 width = output->base.current_mode->width;
2816 height = output->base.current_mode->height;
2817
2818 output->recorder =
2819 create_recorder(b, width, height, "capture.h264");
2820 if (!output->recorder) {
2821 weston_log("failed to create vaapi recorder\n");
2822 return;
2823 }
2824
2825 weston_output_disable_planes_incr(&output->base);
2826
2827 output->recorder_frame_listener.notify = recorder_frame_notify;
2828 wl_signal_add(&output->base.frame_signal,
2829 &output->recorder_frame_listener);
2830
2831 weston_output_schedule_repaint(&output->base);
2832
2833 weston_log("[libva recorder] initialized\n");
2834 } else {
2835 recorder_destroy(output);
2836 }
2837 }
2838 #else
2839 static void
recorder_binding(struct weston_keyboard * keyboard,const struct timespec * time,uint32_t key,void * data)2840 recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
2841 uint32_t key, void *data)
2842 {
2843 weston_log("Compiled without libva support\n");
2844 }
2845 #endif
2846
2847
2848 static const struct weston_drm_output_api api = {
2849 drm_output_set_mode,
2850 drm_output_set_gbm_format,
2851 drm_output_set_seat,
2852 };
2853
2854 // OHOS vsync module
2855 static void
ohos_drm_vsync_thread_main(void * backend)2856 ohos_drm_vsync_thread_main(void *backend)
2857 {
2858 struct drm_backend *b = backend;
2859 while (b->vsync_thread_running) {
2860 drmVBlank vbl = {
2861 .request = {
2862 .type = DRM_VBLANK_RELATIVE,
2863 .sequence = 1,
2864 },
2865 };
2866 if (drmWaitVBlank(b->drm.fd, &vbl) != 0) {
2867 weston_log("Failed to drmWaitVBlank (the first vblank event), because %{public}d", errno);
2868 sleep(0);
2869 } else {
2870 VsyncModuleTrigger();
2871 }
2872 }
2873 }
2874
2875 static struct drm_backend *
drm_backend_create(struct weston_compositor * compositor,struct weston_drm_backend_config * config)2876 drm_backend_create(struct weston_compositor *compositor,
2877 struct weston_drm_backend_config *config)
2878 {
2879 struct drm_backend *b;
2880 struct udev_device *drm_device;
2881 struct wl_event_loop *loop;
2882 const char *seat_id = default_seat;
2883 const char *session_seat;
2884 int ret;
2885
2886 session_seat = getenv("XDG_SEAT");
2887 if (session_seat)
2888 seat_id = session_seat;
2889
2890 if (config->seat_id)
2891 seat_id = config->seat_id;
2892
2893 weston_log("initializing drm backend\n");
2894
2895 b = zalloc(sizeof *b);
2896 if (b == NULL)
2897 return NULL;
2898
2899 b->state_invalid = true;
2900 b->drm.fd = -1;
2901 wl_array_init(&b->unused_crtcs);
2902
2903 // OHOS fix
2904 {
2905 int fd = drmOpen("hisilicon", NULL);
2906 if (fd >= 0) {
2907 b->use_tde = 1;
2908 drmClose(fd);
2909 weston_log("tde open success, \n");
2910 } else {
2911 b->use_tde = 0;
2912 weston_log("tde open failure\n");
2913 }
2914 }
2915
2916 b->compositor = compositor;
2917 b->use_pixman = config->use_pixman;
2918 b->pageflip_timeout = config->pageflip_timeout;
2919 b->use_pixman_shadow = config->use_pixman_shadow;
2920 // OHOS remove logger
2921 // b->debug = weston_compositor_add_log_scope(compositor, "drm-backend",
2922 // "Debug messages from DRM/KMS backend\n",
2923 // NULL, NULL, NULL);
2924
2925 compositor->backend = &b->base;
2926 compositor->require_input = !config->continue_without_input;
2927
2928 if (parse_gbm_format(config->gbm_format, DRM_FORMAT_XRGB8888, &b->gbm_format) < 0)
2929 goto err_compositor;
2930
2931 /* Check if we run drm-backend using weston-launch */
2932 compositor->launcher = weston_launcher_connect(compositor, config->tty,
2933 seat_id, true);
2934 if (compositor->launcher == NULL) {
2935 weston_log("fatal: drm backend should be run using "
2936 "weston-launch binary, or your system should "
2937 "provide the logind D-Bus API.\n");
2938 goto err_compositor;
2939 }
2940
2941 b->udev = udev_new();
2942 if (b->udev == NULL) {
2943 weston_log("failed to initialize udev context\n");
2944 goto err_launcher;
2945 }
2946
2947 b->session_listener.notify = session_notify;
2948 wl_signal_add(&compositor->session_signal, &b->session_listener);
2949
2950 if (config->specific_device)
2951 drm_device = open_specific_drm_device(b, config->specific_device);
2952 else
2953 drm_device = find_primary_gpu(b, seat_id);
2954 if (drm_device == NULL) {
2955 weston_log("no drm device found\n");
2956 goto err_udev;
2957 }
2958
2959 // OHOS vsync module
2960 if (VsyncModuleStart() == 0) {
2961 b->vsync_thread_running = true;
2962 pthread_create(&b->vsync_thread, NULL, ohos_drm_vsync_thread_main, b);
2963 }
2964
2965 // OHOS drm auth: init the wayland drm auth service
2966 InitWaylandDrmAuthService(compositor->wl_display, b->drm.fd);
2967
2968 if (init_kms_caps(b) < 0) {
2969 weston_log("failed to initialize kms\n");
2970 goto err_udev_dev;
2971 }
2972
2973 if (b->use_pixman) {
2974 if (init_pixman(b) < 0) {
2975 weston_log("failed to initialize pixman renderer\n");
2976 goto err_udev_dev;
2977 }
2978 } else {
2979 if (init_egl(b) < 0) {
2980 weston_log("failed to initialize egl\n");
2981 goto err_udev_dev;
2982 }
2983 }
2984
2985 b->base.destroy = drm_destroy;
2986 b->base.repaint_begin = drm_repaint_begin;
2987 b->base.repaint_flush = drm_repaint_flush;
2988 b->base.repaint_cancel = drm_repaint_cancel;
2989 b->base.create_output = drm_output_create;
2990 b->base.device_changed = drm_device_changed;
2991 b->base.can_scanout_dmabuf = drm_can_scanout_dmabuf;
2992
2993 weston_setup_vt_switch_bindings(compositor);
2994
2995 wl_list_init(&b->plane_list);
2996 create_sprites(b);
2997
2998 if (udev_input_init(&b->input,
2999 compositor, b->udev, seat_id,
3000 config->configure_device) < 0) {
3001 weston_log("failed to create input devices\n");
3002 // OHOS build
3003 // goto err_sprite;
3004 }
3005
3006 if (drm_backend_create_heads(b, drm_device) < 0) {
3007 weston_log("Failed to create heads for %s\n", b->drm.filename);
3008 goto err_udev_input;
3009 }
3010
3011 /* 'compute' faked zpos values in case HW doesn't expose any */
3012 drm_backend_create_faked_zpos(b);
3013
3014 /* A this point we have some idea of whether or not we have a working
3015 * cursor plane. */
3016 if (!b->cursors_are_broken)
3017 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
3018
3019 loop = wl_display_get_event_loop(compositor->wl_display);
3020 b->drm_source =
3021 wl_event_loop_add_fd(loop, b->drm.fd,
3022 WL_EVENT_READABLE, on_drm_input, b);
3023
3024 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
3025 if (b->udev_monitor == NULL) {
3026 weston_log("failed to initialize udev monitor\n");
3027 goto err_drm_source;
3028 }
3029 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
3030 "drm", NULL);
3031 b->udev_drm_source =
3032 wl_event_loop_add_fd(loop,
3033 udev_monitor_get_fd(b->udev_monitor),
3034 WL_EVENT_READABLE, udev_drm_event, b);
3035
3036 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
3037 weston_log("failed to enable udev-monitor receiving\n");
3038 goto err_udev_monitor;
3039 }
3040
3041 udev_device_unref(drm_device);
3042
3043 // OHOS remove debugger
3044 // weston_compositor_add_debug_binding(compositor, KEY_O,
3045 // planes_binding, b);
3046 // weston_compositor_add_debug_binding(compositor, KEY_C,
3047 // planes_binding, b);
3048 // weston_compositor_add_debug_binding(compositor, KEY_V,
3049 // planes_binding, b);
3050 // weston_compositor_add_debug_binding(compositor, KEY_Q,
3051 // recorder_binding, b);
3052 // weston_compositor_add_debug_binding(compositor, KEY_W,
3053 // renderer_switch_binding, b);
3054
3055
3056 if (compositor->renderer->import_dmabuf) {
3057 if (linux_dmabuf_setup(compositor) < 0)
3058 weston_log("Error: initializing dmabuf "
3059 "support failed.\n");
3060 if (weston_direct_display_setup(compositor) < 0)
3061 weston_log("Error: initializing direct-display "
3062 "support failed.\n");
3063 }
3064
3065 if (compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC) {
3066 if (linux_explicit_synchronization_setup(compositor) < 0)
3067 weston_log("Error: initializing explicit "
3068 " synchronization support failed.\n");
3069 }
3070
3071 if (b->atomic_modeset)
3072 if (weston_compositor_enable_content_protection(compositor) < 0)
3073 weston_log("Error: initializing content-protection "
3074 "support failed.\n");
3075
3076 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
3077 &api, sizeof(api));
3078
3079 if (ret < 0) {
3080 weston_log("Failed to register output API.\n");
3081 goto err_udev_monitor;
3082 }
3083
3084 ret = drm_backend_init_virtual_output_api(compositor);
3085 if (ret < 0) {
3086 weston_log("Failed to register virtual output API.\n");
3087 goto err_udev_monitor;
3088 }
3089
3090 return b;
3091
3092 err_udev_monitor:
3093 wl_event_source_remove(b->udev_drm_source);
3094 udev_monitor_unref(b->udev_monitor);
3095 err_drm_source:
3096 wl_event_source_remove(b->drm_source);
3097 err_udev_input:
3098 udev_input_destroy(&b->input);
3099 // OHOS build
3100 // err_sprite:
3101 #ifdef BUILD_DRM_GBM
3102 if (b->gbm)
3103 gbm_device_destroy(b->gbm);
3104 #endif
3105 destroy_sprites(b);
3106 err_udev_dev:
3107 udev_device_unref(drm_device);
3108 err_udev:
3109 udev_unref(b->udev);
3110 err_launcher:
3111 weston_launcher_destroy(compositor->launcher);
3112 err_compositor:
3113 weston_compositor_shutdown(compositor);
3114 free(b);
3115 return NULL;
3116 }
3117
3118 static void
config_init_to_defaults(struct weston_drm_backend_config * config)3119 config_init_to_defaults(struct weston_drm_backend_config *config)
3120 {
3121 // OHOS
3122 // config->use_pixman_shadow = true;
3123 config->use_pixman_shadow = false;
3124 }
3125
3126 WL_EXPORT int
weston_backend_init(struct weston_compositor * compositor,struct weston_backend_config * config_base)3127 weston_backend_init(struct weston_compositor *compositor,
3128 struct weston_backend_config *config_base)
3129 {
3130 struct drm_backend *b;
3131 struct weston_drm_backend_config config = {{ 0, }};
3132
3133 if (config_base == NULL ||
3134 config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
3135 config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
3136 weston_log("drm backend config structure is invalid\n");
3137 return -1;
3138 }
3139
3140 config_init_to_defaults(&config);
3141 memcpy(&config, config_base, config_base->struct_size);
3142
3143 b = drm_backend_create(compositor, &config);
3144 if (b == NULL)
3145 return -1;
3146
3147 return 0;
3148 }
3149