main neuswc / libswc / primary_plane.c
  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}