blob: cbb3253d05a30b869084d1c3709691344dbca224 [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040024#define _GNU_SOURCE
25
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
28#include <string.h>
29#include <fcntl.h>
30#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040031#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030032#include <assert.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040033
Benjamin Franzkec649a922011-03-02 11:56:04 +010034#include <xf86drm.h>
35#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050036#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010037
Benjamin Franzke060cf802011-04-30 09:32:11 +020038#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020039#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040040#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020041
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040042#include "compositor.h"
Tiago Vignattice03ec32011-12-19 01:14:03 +020043#include "evdev.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010044#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040045
Kristian Høgsberg061c4252012-06-28 11:28:15 -040046static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060047static char *output_name;
48static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060049static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060050static struct wl_list configured_output_list;
51
52enum output_config {
53 OUTPUT_CONFIG_INVALID = 0,
54 OUTPUT_CONFIG_OFF,
55 OUTPUT_CONFIG_PREFERRED,
56 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060057 OUTPUT_CONFIG_MODE,
58 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060059};
60
61struct drm_configured_output {
62 char *name;
63 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060064 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060065 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060066 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060067 enum output_config config;
68 struct wl_list link;
69};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040070
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040071struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050072 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040073
74 struct udev *udev;
75 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040076
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010077 struct udev_monitor *udev_monitor;
78 struct wl_event_source *udev_drm_source;
79
Benjamin Franzke2af7f102011-03-02 11:14:59 +010080 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010081 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010082 int fd;
83 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020084 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050085 uint32_t *crtcs;
86 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050087 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010088 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050089 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020090
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -040091 struct gbm_surface *dummy_surface;
92 EGLSurface dummy_egl_surface;
93
Rob Clark4339add2012-08-09 14:18:28 -050094 /* we need these parameters in order to not fail drmModeAddFB2()
95 * due to out of bounds dimensions, and then mistakenly set
96 * sprites_are_broken:
97 */
Kristian Høgsberg8a015802012-08-09 17:19:23 -040098 int32_t min_width, max_width;
99 int32_t min_height, max_height;
Rob Clark4339add2012-08-09 14:18:28 -0500100
Jesse Barnes58ef3792012-02-23 09:45:49 -0500101 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500102 int sprites_are_broken;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500103
Rob Clarkab5b1e32012-08-09 13:24:45 -0500104 int cursors_are_broken;
105
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200106 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400107};
108
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400109struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500110 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400111 drmModeModeInfo mode_info;
112};
113
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300114struct drm_output;
115
116struct drm_fb {
117 struct gbm_bo *bo;
118 struct drm_output *output;
119 uint32_t fb_id;
120 int is_client_buffer;
121 struct wl_buffer *buffer;
122 struct wl_listener buffer_destroy_listener;
123};
124
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400125struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500126 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400127
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400128 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400129 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500130 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400131 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700132 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200133
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300134 int vblank_pending;
135 int page_flip_pending;
136
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400137 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400138 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400139 struct weston_plane cursor_plane;
140 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400141 struct weston_surface *cursor_surface;
142 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300143 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200144 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400145};
146
Jesse Barnes58ef3792012-02-23 09:45:49 -0500147/*
148 * An output has a primary display plane plus zero or more sprites for
149 * blending display contents.
150 */
151struct drm_sprite {
152 struct wl_list link;
153
154 uint32_t fb_id;
155 uint32_t pending_fb_id;
156 struct weston_surface *surface;
157 struct weston_surface *pending_surface;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400158 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500159
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300160 struct drm_output *output;
161
Jesse Barnes58ef3792012-02-23 09:45:49 -0500162 struct drm_compositor *compositor;
163
164 struct wl_listener destroy_listener;
165 struct wl_listener pending_destroy_listener;
166
167 uint32_t possible_crtcs;
168 uint32_t plane_id;
169 uint32_t count_formats;
170
171 int32_t src_x, src_y;
172 uint32_t src_w, src_h;
173 uint32_t dest_x, dest_y;
174 uint32_t dest_w, dest_h;
175
176 uint32_t formats[];
177};
178
Pekka Paalanen33156972012-08-03 13:30:30 -0400179struct drm_seat {
180 struct weston_seat base;
181 struct wl_list devices_list;
182 struct udev_monitor *udev_monitor;
183 struct wl_event_source *udev_monitor_source;
184 char *seat_id;
185};
186
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400187static void
188drm_output_set_cursor(struct drm_output *output);
189static void
190drm_disable_unused_sprites(struct weston_output *output_base);
191
Jesse Barnes58ef3792012-02-23 09:45:49 -0500192static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500193drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
194{
195 struct weston_compositor *ec = output_base->compositor;
196 struct drm_compositor *c =(struct drm_compositor *) ec;
197 struct drm_output *output = (struct drm_output *) output_base;
198 int crtc;
199
200 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
201 if (c->crtcs[crtc] != output->crtc_id)
202 continue;
203
204 if (supported & (1 << crtc))
205 return -1;
206 }
207
208 return 0;
209}
210
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300211static void
212drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
213{
214 struct drm_fb *fb = data;
215 struct gbm_device *gbm = gbm_bo_get_device(bo);
216
217 if (fb->fb_id)
218 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
219
220 if (fb->buffer) {
221 weston_buffer_post_release(fb->buffer);
222 wl_list_remove(&fb->buffer_destroy_listener.link);
223 }
224
225 free(data);
226}
227
228static struct drm_fb *
229drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_output *output)
230{
231 struct drm_fb *fb = gbm_bo_get_user_data(bo);
232 struct drm_compositor *compositor =
233 (struct drm_compositor *) output->base.compositor;
234 uint32_t width, height, stride, handle;
235 int ret;
236
237 if (fb)
238 return fb;
239
240 fb = malloc(sizeof *fb);
241
242 fb->bo = bo;
243 fb->output = output;
244 fb->is_client_buffer = 0;
245 fb->buffer = NULL;
246
247 width = gbm_bo_get_width(bo);
248 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400249 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300250 handle = gbm_bo_get_handle(bo).u32;
251
252 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
253 stride, handle, &fb->fb_id);
254 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200255 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300256 free(fb);
257 return NULL;
258 }
259
260 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
261
262 return fb;
263}
264
265static void
266fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
267{
268 struct drm_fb *fb = container_of(listener, struct drm_fb,
269 buffer_destroy_listener);
270
271 fb->buffer = NULL;
272
273 if (fb == fb->output->next ||
274 (fb == fb->output->current && !fb->output->next))
Kristian Høgsberg49952d12012-06-20 00:35:59 -0400275 weston_output_schedule_repaint(&fb->output->base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300276}
277
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400278static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400279drm_output_prepare_scanout_surface(struct weston_output *_output,
280 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500281{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400282 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500283 struct drm_compositor *c =
284 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300285 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500286
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500287 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200288 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200289 es->geometry.width != output->base.current->width ||
290 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200291 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400292 es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400293 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500294
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400295 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
296 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500297
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300298 /* Need to verify output->region contained in surface opaque
299 * region. Or maybe just that format doesn't have alpha.
300 * For now, scanout only if format is XRGB8888. */
301 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
302 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400303 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300304 }
305
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300306 output->next = drm_fb_get_from_bo(bo, output);
307 if (!output->next) {
308 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400309 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300310 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500311
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300312 output->next->is_client_buffer = 1;
313 output->next->buffer = es->buffer;
314 output->next->buffer->busy_count++;
315 output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
316
317 wl_signal_add(&output->next->buffer->resource.destroy_signal,
318 &output->next->buffer_destroy_listener);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500319
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400320 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500321}
322
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500323static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400324drm_output_render(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400325{
Kristian Høgsbergfa1be022012-09-05 22:49:55 -0400326 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300327 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400328
Kristian Høgsbergfa1be022012-09-05 22:49:55 -0400329 ec->renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400330
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300331 bo = gbm_surface_lock_front_buffer(output->surface);
332 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200333 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400334 return;
335 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300336
337 output->next = drm_fb_get_from_bo(bo, output);
338 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200339 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300340 gbm_surface_release_buffer(output->surface, bo);
341 return;
342 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400343}
344
345static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500346drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400347 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100348{
349 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500350 struct drm_compositor *compositor =
351 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500352 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400353 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500354 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100355
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300356 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400357 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300358 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400359 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100360
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400361 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300362 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400363 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300364 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400365 &output->connector_id, 1,
366 &mode->mode_info);
367 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200368 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400369 return;
370 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200371 }
372
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500373 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300374 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500375 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200376 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500377 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500378 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100379
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300380 output->page_flip_pending = 1;
381
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400382 drm_output_set_cursor(output);
383
Jesse Barnes58ef3792012-02-23 09:45:49 -0500384 /*
385 * Now, update all the sprite surfaces
386 */
387 wl_list_for_each(s, &compositor->sprite_list, link) {
388 uint32_t flags = 0;
389 drmVBlank vbl = {
390 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
391 .request.sequence = 1,
392 };
393
394 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
395 continue;
396
397 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
398 output->crtc_id, s->pending_fb_id, flags,
399 s->dest_x, s->dest_y,
400 s->dest_w, s->dest_h,
401 s->src_x, s->src_y,
402 s->src_w, s->src_h);
403 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200404 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500405 ret, strerror(errno));
406
Rob Clark5ca1a472012-08-08 20:27:37 -0500407 if (output->pipe > 0)
408 vbl.request.type |= DRM_VBLANK_SECONDARY;
409
Jesse Barnes58ef3792012-02-23 09:45:49 -0500410 /*
411 * Queue a vblank signal so we know when the surface
412 * becomes active on the display or has been replaced.
413 */
414 vbl.request.signal = (unsigned long)s;
415 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
416 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200417 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500418 ret, strerror(errno));
419 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300420
421 s->output = output;
422 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500423 }
424
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400425 drm_disable_unused_sprites(&output->base);
426
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500427 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400428}
429
430static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500431vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
432 void *data)
433{
434 struct drm_sprite *s = (struct drm_sprite *)data;
435 struct drm_compositor *c = s->compositor;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300436 struct drm_output *output = s->output;
437 uint32_t msecs;
438
439 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500440
441 if (s->surface) {
442 weston_buffer_post_release(s->surface->buffer);
443 wl_list_remove(&s->destroy_listener.link);
444 s->surface = NULL;
445 drmModeRmFB(c->drm.fd, s->fb_id);
446 s->fb_id = 0;
447 }
448
449 if (s->pending_surface) {
450 wl_list_remove(&s->pending_destroy_listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400451 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
452 &s->destroy_listener);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500453 s->surface = s->pending_surface;
454 s->pending_surface = NULL;
455 s->fb_id = s->pending_fb_id;
456 s->pending_fb_id = 0;
457 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300458
459 if (!output->page_flip_pending) {
460 msecs = sec * 1000 + usec / 1000;
461 weston_output_finish_frame(&output->base, msecs);
462 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500463}
464
465static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400466page_flip_handler(int fd, unsigned int frame,
467 unsigned int sec, unsigned int usec, void *data)
468{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200469 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400470 uint32_t msecs;
471
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300472 output->page_flip_pending = 0;
473
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300474 if (output->current) {
475 if (output->current->is_client_buffer)
476 gbm_bo_destroy(output->current->bo);
477 else
478 gbm_surface_release_buffer(output->surface,
479 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200480 }
481
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300482 output->current = output->next;
483 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400484
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300485 if (!output->vblank_pending) {
486 msecs = sec * 1000 + usec / 1000;
487 weston_output_finish_frame(&output->base, msecs);
488 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200489}
490
491static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500492drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
493{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400494 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500495
496 for (i = 0; i < s->count_formats; i++)
497 if (s->formats[i] == format)
498 return 1;
499
500 return 0;
501}
502
503static int
504drm_surface_transform_supported(struct weston_surface *es)
505{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400506 struct weston_matrix *matrix = &es->transform.matrix;
507 int i;
508
509 if (!es->transform.enabled)
510 return 1;
511
512 for (i = 0; i < 16; i++) {
513 switch (i) {
514 case 10:
515 case 15:
516 if (matrix->d[i] != 1.0)
517 return 0;
518 break;
519 case 0:
520 case 5:
521 case 12:
522 case 13:
523 break;
524 default:
525 if (matrix->d[i] != 0.0)
526 return 0;
527 break;
528 }
529 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500530
531 return 1;
532}
533
Jesse Barnes58ef3792012-02-23 09:45:49 -0500534static void
535drm_disable_unused_sprites(struct weston_output *output_base)
536{
537 struct weston_compositor *ec = output_base->compositor;
538 struct drm_compositor *c =(struct drm_compositor *) ec;
539 struct drm_output *output = (struct drm_output *) output_base;
540 struct drm_sprite *s;
541 int ret;
542
543 wl_list_for_each(s, &c->sprite_list, link) {
544 if (s->pending_fb_id)
545 continue;
546
547 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
548 output->crtc_id, 0, 0,
549 0, 0, 0, 0, 0, 0, 0, 0);
550 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200551 weston_log("failed to disable plane: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500552 ret, strerror(errno));
553 drmModeRmFB(c->drm.fd, s->fb_id);
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +0300554
555 if (s->surface) {
556 s->surface = NULL;
557 wl_list_remove(&s->destroy_listener.link);
558 }
559
560 assert(!s->pending_surface);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500561 s->fb_id = 0;
562 s->pending_fb_id = 0;
563 }
564}
565
566/*
567 * This function must take care to damage any previously assigned surface
568 * if the sprite ends up binding to a different surface than in the
569 * previous frame.
570 */
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400571static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500572drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400573 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500574{
575 struct weston_compositor *ec = output_base->compositor;
576 struct drm_compositor *c =(struct drm_compositor *) ec;
577 struct drm_sprite *s;
578 int found = 0;
579 EGLint handle, stride;
580 struct gbm_bo *bo;
581 uint32_t fb_id = 0;
582 uint32_t handles[4], pitches[4], offsets[4];
583 int ret = 0;
584 pixman_region32_t dest_rect, src_rect;
585 pixman_box32_t *box;
586 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400587 wl_fixed_t sx1, sy1, sx2, sy2;
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400588 int32_t width, height;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500589
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500590 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400591 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500592
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300593 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400594 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300595
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400596 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400597 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500598
Rob Clark702ffae2012-08-09 14:18:27 -0500599 if (wl_buffer_is_shm(es->buffer))
600 return NULL;
601
Jesse Barnes58ef3792012-02-23 09:45:49 -0500602 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400603 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500604
Jesse Barnes58ef3792012-02-23 09:45:49 -0500605 wl_list_for_each(s, &c->sprite_list, link) {
606 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
607 continue;
608
609 if (!s->pending_fb_id) {
610 found = 1;
611 break;
612 }
613 }
614
615 /* No sprites available */
616 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400617 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500618
Rob Clark4339add2012-08-09 14:18:28 -0500619 width = es->geometry.width;
620 height = es->geometry.height;
621
622 /* If geometry is out of bounds, don't even bother trying because
623 * we know the AddFB2() call will fail:
624 */
625 if (c->min_width > width || width > c->max_width ||
626 c->min_height > height || height > c->max_height)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400627 return NULL;
Rob Clark4339add2012-08-09 14:18:28 -0500628
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400629 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
630 es->buffer, GBM_BO_USE_SCANOUT);
631 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400632 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400633
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634 format = gbm_bo_get_format(bo);
635 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400636 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500637
638 gbm_bo_destroy(bo);
639
640 if (!drm_surface_format_supported(s, format))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400641 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500642
643 if (!handle)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400644 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500645
646 handles[0] = handle;
647 pitches[0] = stride;
648 offsets[0] = 0;
649
Rob Clark4339add2012-08-09 14:18:28 -0500650 ret = drmModeAddFB2(c->drm.fd, width, height,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500651 format, handles, pitches, offsets,
652 &fb_id, 0);
653 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200654 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500655 c->sprites_are_broken = 1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400656 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500657 }
658
Jesse Barnes58ef3792012-02-23 09:45:49 -0500659 s->pending_fb_id = fb_id;
660 s->pending_surface = es;
661 es->buffer->busy_count++;
662
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400663 box = pixman_region32_extents(&es->transform.boundingbox);
664 s->plane.x = box->x1;
665 s->plane.y = box->y1;
666
Jesse Barnes58ef3792012-02-23 09:45:49 -0500667 /*
668 * Calculate the source & dest rects properly based on actual
669 * postion (note the caller has called weston_surface_update_transform()
670 * for us already).
671 */
672 pixman_region32_init(&dest_rect);
673 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
674 &output_base->region);
675 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
676 box = pixman_region32_extents(&dest_rect);
677 s->dest_x = box->x1;
678 s->dest_y = box->y1;
679 s->dest_w = box->x2 - box->x1;
680 s->dest_h = box->y2 - box->y1;
681 pixman_region32_fini(&dest_rect);
682
683 pixman_region32_init(&src_rect);
684 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
685 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500686 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400687
688 weston_surface_from_global_fixed(es,
689 wl_fixed_from_int(box->x1),
690 wl_fixed_from_int(box->y1),
691 &sx1, &sy1);
692 weston_surface_from_global_fixed(es,
693 wl_fixed_from_int(box->x2),
694 wl_fixed_from_int(box->y2),
695 &sx2, &sy2);
696
697 if (sx1 < 0)
698 sx1 = 0;
699 if (sy1 < 0)
700 sy1 = 0;
701 if (sx2 > wl_fixed_from_int(es->geometry.width))
702 sx2 = wl_fixed_from_int(es->geometry.width);
703 if (sy2 > wl_fixed_from_int(es->geometry.height))
704 sy2 = wl_fixed_from_int(es->geometry.height);
705
706 s->src_x = sx1 << 8;
707 s->src_y = sy1 << 8;
708 s->src_w = (sx2 - sx1) << 8;
709 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500710 pixman_region32_fini(&src_rect);
711
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400712 wl_signal_add(&es->buffer->resource.destroy_signal,
713 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400714
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400715 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500716}
717
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400718static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400719drm_output_prepare_cursor_surface(struct weston_output *output_base,
720 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500721{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400722 struct drm_compositor *c =
723 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400724 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400725
726 if (output->cursor_surface)
727 return NULL;
728 if (es->output_mask != (1u << output_base->id))
729 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500730 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400731 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400732 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
733 es->geometry.width > 64 || es->geometry.height > 64)
734 return NULL;
735
736 output->cursor_surface = es;
737
738 return &output->cursor_plane;
739}
740
741static void
742drm_output_set_cursor(struct drm_output *output)
743{
744 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400745 struct drm_compositor *c =
746 (struct drm_compositor *) output->base.compositor;
747 EGLint handle, stride;
748 struct gbm_bo *bo;
749 uint32_t buf[64 * 64];
750 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400751 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500752
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400753 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400754 if (es == NULL) {
755 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
756 return;
757 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500758
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400759 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
760 pixman_region32_fini(&output->cursor_plane.damage);
761 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400762 output->current_cursor ^= 1;
763 bo = output->cursor_bo[output->current_cursor];
764 memset(buf, 0, sizeof buf);
765 stride = wl_shm_buffer_get_stride(es->buffer);
766 s = wl_shm_buffer_get_data(es->buffer);
767 for (i = 0; i < es->geometry.height; i++)
768 memcpy(buf + i * 64, s + i * stride,
769 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500770
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400771 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300772 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400773
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400774 handle = gbm_bo_get_handle(bo).s32;
775 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500776 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300777 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500778 c->cursors_are_broken = 1;
779 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400780 }
781
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400782 x = es->geometry.x - output->base.x;
783 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400784 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500785 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400786 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500787 c->cursors_are_broken = 1;
788 }
789
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400790 output->cursor_plane.x = x;
791 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400792 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500793}
794
Jesse Barnes58ef3792012-02-23 09:45:49 -0500795static void
796drm_assign_planes(struct weston_output *output)
797{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400798 struct drm_compositor *c =
799 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400800 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400802 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500803
804 /*
805 * Find a surface for each sprite in the output using some heuristics:
806 * 1) size
807 * 2) frequency of update
808 * 3) opacity (though some hw might support alpha blending)
809 * 4) clipping (this can be fixed with color keys)
810 *
811 * The idea is to save on blitting since this should save power.
812 * If we can get a large video surface on the sprite for example,
813 * the main display surface may not need to update at all, and
814 * the client buffer can be used directly for the sprite surface
815 * as we do for flipping full screen surfaces.
816 */
817 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400818 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400819 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500820 pixman_region32_init(&surface_overlap);
821 pixman_region32_intersect(&surface_overlap, &overlap,
822 &es->transform.boundingbox);
823
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400824 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400825 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400826 next_plane = primary;
827 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400828 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400829 if (next_plane == NULL)
830 next_plane = drm_output_prepare_scanout_surface(output, es);
831 if (next_plane == NULL)
832 next_plane = drm_output_prepare_overlay_surface(output, es);
833 if (next_plane == NULL)
834 next_plane = primary;
835 weston_surface_move_to_plane(es, next_plane);
836 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500837 pixman_region32_union(&overlap, &overlap,
838 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400839
Jesse Barnes58ef3792012-02-23 09:45:49 -0500840 pixman_region32_fini(&surface_overlap);
841 }
842 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500843}
844
Matt Roper361d2ad2011-08-29 13:52:23 -0700845static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500846drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700847{
848 struct drm_output *output = (struct drm_output *) output_base;
849 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200850 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700851 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700852
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200853 if (output->backlight)
854 backlight_destroy(output->backlight);
855
Matt Roper361d2ad2011-08-29 13:52:23 -0700856 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400857 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700858
859 /* Restore original CRTC state */
860 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200861 origcrtc->x, origcrtc->y,
862 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700863 drmModeFreeCrtc(origcrtc);
864
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200865 c->crtc_allocator &= ~(1 << output->crtc_id);
866 c->connector_allocator &= ~(1 << output->connector_id);
867
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400868 eglDestroySurface(c->base.egl_display, output->base.egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400869 gbm_surface_destroy(output->surface);
870
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400871 weston_plane_release(&output->fb_plane);
872 weston_plane_release(&output->cursor_plane);
873
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500874 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200875 wl_list_remove(&output->base.link);
876
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400877 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700878 free(output);
879}
880
Alex Wub7b8bda2012-04-17 17:20:48 +0800881static struct drm_mode *
882choose_mode (struct drm_output *output, struct weston_mode *target_mode)
883{
884 struct drm_mode *tmp_mode = NULL, *mode;
885
886 if (output->base.current->width == target_mode->width &&
887 output->base.current->height == target_mode->height &&
888 (output->base.current->refresh == target_mode->refresh ||
889 target_mode->refresh == 0))
890 return (struct drm_mode *)output->base.current;
891
892 wl_list_for_each(mode, &output->base.mode_list, base.link) {
893 if (mode->mode_info.hdisplay == target_mode->width &&
894 mode->mode_info.vdisplay == target_mode->height) {
895 if (mode->mode_info.vrefresh == target_mode->refresh ||
896 target_mode->refresh == 0) {
897 return mode;
898 } else if (!tmp_mode)
899 tmp_mode = mode;
900 }
901 }
902
903 return tmp_mode;
904}
905
906static int
907drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
908{
909 struct drm_output *output;
910 struct drm_mode *drm_mode;
911 int ret;
912 struct drm_compositor *ec;
913 struct gbm_surface *surface;
914 EGLSurface egl_surface;
915
916 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200917 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800918 return -1;
919 }
920
921 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200922 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800923 return -1;
924 }
925
926 ec = (struct drm_compositor *)output_base->compositor;
927 output = (struct drm_output *)output_base;
928 drm_mode = choose_mode (output, mode);
929
930 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200931 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800932 return -1;
933 } else if (&drm_mode->base == output->base.current) {
934 return 0;
935 } else if (drm_mode->base.width == output->base.current->width &&
936 drm_mode->base.height == output->base.current->height) {
937 /* only change refresh value */
938 ret = drmModeSetCrtc(ec->drm.fd,
939 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300940 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800941 &output->connector_id, 1, &drm_mode->mode_info);
942
943 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200944 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800945 drm_mode->base.width,
946 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400947 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800948 ret = -1;
949 } else {
950 output->base.current->flags = 0;
951 output->base.current = &drm_mode->base;
952 drm_mode->base.flags =
953 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
954 ret = 0;
955 }
956
957 return ret;
958 }
959
960 drm_mode->base.flags =
961 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
962
963 surface = gbm_surface_create(ec->gbm,
964 drm_mode->base.width,
965 drm_mode->base.height,
966 GBM_FORMAT_XRGB8888,
967 GBM_BO_USE_SCANOUT |
968 GBM_BO_USE_RENDERING);
969 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200970 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800971 return -1;
972 }
973
974 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400975 eglCreateWindowSurface(ec->base.egl_display,
976 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800977 surface, NULL);
978
979 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200980 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800981 goto err;
982 }
983
984 ret = drmModeSetCrtc(ec->drm.fd,
985 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300986 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800987 &output->connector_id, 1, &drm_mode->mode_info);
988 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200989 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800990 goto err;
991 }
992
993 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300994 if (output->current) {
995 if (output->current->is_client_buffer)
996 gbm_bo_destroy(output->current->bo);
997 else
998 gbm_surface_release_buffer(output->surface,
999 output->current->bo);
1000 }
1001 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001002
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001003 if (output->next) {
1004 if (output->next->is_client_buffer)
1005 gbm_bo_destroy(output->next->bo);
1006 else
1007 gbm_surface_release_buffer(output->surface,
1008 output->next->bo);
1009 }
1010 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001011
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001012 eglDestroySurface(ec->base.egl_display, output->base.egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001013 gbm_surface_destroy(output->surface);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001014 output->base.egl_surface = egl_surface;
Alex Wub7b8bda2012-04-17 17:20:48 +08001015 output->surface = surface;
1016
1017 /*update output*/
1018 output->base.current = &drm_mode->base;
1019 output->base.dirty = 1;
1020 weston_output_move(&output->base, output->base.x, output->base.y);
1021 return 0;
1022
1023err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001024 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001025 gbm_surface_destroy(surface);
1026 return -1;
1027}
1028
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001029static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001030on_drm_input(int fd, uint32_t mask, void *data)
1031{
1032 drmEventContext evctx;
1033
1034 memset(&evctx, 0, sizeof evctx);
1035 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1036 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001037 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001038 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001039
1040 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001041}
1042
1043static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001044init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001045{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001046 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001047 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001048 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -04001049 static const EGLint context_attribs[] = {
1050 EGL_CONTEXT_CLIENT_VERSION, 2,
1051 EGL_NONE
1052 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001053
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001054 static const EGLint config_attribs[] = {
1055 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1056 EGL_RED_SIZE, 1,
1057 EGL_GREEN_SIZE, 1,
1058 EGL_BLUE_SIZE, 1,
1059 EGL_ALPHA_SIZE, 0,
1060 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1061 EGL_NONE
1062 };
1063
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001064 sysnum = udev_device_get_sysnum(device);
1065 if (sysnum)
1066 ec->drm.id = atoi(sysnum);
1067 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001068 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001069 return -1;
1070 }
1071
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001072 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001073 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001074 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001075 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001076 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001077 udev_device_get_devnode(device));
1078 return -1;
1079 }
1080
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001081 weston_log("using %s\n", filename);
1082
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001083 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001084 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001085 ec->base.egl_display = eglGetDisplay(ec->gbm);
1086 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001087 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001088 return -1;
1089 }
1090
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001091 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001092 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001093 return -1;
1094 }
1095
Darxus55973f22010-11-22 21:24:39 -05001096 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001097 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001098 return -1;
1099 }
1100
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001101 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1102 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001103 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001104 return -1;
1105 }
1106
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001107 ec->base.egl_context =
1108 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1109 EGL_NO_CONTEXT, context_attribs);
1110 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001111 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001112 return -1;
1113 }
1114
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001115 ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1116 GBM_FORMAT_XRGB8888,
1117 GBM_BO_USE_RENDERING);
1118 if (!ec->dummy_surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001119 weston_log("failed to create dummy gbm surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001120 return -1;
1121 }
1122
1123 ec->dummy_egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001124 eglCreateWindowSurface(ec->base.egl_display,
1125 ec->base.egl_config,
1126 ec->dummy_surface,
1127 NULL);
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001128 if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001129 weston_log("failed to create egl surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001130 return -1;
1131 }
1132
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001133 if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1134 ec->dummy_egl_surface, ec->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001135 weston_log("failed to make context current\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001136 return -1;
1137 }
1138
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001139 return 0;
1140}
1141
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001142static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001143drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1144{
1145 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001146 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001147
1148 mode = malloc(sizeof *mode);
1149 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001150 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001151
1152 mode->base.flags = 0;
1153 mode->base.width = info->hdisplay;
1154 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001155
1156 /* Calculate higher precision (mHz) refresh rate */
1157 refresh = (info->clock * 1000000LL / info->htotal +
1158 info->vtotal / 2) / info->vtotal;
1159
1160 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1161 refresh *= 2;
1162 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1163 refresh /= 2;
1164 if (info->vscan > 1)
1165 refresh /= info->vscan;
1166
1167 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001168 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001169
1170 if (info->type & DRM_MODE_TYPE_PREFERRED)
1171 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1172
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001173 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1174
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001175 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001176}
1177
1178static int
1179drm_subpixel_to_wayland(int drm_value)
1180{
1181 switch (drm_value) {
1182 default:
1183 case DRM_MODE_SUBPIXEL_UNKNOWN:
1184 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1185 case DRM_MODE_SUBPIXEL_NONE:
1186 return WL_OUTPUT_SUBPIXEL_NONE;
1187 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1188 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1189 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1190 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1191 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1192 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1193 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1194 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1195 }
1196}
1197
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001198static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001199sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001200{
1201 struct drm_sprite *sprite =
1202 container_of(listener, struct drm_sprite,
1203 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001204 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001205
1206 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001207 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1208 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001209}
1210
1211static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001212sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001213{
1214 struct drm_sprite *sprite =
1215 container_of(listener, struct drm_sprite,
1216 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001217 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001218
1219 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001220 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1221 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001222}
1223
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001224/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001225static uint32_t
1226drm_get_backlight(struct drm_output *output)
1227{
1228 long brightness, max_brightness, norm;
1229
1230 brightness = backlight_get_brightness(output->backlight);
1231 max_brightness = backlight_get_max_brightness(output->backlight);
1232
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001233 /* convert it on a scale of 0 to 255 */
1234 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001235
1236 return (uint32_t) norm;
1237}
1238
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001239/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001240static void
1241drm_set_backlight(struct weston_output *output_base, uint32_t value)
1242{
1243 struct drm_output *output = (struct drm_output *) output_base;
1244 long max_brightness, new_brightness;
1245
1246 if (!output->backlight)
1247 return;
1248
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001249 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001250 return;
1251
1252 max_brightness = backlight_get_max_brightness(output->backlight);
1253
1254 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001255 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001256
1257 backlight_set_brightness(output->backlight, new_brightness);
1258}
1259
1260static drmModePropertyPtr
1261drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1262{
1263 drmModePropertyPtr props;
1264 int i;
1265
1266 for (i = 0; i < connector->count_props; i++) {
1267 props = drmModeGetProperty(fd, connector->props[i]);
1268 if (!props)
1269 continue;
1270
1271 if (!strcmp(props->name, name))
1272 return props;
1273
1274 drmModeFreeProperty(props);
1275 }
1276
1277 return NULL;
1278}
1279
1280static void
1281drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1282{
1283 struct drm_output *output = (struct drm_output *) output_base;
1284 struct weston_compositor *ec = output_base->compositor;
1285 struct drm_compositor *c = (struct drm_compositor *) ec;
1286 drmModeConnectorPtr connector;
1287 drmModePropertyPtr prop;
1288
1289 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1290 if (!connector)
1291 return;
1292
1293 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1294 if (!prop) {
1295 drmModeFreeConnector(connector);
1296 return;
1297 }
1298
1299 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1300 prop->prop_id, level);
1301 drmModeFreeProperty(prop);
1302 drmModeFreeConnector(connector);
1303}
1304
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001305static const char *connector_type_names[] = {
1306 "None",
1307 "VGA",
1308 "DVI",
1309 "DVI",
1310 "DVI",
1311 "Composite",
1312 "TV",
1313 "LVDS",
1314 "CTV",
1315 "DIN",
1316 "DP",
1317 "HDMI",
1318 "HDMI",
1319 "TV",
1320 "eDP",
1321};
1322
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001323static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001324find_crtc_for_connector(struct drm_compositor *ec,
1325 drmModeRes *resources, drmModeConnector *connector)
1326{
1327 drmModeEncoder *encoder;
1328 uint32_t possible_crtcs;
1329 int i, j;
1330
1331 for (j = 0; j < connector->count_encoders; j++) {
1332 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1333 if (encoder == NULL) {
1334 weston_log("Failed to get encoder.\n");
1335 return -1;
1336 }
1337 possible_crtcs = encoder->possible_crtcs;
1338 drmModeFreeEncoder(encoder);
1339
1340 for (i = 0; i < resources->count_crtcs; i++) {
1341 if (possible_crtcs & (1 << i) &&
1342 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1343 return i;
1344 }
1345 }
1346
1347 return -1;
1348}
1349
1350static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001351create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001352 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001353 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001354 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001355{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001356 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001357 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1358 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001359 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001360 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001361 drmModeModeInfo crtc_mode;
1362 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001363 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001364 char name[32];
1365 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001366
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001367 i = find_crtc_for_connector(ec, resources, connector);
1368 if (i < 0) {
1369 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001370 return -1;
1371 }
1372
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001373 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001374 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001375 return -1;
1376
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001377 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001378 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1379 output->base.make = "unknown";
1380 output->base.model = "unknown";
1381 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001382
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001383 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1384 type_name = connector_type_names[connector->connector_type];
1385 else
1386 type_name = "UNKNOWN";
1387 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1388 output->name = strdup(name);
1389
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001390 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001391 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001392 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001393 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001394 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001395
Matt Roper361d2ad2011-08-29 13:52:23 -07001396 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1397
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001398 /* Get the current mode on the crtc that's currently driving
1399 * this connector. */
1400 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001401 memset(&crtc_mode, 0, sizeof crtc_mode);
1402 if (encoder != NULL) {
1403 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1404 drmModeFreeEncoder(encoder);
1405 if (crtc == NULL)
1406 goto err_free;
1407 if (crtc->mode_valid)
1408 crtc_mode = crtc->mode;
1409 drmModeFreeCrtc(crtc);
1410 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001411
David Herrmann0f0d54e2011-12-08 17:05:45 +01001412 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001413 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1414 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001415 goto err_free;
1416 }
1417
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001418 preferred = NULL;
1419 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001420 configured = NULL;
1421
1422 wl_list_for_each(temp, &configured_output_list, link) {
1423 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001424 if (temp->mode)
1425 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001426 temp->name, temp->mode);
1427 o = temp;
1428 break;
1429 }
1430 }
1431
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001432 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001433 weston_log("Disabling output %s\n", o->name);
1434
1435 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1436 0, 0, 0, 0, 0, NULL);
1437 goto err_free;
1438 }
1439
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001440 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001441 if (o && o->config == OUTPUT_CONFIG_MODE &&
1442 o->width == drm_mode->base.width &&
1443 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001444 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001445 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001446 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001447 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001448 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001449 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001450
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001451 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001452 configured = drm_output_add_mode(output, &o->crtc_mode);
1453 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001454 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001455 current = configured;
1456 }
1457
Wang Quanxianacb805a2012-07-30 18:09:46 -04001458 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001459 current = drm_output_add_mode(output, &crtc_mode);
1460 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001461 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001462 }
1463
Scott Moreau8ab5d452012-07-30 19:51:08 -06001464 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1465 configured = current;
1466
Wang Quanxianacb805a2012-07-30 18:09:46 -04001467 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001468 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001469 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001470 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001471 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001472 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001473 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001474 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001475
1476 if (output->base.current == NULL) {
1477 weston_log("no available modes for %s\n", output->name);
1478 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001479 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001480
Wang Quanxianacb805a2012-07-30 18:09:46 -04001481 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1482
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001483 output->surface = gbm_surface_create(ec->gbm,
1484 output->base.current->width,
1485 output->base.current->height,
1486 GBM_FORMAT_XRGB8888,
1487 GBM_BO_USE_SCANOUT |
1488 GBM_BO_USE_RENDERING);
1489 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001490 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001491 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001492 }
1493
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001494 output->base.egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001495 eglCreateWindowSurface(ec->base.egl_display,
1496 ec->base.egl_config,
1497 output->surface,
1498 NULL);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001499 if (output->base.egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001500 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001501 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001502 }
1503
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001504 output->cursor_bo[0] =
1505 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1506 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1507 output->cursor_bo[1] =
1508 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1509 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1510
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001511 output->backlight = backlight_init(drm_device,
1512 connector->connector_type);
1513 if (output->backlight) {
1514 output->base.set_backlight = drm_set_backlight;
1515 output->base.backlight_current = drm_get_backlight(output);
1516 }
1517
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001518 weston_output_init(&output->base, &ec->base, x, y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001519 connector->mmWidth, connector->mmHeight,
1520 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001521
1522 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1523
Alex Wubd3354b2012-04-17 17:20:49 +08001524 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001525 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001526 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001527 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001528 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001529 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001530
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001531 weston_plane_init(&output->cursor_plane, 0, 0);
1532 weston_plane_init(&output->fb_plane, 0, 0);
1533
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001534 weston_log("Output %s, (connector %d, crtc %d)\n",
1535 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001536 wl_list_for_each(m, &output->base.mode_list, link)
1537 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1538 m->width, m->height, m->refresh / 1000.0,
1539 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1540 ", preferred" : "",
1541 m->flags & WL_OUTPUT_MODE_CURRENT ?
1542 ", current" : "",
1543 connector->count_modes == 0 ?
1544 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001545
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001546 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001547
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001548err_surface:
1549 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001550err_free:
1551 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1552 base.link) {
1553 wl_list_remove(&drm_mode->base.link);
1554 free(drm_mode);
1555 }
1556
1557 drmModeFreeCrtc(output->original_crtc);
1558 ec->crtc_allocator &= ~(1 << output->crtc_id);
1559 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001560 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001561 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001562
David Herrmann0f0d54e2011-12-08 17:05:45 +01001563 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001564}
1565
Jesse Barnes58ef3792012-02-23 09:45:49 -05001566static void
1567create_sprites(struct drm_compositor *ec)
1568{
1569 struct drm_sprite *sprite;
1570 drmModePlaneRes *plane_res;
1571 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001572 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001573
1574 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1575 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001576 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001577 strerror(errno));
1578 return;
1579 }
1580
1581 for (i = 0; i < plane_res->count_planes; i++) {
1582 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1583 if (!plane)
1584 continue;
1585
1586 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1587 plane->count_formats));
1588 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001589 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001590 __func__);
1591 free(plane);
1592 continue;
1593 }
1594
1595 memset(sprite, 0, sizeof *sprite);
1596
1597 sprite->possible_crtcs = plane->possible_crtcs;
1598 sprite->plane_id = plane->plane_id;
1599 sprite->surface = NULL;
1600 sprite->pending_surface = NULL;
1601 sprite->fb_id = 0;
1602 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001603 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1604 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001605 sprite_handle_pending_buffer_destroy;
1606 sprite->compositor = ec;
1607 sprite->count_formats = plane->count_formats;
1608 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001609 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001610 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001611 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001612
1613 wl_list_insert(&ec->sprite_list, &sprite->link);
1614 }
1615
1616 free(plane_res->planes);
1617 free(plane_res);
1618}
1619
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001620static void
1621destroy_sprites(struct drm_compositor *compositor)
1622{
1623 struct drm_sprite *sprite, *next;
1624 struct drm_output *output;
1625
1626 output = container_of(compositor->base.output_list.next,
1627 struct drm_output, base.link);
1628
1629 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1630 drmModeSetPlane(compositor->drm.fd,
1631 sprite->plane_id,
1632 output->crtc_id, 0, 0,
1633 0, 0, 0, 0, 0, 0, 0, 0);
1634 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001635 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001636 free(sprite);
1637 }
1638}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001639
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001640static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001641create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001642 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001643{
1644 drmModeConnector *connector;
1645 drmModeRes *resources;
1646 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001647 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001648
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001649 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001650 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001651 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001652 return -1;
1653 }
1654
Jesse Barnes58ef3792012-02-23 09:45:49 -05001655 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001656 if (!ec->crtcs) {
1657 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001658 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001659 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001660
Rob Clark4339add2012-08-09 14:18:28 -05001661 ec->min_width = resources->min_width;
1662 ec->max_width = resources->max_width;
1663 ec->min_height = resources->min_height;
1664 ec->max_height = resources->max_height;
1665
Jesse Barnes58ef3792012-02-23 09:45:49 -05001666 ec->num_crtcs = resources->count_crtcs;
1667 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1668
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001669 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001670 connector = drmModeGetConnector(ec->drm.fd,
1671 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001672 if (connector == NULL)
1673 continue;
1674
1675 if (connector->connection == DRM_MODE_CONNECTED &&
1676 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001677 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001678 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001679 connector, x, y,
1680 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001681 drmModeFreeConnector(connector);
1682 continue;
1683 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001684
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001685 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001686 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001687 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001688 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001689
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001690 drmModeFreeConnector(connector);
1691 }
1692
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001693 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001694 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001695 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001696 return -1;
1697 }
1698
1699 drmModeFreeResources(resources);
1700
1701 return 0;
1702}
1703
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001704static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001705update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001706{
1707 drmModeConnector *connector;
1708 drmModeRes *resources;
1709 struct drm_output *output, *next;
1710 int x = 0, y = 0;
1711 int x_offset = 0, y_offset = 0;
1712 uint32_t connected = 0, disconnects = 0;
1713 int i;
1714
1715 resources = drmModeGetResources(ec->drm.fd);
1716 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001717 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001718 return;
1719 }
1720
1721 /* collect new connects */
1722 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001723 int connector_id = resources->connectors[i];
1724
1725 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001726 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001727 continue;
1728
David Herrmann7551cff2011-12-08 17:05:43 +01001729 if (connector->connection != DRM_MODE_CONNECTED) {
1730 drmModeFreeConnector(connector);
1731 continue;
1732 }
1733
Benjamin Franzke117483d2011-08-30 11:38:26 +02001734 connected |= (1 << connector_id);
1735
1736 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001737 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001738 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001739 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001740
1741 /* XXX: not yet needed, we die with 0 outputs */
1742 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001743 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001744 else
1745 x = 0;
1746 y = 0;
1747 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001748 connector, x, y,
1749 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001750 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001751
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001752 }
1753 drmModeFreeConnector(connector);
1754 }
1755 drmModeFreeResources(resources);
1756
1757 disconnects = ec->connector_allocator & ~connected;
1758 if (disconnects) {
1759 wl_list_for_each_safe(output, next, &ec->base.output_list,
1760 base.link) {
1761 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001762 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001763 output->base.x - x_offset,
1764 output->base.y - y_offset);
1765 }
1766
1767 if (disconnects & (1 << output->connector_id)) {
1768 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001769 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001770 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001771 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001772 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001773 }
1774 }
1775 }
1776
1777 /* FIXME: handle zero outputs, without terminating */
1778 if (ec->connector_allocator == 0)
1779 wl_display_terminate(ec->base.wl_display);
1780}
1781
1782static int
David Herrmannd7488c22012-03-11 20:05:21 +01001783udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001784{
David Herrmannd7488c22012-03-11 20:05:21 +01001785 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001786 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001787
1788 sysnum = udev_device_get_sysnum(device);
1789 if (!sysnum || atoi(sysnum) != ec->drm.id)
1790 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001791
David Herrmann6ac52db2012-03-11 20:05:22 +01001792 val = udev_device_get_property_value(device, "HOTPLUG");
1793 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001794 return 0;
1795
David Herrmann6ac52db2012-03-11 20:05:22 +01001796 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001797}
1798
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001799static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001800udev_drm_event(int fd, uint32_t mask, void *data)
1801{
1802 struct drm_compositor *ec = data;
1803 struct udev_device *event;
1804
1805 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001806
David Herrmannd7488c22012-03-11 20:05:21 +01001807 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001808 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001809
1810 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001811
1812 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001813}
1814
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001815static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001816drm_restore(struct weston_compositor *ec)
1817{
1818 struct drm_compositor *d = (struct drm_compositor *) ec;
1819
1820 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1821 weston_log("failed to drop master: %m\n");
1822 tty_reset(d->tty);
1823}
1824
Pekka Paalanen33156972012-08-03 13:30:30 -04001825static const char default_seat[] = "seat0";
1826
1827static void
1828device_added(struct udev_device *udev_device, struct drm_seat *master)
1829{
1830 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001831 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001832 const char *devnode;
1833 const char *device_seat;
1834 int fd;
1835
1836 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1837 if (!device_seat)
1838 device_seat = default_seat;
1839
1840 if (strcmp(device_seat, master->seat_id))
1841 return;
1842
1843 c = master->base.compositor;
1844 devnode = udev_device_get_devnode(udev_device);
1845
1846 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001847 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001848 * read. mtdev_get() also expects this. */
1849 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1850 if (fd < 0) {
1851 weston_log("opening input device '%s' failed.\n", devnode);
1852 return;
1853 }
1854
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001855 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001856 if (!device) {
1857 close(fd);
1858 weston_log("not using input device '%s'.\n", devnode);
1859 return;
1860 }
1861
1862 wl_list_insert(master->devices_list.prev, &device->link);
1863}
1864
1865static void
1866evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1867{
1868 struct drm_seat *seat = (struct drm_seat *) seat_base;
1869 struct udev_enumerate *e;
1870 struct udev_list_entry *entry;
1871 struct udev_device *device;
1872 const char *path, *sysname;
1873
1874 e = udev_enumerate_new(udev);
1875 udev_enumerate_add_match_subsystem(e, "input");
1876 udev_enumerate_scan_devices(e);
1877 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1878 path = udev_list_entry_get_name(entry);
1879 device = udev_device_new_from_syspath(udev, path);
1880
1881 sysname = udev_device_get_sysname(device);
1882 if (strncmp("event", sysname, 5) != 0) {
1883 udev_device_unref(device);
1884 continue;
1885 }
1886
1887 device_added(device, seat);
1888
1889 udev_device_unref(device);
1890 }
1891 udev_enumerate_unref(e);
1892
1893 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1894
1895 if (wl_list_empty(&seat->devices_list)) {
1896 weston_log(
1897 "warning: no input devices on entering Weston. "
1898 "Possible causes:\n"
1899 "\t- no permissions to read /dev/input/event*\n"
1900 "\t- seats misconfigured "
1901 "(Weston backend option 'seat', "
1902 "udev device property ID_SEAT)\n");
1903 }
1904}
1905
1906static int
1907evdev_udev_handler(int fd, uint32_t mask, void *data)
1908{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001909 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001910 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001911 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001912 const char *action;
1913 const char *devnode;
1914
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001915 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001916 if (!udev_device)
1917 return 1;
1918
1919 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001920 if (!action)
1921 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001922
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001923 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1924 goto out;
1925
1926 if (!strcmp(action, "add")) {
1927 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001928 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001929 else if (!strcmp(action, "remove")) {
1930 devnode = udev_device_get_devnode(udev_device);
1931 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1932 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001933 weston_log("input device %s, %s removed\n",
1934 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001935 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001936 break;
1937 }
1938 }
1939
1940out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001941 udev_device_unref(udev_device);
1942
1943 return 0;
1944}
1945
1946static int
1947evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1948{
1949 struct drm_seat *master = (struct drm_seat *) seat_base;
1950 struct wl_event_loop *loop;
1951 struct weston_compositor *c = master->base.compositor;
1952 int fd;
1953
1954 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1955 if (!master->udev_monitor) {
1956 weston_log("udev: failed to create the udev monitor\n");
1957 return 0;
1958 }
1959
1960 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1961 "input", NULL);
1962
1963 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1964 weston_log("udev: failed to bind the udev monitor\n");
1965 udev_monitor_unref(master->udev_monitor);
1966 return 0;
1967 }
1968
1969 loop = wl_display_get_event_loop(c->wl_display);
1970 fd = udev_monitor_get_fd(master->udev_monitor);
1971 master->udev_monitor_source =
1972 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1973 evdev_udev_handler, master);
1974 if (!master->udev_monitor_source) {
1975 udev_monitor_unref(master->udev_monitor);
1976 return 0;
1977 }
1978
1979 return 1;
1980}
1981
1982static void
1983evdev_disable_udev_monitor(struct weston_seat *seat_base)
1984{
1985 struct drm_seat *seat = (struct drm_seat *) seat_base;
1986
1987 if (!seat->udev_monitor)
1988 return;
1989
1990 udev_monitor_unref(seat->udev_monitor);
1991 seat->udev_monitor = NULL;
1992 wl_event_source_remove(seat->udev_monitor_source);
1993 seat->udev_monitor_source = NULL;
1994}
1995
1996static void
1997drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1998{
1999 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002000 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04002001
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03002002 wl_list_for_each(device, &seat->devices_list, link)
2003 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04002004}
2005
2006static void
2007evdev_input_create(struct weston_compositor *c, struct udev *udev,
2008 const char *seat_id)
2009{
2010 struct drm_seat *seat;
2011
2012 seat = malloc(sizeof *seat);
2013 if (seat == NULL)
2014 return;
2015
2016 memset(seat, 0, sizeof *seat);
2017 weston_seat_init(&seat->base, c);
2018 seat->base.led_update = drm_led_update;
2019
2020 wl_list_init(&seat->devices_list);
2021 seat->seat_id = strdup(seat_id);
2022 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
2023 free(seat->seat_id);
2024 free(seat);
2025 return;
2026 }
2027
2028 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002029}
2030
2031static void
2032evdev_remove_devices(struct weston_seat *seat_base)
2033{
2034 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002035 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04002036
2037 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002038 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04002039
Pekka Paalanend8583512012-08-03 14:39:11 +03002040 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04002041 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002042}
2043
2044static void
2045evdev_input_destroy(struct weston_seat *seat_base)
2046{
2047 struct drm_seat *seat = (struct drm_seat *) seat_base;
2048
2049 evdev_remove_devices(seat_base);
2050 evdev_disable_udev_monitor(&seat->base);
2051
2052 weston_seat_release(seat_base);
2053 free(seat->seat_id);
2054 free(seat);
2055}
2056
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002057static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002058drm_free_configured_output(struct drm_configured_output *output)
2059{
2060 free(output->name);
2061 free(output->mode);
2062 free(output);
2063}
2064
2065static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002066drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002067{
2068 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002069 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002070 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002071
Daniel Stone37816df2012-05-16 18:45:18 +01002072 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2073 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002074 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002075 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002076
2077 wl_event_source_remove(d->udev_drm_source);
2078 wl_event_source_remove(d->drm_source);
2079
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002080 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002081
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002082 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002083 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002084 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002085 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002086 eglReleaseThread();
2087
Matt Roper361d2ad2011-08-29 13:52:23 -07002088 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002089 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002090 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002091 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002092 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002093
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002094 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002095}
2096
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002097static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002098drm_compositor_set_modes(struct drm_compositor *compositor)
2099{
2100 struct drm_output *output;
2101 struct drm_mode *drm_mode;
2102 int ret;
2103
2104 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2105 drm_mode = (struct drm_mode *) output->base.current;
2106 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002107 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002108 &output->connector_id, 1,
2109 &drm_mode->mode_info);
2110 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002111 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002112 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002113 drm_mode->base.width, drm_mode->base.height,
2114 output->base.x, output->base.y);
2115 }
2116 }
2117}
2118
2119static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002120vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002121{
2122 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002123 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002124 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002125 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002126
2127 switch (event) {
2128 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002129 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002130 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002131 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002132 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002133 wl_display_terminate(compositor->wl_display);
2134 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002135 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002136 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002137 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002138 wl_list_for_each(seat, &compositor->seat_list, link) {
2139 evdev_add_devices(ec->udev, seat);
2140 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002141 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002142 break;
2143 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002144 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002145 wl_list_for_each(seat, &compositor->seat_list, link) {
2146 evdev_disable_udev_monitor(seat);
2147 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002148 }
2149
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002150 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002151 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002152 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002153
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002154 /* If we have a repaint scheduled (either from a
2155 * pending pageflip or the idle handler), make sure we
2156 * cancel that so we don't try to pageflip when we're
2157 * vt switched away. The SLEEPING state will prevent
2158 * further attemps at repainting. When we switch
2159 * back, we schedule a repaint, which will process
2160 * pending frame callbacks. */
2161
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002162 wl_list_for_each(output, &ec->base.output_list, base.link) {
2163 output->base.repaint_needed = 0;
2164 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002165 }
2166
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002167 output = container_of(ec->base.output_list.next,
2168 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002169
2170 wl_list_for_each(sprite, &ec->sprite_list, link)
2171 drmModeSetPlane(ec->drm.fd,
2172 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002173 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002174 0, 0, 0, 0, 0, 0, 0, 0);
2175
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002176 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002177 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002178
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002179 break;
2180 };
2181}
2182
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002183static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002184switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002185{
2186 struct drm_compositor *ec = data;
2187
Daniel Stone325fc2d2012-05-30 16:31:58 +01002188 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002189}
2190
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002191static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002192drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002193 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002194 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002195{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002196 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002197 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002198 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002199 struct udev_device *device, *drm_device;
2200 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002201 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002202 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002203 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002204
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002205 weston_log("initializing drm backend\n");
2206
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002207 ec = malloc(sizeof *ec);
2208 if (ec == NULL)
2209 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002210 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002211
2212 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002213 config_file) < 0) {
2214 weston_log("weston_compositor_init failed\n");
2215 goto err_base;
2216 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002217
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002218 ec->udev = udev_new();
2219 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002220 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002221 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002222 }
2223
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002224 ec->base.wl_display = display;
2225 ec->tty = tty_create(&ec->base, vt_func, tty);
2226 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002227 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002228 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002229 }
2230
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002231 e = udev_enumerate_new(ec->udev);
2232 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02002233 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002234
Benjamin Franzke117483d2011-08-30 11:38:26 +02002235 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002236 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002237 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002238 path = udev_list_entry_get_name(entry);
2239 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002240 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002241 udev_device_get_property_value(device, "ID_SEAT");
2242 if (!device_seat)
2243 device_seat = default_seat;
2244 if (strcmp(device_seat, seat) == 0) {
2245 drm_device = device;
2246 break;
2247 }
2248 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002249 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002250
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002251 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002252 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002253 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002254 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002255
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002256 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002257 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002258 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002259 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002260
2261 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002262 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002263
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002264 ec->base.focus = 1;
2265
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002266 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002267
Kristian Høgsberg25894fc2012-09-05 22:06:26 -04002268 if (gles2_renderer_init(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01002269 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02002270
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002271 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002272 weston_compositor_add_key_binding(&ec->base, key,
2273 MODIFIER_CTRL | MODIFIER_ALT,
2274 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002275
Jesse Barnes58ef3792012-02-23 09:45:49 -05002276 wl_list_init(&ec->sprite_list);
2277 create_sprites(ec);
2278
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002279 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002280 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002281 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002282 }
2283
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002284 path = NULL;
2285
Tiago Vignattice03ec32011-12-19 01:14:03 +02002286 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002287
2288 loop = wl_display_get_event_loop(ec->base.wl_display);
2289 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002290 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002291 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002292
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002293 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2294 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002295 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002296 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002297 }
2298 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2299 "drm", NULL);
2300 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002301 wl_event_loop_add_fd(loop,
2302 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002303 WL_EVENT_READABLE, udev_drm_event, ec);
2304
2305 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002306 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002307 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002308 }
2309
Daniel Stonea96b93c2012-06-22 14:04:37 +01002310 udev_device_unref(drm_device);
2311 udev_enumerate_unref(e);
2312
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002313 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002314
2315err_udev_monitor:
2316 wl_event_source_remove(ec->udev_drm_source);
2317 udev_monitor_unref(ec->udev_monitor);
2318err_drm_source:
2319 wl_event_source_remove(ec->drm_source);
2320 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2321 evdev_input_destroy(weston_seat);
2322err_sprite:
2323 destroy_sprites(ec);
2324err_egl:
2325 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2326 EGL_NO_CONTEXT);
2327 eglTerminate(ec->base.egl_display);
2328 eglReleaseThread();
2329 gbm_device_destroy(ec->gbm);
2330err_udev_dev:
2331 udev_device_unref(drm_device);
2332err_udev_enum:
2333 udev_enumerate_unref(e);
2334 tty_destroy(ec->tty);
2335err_udev:
2336 udev_unref(ec->udev);
2337err_compositor:
2338 weston_compositor_shutdown(&ec->base);
2339err_base:
2340 free(ec);
2341 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002342}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002343
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002344static int
2345set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2346{
2347 mode->flags = 0;
2348
2349 if (strcmp(hsync, "+hsync") == 0)
2350 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2351 else if (strcmp(hsync, "-hsync") == 0)
2352 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2353 else
2354 return -1;
2355
2356 if (strcmp(vsync, "+vsync") == 0)
2357 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2358 else if (strcmp(vsync, "-vsync") == 0)
2359 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2360 else
2361 return -1;
2362
2363 return 0;
2364}
2365
2366static int
2367check_for_modeline(struct drm_configured_output *output)
2368{
2369 drmModeModeInfo mode;
2370 char hsync[16];
2371 char vsync[16];
2372 char mode_name[16];
2373 float fclock;
2374
2375 mode.type = DRM_MODE_TYPE_USERDEF;
2376 mode.hskew = 0;
2377 mode.vscan = 0;
2378 mode.vrefresh = 0;
2379
2380 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2381 &fclock, &mode.hdisplay,
2382 &mode.hsync_start,
2383 &mode.hsync_end, &mode.htotal,
2384 &mode.vdisplay,
2385 &mode.vsync_start,
2386 &mode.vsync_end, &mode.vtotal,
2387 hsync, vsync) == 11) {
2388 if (set_sync_flags(&mode, hsync, vsync))
2389 return -1;
2390
2391 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2392 strcpy(mode.name, mode_name);
2393
2394 mode.clock = fclock * 1000;
2395 } else
2396 return -1;
2397
2398 output->crtc_mode = mode;
2399
2400 return 0;
2401}
2402
Scott Moreau8ab5d452012-07-30 19:51:08 -06002403static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002404drm_output_set_transform(struct drm_configured_output *output)
2405{
2406 if (!output_transform) {
2407 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2408 return;
2409 }
2410
2411 if (!strcmp(output_transform, "normal"))
2412 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2413 else if (!strcmp(output_transform, "90"))
2414 output->transform = WL_OUTPUT_TRANSFORM_90;
2415 else if (!strcmp(output_transform, "180"))
2416 output->transform = WL_OUTPUT_TRANSFORM_180;
2417 else if (!strcmp(output_transform, "270"))
2418 output->transform = WL_OUTPUT_TRANSFORM_270;
2419 else if (!strcmp(output_transform, "flipped"))
2420 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2421 else if (!strcmp(output_transform, "flipped-90"))
2422 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2423 else if (!strcmp(output_transform, "flipped-180"))
2424 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2425 else if (!strcmp(output_transform, "flipped-270"))
2426 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2427 else {
2428 weston_log("Invalid transform \"%s\" for output %s\n",
2429 output_transform, output_name);
2430 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2431 }
2432
2433 free(output_transform);
2434 output_transform = NULL;
2435}
2436
2437static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002438output_section_done(void *data)
2439{
2440 struct drm_configured_output *output;
2441
2442 output = malloc(sizeof *output);
2443
Scott Moreau1bad5db2012-08-18 01:04:05 -06002444 if (!output || !output_name || (output_name[0] == 'X') ||
2445 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002446 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002447 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002448 free(output_transform);
2449 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002450 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002451 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002452 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002453 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002454
2455 output->config = OUTPUT_CONFIG_INVALID;
2456 output->name = output_name;
2457 output->mode = output_mode;
2458
Scott Moreau1bad5db2012-08-18 01:04:05 -06002459 if (output_mode) {
2460 if (strcmp(output_mode, "off") == 0)
2461 output->config = OUTPUT_CONFIG_OFF;
2462 else if (strcmp(output_mode, "preferred") == 0)
2463 output->config = OUTPUT_CONFIG_PREFERRED;
2464 else if (strcmp(output_mode, "current") == 0)
2465 output->config = OUTPUT_CONFIG_CURRENT;
2466 else if (sscanf(output_mode, "%dx%d",
2467 &output->width, &output->height) == 2)
2468 output->config = OUTPUT_CONFIG_MODE;
2469 else if (check_for_modeline(output) == 0)
2470 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002471
Scott Moreau1bad5db2012-08-18 01:04:05 -06002472 if (output->config == OUTPUT_CONFIG_INVALID)
2473 weston_log("Invalid mode \"%s\" for output %s\n",
2474 output_mode, output_name);
2475 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002476 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002477
2478 drm_output_set_transform(output);
2479
2480 wl_list_insert(&configured_output_list, &output->link);
2481
2482 if (output_transform)
2483 free(output_transform);
2484 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002485}
2486
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002487WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002488backend_init(struct wl_display *display, int argc, char *argv[],
2489 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002490{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002491 int connector = 0, tty = 0;
2492 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002493
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002494 const struct weston_option drm_options[] = {
2495 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2496 { WESTON_OPTION_STRING, "seat", 0, &seat },
2497 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002498 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002499 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002500
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002501 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002502
Scott Moreau8ab5d452012-07-30 19:51:08 -06002503 wl_list_init(&configured_output_list);
2504
2505 const struct config_key drm_config_keys[] = {
2506 { "name", CONFIG_KEY_STRING, &output_name },
2507 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002508 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002509 };
2510
2511 const struct config_section config_section[] = {
2512 { "output", drm_config_keys,
2513 ARRAY_LENGTH(drm_config_keys), output_section_done },
2514 };
2515
2516 parse_config_file(config_file, config_section,
2517 ARRAY_LENGTH(config_section), NULL);
2518
Daniel Stonec1be8e52012-06-01 11:14:02 -04002519 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2520 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002521}