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 "event.h"
26#ifdef ENABLE_DRM
27#include "drm.h"
28#else
29#include "compositor.h"
30#include "fb.h"
31#endif
32#include "internal.h"
33#include "launch.h"
34#include "util.h"
35
36#ifdef ENABLE_DRM
37#include <errno.h>
38#include <wld/drm.h>
39#include <xf86drm.h>
40#include <xf86drmMode.h>
41#endif
42#include <wld/wld.h>
43
44static bool
45update(struct view *view)
46{
47 return true;
48}
49
50static void
51send_frame(void *data)
52{
53 struct primary_plane *plane = data;
54
55 view_frame(&plane->view, get_time());
56}
57
58static int
59attach(struct view *view, struct wld_buffer *buffer)
60{
61 struct primary_plane *plane = wl_container_of(view, plane, view);
62#ifdef ENABLE_DRM
63 uint32_t fb;
64 int ret;
65
66 fb = drm_get_framebuffer(buffer);
67 if (plane->need_modeset) {
68 ret = drmModeSetCrtc(swc.drm->fd, plane->crtc, fb, 0, 0,
69 plane->connectors.data, plane->connectors.size / 4,
70 &plane->mode.info);
71
72 if (ret == 0) {
73 wl_event_loop_add_idle(swc.event_loop, &send_frame, plane);
74 plane->need_modeset = false;
75 } else {
76 ERROR("Could not set CRTC to next framebuffer: %s\n",
77 strerror(-ret));
78 return ret;
79 }
80 } else {
81 ret = drmModePageFlip(swc.drm->fd, plane->crtc, fb,
82 DRM_MODE_PAGE_FLIP_EVENT, &plane->drm_handler);
83
84 if (ret < 0) {
85 ERROR("Page flip failed: %s\n", strerror(errno));
86 return ret;
87 }
88 }
89
90 return 0;
91#else
92 if (!fb_present(buffer, view->geometry.x, view->geometry.y)) {
93 return -1;
94 }
95 wl_event_loop_add_idle(swc.event_loop, &send_frame, plane);
96 return 0;
97#endif
98}
99
100static bool
101move(struct view *view, int32_t x, int32_t y)
102{
103 view_set_position(view, x, y);
104 return true;
105}
106
107static const struct view_impl view_impl = {
108 .update = update,
109 .attach = attach,
110 .move = move,
111};
112
113#ifdef ENABLE_DRM
114static void
115handle_page_flip(struct drm_handler *handler, uint32_t time)
116{
117 struct primary_plane *plane = wl_container_of(handler, plane, drm_handler);
118 view_frame(&plane->view, time);
119}
120#endif
121
122static void
123handle_swc_event(struct wl_listener *listener, void *data)
124{
125 struct event *event = data;
126 struct primary_plane *plane =
127 wl_container_of(listener, plane, swc_listener);
128
129 switch (event->type) {
130 case SWC_EVENT_ACTIVATED:
131#ifdef ENABLE_DRM
132 plane->need_modeset = true;
133#else
134 compositor_damage_all();
135#endif
136 break;
137 }
138}
139
140bool
141#ifdef ENABLE_DRM
142primary_plane_initialize(struct primary_plane *plane, uint32_t crtc,
143 struct mode *mode, uint32_t *connectors,
144 uint32_t num_connectors)
145#else
146primary_plane_initialize(struct primary_plane *plane, struct mode *mode)
147#endif
148{
149#ifdef ENABLE_DRM
150 uint32_t *plane_connectors;
151
152 if (!(plane->original_crtc_state = drmModeGetCrtc(swc.drm->fd, crtc))) {
153 ERROR("Failed to get CRTC state for CRTC %u: %s\n", crtc,
154 strerror(errno));
155 goto error0;
156 }
157
158 wl_array_init(&plane->connectors);
159 plane_connectors = wl_array_add(&plane->connectors,
160 num_connectors * sizeof(connectors[0]));
161
162 if (!plane_connectors) {
163 ERROR("Failed to allocate connector array\n");
164 goto error1;
165 }
166
167 memcpy(plane_connectors, connectors,
168 num_connectors * sizeof(connectors[0]));
169 plane->crtc = crtc;
170 plane->need_modeset = true;
171 view_initialize(&plane->view, &view_impl);
172 plane->view.geometry.width = mode->width;
173 plane->view.geometry.height = mode->height;
174 plane->drm_handler.page_flip = &handle_page_flip;
175 plane->swc_listener.notify = &handle_swc_event;
176 plane->mode = *mode;
177#else
178 view_initialize(&plane->view, &view_impl);
179 plane->view.geometry.width = mode->width;
180 plane->view.geometry.height = mode->height;
181 plane->mode = *mode;
182#endif
183 plane->swc_listener.notify = &handle_swc_event;
184 wl_signal_add(&swc.event_signal, &plane->swc_listener);
185
186 return true;
187
188#ifdef ENABLE_DRM
189error1:
190 drmModeFreeCrtc(plane->original_crtc_state);
191error0:
192 return false;
193#endif
194}
195
196void
197primary_plane_finalize(struct primary_plane *plane)
198{
199 wl_list_remove(&plane->swc_listener.link);
200#ifdef ENABLE_DRM
201 wl_array_release(&plane->connectors);
202 drmModeCrtcPtr crtc = plane->original_crtc_state;
203 drmModeSetCrtc(swc.drm->fd, crtc->crtc_id, crtc->buffer_id, crtc->x,
204 crtc->y, NULL, 0, &crtc->mode);
205 drmModeFreeCrtc(crtc);
206#else
207 (void)plane;
208#endif
209}