1/* swc: primary_plane.c
2 *
3 * Copyright (c) 2013, 2014, 2016 Michael Forney
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include "primary_plane.h"
25#include "drm.h"
26#include "event.h"
27#include "internal.h"
28#include "launch.h"
29#include "util.h"
30
31#include <errno.h>
32#include <wld/drm.h>
33#include <wld/wld.h>
34#include <xf86drm.h>
35#include <xf86drmMode.h>
36
37static bool
38update(struct view *view)
39{
40 return true;
41}
42
43static void
44send_frame(void *data)
45{
46 struct primary_plane *plane = data;
47
48 view_frame(&plane->view, get_time());
49}
50
51static int
52attach(struct view *view, struct wld_buffer *buffer)
53{
54 struct primary_plane *plane = wl_container_of(view, plane, view);
55 uint32_t fb;
56 int ret;
57
58 fb = drm_get_framebuffer(buffer);
59 if (plane->need_modeset) {
60 ret = drmModeSetCrtc(swc.drm->fd, plane->crtc, fb, 0, 0,
61 plane->connectors.data, plane->connectors.size / 4,
62 &plane->mode.info);
63
64 if (ret == 0) {
65 wl_event_loop_add_idle(swc.event_loop, &send_frame, plane);
66 plane->need_modeset = false;
67 } else {
68 ERROR("Could not set CRTC to next framebuffer: %s\n",
69 strerror(-ret));
70 return ret;
71 }
72 } else {
73 ret = drmModePageFlip(swc.drm->fd, plane->crtc, fb,
74 DRM_MODE_PAGE_FLIP_EVENT, &plane->drm_handler);
75
76 if (ret < 0) {
77 ERROR("Page flip failed: %s\n", strerror(errno));
78 return ret;
79 }
80 }
81
82 return 0;
83}
84
85static bool
86move(struct view *view, int32_t x, int32_t y)
87{
88 view_set_position(view, x, y);
89 return true;
90}
91
92static const struct view_impl view_impl = {
93 .update = update,
94 .attach = attach,
95 .move = move,
96};
97
98static void
99handle_page_flip(struct drm_handler *handler, uint32_t time)
100{
101 struct primary_plane *plane = wl_container_of(handler, plane, drm_handler);
102 view_frame(&plane->view, time);
103}
104
105static void
106handle_swc_event(struct wl_listener *listener, void *data)
107{
108 struct event *event = data;
109 struct primary_plane *plane =
110 wl_container_of(listener, plane, swc_listener);
111
112 switch (event->type) {
113 case SWC_EVENT_ACTIVATED:
114 plane->need_modeset = true;
115 break;
116 }
117}
118
119bool
120primary_plane_initialize(struct primary_plane *plane, uint32_t crtc,
121 struct mode *mode, uint32_t *connectors,
122 uint32_t num_connectors)
123{
124 uint32_t *plane_connectors;
125
126 if (!(plane->original_crtc_state = drmModeGetCrtc(swc.drm->fd, crtc))) {
127 ERROR("Failed to get CRTC state for CRTC %u: %s\n", crtc,
128 strerror(errno));
129 goto error0;
130 }
131
132 wl_array_init(&plane->connectors);
133 plane_connectors = wl_array_add(&plane->connectors,
134 num_connectors * sizeof(connectors[0]));
135
136 if (!plane_connectors) {
137 ERROR("Failed to allocate connector array\n");
138 goto error1;
139 }
140
141 memcpy(plane_connectors, connectors,
142 num_connectors * sizeof(connectors[0]));
143 plane->crtc = crtc;
144 plane->need_modeset = true;
145 view_initialize(&plane->view, &view_impl);
146 plane->view.geometry.width = mode->width;
147 plane->view.geometry.height = mode->height;
148 plane->drm_handler.page_flip = &handle_page_flip;
149 plane->swc_listener.notify = &handle_swc_event;
150 plane->mode = *mode;
151 wl_signal_add(&swc.event_signal, &plane->swc_listener);
152
153 return true;
154
155error1:
156 drmModeFreeCrtc(plane->original_crtc_state);
157error0:
158 return false;
159}
160
161void
162primary_plane_finalize(struct primary_plane *plane)
163{
164 wl_array_release(&plane->connectors);
165 drmModeCrtcPtr crtc = plane->original_crtc_state;
166 drmModeSetCrtc(swc.drm->fd, crtc->crtc_id, crtc->buffer_id, crtc->x,
167 crtc->y, NULL, 0, &crtc->mode);
168 drmModeFreeCrtc(crtc);
169}