blob: 24a71f1daf0a897898425e23a7f039965bdb12f0 [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;
1740 int fd;
1741
1742 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1743 if (!device_seat)
1744 device_seat = default_seat;
1745
1746 if (strcmp(device_seat, master->seat_id))
1747 return;
1748
1749 c = master->base.compositor;
1750 devnode = udev_device_get_devnode(udev_device);
1751
1752 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001753 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001754 * read. mtdev_get() also expects this. */
1755 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1756 if (fd < 0) {
1757 weston_log("opening input device '%s' failed.\n", devnode);
1758 return;
1759 }
1760
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001761 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001762 if (!device) {
1763 close(fd);
1764 weston_log("not using input device '%s'.\n", devnode);
1765 return;
1766 }
1767
1768 wl_list_insert(master->devices_list.prev, &device->link);
1769}
1770
1771static void
1772evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1773{
1774 struct drm_seat *seat = (struct drm_seat *) seat_base;
1775 struct udev_enumerate *e;
1776 struct udev_list_entry *entry;
1777 struct udev_device *device;
1778 const char *path, *sysname;
1779
1780 e = udev_enumerate_new(udev);
1781 udev_enumerate_add_match_subsystem(e, "input");
1782 udev_enumerate_scan_devices(e);
1783 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1784 path = udev_list_entry_get_name(entry);
1785 device = udev_device_new_from_syspath(udev, path);
1786
1787 sysname = udev_device_get_sysname(device);
1788 if (strncmp("event", sysname, 5) != 0) {
1789 udev_device_unref(device);
1790 continue;
1791 }
1792
1793 device_added(device, seat);
1794
1795 udev_device_unref(device);
1796 }
1797 udev_enumerate_unref(e);
1798
1799 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1800
1801 if (wl_list_empty(&seat->devices_list)) {
1802 weston_log(
1803 "warning: no input devices on entering Weston. "
1804 "Possible causes:\n"
1805 "\t- no permissions to read /dev/input/event*\n"
1806 "\t- seats misconfigured "
1807 "(Weston backend option 'seat', "
1808 "udev device property ID_SEAT)\n");
1809 }
1810}
1811
1812static int
1813evdev_udev_handler(int fd, uint32_t mask, void *data)
1814{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001815 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001816 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001817 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001818 const char *action;
1819 const char *devnode;
1820
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001821 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001822 if (!udev_device)
1823 return 1;
1824
1825 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001826 if (!action)
1827 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001828
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001829 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1830 goto out;
1831
1832 if (!strcmp(action, "add")) {
1833 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001834 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001835 else if (!strcmp(action, "remove")) {
1836 devnode = udev_device_get_devnode(udev_device);
1837 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1838 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001839 weston_log("input device %s, %s removed\n",
1840 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001841 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001842 break;
1843 }
1844 }
1845
1846out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001847 udev_device_unref(udev_device);
1848
1849 return 0;
1850}
1851
1852static int
1853evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1854{
1855 struct drm_seat *master = (struct drm_seat *) seat_base;
1856 struct wl_event_loop *loop;
1857 struct weston_compositor *c = master->base.compositor;
1858 int fd;
1859
1860 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1861 if (!master->udev_monitor) {
1862 weston_log("udev: failed to create the udev monitor\n");
1863 return 0;
1864 }
1865
1866 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1867 "input", NULL);
1868
1869 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1870 weston_log("udev: failed to bind the udev monitor\n");
1871 udev_monitor_unref(master->udev_monitor);
1872 return 0;
1873 }
1874
1875 loop = wl_display_get_event_loop(c->wl_display);
1876 fd = udev_monitor_get_fd(master->udev_monitor);
1877 master->udev_monitor_source =
1878 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1879 evdev_udev_handler, master);
1880 if (!master->udev_monitor_source) {
1881 udev_monitor_unref(master->udev_monitor);
1882 return 0;
1883 }
1884
1885 return 1;
1886}
1887
1888static void
1889evdev_disable_udev_monitor(struct weston_seat *seat_base)
1890{
1891 struct drm_seat *seat = (struct drm_seat *) seat_base;
1892
1893 if (!seat->udev_monitor)
1894 return;
1895
1896 udev_monitor_unref(seat->udev_monitor);
1897 seat->udev_monitor = NULL;
1898 wl_event_source_remove(seat->udev_monitor_source);
1899 seat->udev_monitor_source = NULL;
1900}
1901
1902static void
1903drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1904{
1905 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001906 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001907
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001908 wl_list_for_each(device, &seat->devices_list, link)
1909 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001910}
1911
1912static void
1913evdev_input_create(struct weston_compositor *c, struct udev *udev,
1914 const char *seat_id)
1915{
1916 struct drm_seat *seat;
1917
1918 seat = malloc(sizeof *seat);
1919 if (seat == NULL)
1920 return;
1921
1922 memset(seat, 0, sizeof *seat);
1923 weston_seat_init(&seat->base, c);
1924 seat->base.led_update = drm_led_update;
1925
1926 wl_list_init(&seat->devices_list);
1927 seat->seat_id = strdup(seat_id);
1928 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1929 free(seat->seat_id);
1930 free(seat);
1931 return;
1932 }
1933
1934 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001935}
1936
1937static void
1938evdev_remove_devices(struct weston_seat *seat_base)
1939{
1940 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001941 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001942
1943 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001944 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001945
Pekka Paalanend8583512012-08-03 14:39:11 +03001946 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001947 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001948}
1949
1950static void
1951evdev_input_destroy(struct weston_seat *seat_base)
1952{
1953 struct drm_seat *seat = (struct drm_seat *) seat_base;
1954
1955 evdev_remove_devices(seat_base);
1956 evdev_disable_udev_monitor(&seat->base);
1957
1958 weston_seat_release(seat_base);
1959 free(seat->seat_id);
1960 free(seat);
1961}
1962
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001963static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001964drm_free_configured_output(struct drm_configured_output *output)
1965{
1966 free(output->name);
1967 free(output->mode);
1968 free(output);
1969}
1970
1971static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001972drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001973{
1974 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001975 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001976 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001977
Daniel Stone37816df2012-05-16 18:45:18 +01001978 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1979 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001980 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06001981 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001982
1983 wl_event_source_remove(d->udev_drm_source);
1984 wl_event_source_remove(d->drm_source);
1985
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001986 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001987
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001988 gl_renderer_destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04001989
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001990 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001991 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001992 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001993 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001994 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001995
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001996 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001997}
1998
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001999static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002000drm_compositor_set_modes(struct drm_compositor *compositor)
2001{
2002 struct drm_output *output;
2003 struct drm_mode *drm_mode;
2004 int ret;
2005
2006 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2007 drm_mode = (struct drm_mode *) output->base.current;
2008 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002009 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002010 &output->connector_id, 1,
2011 &drm_mode->mode_info);
2012 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002013 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002014 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002015 drm_mode->base.width, drm_mode->base.height,
2016 output->base.x, output->base.y);
2017 }
2018 }
2019}
2020
2021static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002022vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002023{
2024 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002025 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002026 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002027 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002028
2029 switch (event) {
2030 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002031 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002032 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002033 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002034 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002035 wl_display_terminate(compositor->wl_display);
2036 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002037 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002038 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002039 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002040 wl_list_for_each(seat, &compositor->seat_list, link) {
2041 evdev_add_devices(ec->udev, seat);
2042 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002043 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002044 break;
2045 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002046 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002047 wl_list_for_each(seat, &compositor->seat_list, link) {
2048 evdev_disable_udev_monitor(seat);
2049 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002050 }
2051
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002052 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002053 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002054 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002055
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002056 /* If we have a repaint scheduled (either from a
2057 * pending pageflip or the idle handler), make sure we
2058 * cancel that so we don't try to pageflip when we're
2059 * vt switched away. The SLEEPING state will prevent
2060 * further attemps at repainting. When we switch
2061 * back, we schedule a repaint, which will process
2062 * pending frame callbacks. */
2063
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002064 wl_list_for_each(output, &ec->base.output_list, base.link) {
2065 output->base.repaint_needed = 0;
2066 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002067 }
2068
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002069 output = container_of(ec->base.output_list.next,
2070 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002071
2072 wl_list_for_each(sprite, &ec->sprite_list, link)
2073 drmModeSetPlane(ec->drm.fd,
2074 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002075 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002076 0, 0, 0, 0, 0, 0, 0, 0);
2077
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002078 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002079 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002080
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002081 break;
2082 };
2083}
2084
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002085static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002086switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002087{
2088 struct drm_compositor *ec = data;
2089
Daniel Stone325fc2d2012-05-30 16:31:58 +01002090 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002091}
2092
David Herrmann0af066f2012-10-29 19:21:16 +01002093/*
2094 * Find primary GPU
2095 * Some systems may have multiple DRM devices attached to a single seat. This
2096 * function loops over all devices and tries to find a PCI device with the
2097 * boot_vga sysfs attribute set to 1.
2098 * If no such device is found, the first DRM device reported by udev is used.
2099 */
2100static struct udev_device*
2101find_primary_gpu(struct drm_compositor *ec, const char *seat)
2102{
2103 struct udev_enumerate *e;
2104 struct udev_list_entry *entry;
2105 const char *path, *device_seat, *id;
2106 struct udev_device *device, *drm_device, *pci;
2107
2108 e = udev_enumerate_new(ec->udev);
2109 udev_enumerate_add_match_subsystem(e, "drm");
2110 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2111
2112 udev_enumerate_scan_devices(e);
2113 drm_device = NULL;
2114 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2115 path = udev_list_entry_get_name(entry);
2116 device = udev_device_new_from_syspath(ec->udev, path);
2117 if (!device)
2118 continue;
2119 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2120 if (!device_seat)
2121 device_seat = default_seat;
2122 if (strcmp(device_seat, seat)) {
2123 udev_device_unref(device);
2124 continue;
2125 }
2126
2127 pci = udev_device_get_parent_with_subsystem_devtype(device,
2128 "pci", NULL);
2129 if (pci) {
2130 id = udev_device_get_sysattr_value(pci, "boot_vga");
2131 if (id && !strcmp(id, "1")) {
2132 if (drm_device)
2133 udev_device_unref(drm_device);
2134 drm_device = device;
2135 break;
2136 }
2137 }
2138
2139 if (!drm_device)
2140 drm_device = device;
2141 else
2142 udev_device_unref(device);
2143 }
2144
2145 udev_enumerate_unref(e);
2146 return drm_device;
2147}
2148
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002149static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002150planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002151{
2152 struct drm_compositor *c = data;
2153
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002154 switch (key) {
2155 case KEY_C:
2156 c->cursors_are_broken ^= 1;
2157 break;
2158 case KEY_V:
2159 c->sprites_are_broken ^= 1;
2160 break;
2161 case KEY_O:
2162 c->sprites_hidden ^= 1;
2163 break;
2164 default:
2165 break;
2166 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002167}
2168
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002169static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002170drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002171 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002172 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002173{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002174 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002175 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002176 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002177 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002178 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002179 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002180
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002181 weston_log("initializing drm backend\n");
2182
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002183 ec = malloc(sizeof *ec);
2184 if (ec == NULL)
2185 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002186 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002187
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002188 /* KMS support for sprites is not complete yet, so disable the
2189 * functionality for now. */
2190 ec->sprites_are_broken = 1;
2191
Daniel Stone725c2c32012-06-22 14:04:36 +01002192 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002193 config_file) < 0) {
2194 weston_log("weston_compositor_init failed\n");
2195 goto err_base;
2196 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002197
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002198 ec->udev = udev_new();
2199 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002200 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002201 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002202 }
2203
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002204 ec->base.wl_display = display;
2205 ec->tty = tty_create(&ec->base, vt_func, tty);
2206 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002207 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002208 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002209 }
2210
David Herrmann0af066f2012-10-29 19:21:16 +01002211 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002212 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002213 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002214 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002215 }
David Herrmann0af066f2012-10-29 19:21:16 +01002216 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002217
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002218 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002219 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002220 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002221 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002222
2223 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002224 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002225
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002226 ec->base.focus = 1;
2227
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002228 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002229
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002230 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002231 weston_compositor_add_key_binding(&ec->base, key,
2232 MODIFIER_CTRL | MODIFIER_ALT,
2233 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002234
Jesse Barnes58ef3792012-02-23 09:45:49 -05002235 wl_list_init(&ec->sprite_list);
2236 create_sprites(ec);
2237
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002238 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002239 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002240 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002241 }
2242
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002243 path = NULL;
2244
Tiago Vignattice03ec32011-12-19 01:14:03 +02002245 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002246
2247 loop = wl_display_get_event_loop(ec->base.wl_display);
2248 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002249 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002250 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002251
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002252 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2253 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002254 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002255 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002256 }
2257 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2258 "drm", NULL);
2259 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002260 wl_event_loop_add_fd(loop,
2261 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002262 WL_EVENT_READABLE, udev_drm_event, ec);
2263
2264 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002265 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002266 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002267 }
2268
Daniel Stonea96b93c2012-06-22 14:04:37 +01002269 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002270
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002271 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002272 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002273 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002274 planes_binding, ec);
2275 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2276 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002277
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002278 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002279
2280err_udev_monitor:
2281 wl_event_source_remove(ec->udev_drm_source);
2282 udev_monitor_unref(ec->udev_monitor);
2283err_drm_source:
2284 wl_event_source_remove(ec->drm_source);
2285 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2286 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002287err_sprite:
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002288 gl_renderer_destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002289 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002290 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002291err_udev_dev:
2292 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002293err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002294 tty_destroy(ec->tty);
2295err_udev:
2296 udev_unref(ec->udev);
2297err_compositor:
2298 weston_compositor_shutdown(&ec->base);
2299err_base:
2300 free(ec);
2301 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002302}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002303
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002304static int
2305set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2306{
2307 mode->flags = 0;
2308
2309 if (strcmp(hsync, "+hsync") == 0)
2310 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2311 else if (strcmp(hsync, "-hsync") == 0)
2312 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2313 else
2314 return -1;
2315
2316 if (strcmp(vsync, "+vsync") == 0)
2317 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2318 else if (strcmp(vsync, "-vsync") == 0)
2319 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2320 else
2321 return -1;
2322
2323 return 0;
2324}
2325
2326static int
2327check_for_modeline(struct drm_configured_output *output)
2328{
2329 drmModeModeInfo mode;
2330 char hsync[16];
2331 char vsync[16];
2332 char mode_name[16];
2333 float fclock;
2334
2335 mode.type = DRM_MODE_TYPE_USERDEF;
2336 mode.hskew = 0;
2337 mode.vscan = 0;
2338 mode.vrefresh = 0;
2339
2340 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2341 &fclock, &mode.hdisplay,
2342 &mode.hsync_start,
2343 &mode.hsync_end, &mode.htotal,
2344 &mode.vdisplay,
2345 &mode.vsync_start,
2346 &mode.vsync_end, &mode.vtotal,
2347 hsync, vsync) == 11) {
2348 if (set_sync_flags(&mode, hsync, vsync))
2349 return -1;
2350
2351 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2352 strcpy(mode.name, mode_name);
2353
2354 mode.clock = fclock * 1000;
2355 } else
2356 return -1;
2357
2358 output->crtc_mode = mode;
2359
2360 return 0;
2361}
2362
Scott Moreau8ab5d452012-07-30 19:51:08 -06002363static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002364drm_output_set_transform(struct drm_configured_output *output)
2365{
2366 if (!output_transform) {
2367 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2368 return;
2369 }
2370
2371 if (!strcmp(output_transform, "normal"))
2372 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2373 else if (!strcmp(output_transform, "90"))
2374 output->transform = WL_OUTPUT_TRANSFORM_90;
2375 else if (!strcmp(output_transform, "180"))
2376 output->transform = WL_OUTPUT_TRANSFORM_180;
2377 else if (!strcmp(output_transform, "270"))
2378 output->transform = WL_OUTPUT_TRANSFORM_270;
2379 else if (!strcmp(output_transform, "flipped"))
2380 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2381 else if (!strcmp(output_transform, "flipped-90"))
2382 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2383 else if (!strcmp(output_transform, "flipped-180"))
2384 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2385 else if (!strcmp(output_transform, "flipped-270"))
2386 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2387 else {
2388 weston_log("Invalid transform \"%s\" for output %s\n",
2389 output_transform, output_name);
2390 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2391 }
2392
2393 free(output_transform);
2394 output_transform = NULL;
2395}
2396
2397static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002398output_section_done(void *data)
2399{
2400 struct drm_configured_output *output;
2401
2402 output = malloc(sizeof *output);
2403
Scott Moreau1bad5db2012-08-18 01:04:05 -06002404 if (!output || !output_name || (output_name[0] == 'X') ||
2405 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002406 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002407 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002408 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002409 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002410 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002411 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002412 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002413 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002414 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002415
2416 output->config = OUTPUT_CONFIG_INVALID;
2417 output->name = output_name;
2418 output->mode = output_mode;
2419
Scott Moreau1bad5db2012-08-18 01:04:05 -06002420 if (output_mode) {
2421 if (strcmp(output_mode, "off") == 0)
2422 output->config = OUTPUT_CONFIG_OFF;
2423 else if (strcmp(output_mode, "preferred") == 0)
2424 output->config = OUTPUT_CONFIG_PREFERRED;
2425 else if (strcmp(output_mode, "current") == 0)
2426 output->config = OUTPUT_CONFIG_CURRENT;
2427 else if (sscanf(output_mode, "%dx%d",
2428 &output->width, &output->height) == 2)
2429 output->config = OUTPUT_CONFIG_MODE;
2430 else if (check_for_modeline(output) == 0)
2431 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002432
Scott Moreau1bad5db2012-08-18 01:04:05 -06002433 if (output->config == OUTPUT_CONFIG_INVALID)
2434 weston_log("Invalid mode \"%s\" for output %s\n",
2435 output_mode, output_name);
2436 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002437 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002438
2439 drm_output_set_transform(output);
2440
2441 wl_list_insert(&configured_output_list, &output->link);
2442
2443 if (output_transform)
2444 free(output_transform);
2445 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002446}
2447
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002448WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002449backend_init(struct wl_display *display, int argc, char *argv[],
2450 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002451{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002452 int connector = 0, tty = 0;
2453 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002454
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002455 const struct weston_option drm_options[] = {
2456 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2457 { WESTON_OPTION_STRING, "seat", 0, &seat },
2458 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002459 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002460 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002461
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002462 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002463
Scott Moreau8ab5d452012-07-30 19:51:08 -06002464 wl_list_init(&configured_output_list);
2465
2466 const struct config_key drm_config_keys[] = {
2467 { "name", CONFIG_KEY_STRING, &output_name },
2468 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002469 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002470 };
2471
2472 const struct config_section config_section[] = {
2473 { "output", drm_config_keys,
2474 ARRAY_LENGTH(drm_config_keys), output_section_done },
2475 };
2476
2477 parse_config_file(config_file, config_section,
2478 ARRAY_LENGTH(config_section), NULL);
2479
Daniel Stonec1be8e52012-06-01 11:14:02 -04002480 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2481 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002482}