blob: 27f2c7d87aae6f2bf4b3688294adce528b6aa8b0 [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"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010043#include "gl-renderer.h"
Tiago Vignattice03ec32011-12-19 01:14:03 +020044#include "evdev.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010045#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040046
Kristian Høgsberg061c4252012-06-28 11:28:15 -040047static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060048static char *output_name;
49static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060050static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060051static struct wl_list configured_output_list;
52
53enum output_config {
54 OUTPUT_CONFIG_INVALID = 0,
55 OUTPUT_CONFIG_OFF,
56 OUTPUT_CONFIG_PREFERRED,
57 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060058 OUTPUT_CONFIG_MODE,
59 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060060};
61
62struct drm_configured_output {
63 char *name;
64 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060065 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060066 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060067 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060068 enum output_config config;
69 struct wl_list link;
70};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040071
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040072struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050073 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074
75 struct udev *udev;
76 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040077
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010078 struct udev_monitor *udev_monitor;
79 struct wl_event_source *udev_drm_source;
80
Benjamin Franzke2af7f102011-03-02 11:14:59 +010081 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010082 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010083 int fd;
84 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020085 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050086 uint32_t *crtcs;
87 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050088 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010089 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050090 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020091
Rob Clark4339add2012-08-09 14:18:28 -050092 /* we need these parameters in order to not fail drmModeAddFB2()
93 * due to out of bounds dimensions, and then mistakenly set
94 * sprites_are_broken:
95 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020096 uint32_t min_width, max_width;
97 uint32_t min_height, max_height;
98 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050099
Jesse Barnes58ef3792012-02-23 09:45:49 -0500100 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500101 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200102 int sprites_hidden;
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
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400154 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500155
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200156 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300157 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500158 struct drm_compositor *compositor;
159
Jesse Barnes58ef3792012-02-23 09:45:49 -0500160 uint32_t possible_crtcs;
161 uint32_t plane_id;
162 uint32_t count_formats;
163
164 int32_t src_x, src_y;
165 uint32_t src_w, src_h;
166 uint32_t dest_x, dest_y;
167 uint32_t dest_w, dest_h;
168
169 uint32_t formats[];
170};
171
Pekka Paalanen33156972012-08-03 13:30:30 -0400172struct drm_seat {
173 struct weston_seat base;
174 struct wl_list devices_list;
175 struct udev_monitor *udev_monitor;
176 struct wl_event_source *udev_monitor_source;
177 char *seat_id;
178};
179
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400180static void
181drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400182
Jesse Barnes58ef3792012-02-23 09:45:49 -0500183static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500184drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
185{
186 struct weston_compositor *ec = output_base->compositor;
187 struct drm_compositor *c =(struct drm_compositor *) ec;
188 struct drm_output *output = (struct drm_output *) output_base;
189 int crtc;
190
191 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
192 if (c->crtcs[crtc] != output->crtc_id)
193 continue;
194
195 if (supported & (1 << crtc))
196 return -1;
197 }
198
199 return 0;
200}
201
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300202static void
203drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
204{
205 struct drm_fb *fb = data;
206 struct gbm_device *gbm = gbm_bo_get_device(bo);
207
208 if (fb->fb_id)
209 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
210
211 if (fb->buffer) {
212 weston_buffer_post_release(fb->buffer);
213 wl_list_remove(&fb->buffer_destroy_listener.link);
214 }
215
216 free(data);
217}
218
219static struct drm_fb *
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200220drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_compositor *compositor)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300221{
222 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200223 uint32_t width, height, stride, handle, format;
224 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300225 int ret;
226
227 if (fb)
228 return fb;
229
230 fb = malloc(sizeof *fb);
231
232 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300233 fb->is_client_buffer = 0;
234 fb->buffer = NULL;
235
236 width = gbm_bo_get_width(bo);
237 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400238 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300239 handle = gbm_bo_get_handle(bo).u32;
240
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200241 if (compositor->min_width > width || width > compositor->max_width ||
242 compositor->min_height > height ||
243 height > compositor->max_height) {
244 weston_log("bo geometry out of bounds\n");
245 goto err_free;
246 }
247
248 ret = -1;
249
250 format = gbm_bo_get_format(bo);
251
252 if (format && !compositor->no_addfb2) {
253 handles[0] = handle;
254 pitches[0] = stride;
255 offsets[0] = 0;
256
257 ret = drmModeAddFB2(compositor->drm.fd, width, height,
258 format, handles, pitches, offsets,
259 &fb->fb_id, 0);
260 if (ret) {
261 weston_log("addfb2 failed: %m\n");
262 compositor->no_addfb2 = 1;
263 compositor->sprites_are_broken = 1;
264 }
265 }
266
267 if (ret)
268 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
269 stride, handle, &fb->fb_id);
270
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300271 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200272 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200273 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300274 }
275
276 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
277
278 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200279
280err_free:
281 free(fb);
282 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300283}
284
285static void
286fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
287{
288 struct drm_fb *fb = container_of(listener, struct drm_fb,
289 buffer_destroy_listener);
290
291 fb->buffer = NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300292}
293
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200294static void
295drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
296{
297 assert(fb->buffer == NULL);
298
299 fb->is_client_buffer = 1;
300 fb->buffer = buffer;
301 fb->buffer->busy_count++;
302 fb->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
303
304 wl_signal_add(&fb->buffer->resource.destroy_signal,
305 &fb->buffer_destroy_listener);
306}
307
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200308static int
309drm_output_check_scanout_format(struct drm_output *output,
310 struct weston_surface *es, struct gbm_bo *bo)
311{
312 int ret = 0;
313 uint32_t format;
314 pixman_region32_t r;
315
316 format = gbm_bo_get_format(bo);
317
318 if (format == GBM_FORMAT_XRGB8888)
319 ret = 1;
320 else if (format == GBM_FORMAT_ARGB8888) {
321 /* We can only scanout an ARGB buffer if the surface's
322 * opaque region covers the whole output */
323 pixman_region32_init(&r);
324 pixman_region32_subtract(&r, &output->base.region,
325 &es->opaque);
326
327 if (!pixman_region32_not_empty(&r))
328 ret = 1;
329
330 pixman_region32_fini(&r);
331 }
332
333 return ret;
334}
335
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400336static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400337drm_output_prepare_scanout_surface(struct weston_output *_output,
338 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500339{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400340 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500341 struct drm_compositor *c =
342 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300343 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500344
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500345 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200346 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200347 es->buffer == NULL ||
348 es->buffer->width != output->base.current->width ||
349 es->buffer->height != output->base.current->height ||
350 output->base.transform != es->buffer_transform ||
351 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400352 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500353
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400354 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
355 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500356
Rob Bradford9b101872012-09-14 23:25:41 +0100357 /* Unable to use the buffer for scanout */
358 if (!bo)
359 return NULL;
360
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200361 if (!drm_output_check_scanout_format(output, es, bo)) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300362 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400363 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300364 }
365
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200366 output->next = drm_fb_get_from_bo(bo, c);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300367 if (!output->next) {
368 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400369 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300370 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500371
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200372 drm_fb_set_buffer(output->next, es->buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500373
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400374 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500375}
376
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500377static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400378drm_output_render(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400379{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200380 struct drm_compositor *c =
381 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300382 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400383
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200384 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400385
Ander Conselvan de Oliveira0a887722012-11-22 15:57:00 +0200386 pixman_region32_subtract(&c->base.primary_plane.damage,
387 &c->base.primary_plane.damage, damage);
388
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300389 bo = gbm_surface_lock_front_buffer(output->surface);
390 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200391 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400392 return;
393 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300394
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200395 output->next = drm_fb_get_from_bo(bo, c);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300396 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200397 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300398 gbm_surface_release_buffer(output->surface, bo);
399 return;
400 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400401}
402
403static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500404drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400405 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100406{
407 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500408 struct drm_compositor *compositor =
409 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500410 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400411 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500412 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100413
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300414 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400415 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300416 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400417 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100418
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400419 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300420 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400421 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300422 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400423 &output->connector_id, 1,
424 &mode->mode_info);
425 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200426 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400427 return;
428 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200429 }
430
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500431 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300432 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500433 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200434 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500435 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500436 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100437
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300438 output->page_flip_pending = 1;
439
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400440 drm_output_set_cursor(output);
441
Jesse Barnes58ef3792012-02-23 09:45:49 -0500442 /*
443 * Now, update all the sprite surfaces
444 */
445 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200446 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500447 drmVBlank vbl = {
448 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
449 .request.sequence = 1,
450 };
451
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200452 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200453 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500454 continue;
455
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200456 if (s->next && !compositor->sprites_hidden)
457 fb_id = s->next->fb_id;
458
Jesse Barnes58ef3792012-02-23 09:45:49 -0500459 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200460 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500461 s->dest_x, s->dest_y,
462 s->dest_w, s->dest_h,
463 s->src_x, s->src_y,
464 s->src_w, s->src_h);
465 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200466 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500467 ret, strerror(errno));
468
Rob Clark5ca1a472012-08-08 20:27:37 -0500469 if (output->pipe > 0)
470 vbl.request.type |= DRM_VBLANK_SECONDARY;
471
Jesse Barnes58ef3792012-02-23 09:45:49 -0500472 /*
473 * Queue a vblank signal so we know when the surface
474 * becomes active on the display or has been replaced.
475 */
476 vbl.request.signal = (unsigned long)s;
477 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
478 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200479 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500480 ret, strerror(errno));
481 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300482
483 s->output = output;
484 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500485 }
486
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500487 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400488}
489
490static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500491vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
492 void *data)
493{
494 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300495 struct drm_output *output = s->output;
496 uint32_t msecs;
497
498 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500499
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200500 if (s->current)
501 gbm_bo_destroy(s->current->bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500502
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200503 s->current = s->next;
504 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300505
506 if (!output->page_flip_pending) {
507 msecs = sec * 1000 + usec / 1000;
508 weston_output_finish_frame(&output->base, msecs);
509 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500510}
511
512static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400513page_flip_handler(int fd, unsigned int frame,
514 unsigned int sec, unsigned int usec, void *data)
515{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200516 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400517 uint32_t msecs;
518
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300519 output->page_flip_pending = 0;
520
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300521 if (output->current) {
522 if (output->current->is_client_buffer)
523 gbm_bo_destroy(output->current->bo);
524 else
525 gbm_surface_release_buffer(output->surface,
526 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200527 }
528
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300529 output->current = output->next;
530 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400531
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300532 if (!output->vblank_pending) {
533 msecs = sec * 1000 + usec / 1000;
534 weston_output_finish_frame(&output->base, msecs);
535 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200536}
537
538static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500539drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
540{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400541 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500542
543 for (i = 0; i < s->count_formats; i++)
544 if (s->formats[i] == format)
545 return 1;
546
547 return 0;
548}
549
550static int
551drm_surface_transform_supported(struct weston_surface *es)
552{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400553 struct weston_matrix *matrix = &es->transform.matrix;
554 int i;
555
556 if (!es->transform.enabled)
557 return 1;
558
559 for (i = 0; i < 16; i++) {
560 switch (i) {
561 case 10:
562 case 15:
563 if (matrix->d[i] != 1.0)
564 return 0;
565 break;
566 case 0:
567 case 5:
568 case 12:
569 case 13:
570 break;
571 default:
572 if (matrix->d[i] != 0.0)
573 return 0;
574 break;
575 }
576 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500577
578 return 1;
579}
580
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400581static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500582drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400583 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500584{
585 struct weston_compositor *ec = output_base->compositor;
586 struct drm_compositor *c =(struct drm_compositor *) ec;
587 struct drm_sprite *s;
588 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500589 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500590 pixman_region32_t dest_rect, src_rect;
591 pixman_box32_t *box;
592 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400593 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500594
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200595 if (output_base->transform != WL_OUTPUT_TRANSFORM_NORMAL)
596 return NULL;
597
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500598 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400599 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500600
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300601 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400602 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300603
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400604 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400605 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500606
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200607 if (es->alpha != 1.0f)
608 return NULL;
609
Rob Clark702ffae2012-08-09 14:18:27 -0500610 if (wl_buffer_is_shm(es->buffer))
611 return NULL;
612
Jesse Barnes58ef3792012-02-23 09:45:49 -0500613 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400614 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500615
Jesse Barnes58ef3792012-02-23 09:45:49 -0500616 wl_list_for_each(s, &c->sprite_list, link) {
617 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
618 continue;
619
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200620 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500621 found = 1;
622 break;
623 }
624 }
625
626 /* No sprites available */
627 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400628 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500629
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400630 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
631 es->buffer, GBM_BO_USE_SCANOUT);
632 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400633 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400634
Jesse Barnes58ef3792012-02-23 09:45:49 -0500635 format = gbm_bo_get_format(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500636
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200637 if (!drm_surface_format_supported(s, format)) {
638 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400639 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500640 }
641
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200642 s->next = drm_fb_get_from_bo(bo, c);
643 if (!s->next) {
644 gbm_bo_destroy(bo);
645 return NULL;
646 }
647
648 drm_fb_set_buffer(s->next, es->buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500649
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400650 box = pixman_region32_extents(&es->transform.boundingbox);
651 s->plane.x = box->x1;
652 s->plane.y = box->y1;
653
Jesse Barnes58ef3792012-02-23 09:45:49 -0500654 /*
655 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200656 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500657 * for us already).
658 */
659 pixman_region32_init(&dest_rect);
660 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
661 &output_base->region);
662 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
663 box = pixman_region32_extents(&dest_rect);
664 s->dest_x = box->x1;
665 s->dest_y = box->y1;
666 s->dest_w = box->x2 - box->x1;
667 s->dest_h = box->y2 - box->y1;
668 pixman_region32_fini(&dest_rect);
669
670 pixman_region32_init(&src_rect);
671 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
672 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500673 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400674
675 weston_surface_from_global_fixed(es,
676 wl_fixed_from_int(box->x1),
677 wl_fixed_from_int(box->y1),
678 &sx1, &sy1);
679 weston_surface_from_global_fixed(es,
680 wl_fixed_from_int(box->x2),
681 wl_fixed_from_int(box->y2),
682 &sx2, &sy2);
683
684 if (sx1 < 0)
685 sx1 = 0;
686 if (sy1 < 0)
687 sy1 = 0;
688 if (sx2 > wl_fixed_from_int(es->geometry.width))
689 sx2 = wl_fixed_from_int(es->geometry.width);
690 if (sy2 > wl_fixed_from_int(es->geometry.height))
691 sy2 = wl_fixed_from_int(es->geometry.height);
692
693 s->src_x = sx1 << 8;
694 s->src_y = sy1 << 8;
695 s->src_w = (sx2 - sx1) << 8;
696 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500697 pixman_region32_fini(&src_rect);
698
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400699 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500700}
701
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400702static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400703drm_output_prepare_cursor_surface(struct weston_output *output_base,
704 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500705{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400706 struct drm_compositor *c =
707 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400708 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400709
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200710 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
711 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400712 if (output->cursor_surface)
713 return NULL;
714 if (es->output_mask != (1u << output_base->id))
715 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500716 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400717 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400718 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
719 es->geometry.width > 64 || es->geometry.height > 64)
720 return NULL;
721
722 output->cursor_surface = es;
723
724 return &output->cursor_plane;
725}
726
727static void
728drm_output_set_cursor(struct drm_output *output)
729{
730 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400731 struct drm_compositor *c =
732 (struct drm_compositor *) output->base.compositor;
733 EGLint handle, stride;
734 struct gbm_bo *bo;
735 uint32_t buf[64 * 64];
736 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400737 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500738
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400739 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400740 if (es == NULL) {
741 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
742 return;
743 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500744
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400745 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
746 pixman_region32_fini(&output->cursor_plane.damage);
747 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400748 output->current_cursor ^= 1;
749 bo = output->cursor_bo[output->current_cursor];
750 memset(buf, 0, sizeof buf);
751 stride = wl_shm_buffer_get_stride(es->buffer);
752 s = wl_shm_buffer_get_data(es->buffer);
753 for (i = 0; i < es->geometry.height; i++)
754 memcpy(buf + i * 64, s + i * stride,
755 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500756
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400757 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300758 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400759
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400760 handle = gbm_bo_get_handle(bo).s32;
761 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500762 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300763 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500764 c->cursors_are_broken = 1;
765 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400766 }
767
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400768 x = es->geometry.x - output->base.x;
769 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400770 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500771 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400772 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500773 c->cursors_are_broken = 1;
774 }
775
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400776 output->cursor_plane.x = x;
777 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400778 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500779}
780
Jesse Barnes58ef3792012-02-23 09:45:49 -0500781static void
782drm_assign_planes(struct weston_output *output)
783{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400784 struct drm_compositor *c =
785 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200786 struct drm_output *drm_output = (struct drm_output *) output;
787 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400788 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500789 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400790 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500791
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200792 /* Reset the opaque region of the planes */
793 pixman_region32_fini(&drm_output->cursor_plane.opaque);
794 pixman_region32_init(&drm_output->cursor_plane.opaque);
795 pixman_region32_fini(&drm_output->fb_plane.opaque);
796 pixman_region32_init(&drm_output->fb_plane.opaque);
797
798 wl_list_for_each (s, &c->sprite_list, link) {
799 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
800 continue;
801
802 pixman_region32_fini(&s->plane.opaque);
803 pixman_region32_init(&s->plane.opaque);
804 }
805
Jesse Barnes58ef3792012-02-23 09:45:49 -0500806 /*
807 * Find a surface for each sprite in the output using some heuristics:
808 * 1) size
809 * 2) frequency of update
810 * 3) opacity (though some hw might support alpha blending)
811 * 4) clipping (this can be fixed with color keys)
812 *
813 * The idea is to save on blitting since this should save power.
814 * If we can get a large video surface on the sprite for example,
815 * the main display surface may not need to update at all, and
816 * the client buffer can be used directly for the sprite surface
817 * as we do for flipping full screen surfaces.
818 */
819 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400820 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400821 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500822 pixman_region32_init(&surface_overlap);
823 pixman_region32_intersect(&surface_overlap, &overlap,
824 &es->transform.boundingbox);
825
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400826 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400827 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400828 next_plane = primary;
829 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400830 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400831 if (next_plane == NULL)
832 next_plane = drm_output_prepare_scanout_surface(output, es);
833 if (next_plane == NULL)
834 next_plane = drm_output_prepare_overlay_surface(output, es);
835 if (next_plane == NULL)
836 next_plane = primary;
837 weston_surface_move_to_plane(es, next_plane);
838 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500839 pixman_region32_union(&overlap, &overlap,
840 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400841
Jesse Barnes58ef3792012-02-23 09:45:49 -0500842 pixman_region32_fini(&surface_overlap);
843 }
844 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500845}
846
Matt Roper361d2ad2011-08-29 13:52:23 -0700847static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500848drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700849{
850 struct drm_output *output = (struct drm_output *) output_base;
851 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200852 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700853 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700854
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200855 if (output->backlight)
856 backlight_destroy(output->backlight);
857
Matt Roper361d2ad2011-08-29 13:52:23 -0700858 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400859 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700860
861 /* Restore original CRTC state */
862 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200863 origcrtc->x, origcrtc->y,
864 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700865 drmModeFreeCrtc(origcrtc);
866
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200867 c->crtc_allocator &= ~(1 << output->crtc_id);
868 c->connector_allocator &= ~(1 << output->connector_id);
869
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100870 gl_renderer_output_destroy(output_base);
John Kåre Alsaker94659272012-11-13 19:10:18 +0100871
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400872 gbm_surface_destroy(output->surface);
873
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400874 weston_plane_release(&output->fb_plane);
875 weston_plane_release(&output->cursor_plane);
876
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500877 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200878 wl_list_remove(&output->base.link);
879
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400880 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700881 free(output);
882}
883
Alex Wub7b8bda2012-04-17 17:20:48 +0800884static struct drm_mode *
885choose_mode (struct drm_output *output, struct weston_mode *target_mode)
886{
887 struct drm_mode *tmp_mode = NULL, *mode;
888
889 if (output->base.current->width == target_mode->width &&
890 output->base.current->height == target_mode->height &&
891 (output->base.current->refresh == target_mode->refresh ||
892 target_mode->refresh == 0))
893 return (struct drm_mode *)output->base.current;
894
895 wl_list_for_each(mode, &output->base.mode_list, base.link) {
896 if (mode->mode_info.hdisplay == target_mode->width &&
897 mode->mode_info.vdisplay == target_mode->height) {
898 if (mode->mode_info.vrefresh == target_mode->refresh ||
899 target_mode->refresh == 0) {
900 return mode;
901 } else if (!tmp_mode)
902 tmp_mode = mode;
903 }
904 }
905
906 return tmp_mode;
907}
908
909static int
910drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
911{
912 struct drm_output *output;
913 struct drm_mode *drm_mode;
914 int ret;
915 struct drm_compositor *ec;
916 struct gbm_surface *surface;
Alex Wub7b8bda2012-04-17 17:20:48 +0800917
918 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200919 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800920 return -1;
921 }
922
923 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200924 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800925 return -1;
926 }
927
928 ec = (struct drm_compositor *)output_base->compositor;
929 output = (struct drm_output *)output_base;
930 drm_mode = choose_mode (output, mode);
931
932 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200933 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800934 return -1;
935 } else if (&drm_mode->base == output->base.current) {
936 return 0;
937 } else if (drm_mode->base.width == output->base.current->width &&
938 drm_mode->base.height == output->base.current->height) {
939 /* only change refresh value */
940 ret = drmModeSetCrtc(ec->drm.fd,
941 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300942 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800943 &output->connector_id, 1, &drm_mode->mode_info);
944
945 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200946 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800947 drm_mode->base.width,
948 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400949 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800950 ret = -1;
951 } else {
952 output->base.current->flags = 0;
953 output->base.current = &drm_mode->base;
954 drm_mode->base.flags =
955 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
956 ret = 0;
957 }
958
959 return ret;
960 }
961
962 drm_mode->base.flags =
963 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
964
965 surface = gbm_surface_create(ec->gbm,
966 drm_mode->base.width,
967 drm_mode->base.height,
968 GBM_FORMAT_XRGB8888,
969 GBM_BO_USE_SCANOUT |
970 GBM_BO_USE_RENDERING);
971 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200972 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800973 return -1;
974 }
975
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100976 gl_renderer_output_destroy(&output->base);
Alex Wub7b8bda2012-04-17 17:20:48 +0800977
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100978 if (!gl_renderer_output_create(&output->base, surface)) {
John Kåre Alsaker94659272012-11-13 19:10:18 +0100979 weston_log("failed to create renderer output\n");
980 goto err_gbm;
Alex Wub7b8bda2012-04-17 17:20:48 +0800981 }
982
983 ret = drmModeSetCrtc(ec->drm.fd,
984 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300985 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800986 &output->connector_id, 1, &drm_mode->mode_info);
987 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200988 weston_log("failed to set mode\n");
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100989 goto err_gl;
Alex Wub7b8bda2012-04-17 17:20:48 +0800990 }
991
992 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300993 if (output->current) {
994 if (output->current->is_client_buffer)
995 gbm_bo_destroy(output->current->bo);
996 else
997 gbm_surface_release_buffer(output->surface,
998 output->current->bo);
999 }
1000 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001001
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001002 if (output->next) {
1003 if (output->next->is_client_buffer)
1004 gbm_bo_destroy(output->next->bo);
1005 else
1006 gbm_surface_release_buffer(output->surface,
1007 output->next->bo);
1008 }
1009 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001010
Alex Wub7b8bda2012-04-17 17:20:48 +08001011 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001012 output->surface = surface;
1013
1014 /*update output*/
1015 output->base.current = &drm_mode->base;
1016 output->base.dirty = 1;
1017 weston_output_move(&output->base, output->base.x, output->base.y);
1018 return 0;
1019
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001020err_gl:
1021 gl_renderer_output_destroy(&output->base);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001022err_gbm:
Alex Wub7b8bda2012-04-17 17:20:48 +08001023 gbm_surface_destroy(surface);
1024 return -1;
1025}
1026
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001027static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001028on_drm_input(int fd, uint32_t mask, void *data)
1029{
1030 drmEventContext evctx;
1031
1032 memset(&evctx, 0, sizeof evctx);
1033 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1034 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001035 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001036 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001037
1038 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001039}
1040
1041static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001042init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001043{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001044 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001045 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001046
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001047 sysnum = udev_device_get_sysnum(device);
1048 if (sysnum)
1049 ec->drm.id = atoi(sysnum);
1050 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001051 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001052 return -1;
1053 }
1054
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001055 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001056 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001057 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001058 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001059 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001060 udev_device_get_devnode(device));
1061 return -1;
1062 }
1063
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001064 weston_log("using %s\n", filename);
1065
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001066 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001067 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001068
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001069 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001070 NULL) < 0) {
1071 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001072 return -1;
1073 }
1074
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001075 return 0;
1076}
1077
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001078static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001079drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1080{
1081 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001082 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001083
1084 mode = malloc(sizeof *mode);
1085 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001086 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001087
1088 mode->base.flags = 0;
1089 mode->base.width = info->hdisplay;
1090 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001091
1092 /* Calculate higher precision (mHz) refresh rate */
1093 refresh = (info->clock * 1000000LL / info->htotal +
1094 info->vtotal / 2) / info->vtotal;
1095
1096 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1097 refresh *= 2;
1098 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1099 refresh /= 2;
1100 if (info->vscan > 1)
1101 refresh /= info->vscan;
1102
1103 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001104 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001105
1106 if (info->type & DRM_MODE_TYPE_PREFERRED)
1107 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1108
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001109 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1110
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001111 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001112}
1113
1114static int
1115drm_subpixel_to_wayland(int drm_value)
1116{
1117 switch (drm_value) {
1118 default:
1119 case DRM_MODE_SUBPIXEL_UNKNOWN:
1120 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1121 case DRM_MODE_SUBPIXEL_NONE:
1122 return WL_OUTPUT_SUBPIXEL_NONE;
1123 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1124 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1125 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1126 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1127 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1128 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1129 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1130 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1131 }
1132}
1133
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001134/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001135static uint32_t
1136drm_get_backlight(struct drm_output *output)
1137{
1138 long brightness, max_brightness, norm;
1139
1140 brightness = backlight_get_brightness(output->backlight);
1141 max_brightness = backlight_get_max_brightness(output->backlight);
1142
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001143 /* convert it on a scale of 0 to 255 */
1144 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001145
1146 return (uint32_t) norm;
1147}
1148
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001149/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001150static void
1151drm_set_backlight(struct weston_output *output_base, uint32_t value)
1152{
1153 struct drm_output *output = (struct drm_output *) output_base;
1154 long max_brightness, new_brightness;
1155
1156 if (!output->backlight)
1157 return;
1158
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001159 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001160 return;
1161
1162 max_brightness = backlight_get_max_brightness(output->backlight);
1163
1164 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001165 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001166
1167 backlight_set_brightness(output->backlight, new_brightness);
1168}
1169
1170static drmModePropertyPtr
1171drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1172{
1173 drmModePropertyPtr props;
1174 int i;
1175
1176 for (i = 0; i < connector->count_props; i++) {
1177 props = drmModeGetProperty(fd, connector->props[i]);
1178 if (!props)
1179 continue;
1180
1181 if (!strcmp(props->name, name))
1182 return props;
1183
1184 drmModeFreeProperty(props);
1185 }
1186
1187 return NULL;
1188}
1189
1190static void
1191drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1192{
1193 struct drm_output *output = (struct drm_output *) output_base;
1194 struct weston_compositor *ec = output_base->compositor;
1195 struct drm_compositor *c = (struct drm_compositor *) ec;
1196 drmModeConnectorPtr connector;
1197 drmModePropertyPtr prop;
1198
1199 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1200 if (!connector)
1201 return;
1202
1203 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1204 if (!prop) {
1205 drmModeFreeConnector(connector);
1206 return;
1207 }
1208
1209 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1210 prop->prop_id, level);
1211 drmModeFreeProperty(prop);
1212 drmModeFreeConnector(connector);
1213}
1214
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001215static const char *connector_type_names[] = {
1216 "None",
1217 "VGA",
1218 "DVI",
1219 "DVI",
1220 "DVI",
1221 "Composite",
1222 "TV",
1223 "LVDS",
1224 "CTV",
1225 "DIN",
1226 "DP",
1227 "HDMI",
1228 "HDMI",
1229 "TV",
1230 "eDP",
1231};
1232
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001233static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001234find_crtc_for_connector(struct drm_compositor *ec,
1235 drmModeRes *resources, drmModeConnector *connector)
1236{
1237 drmModeEncoder *encoder;
1238 uint32_t possible_crtcs;
1239 int i, j;
1240
1241 for (j = 0; j < connector->count_encoders; j++) {
1242 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1243 if (encoder == NULL) {
1244 weston_log("Failed to get encoder.\n");
1245 return -1;
1246 }
1247 possible_crtcs = encoder->possible_crtcs;
1248 drmModeFreeEncoder(encoder);
1249
1250 for (i = 0; i < resources->count_crtcs; i++) {
1251 if (possible_crtcs & (1 << i) &&
1252 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1253 return i;
1254 }
1255 }
1256
1257 return -1;
1258}
1259
1260static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001261create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001262 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001263 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001264 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001265{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001266 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001267 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1268 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001269 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001270 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001271 drmModeModeInfo crtc_mode;
1272 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001273 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001274 char name[32];
1275 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001276
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001277 i = find_crtc_for_connector(ec, resources, connector);
1278 if (i < 0) {
1279 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001280 return -1;
1281 }
1282
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001283 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001284 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001285 return -1;
1286
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001287 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001288 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1289 output->base.make = "unknown";
1290 output->base.model = "unknown";
1291 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001292
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001293 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1294 type_name = connector_type_names[connector->connector_type];
1295 else
1296 type_name = "UNKNOWN";
1297 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1298 output->name = strdup(name);
1299
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001300 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001301 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001302 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001303 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001304 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001305
Matt Roper361d2ad2011-08-29 13:52:23 -07001306 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1307
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001308 /* Get the current mode on the crtc that's currently driving
1309 * this connector. */
1310 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001311 memset(&crtc_mode, 0, sizeof crtc_mode);
1312 if (encoder != NULL) {
1313 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1314 drmModeFreeEncoder(encoder);
1315 if (crtc == NULL)
1316 goto err_free;
1317 if (crtc->mode_valid)
1318 crtc_mode = crtc->mode;
1319 drmModeFreeCrtc(crtc);
1320 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001321
David Herrmann0f0d54e2011-12-08 17:05:45 +01001322 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001323 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1324 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001325 goto err_free;
1326 }
1327
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001328 preferred = NULL;
1329 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001330 configured = NULL;
1331
1332 wl_list_for_each(temp, &configured_output_list, link) {
1333 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001334 if (temp->mode)
1335 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001336 temp->name, temp->mode);
1337 o = temp;
1338 break;
1339 }
1340 }
1341
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001342 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001343 weston_log("Disabling output %s\n", o->name);
1344
1345 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1346 0, 0, 0, 0, 0, NULL);
1347 goto err_free;
1348 }
1349
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001350 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001351 if (o && o->config == OUTPUT_CONFIG_MODE &&
1352 o->width == drm_mode->base.width &&
1353 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001354 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001355 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001356 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001357 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001358 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001359 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001360
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001361 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001362 configured = drm_output_add_mode(output, &o->crtc_mode);
1363 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001364 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001365 current = configured;
1366 }
1367
Wang Quanxianacb805a2012-07-30 18:09:46 -04001368 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001369 current = drm_output_add_mode(output, &crtc_mode);
1370 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001371 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001372 }
1373
Scott Moreau8ab5d452012-07-30 19:51:08 -06001374 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1375 configured = current;
1376
Wang Quanxianacb805a2012-07-30 18:09:46 -04001377 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001378 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001379 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001380 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001381 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001382 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001383 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001384 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001385
1386 if (output->base.current == NULL) {
1387 weston_log("no available modes for %s\n", output->name);
1388 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001389 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001390
Wang Quanxianacb805a2012-07-30 18:09:46 -04001391 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1392
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001393 output->surface = gbm_surface_create(ec->gbm,
1394 output->base.current->width,
1395 output->base.current->height,
1396 GBM_FORMAT_XRGB8888,
1397 GBM_BO_USE_SCANOUT |
1398 GBM_BO_USE_RENDERING);
1399 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001400 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001401 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001402 }
1403
John Kåre Alsaker94659272012-11-13 19:10:18 +01001404 weston_output_init(&output->base, &ec->base, x, y,
1405 connector->mmWidth, connector->mmHeight,
1406 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1407
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001408 if (gl_renderer_output_create(&output->base, output->surface) < 0)
John Kåre Alsaker94659272012-11-13 19:10:18 +01001409 goto err_output;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001410
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001411 output->cursor_bo[0] =
1412 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1413 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1414 output->cursor_bo[1] =
1415 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1416 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001417 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1418 weston_log("cursor buffers unavailable, using gl cursors\n");
1419 ec->cursors_are_broken = 1;
1420 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001421
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001422 output->backlight = backlight_init(drm_device,
1423 connector->connector_type);
1424 if (output->backlight) {
1425 output->base.set_backlight = drm_set_backlight;
1426 output->base.backlight_current = drm_get_backlight(output);
1427 }
1428
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001429 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1430
Alex Wubd3354b2012-04-17 17:20:49 +08001431 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001432 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001433 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001434 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001435 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001436 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001437
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001438 weston_plane_init(&output->cursor_plane, 0, 0);
1439 weston_plane_init(&output->fb_plane, 0, 0);
1440
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001441 weston_log("Output %s, (connector %d, crtc %d)\n",
1442 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001443 wl_list_for_each(m, &output->base.mode_list, link)
1444 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1445 m->width, m->height, m->refresh / 1000.0,
1446 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1447 ", preferred" : "",
1448 m->flags & WL_OUTPUT_MODE_CURRENT ?
1449 ", current" : "",
1450 connector->count_modes == 0 ?
1451 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001452
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001453 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001454
John Kåre Alsaker94659272012-11-13 19:10:18 +01001455err_output:
1456 weston_output_destroy(&output->base);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001457 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001458err_free:
1459 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1460 base.link) {
1461 wl_list_remove(&drm_mode->base.link);
1462 free(drm_mode);
1463 }
1464
1465 drmModeFreeCrtc(output->original_crtc);
1466 ec->crtc_allocator &= ~(1 << output->crtc_id);
1467 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001468 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001469 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001470
David Herrmann0f0d54e2011-12-08 17:05:45 +01001471 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001472}
1473
Jesse Barnes58ef3792012-02-23 09:45:49 -05001474static void
1475create_sprites(struct drm_compositor *ec)
1476{
1477 struct drm_sprite *sprite;
1478 drmModePlaneRes *plane_res;
1479 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001480 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001481
1482 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1483 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001484 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001485 strerror(errno));
1486 return;
1487 }
1488
1489 for (i = 0; i < plane_res->count_planes; i++) {
1490 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1491 if (!plane)
1492 continue;
1493
1494 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1495 plane->count_formats));
1496 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001497 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001498 __func__);
1499 free(plane);
1500 continue;
1501 }
1502
1503 memset(sprite, 0, sizeof *sprite);
1504
1505 sprite->possible_crtcs = plane->possible_crtcs;
1506 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001507 sprite->current = NULL;
1508 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001509 sprite->compositor = ec;
1510 sprite->count_formats = plane->count_formats;
1511 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001512 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001513 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001514 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001515
1516 wl_list_insert(&ec->sprite_list, &sprite->link);
1517 }
1518
1519 free(plane_res->planes);
1520 free(plane_res);
1521}
1522
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001523static void
1524destroy_sprites(struct drm_compositor *compositor)
1525{
1526 struct drm_sprite *sprite, *next;
1527 struct drm_output *output;
1528
1529 output = container_of(compositor->base.output_list.next,
1530 struct drm_output, base.link);
1531
1532 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1533 drmModeSetPlane(compositor->drm.fd,
1534 sprite->plane_id,
1535 output->crtc_id, 0, 0,
1536 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001537 if (sprite->current)
1538 gbm_bo_destroy(sprite->current->bo);
1539 if (sprite->next)
1540 gbm_bo_destroy(sprite->next->bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001541 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001542 free(sprite);
1543 }
1544}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001545
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001546static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001547create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001548 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001549{
1550 drmModeConnector *connector;
1551 drmModeRes *resources;
1552 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001553 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001554
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001555 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001556 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001557 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001558 return -1;
1559 }
1560
Jesse Barnes58ef3792012-02-23 09:45:49 -05001561 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001562 if (!ec->crtcs) {
1563 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001564 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001565 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001566
Rob Clark4339add2012-08-09 14:18:28 -05001567 ec->min_width = resources->min_width;
1568 ec->max_width = resources->max_width;
1569 ec->min_height = resources->min_height;
1570 ec->max_height = resources->max_height;
1571
Jesse Barnes58ef3792012-02-23 09:45:49 -05001572 ec->num_crtcs = resources->count_crtcs;
1573 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1574
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001575 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001576 connector = drmModeGetConnector(ec->drm.fd,
1577 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001578 if (connector == NULL)
1579 continue;
1580
1581 if (connector->connection == DRM_MODE_CONNECTED &&
1582 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001583 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001584 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001585 connector, x, y,
1586 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001587 drmModeFreeConnector(connector);
1588 continue;
1589 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001590
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001591 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001592 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001593 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001594 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001595
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001596 drmModeFreeConnector(connector);
1597 }
1598
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001599 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001600 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001601 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001602 return -1;
1603 }
1604
1605 drmModeFreeResources(resources);
1606
1607 return 0;
1608}
1609
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001610static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001611update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001612{
1613 drmModeConnector *connector;
1614 drmModeRes *resources;
1615 struct drm_output *output, *next;
1616 int x = 0, y = 0;
1617 int x_offset = 0, y_offset = 0;
1618 uint32_t connected = 0, disconnects = 0;
1619 int i;
1620
1621 resources = drmModeGetResources(ec->drm.fd);
1622 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001623 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001624 return;
1625 }
1626
1627 /* collect new connects */
1628 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001629 int connector_id = resources->connectors[i];
1630
1631 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001632 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001633 continue;
1634
David Herrmann7551cff2011-12-08 17:05:43 +01001635 if (connector->connection != DRM_MODE_CONNECTED) {
1636 drmModeFreeConnector(connector);
1637 continue;
1638 }
1639
Benjamin Franzke117483d2011-08-30 11:38:26 +02001640 connected |= (1 << connector_id);
1641
1642 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001643 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001644 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001645 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001646
1647 /* XXX: not yet needed, we die with 0 outputs */
1648 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001649 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001650 else
1651 x = 0;
1652 y = 0;
1653 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001654 connector, x, y,
1655 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001656 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001657
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001658 }
1659 drmModeFreeConnector(connector);
1660 }
1661 drmModeFreeResources(resources);
1662
1663 disconnects = ec->connector_allocator & ~connected;
1664 if (disconnects) {
1665 wl_list_for_each_safe(output, next, &ec->base.output_list,
1666 base.link) {
1667 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001668 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001669 output->base.x - x_offset,
1670 output->base.y - y_offset);
1671 }
1672
1673 if (disconnects & (1 << output->connector_id)) {
1674 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001675 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001676 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001677 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001678 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001679 }
1680 }
1681 }
1682
1683 /* FIXME: handle zero outputs, without terminating */
1684 if (ec->connector_allocator == 0)
1685 wl_display_terminate(ec->base.wl_display);
1686}
1687
1688static int
David Herrmannd7488c22012-03-11 20:05:21 +01001689udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001690{
David Herrmannd7488c22012-03-11 20:05:21 +01001691 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001692 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001693
1694 sysnum = udev_device_get_sysnum(device);
1695 if (!sysnum || atoi(sysnum) != ec->drm.id)
1696 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001697
David Herrmann6ac52db2012-03-11 20:05:22 +01001698 val = udev_device_get_property_value(device, "HOTPLUG");
1699 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001700 return 0;
1701
David Herrmann6ac52db2012-03-11 20:05:22 +01001702 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001703}
1704
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001705static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001706udev_drm_event(int fd, uint32_t mask, void *data)
1707{
1708 struct drm_compositor *ec = data;
1709 struct udev_device *event;
1710
1711 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001712
David Herrmannd7488c22012-03-11 20:05:21 +01001713 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001714 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001715
1716 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001717
1718 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001719}
1720
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001721static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001722drm_restore(struct weston_compositor *ec)
1723{
1724 struct drm_compositor *d = (struct drm_compositor *) ec;
1725
1726 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1727 weston_log("failed to drop master: %m\n");
1728 tty_reset(d->tty);
1729}
1730
Pekka Paalanen33156972012-08-03 13:30:30 -04001731static const char default_seat[] = "seat0";
1732
1733static void
1734device_added(struct udev_device *udev_device, struct drm_seat *master)
1735{
1736 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001737 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001738 const char *devnode;
1739 const char *device_seat;
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001740 const char *calibration_values;
Pekka Paalanen33156972012-08-03 13:30:30 -04001741 int fd;
1742
1743 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1744 if (!device_seat)
1745 device_seat = default_seat;
1746
1747 if (strcmp(device_seat, master->seat_id))
1748 return;
1749
1750 c = master->base.compositor;
1751 devnode = udev_device_get_devnode(udev_device);
1752
1753 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001754 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001755 * read. mtdev_get() also expects this. */
1756 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1757 if (fd < 0) {
1758 weston_log("opening input device '%s' failed.\n", devnode);
1759 return;
1760 }
1761
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001762 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001763 if (!device) {
1764 close(fd);
1765 weston_log("not using input device '%s'.\n", devnode);
1766 return;
1767 }
1768
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001769 calibration_values =
1770 udev_device_get_property_value(udev_device,
1771 "WL_CALIBRATION");
1772
1773 if (calibration_values && sscanf(calibration_values,
1774 "%f %f %f %f %f %f",
1775 &device->abs.calibration[0],
1776 &device->abs.calibration[1],
1777 &device->abs.calibration[2],
1778 &device->abs.calibration[3],
1779 &device->abs.calibration[4],
1780 &device->abs.calibration[5]) == 6) {
1781 device->abs.apply_calibration = 1;
1782 weston_log ("Applying calibration: %f %f %f %f %f %f\n",
1783 device->abs.calibration[0],
1784 device->abs.calibration[1],
1785 device->abs.calibration[2],
1786 device->abs.calibration[3],
1787 device->abs.calibration[4],
1788 device->abs.calibration[5]);
1789 }
1790
Pekka Paalanen33156972012-08-03 13:30:30 -04001791 wl_list_insert(master->devices_list.prev, &device->link);
1792}
1793
1794static void
1795evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1796{
1797 struct drm_seat *seat = (struct drm_seat *) seat_base;
1798 struct udev_enumerate *e;
1799 struct udev_list_entry *entry;
1800 struct udev_device *device;
1801 const char *path, *sysname;
1802
1803 e = udev_enumerate_new(udev);
1804 udev_enumerate_add_match_subsystem(e, "input");
1805 udev_enumerate_scan_devices(e);
1806 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1807 path = udev_list_entry_get_name(entry);
1808 device = udev_device_new_from_syspath(udev, path);
1809
1810 sysname = udev_device_get_sysname(device);
1811 if (strncmp("event", sysname, 5) != 0) {
1812 udev_device_unref(device);
1813 continue;
1814 }
1815
1816 device_added(device, seat);
1817
1818 udev_device_unref(device);
1819 }
1820 udev_enumerate_unref(e);
1821
1822 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1823
1824 if (wl_list_empty(&seat->devices_list)) {
1825 weston_log(
1826 "warning: no input devices on entering Weston. "
1827 "Possible causes:\n"
1828 "\t- no permissions to read /dev/input/event*\n"
1829 "\t- seats misconfigured "
1830 "(Weston backend option 'seat', "
1831 "udev device property ID_SEAT)\n");
1832 }
1833}
1834
1835static int
1836evdev_udev_handler(int fd, uint32_t mask, void *data)
1837{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001838 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001839 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001840 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001841 const char *action;
1842 const char *devnode;
1843
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001844 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001845 if (!udev_device)
1846 return 1;
1847
1848 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001849 if (!action)
1850 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001851
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001852 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1853 goto out;
1854
1855 if (!strcmp(action, "add")) {
1856 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001857 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001858 else if (!strcmp(action, "remove")) {
1859 devnode = udev_device_get_devnode(udev_device);
1860 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1861 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001862 weston_log("input device %s, %s removed\n",
1863 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001864 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001865 break;
1866 }
1867 }
1868
1869out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001870 udev_device_unref(udev_device);
1871
1872 return 0;
1873}
1874
1875static int
1876evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1877{
1878 struct drm_seat *master = (struct drm_seat *) seat_base;
1879 struct wl_event_loop *loop;
1880 struct weston_compositor *c = master->base.compositor;
1881 int fd;
1882
1883 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1884 if (!master->udev_monitor) {
1885 weston_log("udev: failed to create the udev monitor\n");
1886 return 0;
1887 }
1888
1889 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1890 "input", NULL);
1891
1892 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1893 weston_log("udev: failed to bind the udev monitor\n");
1894 udev_monitor_unref(master->udev_monitor);
1895 return 0;
1896 }
1897
1898 loop = wl_display_get_event_loop(c->wl_display);
1899 fd = udev_monitor_get_fd(master->udev_monitor);
1900 master->udev_monitor_source =
1901 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1902 evdev_udev_handler, master);
1903 if (!master->udev_monitor_source) {
1904 udev_monitor_unref(master->udev_monitor);
1905 return 0;
1906 }
1907
1908 return 1;
1909}
1910
1911static void
1912evdev_disable_udev_monitor(struct weston_seat *seat_base)
1913{
1914 struct drm_seat *seat = (struct drm_seat *) seat_base;
1915
1916 if (!seat->udev_monitor)
1917 return;
1918
1919 udev_monitor_unref(seat->udev_monitor);
1920 seat->udev_monitor = NULL;
1921 wl_event_source_remove(seat->udev_monitor_source);
1922 seat->udev_monitor_source = NULL;
1923}
1924
1925static void
1926drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1927{
1928 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001929 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001930
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001931 wl_list_for_each(device, &seat->devices_list, link)
1932 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001933}
1934
1935static void
1936evdev_input_create(struct weston_compositor *c, struct udev *udev,
1937 const char *seat_id)
1938{
1939 struct drm_seat *seat;
1940
1941 seat = malloc(sizeof *seat);
1942 if (seat == NULL)
1943 return;
1944
1945 memset(seat, 0, sizeof *seat);
1946 weston_seat_init(&seat->base, c);
1947 seat->base.led_update = drm_led_update;
1948
1949 wl_list_init(&seat->devices_list);
1950 seat->seat_id = strdup(seat_id);
1951 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1952 free(seat->seat_id);
1953 free(seat);
1954 return;
1955 }
1956
1957 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001958}
1959
1960static void
1961evdev_remove_devices(struct weston_seat *seat_base)
1962{
1963 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001964 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001965
1966 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001967 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001968
Pekka Paalanend8583512012-08-03 14:39:11 +03001969 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001970 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001971}
1972
1973static void
1974evdev_input_destroy(struct weston_seat *seat_base)
1975{
1976 struct drm_seat *seat = (struct drm_seat *) seat_base;
1977
1978 evdev_remove_devices(seat_base);
1979 evdev_disable_udev_monitor(&seat->base);
1980
1981 weston_seat_release(seat_base);
1982 free(seat->seat_id);
1983 free(seat);
1984}
1985
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001986static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001987drm_free_configured_output(struct drm_configured_output *output)
1988{
1989 free(output->name);
1990 free(output->mode);
1991 free(output);
1992}
1993
1994static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001995drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001996{
1997 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001998 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001999 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002000
Daniel Stone37816df2012-05-16 18:45:18 +01002001 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2002 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002003 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002004 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002005
2006 wl_event_source_remove(d->udev_drm_source);
2007 wl_event_source_remove(d->drm_source);
2008
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002009 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002010
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002011 gl_renderer_destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002012
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002013 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002014 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002015 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002016 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002017 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002018
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002019 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002020}
2021
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002022static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002023drm_compositor_set_modes(struct drm_compositor *compositor)
2024{
2025 struct drm_output *output;
2026 struct drm_mode *drm_mode;
2027 int ret;
2028
2029 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2030 drm_mode = (struct drm_mode *) output->base.current;
2031 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002032 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002033 &output->connector_id, 1,
2034 &drm_mode->mode_info);
2035 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002036 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002037 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002038 drm_mode->base.width, drm_mode->base.height,
2039 output->base.x, output->base.y);
2040 }
2041 }
2042}
2043
2044static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002045vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002046{
2047 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002048 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002049 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002050 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002051
2052 switch (event) {
2053 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002054 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002055 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002056 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002057 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002058 wl_display_terminate(compositor->wl_display);
2059 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002060 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002061 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002062 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002063 wl_list_for_each(seat, &compositor->seat_list, link) {
2064 evdev_add_devices(ec->udev, seat);
2065 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002066 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002067 break;
2068 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002069 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002070 wl_list_for_each(seat, &compositor->seat_list, link) {
2071 evdev_disable_udev_monitor(seat);
2072 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002073 }
2074
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002075 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002076 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002077 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002078
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002079 /* If we have a repaint scheduled (either from a
2080 * pending pageflip or the idle handler), make sure we
2081 * cancel that so we don't try to pageflip when we're
2082 * vt switched away. The SLEEPING state will prevent
2083 * further attemps at repainting. When we switch
2084 * back, we schedule a repaint, which will process
2085 * pending frame callbacks. */
2086
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002087 wl_list_for_each(output, &ec->base.output_list, base.link) {
2088 output->base.repaint_needed = 0;
2089 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002090 }
2091
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002092 output = container_of(ec->base.output_list.next,
2093 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002094
2095 wl_list_for_each(sprite, &ec->sprite_list, link)
2096 drmModeSetPlane(ec->drm.fd,
2097 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002098 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002099 0, 0, 0, 0, 0, 0, 0, 0);
2100
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002101 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002102 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002103
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002104 break;
2105 };
2106}
2107
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002108static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002109switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002110{
2111 struct drm_compositor *ec = data;
2112
Daniel Stone325fc2d2012-05-30 16:31:58 +01002113 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002114}
2115
David Herrmann0af066f2012-10-29 19:21:16 +01002116/*
2117 * Find primary GPU
2118 * Some systems may have multiple DRM devices attached to a single seat. This
2119 * function loops over all devices and tries to find a PCI device with the
2120 * boot_vga sysfs attribute set to 1.
2121 * If no such device is found, the first DRM device reported by udev is used.
2122 */
2123static struct udev_device*
2124find_primary_gpu(struct drm_compositor *ec, const char *seat)
2125{
2126 struct udev_enumerate *e;
2127 struct udev_list_entry *entry;
2128 const char *path, *device_seat, *id;
2129 struct udev_device *device, *drm_device, *pci;
2130
2131 e = udev_enumerate_new(ec->udev);
2132 udev_enumerate_add_match_subsystem(e, "drm");
2133 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2134
2135 udev_enumerate_scan_devices(e);
2136 drm_device = NULL;
2137 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2138 path = udev_list_entry_get_name(entry);
2139 device = udev_device_new_from_syspath(ec->udev, path);
2140 if (!device)
2141 continue;
2142 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2143 if (!device_seat)
2144 device_seat = default_seat;
2145 if (strcmp(device_seat, seat)) {
2146 udev_device_unref(device);
2147 continue;
2148 }
2149
2150 pci = udev_device_get_parent_with_subsystem_devtype(device,
2151 "pci", NULL);
2152 if (pci) {
2153 id = udev_device_get_sysattr_value(pci, "boot_vga");
2154 if (id && !strcmp(id, "1")) {
2155 if (drm_device)
2156 udev_device_unref(drm_device);
2157 drm_device = device;
2158 break;
2159 }
2160 }
2161
2162 if (!drm_device)
2163 drm_device = device;
2164 else
2165 udev_device_unref(device);
2166 }
2167
2168 udev_enumerate_unref(e);
2169 return drm_device;
2170}
2171
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002172static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002173planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002174{
2175 struct drm_compositor *c = data;
2176
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002177 switch (key) {
2178 case KEY_C:
2179 c->cursors_are_broken ^= 1;
2180 break;
2181 case KEY_V:
2182 c->sprites_are_broken ^= 1;
2183 break;
2184 case KEY_O:
2185 c->sprites_hidden ^= 1;
2186 break;
2187 default:
2188 break;
2189 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002190}
2191
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002192static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002193drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002194 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002195 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002196{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002197 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002198 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002199 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002200 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002201 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002202 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002203
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002204 weston_log("initializing drm backend\n");
2205
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002206 ec = malloc(sizeof *ec);
2207 if (ec == NULL)
2208 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002209 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002210
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002211 /* KMS support for sprites is not complete yet, so disable the
2212 * functionality for now. */
2213 ec->sprites_are_broken = 1;
2214
Daniel Stone725c2c32012-06-22 14:04:36 +01002215 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002216 config_file) < 0) {
2217 weston_log("weston_compositor_init failed\n");
2218 goto err_base;
2219 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002220
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002221 ec->udev = udev_new();
2222 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002223 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002224 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002225 }
2226
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002227 ec->base.wl_display = display;
2228 ec->tty = tty_create(&ec->base, vt_func, tty);
2229 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002230 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002231 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002232 }
2233
David Herrmann0af066f2012-10-29 19:21:16 +01002234 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002235 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002236 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002237 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002238 }
David Herrmann0af066f2012-10-29 19:21:16 +01002239 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002240
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002241 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002242 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002243 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002244 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002245
2246 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002247 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002248
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002249 ec->base.focus = 1;
2250
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002251 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002252
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002253 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002254 weston_compositor_add_key_binding(&ec->base, key,
2255 MODIFIER_CTRL | MODIFIER_ALT,
2256 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002257
Jesse Barnes58ef3792012-02-23 09:45:49 -05002258 wl_list_init(&ec->sprite_list);
2259 create_sprites(ec);
2260
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002261 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002262 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002263 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002264 }
2265
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002266 path = NULL;
2267
Tiago Vignattice03ec32011-12-19 01:14:03 +02002268 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002269
2270 loop = wl_display_get_event_loop(ec->base.wl_display);
2271 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002272 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002273 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002274
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002275 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2276 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002277 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002278 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002279 }
2280 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2281 "drm", NULL);
2282 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002283 wl_event_loop_add_fd(loop,
2284 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002285 WL_EVENT_READABLE, udev_drm_event, ec);
2286
2287 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002288 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002289 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002290 }
2291
Daniel Stonea96b93c2012-06-22 14:04:37 +01002292 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002293
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002294 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002295 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002296 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002297 planes_binding, ec);
2298 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2299 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002300
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002301 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002302
2303err_udev_monitor:
2304 wl_event_source_remove(ec->udev_drm_source);
2305 udev_monitor_unref(ec->udev_monitor);
2306err_drm_source:
2307 wl_event_source_remove(ec->drm_source);
2308 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2309 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002310err_sprite:
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002311 gl_renderer_destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002312 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002313 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002314err_udev_dev:
2315 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002316err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002317 tty_destroy(ec->tty);
2318err_udev:
2319 udev_unref(ec->udev);
2320err_compositor:
2321 weston_compositor_shutdown(&ec->base);
2322err_base:
2323 free(ec);
2324 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002325}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002326
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002327static int
2328set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2329{
2330 mode->flags = 0;
2331
2332 if (strcmp(hsync, "+hsync") == 0)
2333 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2334 else if (strcmp(hsync, "-hsync") == 0)
2335 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2336 else
2337 return -1;
2338
2339 if (strcmp(vsync, "+vsync") == 0)
2340 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2341 else if (strcmp(vsync, "-vsync") == 0)
2342 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2343 else
2344 return -1;
2345
2346 return 0;
2347}
2348
2349static int
2350check_for_modeline(struct drm_configured_output *output)
2351{
2352 drmModeModeInfo mode;
2353 char hsync[16];
2354 char vsync[16];
2355 char mode_name[16];
2356 float fclock;
2357
2358 mode.type = DRM_MODE_TYPE_USERDEF;
2359 mode.hskew = 0;
2360 mode.vscan = 0;
2361 mode.vrefresh = 0;
2362
2363 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2364 &fclock, &mode.hdisplay,
2365 &mode.hsync_start,
2366 &mode.hsync_end, &mode.htotal,
2367 &mode.vdisplay,
2368 &mode.vsync_start,
2369 &mode.vsync_end, &mode.vtotal,
2370 hsync, vsync) == 11) {
2371 if (set_sync_flags(&mode, hsync, vsync))
2372 return -1;
2373
2374 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2375 strcpy(mode.name, mode_name);
2376
2377 mode.clock = fclock * 1000;
2378 } else
2379 return -1;
2380
2381 output->crtc_mode = mode;
2382
2383 return 0;
2384}
2385
Scott Moreau8ab5d452012-07-30 19:51:08 -06002386static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002387drm_output_set_transform(struct drm_configured_output *output)
2388{
2389 if (!output_transform) {
2390 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2391 return;
2392 }
2393
2394 if (!strcmp(output_transform, "normal"))
2395 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2396 else if (!strcmp(output_transform, "90"))
2397 output->transform = WL_OUTPUT_TRANSFORM_90;
2398 else if (!strcmp(output_transform, "180"))
2399 output->transform = WL_OUTPUT_TRANSFORM_180;
2400 else if (!strcmp(output_transform, "270"))
2401 output->transform = WL_OUTPUT_TRANSFORM_270;
2402 else if (!strcmp(output_transform, "flipped"))
2403 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2404 else if (!strcmp(output_transform, "flipped-90"))
2405 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2406 else if (!strcmp(output_transform, "flipped-180"))
2407 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2408 else if (!strcmp(output_transform, "flipped-270"))
2409 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2410 else {
2411 weston_log("Invalid transform \"%s\" for output %s\n",
2412 output_transform, output_name);
2413 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2414 }
2415
2416 free(output_transform);
2417 output_transform = NULL;
2418}
2419
2420static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002421output_section_done(void *data)
2422{
2423 struct drm_configured_output *output;
2424
2425 output = malloc(sizeof *output);
2426
Scott Moreau1bad5db2012-08-18 01:04:05 -06002427 if (!output || !output_name || (output_name[0] == 'X') ||
2428 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002429 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002430 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002431 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002432 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002433 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002434 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002435 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002436 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002437 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002438
2439 output->config = OUTPUT_CONFIG_INVALID;
2440 output->name = output_name;
2441 output->mode = output_mode;
2442
Scott Moreau1bad5db2012-08-18 01:04:05 -06002443 if (output_mode) {
2444 if (strcmp(output_mode, "off") == 0)
2445 output->config = OUTPUT_CONFIG_OFF;
2446 else if (strcmp(output_mode, "preferred") == 0)
2447 output->config = OUTPUT_CONFIG_PREFERRED;
2448 else if (strcmp(output_mode, "current") == 0)
2449 output->config = OUTPUT_CONFIG_CURRENT;
2450 else if (sscanf(output_mode, "%dx%d",
2451 &output->width, &output->height) == 2)
2452 output->config = OUTPUT_CONFIG_MODE;
2453 else if (check_for_modeline(output) == 0)
2454 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002455
Scott Moreau1bad5db2012-08-18 01:04:05 -06002456 if (output->config == OUTPUT_CONFIG_INVALID)
2457 weston_log("Invalid mode \"%s\" for output %s\n",
2458 output_mode, output_name);
2459 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002460 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002461
2462 drm_output_set_transform(output);
2463
2464 wl_list_insert(&configured_output_list, &output->link);
2465
2466 if (output_transform)
2467 free(output_transform);
2468 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002469}
2470
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002471WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002472backend_init(struct wl_display *display, int argc, char *argv[],
2473 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002474{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002475 int connector = 0, tty = 0;
2476 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002477
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002478 const struct weston_option drm_options[] = {
2479 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2480 { WESTON_OPTION_STRING, "seat", 0, &seat },
2481 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002482 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002483 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002484
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002485 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002486
Scott Moreau8ab5d452012-07-30 19:51:08 -06002487 wl_list_init(&configured_output_list);
2488
2489 const struct config_key drm_config_keys[] = {
2490 { "name", CONFIG_KEY_STRING, &output_name },
2491 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002492 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002493 };
2494
2495 const struct config_section config_section[] = {
2496 { "output", drm_config_keys,
2497 ARRAY_LENGTH(drm_config_keys), output_section_done },
2498 };
2499
2500 parse_config_file(config_file, config_section,
2501 ARRAY_LENGTH(config_section), NULL);
2502
Daniel Stonec1be8e52012-06-01 11:14:02 -04002503 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2504 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002505}