blob: c9529be718a7f7d0fe1d72c7f514de60d90b87ac [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
Richard Hughesab745622013-05-01 21:52:13 +010024#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040028#define _GNU_SOURCE
29
Jesse Barnes58ef3792012-02-23 09:45:49 -050030#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040031#include <stdlib.h>
Richard Hughesb24e48e2013-05-09 20:31:09 +010032#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010033#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040034#include <string.h>
35#include <fcntl.h>
36#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040037#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030038#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020039#include <sys/mman.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030040#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040041
Benjamin Franzkec649a922011-03-02 11:56:04 +010042#include <xf86drm.h>
43#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050044#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010045
Benjamin Franzke060cf802011-04-30 09:32:11 +020046#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020047#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040048#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020049
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040050#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010051#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020052#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050053#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010054#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040055
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030056#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
57#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
58#endif
59
Kristian Høgsberg061c4252012-06-28 11:28:15 -040060static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060061
62enum output_config {
63 OUTPUT_CONFIG_INVALID = 0,
64 OUTPUT_CONFIG_OFF,
65 OUTPUT_CONFIG_PREFERRED,
66 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060067 OUTPUT_CONFIG_MODE,
68 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060069};
70
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040071struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050072 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040073
74 struct udev *udev;
75 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040076
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010077 struct udev_monitor *udev_monitor;
78 struct wl_event_source *udev_drm_source;
79
Benjamin Franzke2af7f102011-03-02 11:14:59 +010080 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010081 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010082 int fd;
83 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020084 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050085 uint32_t *crtcs;
86 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050087 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010088 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050089 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020090
Rob Clark4339add2012-08-09 14:18:28 -050091 /* we need these parameters in order to not fail drmModeAddFB2()
92 * due to out of bounds dimensions, and then mistakenly set
93 * sprites_are_broken:
94 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020095 uint32_t min_width, max_width;
96 uint32_t min_height, max_height;
97 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050098
Jesse Barnes58ef3792012-02-23 09:45:49 -050099 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500100 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200101 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500102
Rob Clarkab5b1e32012-08-09 13:24:45 -0500103 int cursors_are_broken;
104
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200105 int use_pixman;
106
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200107 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300108
109 clockid_t clock;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400110};
111
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400112struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500113 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400114 drmModeModeInfo mode_info;
115};
116
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300117struct drm_output;
118
119struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300120 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200121 uint32_t fb_id, stride, handle, size;
122 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300123 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200124 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200125
126 /* Used by gbm fbs */
127 struct gbm_bo *bo;
128
129 /* Used by dumb fbs */
130 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300131};
132
Richard Hughes2b2092a2013-04-24 14:58:02 +0100133struct drm_edid {
134 char eisa_id[13];
135 char monitor_name[13];
136 char pnp_id[5];
137 char serial_number[13];
138};
139
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400140struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500141 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400142
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400143 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500144 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400145 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700146 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100147 struct drm_edid edid;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200148
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300149 int vblank_pending;
150 int page_flip_pending;
151
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400152 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400153 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400154 struct weston_plane cursor_plane;
155 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400156 struct weston_surface *cursor_surface;
157 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300158 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200159 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200160
161 struct drm_fb *dumb[2];
162 pixman_image_t *image[2];
163 int current_image;
164 pixman_region32_t previous_damage;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400165};
166
Jesse Barnes58ef3792012-02-23 09:45:49 -0500167/*
168 * An output has a primary display plane plus zero or more sprites for
169 * blending display contents.
170 */
171struct drm_sprite {
172 struct wl_list link;
173
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400174 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500175
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200176 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300177 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500178 struct drm_compositor *compositor;
179
Jesse Barnes58ef3792012-02-23 09:45:49 -0500180 uint32_t possible_crtcs;
181 uint32_t plane_id;
182 uint32_t count_formats;
183
184 int32_t src_x, src_y;
185 uint32_t src_w, src_h;
186 uint32_t dest_x, dest_y;
187 uint32_t dest_w, dest_h;
188
189 uint32_t formats[];
190};
191
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500192static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400193
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400194static void
195drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400196
Jesse Barnes58ef3792012-02-23 09:45:49 -0500197static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500198drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
199{
200 struct weston_compositor *ec = output_base->compositor;
201 struct drm_compositor *c =(struct drm_compositor *) ec;
202 struct drm_output *output = (struct drm_output *) output_base;
203 int crtc;
204
205 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
206 if (c->crtcs[crtc] != output->crtc_id)
207 continue;
208
209 if (supported & (1 << crtc))
210 return -1;
211 }
212
213 return 0;
214}
215
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300216static void
217drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
218{
219 struct drm_fb *fb = data;
220 struct gbm_device *gbm = gbm_bo_get_device(bo);
221
222 if (fb->fb_id)
223 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
224
Pekka Paalanende685b82012-12-04 15:58:12 +0200225 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300226
227 free(data);
228}
229
230static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200231drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
232{
233 struct drm_fb *fb;
234 int ret;
235
236 struct drm_mode_create_dumb create_arg;
237 struct drm_mode_destroy_dumb destroy_arg;
238 struct drm_mode_map_dumb map_arg;
239
240 fb = calloc(1, sizeof *fb);
241 if (!fb)
242 return NULL;
243
244 create_arg.bpp = 32;
245 create_arg.width = width;
246 create_arg.height = height;
247
248 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
249 if (ret)
250 goto err_fb;
251
252 fb->handle = create_arg.handle;
253 fb->stride = create_arg.pitch;
254 fb->size = create_arg.size;
255 fb->fd = ec->drm.fd;
256
257 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
258 fb->stride, fb->handle, &fb->fb_id);
259 if (ret)
260 goto err_bo;
261
262 memset(&map_arg, 0, sizeof(map_arg));
263 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400264 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200265 if (ret)
266 goto err_add_fb;
267
268 fb->map = mmap(0, fb->size, PROT_WRITE,
269 MAP_SHARED, ec->drm.fd, map_arg.offset);
270 if (fb->map == MAP_FAILED)
271 goto err_add_fb;
272
273 return fb;
274
275err_add_fb:
276 drmModeRmFB(ec->drm.fd, fb->fb_id);
277err_bo:
278 memset(&destroy_arg, 0, sizeof(destroy_arg));
279 destroy_arg.handle = create_arg.handle;
280 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
281err_fb:
282 free(fb);
283 return NULL;
284}
285
286static void
287drm_fb_destroy_dumb(struct drm_fb *fb)
288{
289 struct drm_mode_destroy_dumb destroy_arg;
290
291 if (!fb->map)
292 return;
293
294 if (fb->fb_id)
295 drmModeRmFB(fb->fd, fb->fb_id);
296
297 weston_buffer_reference(&fb->buffer_ref, NULL);
298
299 munmap(fb->map, fb->size);
300
301 memset(&destroy_arg, 0, sizeof(destroy_arg));
302 destroy_arg.handle = fb->handle;
303 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
304
305 free(fb);
306}
307
308static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500309drm_fb_get_from_bo(struct gbm_bo *bo,
310 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300311{
312 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200313 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200314 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300315 int ret;
316
317 if (fb)
318 return fb;
319
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200320 fb = calloc(1, sizeof *fb);
321 if (!fb)
322 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300323
324 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300325
326 width = gbm_bo_get_width(bo);
327 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200328 fb->stride = gbm_bo_get_stride(bo);
329 fb->handle = gbm_bo_get_handle(bo).u32;
330 fb->size = fb->stride * height;
331 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300332
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200333 if (compositor->min_width > width || width > compositor->max_width ||
334 compositor->min_height > height ||
335 height > compositor->max_height) {
336 weston_log("bo geometry out of bounds\n");
337 goto err_free;
338 }
339
340 ret = -1;
341
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200342 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200343 handles[0] = fb->handle;
344 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200345 offsets[0] = 0;
346
347 ret = drmModeAddFB2(compositor->drm.fd, width, height,
348 format, handles, pitches, offsets,
349 &fb->fb_id, 0);
350 if (ret) {
351 weston_log("addfb2 failed: %m\n");
352 compositor->no_addfb2 = 1;
353 compositor->sprites_are_broken = 1;
354 }
355 }
356
357 if (ret)
358 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200359 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200360
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300361 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200362 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200363 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300364 }
365
366 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
367
368 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200369
370err_free:
371 free(fb);
372 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300373}
374
375static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
377{
Pekka Paalanende685b82012-12-04 15:58:12 +0200378 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200379
380 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200381
Pekka Paalanende685b82012-12-04 15:58:12 +0200382 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200383}
384
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200385static void
386drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
387{
388 if (!fb)
389 return;
390
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200391 if (fb->map &&
392 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200393 drm_fb_destroy_dumb(fb);
394 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200395 if (fb->is_client_buffer)
396 gbm_bo_destroy(fb->bo);
397 else
398 gbm_surface_release_buffer(output->surface,
399 output->current->bo);
400 }
401}
402
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500403static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200404drm_output_check_scanout_format(struct drm_output *output,
405 struct weston_surface *es, struct gbm_bo *bo)
406{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200407 uint32_t format;
408 pixman_region32_t r;
409
410 format = gbm_bo_get_format(bo);
411
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500412 switch (format) {
413 case GBM_FORMAT_XRGB8888:
414 return format;
415 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200416 /* We can only scanout an ARGB buffer if the surface's
417 * opaque region covers the whole output */
418 pixman_region32_init(&r);
419 pixman_region32_subtract(&r, &output->base.region,
420 &es->opaque);
421
422 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500423 format = GBM_FORMAT_XRGB8888;
424 else
425 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200426
427 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200428
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500429 return format;
430 default:
431 return 0;
432 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200433}
434
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400435static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400436drm_output_prepare_scanout_surface(struct weston_output *_output,
437 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500438{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400439 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500440 struct drm_compositor *c =
441 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200442 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300443 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500444 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500445
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500446 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200447 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200448 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200449 buffer->width != output->base.current->width ||
450 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200451 output->base.transform != es->buffer_transform ||
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200452 output->base.scale != es->buffer_scale ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200453 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400454 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500455
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400456 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200457 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500458
Rob Bradford9b101872012-09-14 23:25:41 +0100459 /* Unable to use the buffer for scanout */
460 if (!bo)
461 return NULL;
462
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500463 format = drm_output_check_scanout_format(output, es, bo);
464 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300465 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400466 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300467 }
468
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500469 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300470 if (!output->next) {
471 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400472 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300473 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500474
Pekka Paalanende685b82012-12-04 15:58:12 +0200475 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500476
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400477 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500478}
479
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500480static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200481drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400482{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200483 struct drm_compositor *c =
484 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300485 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400486
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200487 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400488
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300489 bo = gbm_surface_lock_front_buffer(output->surface);
490 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200491 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400492 return;
493 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300494
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500495 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300496 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200497 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300498 gbm_surface_release_buffer(output->surface, bo);
499 return;
500 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400501}
502
503static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200504drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
505{
506 struct weston_compositor *ec = output->base.compositor;
507 pixman_region32_t total_damage, previous_damage;
508
509 pixman_region32_init(&total_damage);
510 pixman_region32_init(&previous_damage);
511
512 pixman_region32_copy(&previous_damage, damage);
513
514 pixman_region32_union(&total_damage, damage, &output->previous_damage);
515 pixman_region32_copy(&output->previous_damage, &previous_damage);
516
517 output->current_image ^= 1;
518
519 output->next = output->dumb[output->current_image];
520 pixman_renderer_output_set_buffer(&output->base,
521 output->image[output->current_image]);
522
523 ec->renderer->repaint_output(&output->base, &total_damage);
524
525 pixman_region32_fini(&total_damage);
526 pixman_region32_fini(&previous_damage);
527}
528
529static void
530drm_output_render(struct drm_output *output, pixman_region32_t *damage)
531{
532 struct drm_compositor *c =
533 (struct drm_compositor *) output->base.compositor;
534
535 if (c->use_pixman)
536 drm_output_render_pixman(output, damage);
537 else
538 drm_output_render_gl(output, damage);
539
540 pixman_region32_subtract(&c->base.primary_plane.damage,
541 &c->base.primary_plane.damage, damage);
542}
543
544static void
Richard Hughese7299962013-05-01 21:52:12 +0100545drm_output_set_gamma(struct weston_output *output_base,
546 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
547{
548 int rc;
549 struct drm_output *output = (struct drm_output *) output_base;
550 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
551
552 /* check */
553 if (output_base->gamma_size != size)
554 return;
555 if (!output->original_crtc)
556 return;
557
558 rc = drmModeCrtcSetGamma(compositor->drm.fd,
559 output->crtc_id,
560 size, r, g, b);
561 if (rc)
562 weston_log("set gamma failed: %m\n");
563}
564
565static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500566drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400567 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100568{
569 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500570 struct drm_compositor *compositor =
571 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500572 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400573 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500574 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100575
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300576 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400577 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300578 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400579 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100580
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400581 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300582 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400583 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300584 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400585 &output->connector_id, 1,
586 &mode->mode_info);
587 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200588 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400589 return;
590 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200591 }
592
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500593 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300594 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500595 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200596 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500597 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500598 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100599
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300600 output->page_flip_pending = 1;
601
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400602 drm_output_set_cursor(output);
603
Jesse Barnes58ef3792012-02-23 09:45:49 -0500604 /*
605 * Now, update all the sprite surfaces
606 */
607 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200608 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500609 drmVBlank vbl = {
610 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
611 .request.sequence = 1,
612 };
613
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200614 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200615 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500616 continue;
617
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200618 if (s->next && !compositor->sprites_hidden)
619 fb_id = s->next->fb_id;
620
Jesse Barnes58ef3792012-02-23 09:45:49 -0500621 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200622 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500623 s->dest_x, s->dest_y,
624 s->dest_w, s->dest_h,
625 s->src_x, s->src_y,
626 s->src_w, s->src_h);
627 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200628 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500629 ret, strerror(errno));
630
Rob Clark5ca1a472012-08-08 20:27:37 -0500631 if (output->pipe > 0)
632 vbl.request.type |= DRM_VBLANK_SECONDARY;
633
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634 /*
635 * Queue a vblank signal so we know when the surface
636 * becomes active on the display or has been replaced.
637 */
638 vbl.request.signal = (unsigned long)s;
639 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
640 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200641 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500642 ret, strerror(errno));
643 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300644
645 s->output = output;
646 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500647 }
648
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500649 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400650}
651
652static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200653drm_output_start_repaint_loop(struct weston_output *output_base)
654{
655 struct drm_output *output = (struct drm_output *) output_base;
656 struct drm_compositor *compositor = (struct drm_compositor *)
657 output_base->compositor;
658 uint32_t fb_id;
659
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300660 struct timespec ts;
661
662 if (!output->current) {
663 /* We can't page flip if there's no mode set */
664 uint32_t msec;
665
666 clock_gettime(compositor->clock, &ts);
667 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
668 weston_output_finish_frame(output_base, msec);
669 return;
670 }
671
672 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200673
674 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
675 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
676 weston_log("queueing pageflip failed: %m\n");
677 return;
678 }
679}
680
681static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500682vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
683 void *data)
684{
685 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300686 struct drm_output *output = s->output;
687 uint32_t msecs;
688
689 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500690
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200691 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200692 s->current = s->next;
693 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300694
695 if (!output->page_flip_pending) {
696 msecs = sec * 1000 + usec / 1000;
697 weston_output_finish_frame(&output->base, msecs);
698 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500699}
700
701static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400702page_flip_handler(int fd, unsigned int frame,
703 unsigned int sec, unsigned int usec, void *data)
704{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200705 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400706 uint32_t msecs;
707
Jonas Ådahle5a12252013-04-05 23:07:11 +0200708 /* We don't set page_flip_pending on start_repaint_loop, in that case
709 * we just want to page flip to the current buffer to get an accurate
710 * timestamp */
711 if (output->page_flip_pending) {
712 drm_output_release_fb(output, output->current);
713 output->current = output->next;
714 output->next = NULL;
715 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300716
Jonas Ådahle5a12252013-04-05 23:07:11 +0200717 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400718
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300719 if (!output->vblank_pending) {
720 msecs = sec * 1000 + usec / 1000;
721 weston_output_finish_frame(&output->base, msecs);
722 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200723}
724
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500725static uint32_t
726drm_output_check_sprite_format(struct drm_sprite *s,
727 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500728{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500729 uint32_t i, format;
730
731 format = gbm_bo_get_format(bo);
732
733 if (format == GBM_FORMAT_ARGB8888) {
734 pixman_region32_t r;
735
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500736 pixman_region32_init_rect(&r, 0, 0,
737 es->geometry.width,
738 es->geometry.height);
739 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500740
741 if (!pixman_region32_not_empty(&r))
742 format = GBM_FORMAT_XRGB8888;
743
744 pixman_region32_fini(&r);
745 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500746
747 for (i = 0; i < s->count_formats; i++)
748 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500749 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500750
751 return 0;
752}
753
754static int
755drm_surface_transform_supported(struct weston_surface *es)
756{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500757 return !es->transform.enabled ||
758 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500759}
760
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400761static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500762drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400763 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500764{
765 struct weston_compositor *ec = output_base->compositor;
766 struct drm_compositor *c =(struct drm_compositor *) ec;
767 struct drm_sprite *s;
768 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500769 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500770 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200771 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500772 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400773 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500774
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200775 if (c->gbm == NULL)
776 return NULL;
777
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200778 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200779 return NULL;
780
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200781 if (es->buffer_scale != output_base->scale)
782 return NULL;
783
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500784 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400785 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500786
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300787 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400788 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300789
Pekka Paalanende685b82012-12-04 15:58:12 +0200790 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400791 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500792
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200793 if (es->alpha != 1.0f)
794 return NULL;
795
Pekka Paalanende685b82012-12-04 15:58:12 +0200796 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500797 return NULL;
798
Jesse Barnes58ef3792012-02-23 09:45:49 -0500799 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400800 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801
Jesse Barnes58ef3792012-02-23 09:45:49 -0500802 wl_list_for_each(s, &c->sprite_list, link) {
803 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
804 continue;
805
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200806 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500807 found = 1;
808 break;
809 }
810 }
811
812 /* No sprites available */
813 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400814 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500815
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400816 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200817 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400818 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400819 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400820
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500821 format = drm_output_check_sprite_format(s, es, bo);
822 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200823 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400824 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500825 }
826
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200827 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200828 if (!s->next) {
829 gbm_bo_destroy(bo);
830 return NULL;
831 }
832
Pekka Paalanende685b82012-12-04 15:58:12 +0200833 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500834
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400835 box = pixman_region32_extents(&es->transform.boundingbox);
836 s->plane.x = box->x1;
837 s->plane.y = box->y1;
838
Jesse Barnes58ef3792012-02-23 09:45:49 -0500839 /*
840 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200841 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500842 * for us already).
843 */
844 pixman_region32_init(&dest_rect);
845 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
846 &output_base->region);
847 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
848 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200849 tbox = weston_transformed_rect(output_base->width,
850 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200851 output_base->transform,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200852 output_base->scale,
853 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200854 s->dest_x = tbox.x1;
855 s->dest_y = tbox.y1;
856 s->dest_w = tbox.x2 - tbox.x1;
857 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500858 pixman_region32_fini(&dest_rect);
859
860 pixman_region32_init(&src_rect);
861 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
862 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500863 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400864
865 weston_surface_from_global_fixed(es,
866 wl_fixed_from_int(box->x1),
867 wl_fixed_from_int(box->y1),
868 &sx1, &sy1);
869 weston_surface_from_global_fixed(es,
870 wl_fixed_from_int(box->x2),
871 wl_fixed_from_int(box->y2),
872 &sx2, &sy2);
873
874 if (sx1 < 0)
875 sx1 = 0;
876 if (sy1 < 0)
877 sy1 = 0;
878 if (sx2 > wl_fixed_from_int(es->geometry.width))
879 sx2 = wl_fixed_from_int(es->geometry.width);
880 if (sy2 > wl_fixed_from_int(es->geometry.height))
881 sy2 = wl_fixed_from_int(es->geometry.height);
882
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200883 tbox.x1 = sx1;
884 tbox.y1 = sy1;
885 tbox.x2 = sx2;
886 tbox.y2 = sy2;
887
888 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
889 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200890 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200891
892 s->src_x = tbox.x1 << 8;
893 s->src_y = tbox.y1 << 8;
894 s->src_w = (tbox.x2 - tbox.x1) << 8;
895 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500896 pixman_region32_fini(&src_rect);
897
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400898 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500899}
900
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400901static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400902drm_output_prepare_cursor_surface(struct weston_output *output_base,
903 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500904{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400905 struct drm_compositor *c =
906 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400907 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400908
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200909 if (c->gbm == NULL)
910 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200911 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
912 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400913 if (output->cursor_surface)
914 return NULL;
915 if (es->output_mask != (1u << output_base->id))
916 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500917 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400918 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200919 if (es->buffer_ref.buffer == NULL ||
920 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400921 es->geometry.width > 64 || es->geometry.height > 64)
922 return NULL;
923
924 output->cursor_surface = es;
925
926 return &output->cursor_plane;
927}
928
929static void
930drm_output_set_cursor(struct drm_output *output)
931{
932 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400933 struct drm_compositor *c =
934 (struct drm_compositor *) output->base.compositor;
935 EGLint handle, stride;
936 struct gbm_bo *bo;
937 uint32_t buf[64 * 64];
938 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400939 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500940
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400941 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400942 if (es == NULL) {
943 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
944 return;
945 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500946
Pekka Paalanende685b82012-12-04 15:58:12 +0200947 if (es->buffer_ref.buffer &&
948 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400949 pixman_region32_fini(&output->cursor_plane.damage);
950 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400951 output->current_cursor ^= 1;
952 bo = output->cursor_bo[output->current_cursor];
953 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200954 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
955 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400956 for (i = 0; i < es->geometry.height; i++)
957 memcpy(buf + i * 64, s + i * stride,
958 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500959
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400960 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300961 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400962
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400963 handle = gbm_bo_get_handle(bo).s32;
964 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500965 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300966 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500967 c->cursors_are_broken = 1;
968 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400969 }
970
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200971 x = (es->geometry.x - output->base.x) * output->base.scale;
972 y = (es->geometry.y - output->base.y) * output->base.scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400973 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500974 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400975 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500976 c->cursors_are_broken = 1;
977 }
978
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400979 output->cursor_plane.x = x;
980 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400981 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500982}
983
Jesse Barnes58ef3792012-02-23 09:45:49 -0500984static void
985drm_assign_planes(struct weston_output *output)
986{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400987 struct drm_compositor *c =
988 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400989 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500990 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400991 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500992
993 /*
994 * Find a surface for each sprite in the output using some heuristics:
995 * 1) size
996 * 2) frequency of update
997 * 3) opacity (though some hw might support alpha blending)
998 * 4) clipping (this can be fixed with color keys)
999 *
1000 * The idea is to save on blitting since this should save power.
1001 * If we can get a large video surface on the sprite for example,
1002 * the main display surface may not need to update at all, and
1003 * the client buffer can be used directly for the sprite surface
1004 * as we do for flipping full screen surfaces.
1005 */
1006 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001007 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001008 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001009 /* test whether this buffer can ever go into a plane:
1010 * non-shm, or small enough to be a cursor
1011 */
1012 if ((es->buffer_ref.buffer &&
1013 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
1014 (es->geometry.width <= 64 && es->geometry.height <= 64))
1015 es->keep_buffer = 1;
1016 else
1017 es->keep_buffer = 0;
1018
Jesse Barnes58ef3792012-02-23 09:45:49 -05001019 pixman_region32_init(&surface_overlap);
1020 pixman_region32_intersect(&surface_overlap, &overlap,
1021 &es->transform.boundingbox);
1022
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001023 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001024 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001025 next_plane = primary;
1026 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001027 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001028 if (next_plane == NULL)
1029 next_plane = drm_output_prepare_scanout_surface(output, es);
1030 if (next_plane == NULL)
1031 next_plane = drm_output_prepare_overlay_surface(output, es);
1032 if (next_plane == NULL)
1033 next_plane = primary;
1034 weston_surface_move_to_plane(es, next_plane);
1035 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001036 pixman_region32_union(&overlap, &overlap,
1037 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001038
Jesse Barnes58ef3792012-02-23 09:45:49 -05001039 pixman_region32_fini(&surface_overlap);
1040 }
1041 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001042}
1043
Matt Roper361d2ad2011-08-29 13:52:23 -07001044static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001045drm_output_fini_pixman(struct drm_output *output);
1046
1047static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001048drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001049{
1050 struct drm_output *output = (struct drm_output *) output_base;
1051 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001052 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001053 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001054
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001055 if (output->backlight)
1056 backlight_destroy(output->backlight);
1057
Matt Roper361d2ad2011-08-29 13:52:23 -07001058 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001059 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001060
1061 /* Restore original CRTC state */
1062 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001063 origcrtc->x, origcrtc->y,
1064 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001065 drmModeFreeCrtc(origcrtc);
1066
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001067 c->crtc_allocator &= ~(1 << output->crtc_id);
1068 c->connector_allocator &= ~(1 << output->connector_id);
1069
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001070 if (c->use_pixman) {
1071 drm_output_fini_pixman(output);
1072 } else {
1073 gl_renderer_output_destroy(output_base);
1074 gbm_surface_destroy(output->surface);
1075 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001076
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001077 weston_plane_release(&output->fb_plane);
1078 weston_plane_release(&output->cursor_plane);
1079
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001080 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001081 wl_list_remove(&output->base.link);
1082
Matt Roper361d2ad2011-08-29 13:52:23 -07001083 free(output);
1084}
1085
Alex Wub7b8bda2012-04-17 17:20:48 +08001086static struct drm_mode *
1087choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1088{
1089 struct drm_mode *tmp_mode = NULL, *mode;
1090
1091 if (output->base.current->width == target_mode->width &&
1092 output->base.current->height == target_mode->height &&
1093 (output->base.current->refresh == target_mode->refresh ||
1094 target_mode->refresh == 0))
1095 return (struct drm_mode *)output->base.current;
1096
1097 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1098 if (mode->mode_info.hdisplay == target_mode->width &&
1099 mode->mode_info.vdisplay == target_mode->height) {
1100 if (mode->mode_info.vrefresh == target_mode->refresh ||
1101 target_mode->refresh == 0) {
1102 return mode;
1103 } else if (!tmp_mode)
1104 tmp_mode = mode;
1105 }
1106 }
1107
1108 return tmp_mode;
1109}
1110
1111static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001112drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001113static int
1114drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001115
1116static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001117drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1118{
1119 struct drm_output *output;
1120 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001121 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001122
1123 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001124 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001125 return -1;
1126 }
1127
1128 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001129 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001130 return -1;
1131 }
1132
1133 ec = (struct drm_compositor *)output_base->compositor;
1134 output = (struct drm_output *)output_base;
1135 drm_mode = choose_mode (output, mode);
1136
1137 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001138 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001139 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001140 }
1141
1142 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001143 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001144
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001145 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001146
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001147 output->base.current = &drm_mode->base;
1148 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001149 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1150
Alex Wub7b8bda2012-04-17 17:20:48 +08001151 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001152 drm_output_release_fb(output, output->current);
1153 drm_output_release_fb(output, output->next);
1154 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001155
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001156 if (ec->use_pixman) {
1157 drm_output_fini_pixman(output);
1158 if (drm_output_init_pixman(output, ec) < 0) {
1159 weston_log("failed to init output pixman state with "
1160 "new mode\n");
1161 return -1;
1162 }
1163 } else {
1164 gl_renderer_output_destroy(&output->base);
1165 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001166
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001167 if (drm_output_init_egl(output, ec) < 0) {
1168 weston_log("failed to init output egl state with "
1169 "new mode");
1170 return -1;
1171 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001172 }
1173
Alex Wub7b8bda2012-04-17 17:20:48 +08001174 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001175}
1176
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001177static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001178on_drm_input(int fd, uint32_t mask, void *data)
1179{
1180 drmEventContext evctx;
1181
1182 memset(&evctx, 0, sizeof evctx);
1183 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1184 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001185 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001186 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001187
1188 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001189}
1190
1191static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001192init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001193{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001194 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001195 uint64_t cap;
1196 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001197
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001198 sysnum = udev_device_get_sysnum(device);
1199 if (sysnum)
1200 ec->drm.id = atoi(sysnum);
1201 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001202 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001203 return -1;
1204 }
1205
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001206 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001207 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001208 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001209 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001210 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001211 udev_device_get_devnode(device));
1212 return -1;
1213 }
1214
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001215 weston_log("using %s\n", filename);
1216
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001217 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001218
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001219 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1220 if (ret == 0 && cap == 1)
1221 ec->clock = CLOCK_MONOTONIC;
1222 else
1223 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001224
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001225 return 0;
1226}
1227
1228static int
1229init_egl(struct drm_compositor *ec)
1230{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001231 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001232
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001233 if (!ec->gbm)
1234 return -1;
1235
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001236 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001237 NULL) < 0) {
1238 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001239 return -1;
1240 }
1241
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001242 return 0;
1243}
1244
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001245static int
1246init_pixman(struct drm_compositor *ec)
1247{
1248 return pixman_renderer_init(&ec->base);
1249}
1250
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001251static struct drm_mode *
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001252drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info, int scale)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001253{
1254 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001255 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001256
1257 mode = malloc(sizeof *mode);
1258 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001259 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001260
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001261 if (info->hdisplay % scale != 0 ||
1262 info->vdisplay % scale) {
1263 weston_log("Mode %dx%d not multiple of scale %d\n", info->hdisplay, info->vdisplay, scale);
1264 return NULL;
1265 }
1266
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001267 mode->base.flags = 0;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001268 mode->base.width = info->hdisplay / scale;
1269 mode->base.height = info->vdisplay / scale;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001270
1271 /* Calculate higher precision (mHz) refresh rate */
1272 refresh = (info->clock * 1000000LL / info->htotal +
1273 info->vtotal / 2) / info->vtotal;
1274
1275 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1276 refresh *= 2;
1277 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1278 refresh /= 2;
1279 if (info->vscan > 1)
1280 refresh /= info->vscan;
1281
1282 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001283 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001284
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001285 if (scale != 1)
1286 mode->base.flags |= WL_OUTPUT_MODE_SCALED;
1287
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001288 if (info->type & DRM_MODE_TYPE_PREFERRED)
1289 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1290
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001291 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1292
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001293 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001294}
1295
1296static int
1297drm_subpixel_to_wayland(int drm_value)
1298{
1299 switch (drm_value) {
1300 default:
1301 case DRM_MODE_SUBPIXEL_UNKNOWN:
1302 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1303 case DRM_MODE_SUBPIXEL_NONE:
1304 return WL_OUTPUT_SUBPIXEL_NONE;
1305 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1306 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1307 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1308 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1309 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1310 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1311 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1312 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1313 }
1314}
1315
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001316/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001317static uint32_t
1318drm_get_backlight(struct drm_output *output)
1319{
1320 long brightness, max_brightness, norm;
1321
1322 brightness = backlight_get_brightness(output->backlight);
1323 max_brightness = backlight_get_max_brightness(output->backlight);
1324
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001325 /* convert it on a scale of 0 to 255 */
1326 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001327
1328 return (uint32_t) norm;
1329}
1330
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001331/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001332static void
1333drm_set_backlight(struct weston_output *output_base, uint32_t value)
1334{
1335 struct drm_output *output = (struct drm_output *) output_base;
1336 long max_brightness, new_brightness;
1337
1338 if (!output->backlight)
1339 return;
1340
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001341 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001342 return;
1343
1344 max_brightness = backlight_get_max_brightness(output->backlight);
1345
1346 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001347 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001348
1349 backlight_set_brightness(output->backlight, new_brightness);
1350}
1351
1352static drmModePropertyPtr
1353drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1354{
1355 drmModePropertyPtr props;
1356 int i;
1357
1358 for (i = 0; i < connector->count_props; i++) {
1359 props = drmModeGetProperty(fd, connector->props[i]);
1360 if (!props)
1361 continue;
1362
1363 if (!strcmp(props->name, name))
1364 return props;
1365
1366 drmModeFreeProperty(props);
1367 }
1368
1369 return NULL;
1370}
1371
1372static void
1373drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1374{
1375 struct drm_output *output = (struct drm_output *) output_base;
1376 struct weston_compositor *ec = output_base->compositor;
1377 struct drm_compositor *c = (struct drm_compositor *) ec;
1378 drmModeConnectorPtr connector;
1379 drmModePropertyPtr prop;
1380
1381 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1382 if (!connector)
1383 return;
1384
1385 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1386 if (!prop) {
1387 drmModeFreeConnector(connector);
1388 return;
1389 }
1390
1391 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1392 prop->prop_id, level);
1393 drmModeFreeProperty(prop);
1394 drmModeFreeConnector(connector);
1395}
1396
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001397static const char *connector_type_names[] = {
1398 "None",
1399 "VGA",
1400 "DVI",
1401 "DVI",
1402 "DVI",
1403 "Composite",
1404 "TV",
1405 "LVDS",
1406 "CTV",
1407 "DIN",
1408 "DP",
1409 "HDMI",
1410 "HDMI",
1411 "TV",
1412 "eDP",
1413};
1414
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001415static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001416find_crtc_for_connector(struct drm_compositor *ec,
1417 drmModeRes *resources, drmModeConnector *connector)
1418{
1419 drmModeEncoder *encoder;
1420 uint32_t possible_crtcs;
1421 int i, j;
1422
1423 for (j = 0; j < connector->count_encoders; j++) {
1424 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1425 if (encoder == NULL) {
1426 weston_log("Failed to get encoder.\n");
1427 return -1;
1428 }
1429 possible_crtcs = encoder->possible_crtcs;
1430 drmModeFreeEncoder(encoder);
1431
1432 for (i = 0; i < resources->count_crtcs; i++) {
1433 if (possible_crtcs & (1 << i) &&
1434 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1435 return i;
1436 }
1437 }
1438
1439 return -1;
1440}
1441
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001442/* Init output state that depends on gl or gbm */
1443static int
1444drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1445{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001446 int i, flags;
1447
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001448 output->surface = gbm_surface_create(ec->gbm,
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001449 output->base.current->width * output->base.scale,
1450 output->base.current->height * output->base.scale,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001451 GBM_FORMAT_XRGB8888,
1452 GBM_BO_USE_SCANOUT |
1453 GBM_BO_USE_RENDERING);
1454 if (!output->surface) {
1455 weston_log("failed to create gbm surface\n");
1456 return -1;
1457 }
1458
1459 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001460 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001461 gbm_surface_destroy(output->surface);
1462 return -1;
1463 }
1464
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001465 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1466
1467 for (i = 0; i < 2; i++) {
1468 if (output->cursor_bo[i])
1469 continue;
1470
1471 output->cursor_bo[i] =
1472 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1473 flags);
1474 }
1475
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001476 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1477 weston_log("cursor buffers unavailable, using gl cursors\n");
1478 ec->cursors_are_broken = 1;
1479 }
1480
1481 return 0;
1482}
1483
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001484static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001485drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1486{
1487 int w = output->base.current->width;
1488 int h = output->base.current->height;
1489 unsigned int i;
1490
1491 /* FIXME error checking */
1492
1493 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001494 output->dumb[i] = drm_fb_create_dumb(c, w * output->base.scale, h * output->base.scale);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001495 if (!output->dumb[i])
1496 goto err;
1497
1498 output->image[i] =
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001499 pixman_image_create_bits(PIXMAN_x8r8g8b8, w * output->base.scale, h * output->base.scale,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001500 output->dumb[i]->map,
1501 output->dumb[i]->stride);
1502 if (!output->image[i])
1503 goto err;
1504 }
1505
1506 if (pixman_renderer_output_create(&output->base) < 0)
1507 goto err;
1508
1509 pixman_region32_init_rect(&output->previous_damage,
1510 output->base.x, output->base.y, w, h);
1511
1512 return 0;
1513
1514err:
1515 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1516 if (output->dumb[i])
1517 drm_fb_destroy_dumb(output->dumb[i]);
1518 if (output->image[i])
1519 pixman_image_unref(output->image[i]);
1520
1521 output->dumb[i] = NULL;
1522 output->image[i] = NULL;
1523 }
1524
1525 return -1;
1526}
1527
1528static void
1529drm_output_fini_pixman(struct drm_output *output)
1530{
1531 unsigned int i;
1532
1533 pixman_renderer_output_destroy(&output->base);
1534 pixman_region32_fini(&output->previous_damage);
1535
1536 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1537 drm_fb_destroy_dumb(output->dumb[i]);
1538 pixman_image_unref(output->image[i]);
1539 output->dumb[i] = NULL;
1540 output->image[i] = NULL;
1541 }
1542}
1543
Richard Hughes2b2092a2013-04-24 14:58:02 +01001544static void
1545edid_parse_string(const uint8_t *data, char text[])
1546{
1547 int i;
1548 int replaced = 0;
1549
1550 /* this is always 12 bytes, but we can't guarantee it's null
1551 * terminated or not junk. */
1552 strncpy(text, (const char *) data, 12);
1553
1554 /* remove insane chars */
1555 for (i = 0; text[i] != '\0'; i++) {
1556 if (text[i] == '\n' ||
1557 text[i] == '\r') {
1558 text[i] = '\0';
1559 break;
1560 }
1561 }
1562
1563 /* ensure string is printable */
1564 for (i = 0; text[i] != '\0'; i++) {
1565 if (!isprint(text[i])) {
1566 text[i] = '-';
1567 replaced++;
1568 }
1569 }
1570
1571 /* if the string is random junk, ignore the string */
1572 if (replaced > 4)
1573 text[0] = '\0';
1574}
1575
1576#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1577#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1578#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1579#define EDID_OFFSET_DATA_BLOCKS 0x36
1580#define EDID_OFFSET_LAST_BLOCK 0x6c
1581#define EDID_OFFSET_PNPID 0x08
1582#define EDID_OFFSET_SERIAL 0x0c
1583
1584static int
1585edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1586{
1587 int i;
1588 uint32_t serial_number;
1589
1590 /* check header */
1591 if (length < 128)
1592 return -1;
1593 if (data[0] != 0x00 || data[1] != 0xff)
1594 return -1;
1595
1596 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1597 * /--08--\/--09--\
1598 * 7654321076543210
1599 * |\---/\---/\---/
1600 * R C1 C2 C3 */
1601 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1602 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1603 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1604 edid->pnp_id[3] = '\0';
1605
1606 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1607 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1608 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1609 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1610 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1611 if (serial_number > 0)
1612 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1613
1614 /* parse EDID data */
1615 for (i = EDID_OFFSET_DATA_BLOCKS;
1616 i <= EDID_OFFSET_LAST_BLOCK;
1617 i += 18) {
1618 /* ignore pixel clock data */
1619 if (data[i] != 0)
1620 continue;
1621 if (data[i+2] != 0)
1622 continue;
1623
1624 /* any useful blocks? */
1625 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1626 edid_parse_string(&data[i+5],
1627 edid->monitor_name);
1628 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1629 edid_parse_string(&data[i+5],
1630 edid->serial_number);
1631 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1632 edid_parse_string(&data[i+5],
1633 edid->eisa_id);
1634 }
1635 }
1636 return 0;
1637}
1638
1639static void
1640find_and_parse_output_edid(struct drm_compositor *ec,
1641 struct drm_output *output,
1642 drmModeConnector *connector)
1643{
1644 drmModePropertyBlobPtr edid_blob = NULL;
1645 drmModePropertyPtr property;
1646 int i;
1647 int rc;
1648
1649 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1650 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1651 if (!property)
1652 continue;
1653 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1654 !strcmp(property->name, "EDID")) {
1655 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1656 connector->prop_values[i]);
1657 }
1658 drmModeFreeProperty(property);
1659 }
1660 if (!edid_blob)
1661 return;
1662
1663 rc = edid_parse(&output->edid,
1664 edid_blob->data,
1665 edid_blob->length);
1666 if (!rc) {
1667 weston_log("EDID data '%s', '%s', '%s'\n",
1668 output->edid.pnp_id,
1669 output->edid.monitor_name,
1670 output->edid.serial_number);
1671 if (output->edid.pnp_id[0] != '\0')
1672 output->base.make = output->edid.pnp_id;
1673 if (output->edid.monitor_name[0] != '\0')
1674 output->base.model = output->edid.monitor_name;
1675 if (output->edid.serial_number[0] != '\0')
1676 output->base.serial_number = output->edid.serial_number;
1677 }
1678 drmModeFreePropertyBlob(edid_blob);
1679}
1680
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001681
1682
1683static int
1684parse_modeline(const char *s, drmModeModeInfo *mode)
1685{
1686 char hsync[16];
1687 char vsync[16];
1688 float fclock;
1689
1690 mode->type = DRM_MODE_TYPE_USERDEF;
1691 mode->hskew = 0;
1692 mode->vscan = 0;
1693 mode->vrefresh = 0;
1694 mode->flags = 0;
1695
1696 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
1697 &fclock,
1698 &mode->hdisplay,
1699 &mode->hsync_start,
1700 &mode->hsync_end,
1701 &mode->htotal,
1702 &mode->vdisplay,
1703 &mode->vsync_start,
1704 &mode->vsync_end,
1705 &mode->vtotal, hsync, vsync) != 11)
1706 return -1;
1707
1708 mode->clock = fclock * 1000;
1709 if (strcmp(hsync, "+hsync") == 0)
1710 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1711 else if (strcmp(hsync, "-hsync") == 0)
1712 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1713 else
1714 return -1;
1715
1716 if (strcmp(vsync, "+vsync") == 0)
1717 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1718 else if (strcmp(vsync, "-vsync") == 0)
1719 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1720 else
1721 return -1;
1722
1723 return 0;
1724}
1725
1726static uint32_t
1727parse_transform(const char *transform, const char *output_name)
1728{
1729 static const struct { const char *name; uint32_t token; } names[] = {
1730 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1731 { "90", WL_OUTPUT_TRANSFORM_90 },
1732 { "180", WL_OUTPUT_TRANSFORM_180 },
1733 { "270", WL_OUTPUT_TRANSFORM_270 },
1734 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1735 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1736 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1737 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1738 };
1739 unsigned int i;
1740
1741 for (i = 0; i < ARRAY_LENGTH(names); i++)
1742 if (strcmp(names[i].name, transform) == 0)
1743 return names[i].token;
1744
1745 weston_log("Invalid transform \"%s\" for output %s\n",
1746 transform, output_name);
1747
1748 return WL_OUTPUT_TRANSFORM_NORMAL;
1749}
1750
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001751static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001752create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001753 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001754 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001755 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001756{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001757 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001758 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1759 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001760 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001761 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001762 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001763 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001764 int i, width, height, scale;
1765 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001766 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001767 enum output_config config;
1768 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001769
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001770 i = find_crtc_for_connector(ec, resources, connector);
1771 if (i < 0) {
1772 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001773 return -1;
1774 }
1775
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001776 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001777 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001778 return -1;
1779
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001780 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001781 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1782 output->base.make = "unknown";
1783 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001784 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001785 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001786
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001787 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1788 type_name = connector_type_names[connector->connector_type];
1789 else
1790 type_name = "UNKNOWN";
1791 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001792 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001793
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001794 section = weston_config_get_section(ec->base.config, "output", "name",
1795 output->base.name);
1796 weston_config_section_get_string(section, "mode", &s, "preferred");
1797 if (strcmp(s, "off") == 0)
1798 config = OUTPUT_CONFIG_OFF;
1799 else if (strcmp(s, "preferred") == 0)
1800 config = OUTPUT_CONFIG_PREFERRED;
1801 else if (strcmp(s, "current") == 0)
1802 config = OUTPUT_CONFIG_CURRENT;
1803 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1804 config = OUTPUT_CONFIG_MODE;
1805 else if (parse_modeline(s, &modeline) == 0)
1806 config = OUTPUT_CONFIG_MODELINE;
1807 else {
1808 weston_log("Invalid mode \"%s\" for output %s\n",
1809 s, output->base.name);
1810 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001811 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001812 free(s);
1813
1814 weston_config_section_get_int(section, "scale", &scale, 1);
1815 weston_config_section_get_string(section, "transform", &s, "normal");
1816 transform = parse_transform(s, output->base.name);
1817 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001818
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001819 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001820 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001821 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001822 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001823 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001824
Matt Roper361d2ad2011-08-29 13:52:23 -07001825 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1826
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001827 /* Get the current mode on the crtc that's currently driving
1828 * this connector. */
1829 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001830 memset(&crtc_mode, 0, sizeof crtc_mode);
1831 if (encoder != NULL) {
1832 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1833 drmModeFreeEncoder(encoder);
1834 if (crtc == NULL)
1835 goto err_free;
1836 if (crtc->mode_valid)
1837 crtc_mode = crtc->mode;
1838 drmModeFreeCrtc(crtc);
1839 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001840
David Herrmann0f0d54e2011-12-08 17:05:45 +01001841 for (i = 0; i < connector->count_modes; i++) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001842 drm_mode = drm_output_add_mode(output,
1843 &connector->modes[i], scale);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001844 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001845 goto err_free;
1846 }
1847
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001848 if (config == OUTPUT_CONFIG_OFF) {
1849 weston_log("Disabling output %s\n", output->base.name);
1850 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1851 0, 0, 0, 0, 0, NULL);
1852 goto err_free;
1853 }
1854
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001855 preferred = NULL;
1856 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001857 configured = NULL;
1858
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001859 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001860 if (config == OUTPUT_CONFIG_MODE &&
1861 width == drm_mode->base.width * scale &&
1862 height == drm_mode->base.height * scale)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001863 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001864 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001865 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001866 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001867 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001868 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001869
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001870 if (config == OUTPUT_CONFIG_MODELINE) {
1871 configured = drm_output_add_mode(output, &modeline, scale);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001872 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001873 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001874 }
1875
Wang Quanxianacb805a2012-07-30 18:09:46 -04001876 if (current == NULL && crtc_mode.clock != 0) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001877 current = drm_output_add_mode(output, &crtc_mode, scale);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001878 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001879 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001880 }
1881
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001882 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001883 configured = current;
1884
Wang Quanxianacb805a2012-07-30 18:09:46 -04001885 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001886 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001887 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001888 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001889 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001890 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001891 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001892 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001893
1894 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001895 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001896 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001897 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001898
Wang Quanxianacb805a2012-07-30 18:09:46 -04001899 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1900
John Kåre Alsaker94659272012-11-13 19:10:18 +01001901 weston_output_init(&output->base, &ec->base, x, y,
1902 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001903 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001904
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001905 if (ec->use_pixman) {
1906 if (drm_output_init_pixman(output, ec) < 0) {
1907 weston_log("Failed to init output pixman state\n");
1908 goto err_output;
1909 }
1910 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001911 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001912 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001913 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001914
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001915 output->backlight = backlight_init(drm_device,
1916 connector->connector_type);
1917 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001918 weston_log("Initialized backlight, device %s\n",
1919 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001920 output->base.set_backlight = drm_set_backlight;
1921 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001922 } else {
1923 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001924 }
1925
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001926 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1927
Richard Hughes2b2092a2013-04-24 14:58:02 +01001928 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001929 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1930 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001931
Alex Wubd3354b2012-04-17 17:20:49 +08001932 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001933 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001934 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001935 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001936 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001937 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001938 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001939
Richard Hughese7299962013-05-01 21:52:12 +01001940 output->base.gamma_size = output->original_crtc->gamma_size;
1941 output->base.set_gamma = drm_output_set_gamma;
1942
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001943 weston_plane_init(&output->cursor_plane, 0, 0);
1944 weston_plane_init(&output->fb_plane, 0, 0);
1945
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001946 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1947 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1948 &ec->base.primary_plane);
1949
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001950 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001951 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001952 wl_list_for_each(m, &output->base.mode_list, link)
1953 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1954 m->width, m->height, m->refresh / 1000.0,
1955 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1956 ", preferred" : "",
1957 m->flags & WL_OUTPUT_MODE_CURRENT ?
1958 ", current" : "",
1959 connector->count_modes == 0 ?
1960 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001961
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001962 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001963
John Kåre Alsaker94659272012-11-13 19:10:18 +01001964err_output:
1965 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001966err_free:
1967 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1968 base.link) {
1969 wl_list_remove(&drm_mode->base.link);
1970 free(drm_mode);
1971 }
1972
1973 drmModeFreeCrtc(output->original_crtc);
1974 ec->crtc_allocator &= ~(1 << output->crtc_id);
1975 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001976 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001977
David Herrmann0f0d54e2011-12-08 17:05:45 +01001978 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001979}
1980
Jesse Barnes58ef3792012-02-23 09:45:49 -05001981static void
1982create_sprites(struct drm_compositor *ec)
1983{
1984 struct drm_sprite *sprite;
1985 drmModePlaneRes *plane_res;
1986 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001987 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001988
1989 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1990 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001991 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001992 strerror(errno));
1993 return;
1994 }
1995
1996 for (i = 0; i < plane_res->count_planes; i++) {
1997 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1998 if (!plane)
1999 continue;
2000
2001 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
2002 plane->count_formats));
2003 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002004 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002005 __func__);
2006 free(plane);
2007 continue;
2008 }
2009
2010 memset(sprite, 0, sizeof *sprite);
2011
2012 sprite->possible_crtcs = plane->possible_crtcs;
2013 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002014 sprite->current = NULL;
2015 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002016 sprite->compositor = ec;
2017 sprite->count_formats = plane->count_formats;
2018 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002019 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002020 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002021 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002022 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2023 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002024
2025 wl_list_insert(&ec->sprite_list, &sprite->link);
2026 }
2027
2028 free(plane_res->planes);
2029 free(plane_res);
2030}
2031
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002032static void
2033destroy_sprites(struct drm_compositor *compositor)
2034{
2035 struct drm_sprite *sprite, *next;
2036 struct drm_output *output;
2037
2038 output = container_of(compositor->base.output_list.next,
2039 struct drm_output, base.link);
2040
2041 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2042 drmModeSetPlane(compositor->drm.fd,
2043 sprite->plane_id,
2044 output->crtc_id, 0, 0,
2045 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002046 drm_output_release_fb(output, sprite->current);
2047 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002048 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002049 free(sprite);
2050 }
2051}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002052
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002053static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002054create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002055 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002056{
2057 drmModeConnector *connector;
2058 drmModeRes *resources;
2059 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002060 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002061
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002062 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002063 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002064 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002065 return -1;
2066 }
2067
Jesse Barnes58ef3792012-02-23 09:45:49 -05002068 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002069 if (!ec->crtcs) {
2070 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002071 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002072 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002073
Rob Clark4339add2012-08-09 14:18:28 -05002074 ec->min_width = resources->min_width;
2075 ec->max_width = resources->max_width;
2076 ec->min_height = resources->min_height;
2077 ec->max_height = resources->max_height;
2078
Jesse Barnes58ef3792012-02-23 09:45:49 -05002079 ec->num_crtcs = resources->count_crtcs;
2080 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2081
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002082 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002083 connector = drmModeGetConnector(ec->drm.fd,
2084 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002085 if (connector == NULL)
2086 continue;
2087
2088 if (connector->connection == DRM_MODE_CONNECTED &&
2089 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002090 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002091 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002092 connector, x, y,
2093 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002094 drmModeFreeConnector(connector);
2095 continue;
2096 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002097
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002098 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002099 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002100 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002101 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002102
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002103 drmModeFreeConnector(connector);
2104 }
2105
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002106 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002107 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002108 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002109 return -1;
2110 }
2111
2112 drmModeFreeResources(resources);
2113
2114 return 0;
2115}
2116
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002117static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002118update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002119{
2120 drmModeConnector *connector;
2121 drmModeRes *resources;
2122 struct drm_output *output, *next;
2123 int x = 0, y = 0;
2124 int x_offset = 0, y_offset = 0;
2125 uint32_t connected = 0, disconnects = 0;
2126 int i;
2127
2128 resources = drmModeGetResources(ec->drm.fd);
2129 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002130 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002131 return;
2132 }
2133
2134 /* collect new connects */
2135 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002136 int connector_id = resources->connectors[i];
2137
2138 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002139 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002140 continue;
2141
David Herrmann7551cff2011-12-08 17:05:43 +01002142 if (connector->connection != DRM_MODE_CONNECTED) {
2143 drmModeFreeConnector(connector);
2144 continue;
2145 }
2146
Benjamin Franzke117483d2011-08-30 11:38:26 +02002147 connected |= (1 << connector_id);
2148
2149 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002150 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002151 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002152 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002153
2154 /* XXX: not yet needed, we die with 0 outputs */
2155 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002156 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002157 else
2158 x = 0;
2159 y = 0;
2160 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002161 connector, x, y,
2162 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002163 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002164
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002165 }
2166 drmModeFreeConnector(connector);
2167 }
2168 drmModeFreeResources(resources);
2169
2170 disconnects = ec->connector_allocator & ~connected;
2171 if (disconnects) {
2172 wl_list_for_each_safe(output, next, &ec->base.output_list,
2173 base.link) {
2174 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002175 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002176 output->base.x - x_offset,
2177 output->base.y - y_offset);
2178 }
2179
2180 if (disconnects & (1 << output->connector_id)) {
2181 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002182 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002183 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002184 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002185 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002186 }
2187 }
2188 }
2189
2190 /* FIXME: handle zero outputs, without terminating */
2191 if (ec->connector_allocator == 0)
2192 wl_display_terminate(ec->base.wl_display);
2193}
2194
2195static int
David Herrmannd7488c22012-03-11 20:05:21 +01002196udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002197{
David Herrmannd7488c22012-03-11 20:05:21 +01002198 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002199 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002200
2201 sysnum = udev_device_get_sysnum(device);
2202 if (!sysnum || atoi(sysnum) != ec->drm.id)
2203 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002204
David Herrmann6ac52db2012-03-11 20:05:22 +01002205 val = udev_device_get_property_value(device, "HOTPLUG");
2206 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002207 return 0;
2208
David Herrmann6ac52db2012-03-11 20:05:22 +01002209 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002210}
2211
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002212static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002213udev_drm_event(int fd, uint32_t mask, void *data)
2214{
2215 struct drm_compositor *ec = data;
2216 struct udev_device *event;
2217
2218 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002219
David Herrmannd7488c22012-03-11 20:05:21 +01002220 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002221 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002222
2223 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002224
2225 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002226}
2227
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002228static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002229drm_restore(struct weston_compositor *ec)
2230{
2231 struct drm_compositor *d = (struct drm_compositor *) ec;
2232
2233 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2234 weston_log("failed to drop master: %m\n");
2235 tty_reset(d->tty);
2236}
2237
2238static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002239drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002240{
2241 struct drm_compositor *d = (struct drm_compositor *) ec;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002242 struct udev_seat *seat, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002243
Kristian Høgsberge8091032013-02-18 15:43:29 -05002244 wl_list_for_each_safe(seat, next, &ec->seat_list, base.link)
2245 udev_seat_destroy(seat);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002246
2247 wl_event_source_remove(d->udev_drm_source);
2248 wl_event_source_remove(d->drm_source);
2249
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002250 destroy_sprites(d);
2251
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002252 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002253
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002254 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002255
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002256 if (d->gbm)
2257 gbm_device_destroy(d->gbm);
2258
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002259 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002260 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002261 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002262
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002263 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002264}
2265
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002266static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002267drm_compositor_set_modes(struct drm_compositor *compositor)
2268{
2269 struct drm_output *output;
2270 struct drm_mode *drm_mode;
2271 int ret;
2272
2273 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002274 if (!output->current) {
2275 /* If something that would cause the output to
2276 * switch mode happened while in another vt, we
2277 * might not have a current drm_fb. In that case,
2278 * schedule a repaint and let drm_output_repaint
2279 * handle setting the mode. */
2280 weston_output_schedule_repaint(&output->base);
2281 continue;
2282 }
2283
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002284 drm_mode = (struct drm_mode *) output->base.current;
2285 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002286 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002287 &output->connector_id, 1,
2288 &drm_mode->mode_info);
2289 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002290 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002291 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002292 drm_mode->base.width, drm_mode->base.height,
2293 output->base.x, output->base.y);
2294 }
2295 }
2296}
2297
2298static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002299vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002300{
2301 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002302 struct udev_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002303 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002304 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002305
2306 switch (event) {
2307 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002308 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002309 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002310 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002311 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002312 wl_display_terminate(compositor->wl_display);
2313 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002314 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002315 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002316 weston_compositor_damage_all(compositor);
Kristian Høgsberg87644662013-02-18 16:50:19 -05002317 wl_list_for_each(seat, &compositor->seat_list, base.link)
2318 udev_seat_enable(seat, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002319 break;
2320 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002321 weston_log("leaving VT\n");
Kristian Høgsberg87644662013-02-18 16:50:19 -05002322 wl_list_for_each(seat, &compositor->seat_list, base.link)
2323 udev_seat_disable(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002324
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002325 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002326 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002327 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002328
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002329 /* If we have a repaint scheduled (either from a
2330 * pending pageflip or the idle handler), make sure we
2331 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002332 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002333 * further attemps at repainting. When we switch
2334 * back, we schedule a repaint, which will process
2335 * pending frame callbacks. */
2336
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002337 wl_list_for_each(output, &ec->base.output_list, base.link) {
2338 output->base.repaint_needed = 0;
2339 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002340 }
2341
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002342 output = container_of(ec->base.output_list.next,
2343 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002344
2345 wl_list_for_each(sprite, &ec->sprite_list, link)
2346 drmModeSetPlane(ec->drm.fd,
2347 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002348 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002349 0, 0, 0, 0, 0, 0, 0, 0);
2350
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002351 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002352 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002353
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002354 break;
2355 };
2356}
2357
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002358static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002359switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002360{
2361 struct drm_compositor *ec = data;
2362
Daniel Stone325fc2d2012-05-30 16:31:58 +01002363 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002364}
2365
David Herrmann0af066f2012-10-29 19:21:16 +01002366/*
2367 * Find primary GPU
2368 * Some systems may have multiple DRM devices attached to a single seat. This
2369 * function loops over all devices and tries to find a PCI device with the
2370 * boot_vga sysfs attribute set to 1.
2371 * If no such device is found, the first DRM device reported by udev is used.
2372 */
2373static struct udev_device*
2374find_primary_gpu(struct drm_compositor *ec, const char *seat)
2375{
2376 struct udev_enumerate *e;
2377 struct udev_list_entry *entry;
2378 const char *path, *device_seat, *id;
2379 struct udev_device *device, *drm_device, *pci;
2380
2381 e = udev_enumerate_new(ec->udev);
2382 udev_enumerate_add_match_subsystem(e, "drm");
2383 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2384
2385 udev_enumerate_scan_devices(e);
2386 drm_device = NULL;
2387 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2388 path = udev_list_entry_get_name(entry);
2389 device = udev_device_new_from_syspath(ec->udev, path);
2390 if (!device)
2391 continue;
2392 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2393 if (!device_seat)
2394 device_seat = default_seat;
2395 if (strcmp(device_seat, seat)) {
2396 udev_device_unref(device);
2397 continue;
2398 }
2399
2400 pci = udev_device_get_parent_with_subsystem_devtype(device,
2401 "pci", NULL);
2402 if (pci) {
2403 id = udev_device_get_sysattr_value(pci, "boot_vga");
2404 if (id && !strcmp(id, "1")) {
2405 if (drm_device)
2406 udev_device_unref(drm_device);
2407 drm_device = device;
2408 break;
2409 }
2410 }
2411
2412 if (!drm_device)
2413 drm_device = device;
2414 else
2415 udev_device_unref(device);
2416 }
2417
2418 udev_enumerate_unref(e);
2419 return drm_device;
2420}
2421
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002422static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002423planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002424{
2425 struct drm_compositor *c = data;
2426
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002427 switch (key) {
2428 case KEY_C:
2429 c->cursors_are_broken ^= 1;
2430 break;
2431 case KEY_V:
2432 c->sprites_are_broken ^= 1;
2433 break;
2434 case KEY_O:
2435 c->sprites_hidden ^= 1;
2436 break;
2437 default:
2438 break;
2439 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002440}
2441
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002442static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002443drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002444 int connector, const char *seat, int tty, int pixman,
Ossama Othmana50e6e42013-05-14 09:48:26 -07002445 int *argc, char *argv[], int config_fd)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002446{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002447 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002448 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002449 struct wl_event_loop *loop;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002450 struct udev_seat *udev_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002451 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002452 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002453
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002454 weston_log("initializing drm backend\n");
2455
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002456 ec = malloc(sizeof *ec);
2457 if (ec == NULL)
2458 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002459 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002460
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002461 /* KMS support for sprites is not complete yet, so disable the
2462 * functionality for now. */
2463 ec->sprites_are_broken = 1;
2464
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002465 ec->use_pixman = pixman;
2466
Daniel Stone725c2c32012-06-22 14:04:36 +01002467 if (weston_compositor_init(&ec->base, display, argc, argv,
Ossama Othmana50e6e42013-05-14 09:48:26 -07002468 config_fd) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002469 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002470 goto err_base;
2471 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002472
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002473 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002474 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002475 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002476 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002477 goto err_compositor;
2478 }
2479
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002480 ec->udev = udev_new();
2481 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002482 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002483 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002484 }
2485
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002486 ec->base.wl_display = display;
2487 ec->tty = tty_create(&ec->base, vt_func, tty);
2488 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002489 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002490 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002491 }
2492
David Herrmann0af066f2012-10-29 19:21:16 +01002493 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002494 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002495 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002496 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002497 }
David Herrmann0af066f2012-10-29 19:21:16 +01002498 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002499
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002500 if (init_drm(ec, drm_device) < 0) {
2501 weston_log("failed to initialize kms\n");
2502 goto err_udev_dev;
2503 }
2504
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002505 if (ec->use_pixman) {
2506 if (init_pixman(ec) < 0) {
2507 weston_log("failed to initialize pixman renderer\n");
2508 goto err_udev_dev;
2509 }
2510 } else {
2511 if (init_egl(ec) < 0) {
2512 weston_log("failed to initialize egl\n");
2513 goto err_udev_dev;
2514 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002515 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002516
2517 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002518 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002519
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002520 ec->base.focus = 1;
2521
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002522 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002523
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002524 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002525 weston_compositor_add_key_binding(&ec->base, key,
2526 MODIFIER_CTRL | MODIFIER_ALT,
2527 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002528
Jesse Barnes58ef3792012-02-23 09:45:49 -05002529 wl_list_init(&ec->sprite_list);
2530 create_sprites(ec);
2531
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002532 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002533 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002534 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002535 }
2536
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002537 path = NULL;
2538
Kristian Høgsberge8091032013-02-18 15:43:29 -05002539 if (udev_seat_create(&ec->base, ec->udev, seat) == NULL) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002540 weston_log("failed to create input devices\n");
2541 goto err_sprite;
2542 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002543
2544 loop = wl_display_get_event_loop(ec->base.wl_display);
2545 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002546 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002547 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002548
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002549 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2550 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002551 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002552 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002553 }
2554 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2555 "drm", NULL);
2556 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002557 wl_event_loop_add_fd(loop,
2558 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002559 WL_EVENT_READABLE, udev_drm_event, ec);
2560
2561 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002562 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002563 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002564 }
2565
Daniel Stonea96b93c2012-06-22 14:04:37 +01002566 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002567
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002568 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002569 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002570 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002571 planes_binding, ec);
2572 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2573 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002574
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002575 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002576
2577err_udev_monitor:
2578 wl_event_source_remove(ec->udev_drm_source);
2579 udev_monitor_unref(ec->udev_monitor);
2580err_drm_source:
2581 wl_event_source_remove(ec->drm_source);
Kristian Høgsberge8091032013-02-18 15:43:29 -05002582 wl_list_for_each_safe(udev_seat, next, &ec->base.seat_list, base.link)
2583 udev_seat_destroy(udev_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002584err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002585 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002586 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002587 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002588err_udev_dev:
2589 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002590err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002591 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2592 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002593 tty_destroy(ec->tty);
2594err_udev:
2595 udev_unref(ec->udev);
2596err_compositor:
2597 weston_compositor_shutdown(&ec->base);
2598err_base:
2599 free(ec);
2600 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002601}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002602
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002603WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002604backend_init(struct wl_display *display, int *argc, char *argv[],
Ossama Othmana50e6e42013-05-14 09:48:26 -07002605 int config_fd)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002606{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002607 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002608 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002609
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002610 const struct weston_option drm_options[] = {
2611 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2612 { WESTON_OPTION_STRING, "seat", 0, &seat },
2613 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002614 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002615 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002616 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002617
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002618 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002619
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002620 return drm_compositor_create(display, connector, seat, tty, use_pixman,
Ossama Othmana50e6e42013-05-14 09:48:26 -07002621 argc, argv, config_fd);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002622}