blob: 4222e575ca519e10c5fffe4ffc240c23027798ae [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 ||
452 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400453 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500454
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400455 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200456 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500457
Rob Bradford9b101872012-09-14 23:25:41 +0100458 /* Unable to use the buffer for scanout */
459 if (!bo)
460 return NULL;
461
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500462 format = drm_output_check_scanout_format(output, es, bo);
463 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300464 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400465 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300466 }
467
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500468 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300469 if (!output->next) {
470 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400471 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300472 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500473
Pekka Paalanende685b82012-12-04 15:58:12 +0200474 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500475
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400476 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500477}
478
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500479static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200480drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400481{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200482 struct drm_compositor *c =
483 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300484 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400485
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200486 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400487
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300488 bo = gbm_surface_lock_front_buffer(output->surface);
489 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200490 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400491 return;
492 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300493
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500494 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300495 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200496 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300497 gbm_surface_release_buffer(output->surface, bo);
498 return;
499 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400500}
501
502static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200503drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
504{
505 struct weston_compositor *ec = output->base.compositor;
506 pixman_region32_t total_damage, previous_damage;
507
508 pixman_region32_init(&total_damage);
509 pixman_region32_init(&previous_damage);
510
511 pixman_region32_copy(&previous_damage, damage);
512
513 pixman_region32_union(&total_damage, damage, &output->previous_damage);
514 pixman_region32_copy(&output->previous_damage, &previous_damage);
515
516 output->current_image ^= 1;
517
518 output->next = output->dumb[output->current_image];
519 pixman_renderer_output_set_buffer(&output->base,
520 output->image[output->current_image]);
521
522 ec->renderer->repaint_output(&output->base, &total_damage);
523
524 pixman_region32_fini(&total_damage);
525 pixman_region32_fini(&previous_damage);
526}
527
528static void
529drm_output_render(struct drm_output *output, pixman_region32_t *damage)
530{
531 struct drm_compositor *c =
532 (struct drm_compositor *) output->base.compositor;
533
534 if (c->use_pixman)
535 drm_output_render_pixman(output, damage);
536 else
537 drm_output_render_gl(output, damage);
538
539 pixman_region32_subtract(&c->base.primary_plane.damage,
540 &c->base.primary_plane.damage, damage);
541}
542
543static void
Richard Hughese7299962013-05-01 21:52:12 +0100544drm_output_set_gamma(struct weston_output *output_base,
545 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
546{
547 int rc;
548 struct drm_output *output = (struct drm_output *) output_base;
549 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
550
551 /* check */
552 if (output_base->gamma_size != size)
553 return;
554 if (!output->original_crtc)
555 return;
556
557 rc = drmModeCrtcSetGamma(compositor->drm.fd,
558 output->crtc_id,
559 size, r, g, b);
560 if (rc)
561 weston_log("set gamma failed: %m\n");
562}
563
564static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500565drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400566 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100567{
568 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500569 struct drm_compositor *compositor =
570 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500571 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400572 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500573 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100574
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300575 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400576 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300577 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400578 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100579
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400580 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300581 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400582 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300583 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400584 &output->connector_id, 1,
585 &mode->mode_info);
586 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200587 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400588 return;
589 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200590 }
591
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500592 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300593 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500594 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200595 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500596 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500597 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100598
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300599 output->page_flip_pending = 1;
600
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400601 drm_output_set_cursor(output);
602
Jesse Barnes58ef3792012-02-23 09:45:49 -0500603 /*
604 * Now, update all the sprite surfaces
605 */
606 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200607 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500608 drmVBlank vbl = {
609 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
610 .request.sequence = 1,
611 };
612
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200613 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200614 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500615 continue;
616
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200617 if (s->next && !compositor->sprites_hidden)
618 fb_id = s->next->fb_id;
619
Jesse Barnes58ef3792012-02-23 09:45:49 -0500620 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200621 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500622 s->dest_x, s->dest_y,
623 s->dest_w, s->dest_h,
624 s->src_x, s->src_y,
625 s->src_w, s->src_h);
626 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200627 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500628 ret, strerror(errno));
629
Rob Clark5ca1a472012-08-08 20:27:37 -0500630 if (output->pipe > 0)
631 vbl.request.type |= DRM_VBLANK_SECONDARY;
632
Jesse Barnes58ef3792012-02-23 09:45:49 -0500633 /*
634 * Queue a vblank signal so we know when the surface
635 * becomes active on the display or has been replaced.
636 */
637 vbl.request.signal = (unsigned long)s;
638 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
639 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200640 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500641 ret, strerror(errno));
642 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300643
644 s->output = output;
645 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500646 }
647
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500648 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400649}
650
651static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200652drm_output_start_repaint_loop(struct weston_output *output_base)
653{
654 struct drm_output *output = (struct drm_output *) output_base;
655 struct drm_compositor *compositor = (struct drm_compositor *)
656 output_base->compositor;
657 uint32_t fb_id;
658
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300659 struct timespec ts;
660
661 if (!output->current) {
662 /* We can't page flip if there's no mode set */
663 uint32_t msec;
664
665 clock_gettime(compositor->clock, &ts);
666 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
667 weston_output_finish_frame(output_base, msec);
668 return;
669 }
670
671 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200672
673 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
674 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
675 weston_log("queueing pageflip failed: %m\n");
676 return;
677 }
678}
679
680static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500681vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
682 void *data)
683{
684 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300685 struct drm_output *output = s->output;
686 uint32_t msecs;
687
688 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500689
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200690 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200691 s->current = s->next;
692 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300693
694 if (!output->page_flip_pending) {
695 msecs = sec * 1000 + usec / 1000;
696 weston_output_finish_frame(&output->base, msecs);
697 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500698}
699
700static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400701page_flip_handler(int fd, unsigned int frame,
702 unsigned int sec, unsigned int usec, void *data)
703{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200704 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400705 uint32_t msecs;
706
Jonas Ådahle5a12252013-04-05 23:07:11 +0200707 /* We don't set page_flip_pending on start_repaint_loop, in that case
708 * we just want to page flip to the current buffer to get an accurate
709 * timestamp */
710 if (output->page_flip_pending) {
711 drm_output_release_fb(output, output->current);
712 output->current = output->next;
713 output->next = NULL;
714 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300715
Jonas Ådahle5a12252013-04-05 23:07:11 +0200716 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400717
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300718 if (!output->vblank_pending) {
719 msecs = sec * 1000 + usec / 1000;
720 weston_output_finish_frame(&output->base, msecs);
721 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200722}
723
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500724static uint32_t
725drm_output_check_sprite_format(struct drm_sprite *s,
726 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500727{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500728 uint32_t i, format;
729
730 format = gbm_bo_get_format(bo);
731
732 if (format == GBM_FORMAT_ARGB8888) {
733 pixman_region32_t r;
734
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500735 pixman_region32_init_rect(&r, 0, 0,
736 es->geometry.width,
737 es->geometry.height);
738 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500739
740 if (!pixman_region32_not_empty(&r))
741 format = GBM_FORMAT_XRGB8888;
742
743 pixman_region32_fini(&r);
744 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500745
746 for (i = 0; i < s->count_formats; i++)
747 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500748 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500749
750 return 0;
751}
752
753static int
754drm_surface_transform_supported(struct weston_surface *es)
755{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500756 return !es->transform.enabled ||
757 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500758}
759
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400760static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500761drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400762 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500763{
764 struct weston_compositor *ec = output_base->compositor;
765 struct drm_compositor *c =(struct drm_compositor *) ec;
766 struct drm_sprite *s;
767 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500768 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500769 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200770 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500771 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400772 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500773
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200774 if (c->gbm == NULL)
775 return NULL;
776
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200777 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200778 return NULL;
779
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200780 if (es->buffer_scale != output_base->scale)
781 return NULL;
782
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500783 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400784 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500785
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300786 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400787 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300788
Pekka Paalanende685b82012-12-04 15:58:12 +0200789 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400790 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500791
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200792 if (es->alpha != 1.0f)
793 return NULL;
794
Pekka Paalanende685b82012-12-04 15:58:12 +0200795 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500796 return NULL;
797
Jesse Barnes58ef3792012-02-23 09:45:49 -0500798 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400799 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500800
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801 wl_list_for_each(s, &c->sprite_list, link) {
802 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
803 continue;
804
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200805 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500806 found = 1;
807 break;
808 }
809 }
810
811 /* No sprites available */
812 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400813 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500814
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400815 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200816 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400817 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400818 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400819
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500820 format = drm_output_check_sprite_format(s, es, bo);
821 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200822 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400823 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500824 }
825
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200826 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200827 if (!s->next) {
828 gbm_bo_destroy(bo);
829 return NULL;
830 }
831
Pekka Paalanende685b82012-12-04 15:58:12 +0200832 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500833
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400834 box = pixman_region32_extents(&es->transform.boundingbox);
835 s->plane.x = box->x1;
836 s->plane.y = box->y1;
837
Jesse Barnes58ef3792012-02-23 09:45:49 -0500838 /*
839 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200840 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500841 * for us already).
842 */
843 pixman_region32_init(&dest_rect);
844 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
845 &output_base->region);
846 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
847 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200848 tbox = weston_transformed_rect(output_base->width,
849 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200850 output_base->transform,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200851 output_base->scale,
852 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200853 s->dest_x = tbox.x1;
854 s->dest_y = tbox.y1;
855 s->dest_w = tbox.x2 - tbox.x1;
856 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500857 pixman_region32_fini(&dest_rect);
858
859 pixman_region32_init(&src_rect);
860 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
861 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500862 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400863
864 weston_surface_from_global_fixed(es,
865 wl_fixed_from_int(box->x1),
866 wl_fixed_from_int(box->y1),
867 &sx1, &sy1);
868 weston_surface_from_global_fixed(es,
869 wl_fixed_from_int(box->x2),
870 wl_fixed_from_int(box->y2),
871 &sx2, &sy2);
872
873 if (sx1 < 0)
874 sx1 = 0;
875 if (sy1 < 0)
876 sy1 = 0;
877 if (sx2 > wl_fixed_from_int(es->geometry.width))
878 sx2 = wl_fixed_from_int(es->geometry.width);
879 if (sy2 > wl_fixed_from_int(es->geometry.height))
880 sy2 = wl_fixed_from_int(es->geometry.height);
881
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200882 tbox.x1 = sx1;
883 tbox.y1 = sy1;
884 tbox.x2 = sx2;
885 tbox.y2 = sy2;
886
887 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
888 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200889 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200890
891 s->src_x = tbox.x1 << 8;
892 s->src_y = tbox.y1 << 8;
893 s->src_w = (tbox.x2 - tbox.x1) << 8;
894 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500895 pixman_region32_fini(&src_rect);
896
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400897 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500898}
899
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400900static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400901drm_output_prepare_cursor_surface(struct weston_output *output_base,
902 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500903{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400904 struct drm_compositor *c =
905 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400906 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400907
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200908 if (c->gbm == NULL)
909 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200910 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
911 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400912 if (output->cursor_surface)
913 return NULL;
914 if (es->output_mask != (1u << output_base->id))
915 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500916 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400917 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200918 if (es->buffer_ref.buffer == NULL ||
919 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400920 es->geometry.width > 64 || es->geometry.height > 64)
921 return NULL;
922
923 output->cursor_surface = es;
924
925 return &output->cursor_plane;
926}
927
928static void
929drm_output_set_cursor(struct drm_output *output)
930{
931 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400932 struct drm_compositor *c =
933 (struct drm_compositor *) output->base.compositor;
934 EGLint handle, stride;
935 struct gbm_bo *bo;
936 uint32_t buf[64 * 64];
937 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400938 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500939
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400940 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400941 if (es == NULL) {
942 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
943 return;
944 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500945
Pekka Paalanende685b82012-12-04 15:58:12 +0200946 if (es->buffer_ref.buffer &&
947 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400948 pixman_region32_fini(&output->cursor_plane.damage);
949 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400950 output->current_cursor ^= 1;
951 bo = output->cursor_bo[output->current_cursor];
952 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200953 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
954 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400955 for (i = 0; i < es->geometry.height; i++)
956 memcpy(buf + i * 64, s + i * stride,
957 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500958
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400959 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300960 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400961
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400962 handle = gbm_bo_get_handle(bo).s32;
963 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500964 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300965 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500966 c->cursors_are_broken = 1;
967 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400968 }
969
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200970 x = (es->geometry.x - output->base.x) * output->base.scale;
971 y = (es->geometry.y - output->base.y) * output->base.scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400972 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500973 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400974 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500975 c->cursors_are_broken = 1;
976 }
977
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400978 output->cursor_plane.x = x;
979 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400980 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500981}
982
Jesse Barnes58ef3792012-02-23 09:45:49 -0500983static void
984drm_assign_planes(struct weston_output *output)
985{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400986 struct drm_compositor *c =
987 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400988 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500989 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400990 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500991
992 /*
993 * Find a surface for each sprite in the output using some heuristics:
994 * 1) size
995 * 2) frequency of update
996 * 3) opacity (though some hw might support alpha blending)
997 * 4) clipping (this can be fixed with color keys)
998 *
999 * The idea is to save on blitting since this should save power.
1000 * If we can get a large video surface on the sprite for example,
1001 * the main display surface may not need to update at all, and
1002 * the client buffer can be used directly for the sprite surface
1003 * as we do for flipping full screen surfaces.
1004 */
1005 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001006 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001007 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001008 /* test whether this buffer can ever go into a plane:
1009 * non-shm, or small enough to be a cursor
1010 */
1011 if ((es->buffer_ref.buffer &&
1012 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
1013 (es->geometry.width <= 64 && es->geometry.height <= 64))
1014 es->keep_buffer = 1;
1015 else
1016 es->keep_buffer = 0;
1017
Jesse Barnes58ef3792012-02-23 09:45:49 -05001018 pixman_region32_init(&surface_overlap);
1019 pixman_region32_intersect(&surface_overlap, &overlap,
1020 &es->transform.boundingbox);
1021
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001022 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001023 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001024 next_plane = primary;
1025 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001026 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001027 if (next_plane == NULL)
1028 next_plane = drm_output_prepare_scanout_surface(output, es);
1029 if (next_plane == NULL)
1030 next_plane = drm_output_prepare_overlay_surface(output, es);
1031 if (next_plane == NULL)
1032 next_plane = primary;
1033 weston_surface_move_to_plane(es, next_plane);
1034 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001035 pixman_region32_union(&overlap, &overlap,
1036 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001037
Jesse Barnes58ef3792012-02-23 09:45:49 -05001038 pixman_region32_fini(&surface_overlap);
1039 }
1040 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001041}
1042
Matt Roper361d2ad2011-08-29 13:52:23 -07001043static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001044drm_output_fini_pixman(struct drm_output *output);
1045
1046static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001047drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001048{
1049 struct drm_output *output = (struct drm_output *) output_base;
1050 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001051 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001052 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001053
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001054 if (output->backlight)
1055 backlight_destroy(output->backlight);
1056
Matt Roper361d2ad2011-08-29 13:52:23 -07001057 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001058 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001059
1060 /* Restore original CRTC state */
1061 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001062 origcrtc->x, origcrtc->y,
1063 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001064 drmModeFreeCrtc(origcrtc);
1065
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001066 c->crtc_allocator &= ~(1 << output->crtc_id);
1067 c->connector_allocator &= ~(1 << output->connector_id);
1068
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001069 if (c->use_pixman) {
1070 drm_output_fini_pixman(output);
1071 } else {
1072 gl_renderer_output_destroy(output_base);
1073 gbm_surface_destroy(output->surface);
1074 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001075
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001076 weston_plane_release(&output->fb_plane);
1077 weston_plane_release(&output->cursor_plane);
1078
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001079 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001080 wl_list_remove(&output->base.link);
1081
Matt Roper361d2ad2011-08-29 13:52:23 -07001082 free(output);
1083}
1084
Alex Wub7b8bda2012-04-17 17:20:48 +08001085static struct drm_mode *
1086choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1087{
1088 struct drm_mode *tmp_mode = NULL, *mode;
1089
1090 if (output->base.current->width == target_mode->width &&
1091 output->base.current->height == target_mode->height &&
1092 (output->base.current->refresh == target_mode->refresh ||
1093 target_mode->refresh == 0))
1094 return (struct drm_mode *)output->base.current;
1095
1096 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1097 if (mode->mode_info.hdisplay == target_mode->width &&
1098 mode->mode_info.vdisplay == target_mode->height) {
1099 if (mode->mode_info.vrefresh == target_mode->refresh ||
1100 target_mode->refresh == 0) {
1101 return mode;
1102 } else if (!tmp_mode)
1103 tmp_mode = mode;
1104 }
1105 }
1106
1107 return tmp_mode;
1108}
1109
1110static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001111drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001112static int
1113drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001114
1115static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001116drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1117{
1118 struct drm_output *output;
1119 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001120 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001121
1122 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001123 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001124 return -1;
1125 }
1126
1127 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001128 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001129 return -1;
1130 }
1131
1132 ec = (struct drm_compositor *)output_base->compositor;
1133 output = (struct drm_output *)output_base;
1134 drm_mode = choose_mode (output, mode);
1135
1136 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001137 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001138 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001139 }
1140
1141 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001142 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001143
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001144 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001145
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001146 output->base.current = &drm_mode->base;
1147 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001148 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1149
Alex Wub7b8bda2012-04-17 17:20:48 +08001150 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001151 drm_output_release_fb(output, output->current);
1152 drm_output_release_fb(output, output->next);
1153 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001154
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001155 if (ec->use_pixman) {
1156 drm_output_fini_pixman(output);
1157 if (drm_output_init_pixman(output, ec) < 0) {
1158 weston_log("failed to init output pixman state with "
1159 "new mode\n");
1160 return -1;
1161 }
1162 } else {
1163 gl_renderer_output_destroy(&output->base);
1164 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001165
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001166 if (drm_output_init_egl(output, ec) < 0) {
1167 weston_log("failed to init output egl state with "
1168 "new mode");
1169 return -1;
1170 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001171 }
1172
Alex Wub7b8bda2012-04-17 17:20:48 +08001173 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001174}
1175
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001176static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001177on_drm_input(int fd, uint32_t mask, void *data)
1178{
1179 drmEventContext evctx;
1180
1181 memset(&evctx, 0, sizeof evctx);
1182 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1183 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001184 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001185 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001186
1187 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001188}
1189
1190static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001191init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001192{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001193 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001194 uint64_t cap;
1195 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001196
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001197 sysnum = udev_device_get_sysnum(device);
1198 if (sysnum)
1199 ec->drm.id = atoi(sysnum);
1200 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001201 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001202 return -1;
1203 }
1204
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001205 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001206 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001207 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001208 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001209 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001210 udev_device_get_devnode(device));
1211 return -1;
1212 }
1213
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001214 weston_log("using %s\n", filename);
1215
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001216 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001217
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001218 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1219 if (ret == 0 && cap == 1)
1220 ec->clock = CLOCK_MONOTONIC;
1221 else
1222 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001223
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001224 return 0;
1225}
1226
1227static int
1228init_egl(struct drm_compositor *ec)
1229{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001230 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001231
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001232 if (!ec->gbm)
1233 return -1;
1234
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001235 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001236 NULL) < 0) {
1237 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001238 return -1;
1239 }
1240
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001241 return 0;
1242}
1243
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001244static int
1245init_pixman(struct drm_compositor *ec)
1246{
1247 return pixman_renderer_init(&ec->base);
1248}
1249
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001250static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001251drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001252{
1253 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001254 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001255
1256 mode = malloc(sizeof *mode);
1257 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001258 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001259
1260 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001261 mode->base.width = info->hdisplay;
1262 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001263
1264 /* Calculate higher precision (mHz) refresh rate */
1265 refresh = (info->clock * 1000000LL / info->htotal +
1266 info->vtotal / 2) / info->vtotal;
1267
1268 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1269 refresh *= 2;
1270 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1271 refresh /= 2;
1272 if (info->vscan > 1)
1273 refresh /= info->vscan;
1274
1275 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001276 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001277
1278 if (info->type & DRM_MODE_TYPE_PREFERRED)
1279 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1280
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001281 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1282
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001283 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001284}
1285
1286static int
1287drm_subpixel_to_wayland(int drm_value)
1288{
1289 switch (drm_value) {
1290 default:
1291 case DRM_MODE_SUBPIXEL_UNKNOWN:
1292 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1293 case DRM_MODE_SUBPIXEL_NONE:
1294 return WL_OUTPUT_SUBPIXEL_NONE;
1295 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1296 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1297 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1298 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1299 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1300 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1301 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1302 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1303 }
1304}
1305
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001306/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001307static uint32_t
1308drm_get_backlight(struct drm_output *output)
1309{
1310 long brightness, max_brightness, norm;
1311
1312 brightness = backlight_get_brightness(output->backlight);
1313 max_brightness = backlight_get_max_brightness(output->backlight);
1314
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001315 /* convert it on a scale of 0 to 255 */
1316 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001317
1318 return (uint32_t) norm;
1319}
1320
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001321/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001322static void
1323drm_set_backlight(struct weston_output *output_base, uint32_t value)
1324{
1325 struct drm_output *output = (struct drm_output *) output_base;
1326 long max_brightness, new_brightness;
1327
1328 if (!output->backlight)
1329 return;
1330
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001331 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001332 return;
1333
1334 max_brightness = backlight_get_max_brightness(output->backlight);
1335
1336 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001337 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001338
1339 backlight_set_brightness(output->backlight, new_brightness);
1340}
1341
1342static drmModePropertyPtr
1343drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1344{
1345 drmModePropertyPtr props;
1346 int i;
1347
1348 for (i = 0; i < connector->count_props; i++) {
1349 props = drmModeGetProperty(fd, connector->props[i]);
1350 if (!props)
1351 continue;
1352
1353 if (!strcmp(props->name, name))
1354 return props;
1355
1356 drmModeFreeProperty(props);
1357 }
1358
1359 return NULL;
1360}
1361
1362static void
1363drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1364{
1365 struct drm_output *output = (struct drm_output *) output_base;
1366 struct weston_compositor *ec = output_base->compositor;
1367 struct drm_compositor *c = (struct drm_compositor *) ec;
1368 drmModeConnectorPtr connector;
1369 drmModePropertyPtr prop;
1370
1371 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1372 if (!connector)
1373 return;
1374
1375 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1376 if (!prop) {
1377 drmModeFreeConnector(connector);
1378 return;
1379 }
1380
1381 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1382 prop->prop_id, level);
1383 drmModeFreeProperty(prop);
1384 drmModeFreeConnector(connector);
1385}
1386
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001387static const char *connector_type_names[] = {
1388 "None",
1389 "VGA",
1390 "DVI",
1391 "DVI",
1392 "DVI",
1393 "Composite",
1394 "TV",
1395 "LVDS",
1396 "CTV",
1397 "DIN",
1398 "DP",
1399 "HDMI",
1400 "HDMI",
1401 "TV",
1402 "eDP",
1403};
1404
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001405static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001406find_crtc_for_connector(struct drm_compositor *ec,
1407 drmModeRes *resources, drmModeConnector *connector)
1408{
1409 drmModeEncoder *encoder;
1410 uint32_t possible_crtcs;
1411 int i, j;
1412
1413 for (j = 0; j < connector->count_encoders; j++) {
1414 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1415 if (encoder == NULL) {
1416 weston_log("Failed to get encoder.\n");
1417 return -1;
1418 }
1419 possible_crtcs = encoder->possible_crtcs;
1420 drmModeFreeEncoder(encoder);
1421
1422 for (i = 0; i < resources->count_crtcs; i++) {
1423 if (possible_crtcs & (1 << i) &&
1424 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1425 return i;
1426 }
1427 }
1428
1429 return -1;
1430}
1431
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001432/* Init output state that depends on gl or gbm */
1433static int
1434drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1435{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001436 int i, flags;
1437
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001438 output->surface = gbm_surface_create(ec->gbm,
Alexander Larsson0b135062013-05-28 16:23:36 +02001439 output->base.current->width,
1440 output->base.current->height,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001441 GBM_FORMAT_XRGB8888,
1442 GBM_BO_USE_SCANOUT |
1443 GBM_BO_USE_RENDERING);
1444 if (!output->surface) {
1445 weston_log("failed to create gbm surface\n");
1446 return -1;
1447 }
1448
1449 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001450 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001451 gbm_surface_destroy(output->surface);
1452 return -1;
1453 }
1454
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001455 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1456
1457 for (i = 0; i < 2; i++) {
1458 if (output->cursor_bo[i])
1459 continue;
1460
1461 output->cursor_bo[i] =
1462 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1463 flags);
1464 }
1465
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001466 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1467 weston_log("cursor buffers unavailable, using gl cursors\n");
1468 ec->cursors_are_broken = 1;
1469 }
1470
1471 return 0;
1472}
1473
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001474static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001475drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1476{
1477 int w = output->base.current->width;
1478 int h = output->base.current->height;
1479 unsigned int i;
1480
1481 /* FIXME error checking */
1482
1483 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001484 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001485 if (!output->dumb[i])
1486 goto err;
1487
1488 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001489 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001490 output->dumb[i]->map,
1491 output->dumb[i]->stride);
1492 if (!output->image[i])
1493 goto err;
1494 }
1495
1496 if (pixman_renderer_output_create(&output->base) < 0)
1497 goto err;
1498
1499 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001500 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001501
1502 return 0;
1503
1504err:
1505 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1506 if (output->dumb[i])
1507 drm_fb_destroy_dumb(output->dumb[i]);
1508 if (output->image[i])
1509 pixman_image_unref(output->image[i]);
1510
1511 output->dumb[i] = NULL;
1512 output->image[i] = NULL;
1513 }
1514
1515 return -1;
1516}
1517
1518static void
1519drm_output_fini_pixman(struct drm_output *output)
1520{
1521 unsigned int i;
1522
1523 pixman_renderer_output_destroy(&output->base);
1524 pixman_region32_fini(&output->previous_damage);
1525
1526 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1527 drm_fb_destroy_dumb(output->dumb[i]);
1528 pixman_image_unref(output->image[i]);
1529 output->dumb[i] = NULL;
1530 output->image[i] = NULL;
1531 }
1532}
1533
Richard Hughes2b2092a2013-04-24 14:58:02 +01001534static void
1535edid_parse_string(const uint8_t *data, char text[])
1536{
1537 int i;
1538 int replaced = 0;
1539
1540 /* this is always 12 bytes, but we can't guarantee it's null
1541 * terminated or not junk. */
1542 strncpy(text, (const char *) data, 12);
1543
1544 /* remove insane chars */
1545 for (i = 0; text[i] != '\0'; i++) {
1546 if (text[i] == '\n' ||
1547 text[i] == '\r') {
1548 text[i] = '\0';
1549 break;
1550 }
1551 }
1552
1553 /* ensure string is printable */
1554 for (i = 0; text[i] != '\0'; i++) {
1555 if (!isprint(text[i])) {
1556 text[i] = '-';
1557 replaced++;
1558 }
1559 }
1560
1561 /* if the string is random junk, ignore the string */
1562 if (replaced > 4)
1563 text[0] = '\0';
1564}
1565
1566#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1567#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1568#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1569#define EDID_OFFSET_DATA_BLOCKS 0x36
1570#define EDID_OFFSET_LAST_BLOCK 0x6c
1571#define EDID_OFFSET_PNPID 0x08
1572#define EDID_OFFSET_SERIAL 0x0c
1573
1574static int
1575edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1576{
1577 int i;
1578 uint32_t serial_number;
1579
1580 /* check header */
1581 if (length < 128)
1582 return -1;
1583 if (data[0] != 0x00 || data[1] != 0xff)
1584 return -1;
1585
1586 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1587 * /--08--\/--09--\
1588 * 7654321076543210
1589 * |\---/\---/\---/
1590 * R C1 C2 C3 */
1591 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1592 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1593 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1594 edid->pnp_id[3] = '\0';
1595
1596 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1597 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1598 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1599 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1600 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1601 if (serial_number > 0)
1602 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1603
1604 /* parse EDID data */
1605 for (i = EDID_OFFSET_DATA_BLOCKS;
1606 i <= EDID_OFFSET_LAST_BLOCK;
1607 i += 18) {
1608 /* ignore pixel clock data */
1609 if (data[i] != 0)
1610 continue;
1611 if (data[i+2] != 0)
1612 continue;
1613
1614 /* any useful blocks? */
1615 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1616 edid_parse_string(&data[i+5],
1617 edid->monitor_name);
1618 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1619 edid_parse_string(&data[i+5],
1620 edid->serial_number);
1621 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1622 edid_parse_string(&data[i+5],
1623 edid->eisa_id);
1624 }
1625 }
1626 return 0;
1627}
1628
1629static void
1630find_and_parse_output_edid(struct drm_compositor *ec,
1631 struct drm_output *output,
1632 drmModeConnector *connector)
1633{
1634 drmModePropertyBlobPtr edid_blob = NULL;
1635 drmModePropertyPtr property;
1636 int i;
1637 int rc;
1638
1639 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1640 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1641 if (!property)
1642 continue;
1643 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1644 !strcmp(property->name, "EDID")) {
1645 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1646 connector->prop_values[i]);
1647 }
1648 drmModeFreeProperty(property);
1649 }
1650 if (!edid_blob)
1651 return;
1652
1653 rc = edid_parse(&output->edid,
1654 edid_blob->data,
1655 edid_blob->length);
1656 if (!rc) {
1657 weston_log("EDID data '%s', '%s', '%s'\n",
1658 output->edid.pnp_id,
1659 output->edid.monitor_name,
1660 output->edid.serial_number);
1661 if (output->edid.pnp_id[0] != '\0')
1662 output->base.make = output->edid.pnp_id;
1663 if (output->edid.monitor_name[0] != '\0')
1664 output->base.model = output->edid.monitor_name;
1665 if (output->edid.serial_number[0] != '\0')
1666 output->base.serial_number = output->edid.serial_number;
1667 }
1668 drmModeFreePropertyBlob(edid_blob);
1669}
1670
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001671
1672
1673static int
1674parse_modeline(const char *s, drmModeModeInfo *mode)
1675{
1676 char hsync[16];
1677 char vsync[16];
1678 float fclock;
1679
1680 mode->type = DRM_MODE_TYPE_USERDEF;
1681 mode->hskew = 0;
1682 mode->vscan = 0;
1683 mode->vrefresh = 0;
1684 mode->flags = 0;
1685
1686 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
1687 &fclock,
1688 &mode->hdisplay,
1689 &mode->hsync_start,
1690 &mode->hsync_end,
1691 &mode->htotal,
1692 &mode->vdisplay,
1693 &mode->vsync_start,
1694 &mode->vsync_end,
1695 &mode->vtotal, hsync, vsync) != 11)
1696 return -1;
1697
1698 mode->clock = fclock * 1000;
1699 if (strcmp(hsync, "+hsync") == 0)
1700 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1701 else if (strcmp(hsync, "-hsync") == 0)
1702 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1703 else
1704 return -1;
1705
1706 if (strcmp(vsync, "+vsync") == 0)
1707 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1708 else if (strcmp(vsync, "-vsync") == 0)
1709 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1710 else
1711 return -1;
1712
1713 return 0;
1714}
1715
1716static uint32_t
1717parse_transform(const char *transform, const char *output_name)
1718{
1719 static const struct { const char *name; uint32_t token; } names[] = {
1720 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1721 { "90", WL_OUTPUT_TRANSFORM_90 },
1722 { "180", WL_OUTPUT_TRANSFORM_180 },
1723 { "270", WL_OUTPUT_TRANSFORM_270 },
1724 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1725 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1726 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1727 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1728 };
1729 unsigned int i;
1730
1731 for (i = 0; i < ARRAY_LENGTH(names); i++)
1732 if (strcmp(names[i].name, transform) == 0)
1733 return names[i].token;
1734
1735 weston_log("Invalid transform \"%s\" for output %s\n",
1736 transform, output_name);
1737
1738 return WL_OUTPUT_TRANSFORM_NORMAL;
1739}
1740
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001741static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001742create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001743 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001744 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001745 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001746{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001747 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001748 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1749 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001750 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001751 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001752 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001753 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001754 int i, width, height, scale;
1755 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001756 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001757 enum output_config config;
1758 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001759
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001760 i = find_crtc_for_connector(ec, resources, connector);
1761 if (i < 0) {
1762 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001763 return -1;
1764 }
1765
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001766 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001767 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001768 return -1;
1769
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001770 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001771 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1772 output->base.make = "unknown";
1773 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001774 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001775 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001776
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001777 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1778 type_name = connector_type_names[connector->connector_type];
1779 else
1780 type_name = "UNKNOWN";
1781 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001782 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001783
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001784 section = weston_config_get_section(ec->base.config, "output", "name",
1785 output->base.name);
1786 weston_config_section_get_string(section, "mode", &s, "preferred");
1787 if (strcmp(s, "off") == 0)
1788 config = OUTPUT_CONFIG_OFF;
1789 else if (strcmp(s, "preferred") == 0)
1790 config = OUTPUT_CONFIG_PREFERRED;
1791 else if (strcmp(s, "current") == 0)
1792 config = OUTPUT_CONFIG_CURRENT;
1793 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1794 config = OUTPUT_CONFIG_MODE;
1795 else if (parse_modeline(s, &modeline) == 0)
1796 config = OUTPUT_CONFIG_MODELINE;
1797 else {
1798 weston_log("Invalid mode \"%s\" for output %s\n",
1799 s, output->base.name);
1800 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001801 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001802 free(s);
1803
1804 weston_config_section_get_int(section, "scale", &scale, 1);
1805 weston_config_section_get_string(section, "transform", &s, "normal");
1806 transform = parse_transform(s, output->base.name);
1807 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001808
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001809 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001810 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001811 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001812 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001813 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001814
Matt Roper361d2ad2011-08-29 13:52:23 -07001815 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1816
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001817 /* Get the current mode on the crtc that's currently driving
1818 * this connector. */
1819 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001820 memset(&crtc_mode, 0, sizeof crtc_mode);
1821 if (encoder != NULL) {
1822 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1823 drmModeFreeEncoder(encoder);
1824 if (crtc == NULL)
1825 goto err_free;
1826 if (crtc->mode_valid)
1827 crtc_mode = crtc->mode;
1828 drmModeFreeCrtc(crtc);
1829 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001830
David Herrmann0f0d54e2011-12-08 17:05:45 +01001831 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001832 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001833 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001834 goto err_free;
1835 }
1836
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001837 if (config == OUTPUT_CONFIG_OFF) {
1838 weston_log("Disabling output %s\n", output->base.name);
1839 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1840 0, 0, 0, 0, 0, NULL);
1841 goto err_free;
1842 }
1843
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001844 preferred = NULL;
1845 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001846 configured = NULL;
1847
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001848 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001849 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001850 width == drm_mode->base.width &&
1851 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001852 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001853 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001854 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001855 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001856 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001857 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001858
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001859 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001860 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001861 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001862 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001863 }
1864
Wang Quanxianacb805a2012-07-30 18:09:46 -04001865 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001866 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001867 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001868 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001869 }
1870
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001871 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001872 configured = current;
1873
Wang Quanxianacb805a2012-07-30 18:09:46 -04001874 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001875 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001876 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001877 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001878 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001879 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001880 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001881 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001882
1883 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001884 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001885 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001886 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001887
Wang Quanxianacb805a2012-07-30 18:09:46 -04001888 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1889
John Kåre Alsaker94659272012-11-13 19:10:18 +01001890 weston_output_init(&output->base, &ec->base, x, y,
1891 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001892 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001893
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001894 if (ec->use_pixman) {
1895 if (drm_output_init_pixman(output, ec) < 0) {
1896 weston_log("Failed to init output pixman state\n");
1897 goto err_output;
1898 }
1899 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001900 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001901 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001902 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001903
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001904 output->backlight = backlight_init(drm_device,
1905 connector->connector_type);
1906 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001907 weston_log("Initialized backlight, device %s\n",
1908 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001909 output->base.set_backlight = drm_set_backlight;
1910 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001911 } else {
1912 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001913 }
1914
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001915 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1916
Richard Hughes2b2092a2013-04-24 14:58:02 +01001917 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001918 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1919 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001920
Alex Wubd3354b2012-04-17 17:20:49 +08001921 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001922 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001923 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001924 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001925 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001926 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001927 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001928
Richard Hughese7299962013-05-01 21:52:12 +01001929 output->base.gamma_size = output->original_crtc->gamma_size;
1930 output->base.set_gamma = drm_output_set_gamma;
1931
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001932 weston_plane_init(&output->cursor_plane, 0, 0);
1933 weston_plane_init(&output->fb_plane, 0, 0);
1934
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001935 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1936 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1937 &ec->base.primary_plane);
1938
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001939 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001940 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001941 wl_list_for_each(m, &output->base.mode_list, link)
1942 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1943 m->width, m->height, m->refresh / 1000.0,
1944 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1945 ", preferred" : "",
1946 m->flags & WL_OUTPUT_MODE_CURRENT ?
1947 ", current" : "",
1948 connector->count_modes == 0 ?
1949 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001950
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001951 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001952
John Kåre Alsaker94659272012-11-13 19:10:18 +01001953err_output:
1954 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001955err_free:
1956 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1957 base.link) {
1958 wl_list_remove(&drm_mode->base.link);
1959 free(drm_mode);
1960 }
1961
1962 drmModeFreeCrtc(output->original_crtc);
1963 ec->crtc_allocator &= ~(1 << output->crtc_id);
1964 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001965 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001966
David Herrmann0f0d54e2011-12-08 17:05:45 +01001967 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001968}
1969
Jesse Barnes58ef3792012-02-23 09:45:49 -05001970static void
1971create_sprites(struct drm_compositor *ec)
1972{
1973 struct drm_sprite *sprite;
1974 drmModePlaneRes *plane_res;
1975 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001976 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001977
1978 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1979 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001980 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001981 strerror(errno));
1982 return;
1983 }
1984
1985 for (i = 0; i < plane_res->count_planes; i++) {
1986 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1987 if (!plane)
1988 continue;
1989
1990 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1991 plane->count_formats));
1992 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001993 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001994 __func__);
1995 free(plane);
1996 continue;
1997 }
1998
1999 memset(sprite, 0, sizeof *sprite);
2000
2001 sprite->possible_crtcs = plane->possible_crtcs;
2002 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002003 sprite->current = NULL;
2004 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002005 sprite->compositor = ec;
2006 sprite->count_formats = plane->count_formats;
2007 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002008 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002009 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002010 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002011 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2012 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002013
2014 wl_list_insert(&ec->sprite_list, &sprite->link);
2015 }
2016
2017 free(plane_res->planes);
2018 free(plane_res);
2019}
2020
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002021static void
2022destroy_sprites(struct drm_compositor *compositor)
2023{
2024 struct drm_sprite *sprite, *next;
2025 struct drm_output *output;
2026
2027 output = container_of(compositor->base.output_list.next,
2028 struct drm_output, base.link);
2029
2030 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2031 drmModeSetPlane(compositor->drm.fd,
2032 sprite->plane_id,
2033 output->crtc_id, 0, 0,
2034 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002035 drm_output_release_fb(output, sprite->current);
2036 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002037 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002038 free(sprite);
2039 }
2040}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002041
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002042static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002043create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002044 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002045{
2046 drmModeConnector *connector;
2047 drmModeRes *resources;
2048 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002049 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002050
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002051 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002052 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002053 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002054 return -1;
2055 }
2056
Jesse Barnes58ef3792012-02-23 09:45:49 -05002057 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002058 if (!ec->crtcs) {
2059 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002060 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002061 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002062
Rob Clark4339add2012-08-09 14:18:28 -05002063 ec->min_width = resources->min_width;
2064 ec->max_width = resources->max_width;
2065 ec->min_height = resources->min_height;
2066 ec->max_height = resources->max_height;
2067
Jesse Barnes58ef3792012-02-23 09:45:49 -05002068 ec->num_crtcs = resources->count_crtcs;
2069 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2070
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002071 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002072 connector = drmModeGetConnector(ec->drm.fd,
2073 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002074 if (connector == NULL)
2075 continue;
2076
2077 if (connector->connection == DRM_MODE_CONNECTED &&
2078 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002079 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002080 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002081 connector, x, y,
2082 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002083 drmModeFreeConnector(connector);
2084 continue;
2085 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002086
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002087 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002088 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002089 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002090 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002091
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002092 drmModeFreeConnector(connector);
2093 }
2094
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002095 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002096 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002097 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002098 return -1;
2099 }
2100
2101 drmModeFreeResources(resources);
2102
2103 return 0;
2104}
2105
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002106static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002107update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002108{
2109 drmModeConnector *connector;
2110 drmModeRes *resources;
2111 struct drm_output *output, *next;
2112 int x = 0, y = 0;
2113 int x_offset = 0, y_offset = 0;
2114 uint32_t connected = 0, disconnects = 0;
2115 int i;
2116
2117 resources = drmModeGetResources(ec->drm.fd);
2118 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002119 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002120 return;
2121 }
2122
2123 /* collect new connects */
2124 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002125 int connector_id = resources->connectors[i];
2126
2127 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002128 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002129 continue;
2130
David Herrmann7551cff2011-12-08 17:05:43 +01002131 if (connector->connection != DRM_MODE_CONNECTED) {
2132 drmModeFreeConnector(connector);
2133 continue;
2134 }
2135
Benjamin Franzke117483d2011-08-30 11:38:26 +02002136 connected |= (1 << connector_id);
2137
2138 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002139 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002140 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002141 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002142
2143 /* XXX: not yet needed, we die with 0 outputs */
2144 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002145 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002146 else
2147 x = 0;
2148 y = 0;
2149 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002150 connector, x, y,
2151 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002152 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002153
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002154 }
2155 drmModeFreeConnector(connector);
2156 }
2157 drmModeFreeResources(resources);
2158
2159 disconnects = ec->connector_allocator & ~connected;
2160 if (disconnects) {
2161 wl_list_for_each_safe(output, next, &ec->base.output_list,
2162 base.link) {
2163 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002164 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002165 output->base.x - x_offset,
2166 output->base.y - y_offset);
2167 }
2168
2169 if (disconnects & (1 << output->connector_id)) {
2170 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002171 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002172 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002173 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002174 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002175 }
2176 }
2177 }
2178
2179 /* FIXME: handle zero outputs, without terminating */
2180 if (ec->connector_allocator == 0)
2181 wl_display_terminate(ec->base.wl_display);
2182}
2183
2184static int
David Herrmannd7488c22012-03-11 20:05:21 +01002185udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002186{
David Herrmannd7488c22012-03-11 20:05:21 +01002187 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002188 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002189
2190 sysnum = udev_device_get_sysnum(device);
2191 if (!sysnum || atoi(sysnum) != ec->drm.id)
2192 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002193
David Herrmann6ac52db2012-03-11 20:05:22 +01002194 val = udev_device_get_property_value(device, "HOTPLUG");
2195 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002196 return 0;
2197
David Herrmann6ac52db2012-03-11 20:05:22 +01002198 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002199}
2200
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002201static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002202udev_drm_event(int fd, uint32_t mask, void *data)
2203{
2204 struct drm_compositor *ec = data;
2205 struct udev_device *event;
2206
2207 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002208
David Herrmannd7488c22012-03-11 20:05:21 +01002209 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002210 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002211
2212 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002213
2214 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002215}
2216
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002217static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002218drm_restore(struct weston_compositor *ec)
2219{
2220 struct drm_compositor *d = (struct drm_compositor *) ec;
2221
2222 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2223 weston_log("failed to drop master: %m\n");
2224 tty_reset(d->tty);
2225}
2226
2227static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002228drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002229{
2230 struct drm_compositor *d = (struct drm_compositor *) ec;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002231 struct udev_seat *seat, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002232
Kristian Høgsberge8091032013-02-18 15:43:29 -05002233 wl_list_for_each_safe(seat, next, &ec->seat_list, base.link)
2234 udev_seat_destroy(seat);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002235
2236 wl_event_source_remove(d->udev_drm_source);
2237 wl_event_source_remove(d->drm_source);
2238
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002239 destroy_sprites(d);
2240
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002241 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002242
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002243 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002244
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002245 if (d->gbm)
2246 gbm_device_destroy(d->gbm);
2247
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002248 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002249 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002250 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002251
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002252 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002253}
2254
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002255static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002256drm_compositor_set_modes(struct drm_compositor *compositor)
2257{
2258 struct drm_output *output;
2259 struct drm_mode *drm_mode;
2260 int ret;
2261
2262 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002263 if (!output->current) {
2264 /* If something that would cause the output to
2265 * switch mode happened while in another vt, we
2266 * might not have a current drm_fb. In that case,
2267 * schedule a repaint and let drm_output_repaint
2268 * handle setting the mode. */
2269 weston_output_schedule_repaint(&output->base);
2270 continue;
2271 }
2272
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002273 drm_mode = (struct drm_mode *) output->base.current;
2274 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002275 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002276 &output->connector_id, 1,
2277 &drm_mode->mode_info);
2278 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002279 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002280 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002281 drm_mode->base.width, drm_mode->base.height,
2282 output->base.x, output->base.y);
2283 }
2284 }
2285}
2286
2287static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002288vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002289{
2290 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002291 struct udev_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002292 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002293 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002294
2295 switch (event) {
2296 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002297 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002298 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002299 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002300 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002301 wl_display_terminate(compositor->wl_display);
2302 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002303 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002304 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002305 weston_compositor_damage_all(compositor);
Kristian Høgsberg87644662013-02-18 16:50:19 -05002306 wl_list_for_each(seat, &compositor->seat_list, base.link)
2307 udev_seat_enable(seat, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002308 break;
2309 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002310 weston_log("leaving VT\n");
Kristian Høgsberg87644662013-02-18 16:50:19 -05002311 wl_list_for_each(seat, &compositor->seat_list, base.link)
2312 udev_seat_disable(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002313
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002314 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002315 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002316 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002317
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002318 /* If we have a repaint scheduled (either from a
2319 * pending pageflip or the idle handler), make sure we
2320 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002321 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002322 * further attemps at repainting. When we switch
2323 * back, we schedule a repaint, which will process
2324 * pending frame callbacks. */
2325
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002326 wl_list_for_each(output, &ec->base.output_list, base.link) {
2327 output->base.repaint_needed = 0;
2328 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002329 }
2330
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002331 output = container_of(ec->base.output_list.next,
2332 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002333
2334 wl_list_for_each(sprite, &ec->sprite_list, link)
2335 drmModeSetPlane(ec->drm.fd,
2336 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002337 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002338 0, 0, 0, 0, 0, 0, 0, 0);
2339
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002340 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002341 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002342
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002343 break;
2344 };
2345}
2346
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002347static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002348switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002349{
2350 struct drm_compositor *ec = data;
2351
Daniel Stone325fc2d2012-05-30 16:31:58 +01002352 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002353}
2354
David Herrmann0af066f2012-10-29 19:21:16 +01002355/*
2356 * Find primary GPU
2357 * Some systems may have multiple DRM devices attached to a single seat. This
2358 * function loops over all devices and tries to find a PCI device with the
2359 * boot_vga sysfs attribute set to 1.
2360 * If no such device is found, the first DRM device reported by udev is used.
2361 */
2362static struct udev_device*
2363find_primary_gpu(struct drm_compositor *ec, const char *seat)
2364{
2365 struct udev_enumerate *e;
2366 struct udev_list_entry *entry;
2367 const char *path, *device_seat, *id;
2368 struct udev_device *device, *drm_device, *pci;
2369
2370 e = udev_enumerate_new(ec->udev);
2371 udev_enumerate_add_match_subsystem(e, "drm");
2372 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2373
2374 udev_enumerate_scan_devices(e);
2375 drm_device = NULL;
2376 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2377 path = udev_list_entry_get_name(entry);
2378 device = udev_device_new_from_syspath(ec->udev, path);
2379 if (!device)
2380 continue;
2381 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2382 if (!device_seat)
2383 device_seat = default_seat;
2384 if (strcmp(device_seat, seat)) {
2385 udev_device_unref(device);
2386 continue;
2387 }
2388
2389 pci = udev_device_get_parent_with_subsystem_devtype(device,
2390 "pci", NULL);
2391 if (pci) {
2392 id = udev_device_get_sysattr_value(pci, "boot_vga");
2393 if (id && !strcmp(id, "1")) {
2394 if (drm_device)
2395 udev_device_unref(drm_device);
2396 drm_device = device;
2397 break;
2398 }
2399 }
2400
2401 if (!drm_device)
2402 drm_device = device;
2403 else
2404 udev_device_unref(device);
2405 }
2406
2407 udev_enumerate_unref(e);
2408 return drm_device;
2409}
2410
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002411static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002412planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002413{
2414 struct drm_compositor *c = data;
2415
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002416 switch (key) {
2417 case KEY_C:
2418 c->cursors_are_broken ^= 1;
2419 break;
2420 case KEY_V:
2421 c->sprites_are_broken ^= 1;
2422 break;
2423 case KEY_O:
2424 c->sprites_hidden ^= 1;
2425 break;
2426 default:
2427 break;
2428 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002429}
2430
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002431static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002432drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002433 int connector, const char *seat, int tty, int pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002434 int *argc, char *argv[],
2435 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002436{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002437 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002438 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002439 struct wl_event_loop *loop;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002440 struct udev_seat *udev_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002441 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002442 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002443
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002444 weston_log("initializing drm backend\n");
2445
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002446 ec = malloc(sizeof *ec);
2447 if (ec == NULL)
2448 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002449 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002450
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002451 /* KMS support for sprites is not complete yet, so disable the
2452 * functionality for now. */
2453 ec->sprites_are_broken = 1;
2454
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002455 ec->use_pixman = pixman;
2456
Daniel Stone725c2c32012-06-22 14:04:36 +01002457 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002458 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002459 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002460 goto err_base;
2461 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002462
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002463 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002464 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002465 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002466 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002467 goto err_compositor;
2468 }
2469
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002470 ec->udev = udev_new();
2471 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002472 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002473 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002474 }
2475
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002476 ec->base.wl_display = display;
2477 ec->tty = tty_create(&ec->base, vt_func, tty);
2478 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002479 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002480 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002481 }
2482
David Herrmann0af066f2012-10-29 19:21:16 +01002483 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002484 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002485 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002486 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002487 }
David Herrmann0af066f2012-10-29 19:21:16 +01002488 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002489
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002490 if (init_drm(ec, drm_device) < 0) {
2491 weston_log("failed to initialize kms\n");
2492 goto err_udev_dev;
2493 }
2494
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002495 if (ec->use_pixman) {
2496 if (init_pixman(ec) < 0) {
2497 weston_log("failed to initialize pixman renderer\n");
2498 goto err_udev_dev;
2499 }
2500 } else {
2501 if (init_egl(ec) < 0) {
2502 weston_log("failed to initialize egl\n");
2503 goto err_udev_dev;
2504 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002505 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002506
2507 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002508 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002509
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002510 ec->base.focus = 1;
2511
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002512 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002513
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002514 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002515 weston_compositor_add_key_binding(&ec->base, key,
2516 MODIFIER_CTRL | MODIFIER_ALT,
2517 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002518
Jesse Barnes58ef3792012-02-23 09:45:49 -05002519 wl_list_init(&ec->sprite_list);
2520 create_sprites(ec);
2521
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002522 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002523 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002524 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002525 }
2526
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002527 path = NULL;
2528
Kristian Høgsberge8091032013-02-18 15:43:29 -05002529 if (udev_seat_create(&ec->base, ec->udev, seat) == NULL) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002530 weston_log("failed to create input devices\n");
2531 goto err_sprite;
2532 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002533
2534 loop = wl_display_get_event_loop(ec->base.wl_display);
2535 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002536 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002537 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002538
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002539 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2540 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002541 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002542 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002543 }
2544 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2545 "drm", NULL);
2546 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002547 wl_event_loop_add_fd(loop,
2548 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002549 WL_EVENT_READABLE, udev_drm_event, ec);
2550
2551 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002552 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002553 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002554 }
2555
Daniel Stonea96b93c2012-06-22 14:04:37 +01002556 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002557
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002558 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002559 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002560 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002561 planes_binding, ec);
2562 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2563 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002564
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002565 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002566
2567err_udev_monitor:
2568 wl_event_source_remove(ec->udev_drm_source);
2569 udev_monitor_unref(ec->udev_monitor);
2570err_drm_source:
2571 wl_event_source_remove(ec->drm_source);
Kristian Høgsberge8091032013-02-18 15:43:29 -05002572 wl_list_for_each_safe(udev_seat, next, &ec->base.seat_list, base.link)
2573 udev_seat_destroy(udev_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002574err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002575 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002576 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002577 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002578err_udev_dev:
2579 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002580err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002581 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2582 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002583 tty_destroy(ec->tty);
2584err_udev:
2585 udev_unref(ec->udev);
2586err_compositor:
2587 weston_compositor_shutdown(&ec->base);
2588err_base:
2589 free(ec);
2590 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002591}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002592
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002593WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002594backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002595 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002596{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002597 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002598 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002599
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002600 const struct weston_option drm_options[] = {
2601 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2602 { WESTON_OPTION_STRING, "seat", 0, &seat },
2603 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002604 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002605 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002606 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002607
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002608 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002609
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002610 return drm_compositor_create(display, connector, seat, tty, use_pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002611 argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002612}