blob: 4216937f3684b465a66493121a68d404280aed26 [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;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300148 drmModePropertyPtr dpms_prop;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200149
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300150 int vblank_pending;
151 int page_flip_pending;
152
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400153 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400154 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400155 struct weston_plane cursor_plane;
156 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400157 struct weston_surface *cursor_surface;
158 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300159 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200160 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200161
162 struct drm_fb *dumb[2];
163 pixman_image_t *image[2];
164 int current_image;
165 pixman_region32_t previous_damage;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400166};
167
Jesse Barnes58ef3792012-02-23 09:45:49 -0500168/*
169 * An output has a primary display plane plus zero or more sprites for
170 * blending display contents.
171 */
172struct drm_sprite {
173 struct wl_list link;
174
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400175 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500176
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200177 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300178 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500179 struct drm_compositor *compositor;
180
Jesse Barnes58ef3792012-02-23 09:45:49 -0500181 uint32_t possible_crtcs;
182 uint32_t plane_id;
183 uint32_t count_formats;
184
185 int32_t src_x, src_y;
186 uint32_t src_w, src_h;
187 uint32_t dest_x, dest_y;
188 uint32_t dest_w, dest_h;
189
190 uint32_t formats[];
191};
192
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500193static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400194
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400195static void
196drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400197
Jesse Barnes58ef3792012-02-23 09:45:49 -0500198static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500199drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
200{
201 struct weston_compositor *ec = output_base->compositor;
202 struct drm_compositor *c =(struct drm_compositor *) ec;
203 struct drm_output *output = (struct drm_output *) output_base;
204 int crtc;
205
206 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
207 if (c->crtcs[crtc] != output->crtc_id)
208 continue;
209
210 if (supported & (1 << crtc))
211 return -1;
212 }
213
214 return 0;
215}
216
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300217static void
218drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
219{
220 struct drm_fb *fb = data;
221 struct gbm_device *gbm = gbm_bo_get_device(bo);
222
223 if (fb->fb_id)
224 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
225
Pekka Paalanende685b82012-12-04 15:58:12 +0200226 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300227
228 free(data);
229}
230
231static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200232drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
233{
234 struct drm_fb *fb;
235 int ret;
236
237 struct drm_mode_create_dumb create_arg;
238 struct drm_mode_destroy_dumb destroy_arg;
239 struct drm_mode_map_dumb map_arg;
240
241 fb = calloc(1, sizeof *fb);
242 if (!fb)
243 return NULL;
244
245 create_arg.bpp = 32;
246 create_arg.width = width;
247 create_arg.height = height;
248
249 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
250 if (ret)
251 goto err_fb;
252
253 fb->handle = create_arg.handle;
254 fb->stride = create_arg.pitch;
255 fb->size = create_arg.size;
256 fb->fd = ec->drm.fd;
257
258 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
259 fb->stride, fb->handle, &fb->fb_id);
260 if (ret)
261 goto err_bo;
262
263 memset(&map_arg, 0, sizeof(map_arg));
264 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400265 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200266 if (ret)
267 goto err_add_fb;
268
269 fb->map = mmap(0, fb->size, PROT_WRITE,
270 MAP_SHARED, ec->drm.fd, map_arg.offset);
271 if (fb->map == MAP_FAILED)
272 goto err_add_fb;
273
274 return fb;
275
276err_add_fb:
277 drmModeRmFB(ec->drm.fd, fb->fb_id);
278err_bo:
279 memset(&destroy_arg, 0, sizeof(destroy_arg));
280 destroy_arg.handle = create_arg.handle;
281 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
282err_fb:
283 free(fb);
284 return NULL;
285}
286
287static void
288drm_fb_destroy_dumb(struct drm_fb *fb)
289{
290 struct drm_mode_destroy_dumb destroy_arg;
291
292 if (!fb->map)
293 return;
294
295 if (fb->fb_id)
296 drmModeRmFB(fb->fd, fb->fb_id);
297
298 weston_buffer_reference(&fb->buffer_ref, NULL);
299
300 munmap(fb->map, fb->size);
301
302 memset(&destroy_arg, 0, sizeof(destroy_arg));
303 destroy_arg.handle = fb->handle;
304 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
305
306 free(fb);
307}
308
309static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500310drm_fb_get_from_bo(struct gbm_bo *bo,
311 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300312{
313 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200314 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200315 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300316 int ret;
317
318 if (fb)
319 return fb;
320
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200321 fb = calloc(1, sizeof *fb);
322 if (!fb)
323 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300324
325 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300326
327 width = gbm_bo_get_width(bo);
328 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200329 fb->stride = gbm_bo_get_stride(bo);
330 fb->handle = gbm_bo_get_handle(bo).u32;
331 fb->size = fb->stride * height;
332 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300333
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200334 if (compositor->min_width > width || width > compositor->max_width ||
335 compositor->min_height > height ||
336 height > compositor->max_height) {
337 weston_log("bo geometry out of bounds\n");
338 goto err_free;
339 }
340
341 ret = -1;
342
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200343 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200344 handles[0] = fb->handle;
345 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200346 offsets[0] = 0;
347
348 ret = drmModeAddFB2(compositor->drm.fd, width, height,
349 format, handles, pitches, offsets,
350 &fb->fb_id, 0);
351 if (ret) {
352 weston_log("addfb2 failed: %m\n");
353 compositor->no_addfb2 = 1;
354 compositor->sprites_are_broken = 1;
355 }
356 }
357
358 if (ret)
359 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200360 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200361
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300362 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200363 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200364 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300365 }
366
367 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
368
369 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200370
371err_free:
372 free(fb);
373 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300374}
375
376static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200377drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
378{
Pekka Paalanende685b82012-12-04 15:58:12 +0200379 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200380
381 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200382
Pekka Paalanende685b82012-12-04 15:58:12 +0200383 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200384}
385
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200386static void
387drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
388{
389 if (!fb)
390 return;
391
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200392 if (fb->map &&
393 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200394 drm_fb_destroy_dumb(fb);
395 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200396 if (fb->is_client_buffer)
397 gbm_bo_destroy(fb->bo);
398 else
399 gbm_surface_release_buffer(output->surface,
400 output->current->bo);
401 }
402}
403
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500404static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200405drm_output_check_scanout_format(struct drm_output *output,
406 struct weston_surface *es, struct gbm_bo *bo)
407{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200408 uint32_t format;
409 pixman_region32_t r;
410
411 format = gbm_bo_get_format(bo);
412
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500413 switch (format) {
414 case GBM_FORMAT_XRGB8888:
415 return format;
416 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200417 /* We can only scanout an ARGB buffer if the surface's
418 * opaque region covers the whole output */
419 pixman_region32_init(&r);
420 pixman_region32_subtract(&r, &output->base.region,
421 &es->opaque);
422
423 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500424 format = GBM_FORMAT_XRGB8888;
425 else
426 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200427
428 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200429
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500430 return format;
431 default:
432 return 0;
433 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200434}
435
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400436static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400437drm_output_prepare_scanout_surface(struct weston_output *_output,
438 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500439{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400440 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500441 struct drm_compositor *c =
442 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200443 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300444 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500445 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500446
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500447 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200448 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200449 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200450 buffer->width != output->base.current->width ||
451 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200452 output->base.transform != es->buffer_transform ||
453 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400454 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500455
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400456 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200457 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500458
Rob Bradford9b101872012-09-14 23:25:41 +0100459 /* Unable to use the buffer for scanout */
460 if (!bo)
461 return NULL;
462
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500463 format = drm_output_check_scanout_format(output, es, bo);
464 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300465 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400466 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300467 }
468
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500469 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300470 if (!output->next) {
471 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400472 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300473 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500474
Pekka Paalanende685b82012-12-04 15:58:12 +0200475 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500476
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400477 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500478}
479
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500480static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200481drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400482{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200483 struct drm_compositor *c =
484 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300485 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400486
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200487 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400488
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300489 bo = gbm_surface_lock_front_buffer(output->surface);
490 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200491 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400492 return;
493 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300494
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500495 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300496 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200497 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300498 gbm_surface_release_buffer(output->surface, bo);
499 return;
500 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400501}
502
503static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200504drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
505{
506 struct weston_compositor *ec = output->base.compositor;
507 pixman_region32_t total_damage, previous_damage;
508
509 pixman_region32_init(&total_damage);
510 pixman_region32_init(&previous_damage);
511
512 pixman_region32_copy(&previous_damage, damage);
513
514 pixman_region32_union(&total_damage, damage, &output->previous_damage);
515 pixman_region32_copy(&output->previous_damage, &previous_damage);
516
517 output->current_image ^= 1;
518
519 output->next = output->dumb[output->current_image];
520 pixman_renderer_output_set_buffer(&output->base,
521 output->image[output->current_image]);
522
523 ec->renderer->repaint_output(&output->base, &total_damage);
524
525 pixman_region32_fini(&total_damage);
526 pixman_region32_fini(&previous_damage);
527}
528
529static void
530drm_output_render(struct drm_output *output, pixman_region32_t *damage)
531{
532 struct drm_compositor *c =
533 (struct drm_compositor *) output->base.compositor;
534
535 if (c->use_pixman)
536 drm_output_render_pixman(output, damage);
537 else
538 drm_output_render_gl(output, damage);
539
540 pixman_region32_subtract(&c->base.primary_plane.damage,
541 &c->base.primary_plane.damage, damage);
542}
543
544static void
Richard Hughese7299962013-05-01 21:52:12 +0100545drm_output_set_gamma(struct weston_output *output_base,
546 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
547{
548 int rc;
549 struct drm_output *output = (struct drm_output *) output_base;
550 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
551
552 /* check */
553 if (output_base->gamma_size != size)
554 return;
555 if (!output->original_crtc)
556 return;
557
558 rc = drmModeCrtcSetGamma(compositor->drm.fd,
559 output->crtc_id,
560 size, r, g, b);
561 if (rc)
562 weston_log("set gamma failed: %m\n");
563}
564
565static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500566drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400567 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100568{
569 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500570 struct drm_compositor *compositor =
571 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500572 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400573 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500574 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100575
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300576 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400577 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300578 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400579 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100580
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400581 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300582 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400583 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300584 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400585 &output->connector_id, 1,
586 &mode->mode_info);
587 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200588 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400589 return;
590 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300591 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200592 }
593
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500594 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300595 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500596 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200597 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500598 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500599 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100600
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300601 output->page_flip_pending = 1;
602
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400603 drm_output_set_cursor(output);
604
Jesse Barnes58ef3792012-02-23 09:45:49 -0500605 /*
606 * Now, update all the sprite surfaces
607 */
608 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200609 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500610 drmVBlank vbl = {
611 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
612 .request.sequence = 1,
613 };
614
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200615 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200616 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500617 continue;
618
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200619 if (s->next && !compositor->sprites_hidden)
620 fb_id = s->next->fb_id;
621
Jesse Barnes58ef3792012-02-23 09:45:49 -0500622 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200623 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500624 s->dest_x, s->dest_y,
625 s->dest_w, s->dest_h,
626 s->src_x, s->src_y,
627 s->src_w, s->src_h);
628 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200629 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500630 ret, strerror(errno));
631
Rob Clark5ca1a472012-08-08 20:27:37 -0500632 if (output->pipe > 0)
633 vbl.request.type |= DRM_VBLANK_SECONDARY;
634
Jesse Barnes58ef3792012-02-23 09:45:49 -0500635 /*
636 * Queue a vblank signal so we know when the surface
637 * becomes active on the display or has been replaced.
638 */
639 vbl.request.signal = (unsigned long)s;
640 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
641 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200642 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500643 ret, strerror(errno));
644 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300645
646 s->output = output;
647 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500648 }
649
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500650 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400651}
652
653static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200654drm_output_start_repaint_loop(struct weston_output *output_base)
655{
656 struct drm_output *output = (struct drm_output *) output_base;
657 struct drm_compositor *compositor = (struct drm_compositor *)
658 output_base->compositor;
659 uint32_t fb_id;
660
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300661 struct timespec ts;
662
663 if (!output->current) {
664 /* We can't page flip if there's no mode set */
665 uint32_t msec;
666
667 clock_gettime(compositor->clock, &ts);
668 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
669 weston_output_finish_frame(output_base, msec);
670 return;
671 }
672
673 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200674
675 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
676 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
677 weston_log("queueing pageflip failed: %m\n");
678 return;
679 }
680}
681
682static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500683vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
684 void *data)
685{
686 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300687 struct drm_output *output = s->output;
688 uint32_t msecs;
689
690 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500691
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200692 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200693 s->current = s->next;
694 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300695
696 if (!output->page_flip_pending) {
697 msecs = sec * 1000 + usec / 1000;
698 weston_output_finish_frame(&output->base, msecs);
699 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500700}
701
702static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400703page_flip_handler(int fd, unsigned int frame,
704 unsigned int sec, unsigned int usec, void *data)
705{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200706 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400707 uint32_t msecs;
708
Jonas Ådahle5a12252013-04-05 23:07:11 +0200709 /* We don't set page_flip_pending on start_repaint_loop, in that case
710 * we just want to page flip to the current buffer to get an accurate
711 * timestamp */
712 if (output->page_flip_pending) {
713 drm_output_release_fb(output, output->current);
714 output->current = output->next;
715 output->next = NULL;
716 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300717
Jonas Ådahle5a12252013-04-05 23:07:11 +0200718 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400719
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300720 if (!output->vblank_pending) {
721 msecs = sec * 1000 + usec / 1000;
722 weston_output_finish_frame(&output->base, msecs);
723 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200724}
725
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500726static uint32_t
727drm_output_check_sprite_format(struct drm_sprite *s,
728 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500729{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500730 uint32_t i, format;
731
732 format = gbm_bo_get_format(bo);
733
734 if (format == GBM_FORMAT_ARGB8888) {
735 pixman_region32_t r;
736
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500737 pixman_region32_init_rect(&r, 0, 0,
738 es->geometry.width,
739 es->geometry.height);
740 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500741
742 if (!pixman_region32_not_empty(&r))
743 format = GBM_FORMAT_XRGB8888;
744
745 pixman_region32_fini(&r);
746 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500747
748 for (i = 0; i < s->count_formats; i++)
749 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500750 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500751
752 return 0;
753}
754
755static int
756drm_surface_transform_supported(struct weston_surface *es)
757{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500758 return !es->transform.enabled ||
759 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500760}
761
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400762static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500763drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400764 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500765{
766 struct weston_compositor *ec = output_base->compositor;
767 struct drm_compositor *c =(struct drm_compositor *) ec;
768 struct drm_sprite *s;
769 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500770 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500771 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200772 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500773 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400774 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500775
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200776 if (c->gbm == NULL)
777 return NULL;
778
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200779 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200780 return NULL;
781
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200782 if (es->buffer_scale != output_base->scale)
783 return NULL;
784
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500785 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400786 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500787
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300788 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400789 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300790
Pekka Paalanende685b82012-12-04 15:58:12 +0200791 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400792 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500793
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200794 if (es->alpha != 1.0f)
795 return NULL;
796
Pekka Paalanende685b82012-12-04 15:58:12 +0200797 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500798 return NULL;
799
Jesse Barnes58ef3792012-02-23 09:45:49 -0500800 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400801 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500802
Jesse Barnes58ef3792012-02-23 09:45:49 -0500803 wl_list_for_each(s, &c->sprite_list, link) {
804 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
805 continue;
806
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200807 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500808 found = 1;
809 break;
810 }
811 }
812
813 /* No sprites available */
814 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400815 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500816
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400817 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200818 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400819 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400820 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400821
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500822 format = drm_output_check_sprite_format(s, es, bo);
823 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200824 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400825 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500826 }
827
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200828 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200829 if (!s->next) {
830 gbm_bo_destroy(bo);
831 return NULL;
832 }
833
Pekka Paalanende685b82012-12-04 15:58:12 +0200834 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500835
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400836 box = pixman_region32_extents(&es->transform.boundingbox);
837 s->plane.x = box->x1;
838 s->plane.y = box->y1;
839
Jesse Barnes58ef3792012-02-23 09:45:49 -0500840 /*
841 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200842 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500843 * for us already).
844 */
845 pixman_region32_init(&dest_rect);
846 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
847 &output_base->region);
848 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
849 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200850 tbox = weston_transformed_rect(output_base->width,
851 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200852 output_base->transform,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200853 output_base->scale,
854 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200855 s->dest_x = tbox.x1;
856 s->dest_y = tbox.y1;
857 s->dest_w = tbox.x2 - tbox.x1;
858 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500859 pixman_region32_fini(&dest_rect);
860
861 pixman_region32_init(&src_rect);
862 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
863 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500864 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400865
866 weston_surface_from_global_fixed(es,
867 wl_fixed_from_int(box->x1),
868 wl_fixed_from_int(box->y1),
869 &sx1, &sy1);
870 weston_surface_from_global_fixed(es,
871 wl_fixed_from_int(box->x2),
872 wl_fixed_from_int(box->y2),
873 &sx2, &sy2);
874
875 if (sx1 < 0)
876 sx1 = 0;
877 if (sy1 < 0)
878 sy1 = 0;
879 if (sx2 > wl_fixed_from_int(es->geometry.width))
880 sx2 = wl_fixed_from_int(es->geometry.width);
881 if (sy2 > wl_fixed_from_int(es->geometry.height))
882 sy2 = wl_fixed_from_int(es->geometry.height);
883
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200884 tbox.x1 = sx1;
885 tbox.y1 = sy1;
886 tbox.x2 = sx2;
887 tbox.y2 = sy2;
888
889 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
890 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200891 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200892
893 s->src_x = tbox.x1 << 8;
894 s->src_y = tbox.y1 << 8;
895 s->src_w = (tbox.x2 - tbox.x1) << 8;
896 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500897 pixman_region32_fini(&src_rect);
898
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400899 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500900}
901
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400902static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400903drm_output_prepare_cursor_surface(struct weston_output *output_base,
904 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500905{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400906 struct drm_compositor *c =
907 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400908 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400909
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200910 if (c->gbm == NULL)
911 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200912 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
913 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400914 if (output->cursor_surface)
915 return NULL;
916 if (es->output_mask != (1u << output_base->id))
917 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500918 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400919 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200920 if (es->buffer_ref.buffer == NULL ||
921 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400922 es->geometry.width > 64 || es->geometry.height > 64)
923 return NULL;
924
925 output->cursor_surface = es;
926
927 return &output->cursor_plane;
928}
929
930static void
931drm_output_set_cursor(struct drm_output *output)
932{
933 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400934 struct drm_compositor *c =
935 (struct drm_compositor *) output->base.compositor;
936 EGLint handle, stride;
937 struct gbm_bo *bo;
938 uint32_t buf[64 * 64];
939 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400940 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500941
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400942 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400943 if (es == NULL) {
944 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
945 return;
946 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500947
Pekka Paalanende685b82012-12-04 15:58:12 +0200948 if (es->buffer_ref.buffer &&
949 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400950 pixman_region32_fini(&output->cursor_plane.damage);
951 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400952 output->current_cursor ^= 1;
953 bo = output->cursor_bo[output->current_cursor];
954 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200955 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
956 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400957 for (i = 0; i < es->geometry.height; i++)
958 memcpy(buf + i * 64, s + i * stride,
959 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500960
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400961 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300962 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400963
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400964 handle = gbm_bo_get_handle(bo).s32;
965 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500966 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300967 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500968 c->cursors_are_broken = 1;
969 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400970 }
971
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200972 x = (es->geometry.x - output->base.x) * output->base.scale;
973 y = (es->geometry.y - output->base.y) * output->base.scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400974 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500975 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400976 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500977 c->cursors_are_broken = 1;
978 }
979
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400980 output->cursor_plane.x = x;
981 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400982 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500983}
984
Jesse Barnes58ef3792012-02-23 09:45:49 -0500985static void
986drm_assign_planes(struct weston_output *output)
987{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400988 struct drm_compositor *c =
989 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400990 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500991 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400992 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500993
994 /*
995 * Find a surface for each sprite in the output using some heuristics:
996 * 1) size
997 * 2) frequency of update
998 * 3) opacity (though some hw might support alpha blending)
999 * 4) clipping (this can be fixed with color keys)
1000 *
1001 * The idea is to save on blitting since this should save power.
1002 * If we can get a large video surface on the sprite for example,
1003 * the main display surface may not need to update at all, and
1004 * the client buffer can be used directly for the sprite surface
1005 * as we do for flipping full screen surfaces.
1006 */
1007 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001008 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001009 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001010 /* test whether this buffer can ever go into a plane:
1011 * non-shm, or small enough to be a cursor
1012 */
1013 if ((es->buffer_ref.buffer &&
1014 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
1015 (es->geometry.width <= 64 && es->geometry.height <= 64))
1016 es->keep_buffer = 1;
1017 else
1018 es->keep_buffer = 0;
1019
Jesse Barnes58ef3792012-02-23 09:45:49 -05001020 pixman_region32_init(&surface_overlap);
1021 pixman_region32_intersect(&surface_overlap, &overlap,
1022 &es->transform.boundingbox);
1023
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001024 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001025 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001026 next_plane = primary;
1027 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001028 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001029 if (next_plane == NULL)
1030 next_plane = drm_output_prepare_scanout_surface(output, es);
1031 if (next_plane == NULL)
1032 next_plane = drm_output_prepare_overlay_surface(output, es);
1033 if (next_plane == NULL)
1034 next_plane = primary;
1035 weston_surface_move_to_plane(es, next_plane);
1036 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001037 pixman_region32_union(&overlap, &overlap,
1038 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001039
Jesse Barnes58ef3792012-02-23 09:45:49 -05001040 pixman_region32_fini(&surface_overlap);
1041 }
1042 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001043}
1044
Matt Roper361d2ad2011-08-29 13:52:23 -07001045static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001046drm_output_fini_pixman(struct drm_output *output);
1047
1048static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001049drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001050{
1051 struct drm_output *output = (struct drm_output *) output_base;
1052 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001053 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001054 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001055
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001056 if (output->backlight)
1057 backlight_destroy(output->backlight);
1058
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001059 drmModeFreeProperty(output->dpms_prop);
1060
Matt Roper361d2ad2011-08-29 13:52:23 -07001061 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001062 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001063
1064 /* Restore original CRTC state */
1065 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001066 origcrtc->x, origcrtc->y,
1067 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001068 drmModeFreeCrtc(origcrtc);
1069
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001070 c->crtc_allocator &= ~(1 << output->crtc_id);
1071 c->connector_allocator &= ~(1 << output->connector_id);
1072
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001073 if (c->use_pixman) {
1074 drm_output_fini_pixman(output);
1075 } else {
1076 gl_renderer_output_destroy(output_base);
1077 gbm_surface_destroy(output->surface);
1078 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001079
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001080 weston_plane_release(&output->fb_plane);
1081 weston_plane_release(&output->cursor_plane);
1082
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001083 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001084 wl_list_remove(&output->base.link);
1085
Matt Roper361d2ad2011-08-29 13:52:23 -07001086 free(output);
1087}
1088
Alex Wub7b8bda2012-04-17 17:20:48 +08001089static struct drm_mode *
1090choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1091{
1092 struct drm_mode *tmp_mode = NULL, *mode;
1093
1094 if (output->base.current->width == target_mode->width &&
1095 output->base.current->height == target_mode->height &&
1096 (output->base.current->refresh == target_mode->refresh ||
1097 target_mode->refresh == 0))
1098 return (struct drm_mode *)output->base.current;
1099
1100 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1101 if (mode->mode_info.hdisplay == target_mode->width &&
1102 mode->mode_info.vdisplay == target_mode->height) {
1103 if (mode->mode_info.vrefresh == target_mode->refresh ||
1104 target_mode->refresh == 0) {
1105 return mode;
1106 } else if (!tmp_mode)
1107 tmp_mode = mode;
1108 }
1109 }
1110
1111 return tmp_mode;
1112}
1113
1114static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001115drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001116static int
1117drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001118
1119static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001120drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1121{
1122 struct drm_output *output;
1123 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001124 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001125
1126 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001127 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001128 return -1;
1129 }
1130
1131 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001132 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001133 return -1;
1134 }
1135
1136 ec = (struct drm_compositor *)output_base->compositor;
1137 output = (struct drm_output *)output_base;
1138 drm_mode = choose_mode (output, mode);
1139
1140 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001141 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001142 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001143 }
1144
1145 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001146 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001147
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001148 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001149
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001150 output->base.current = &drm_mode->base;
1151 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001152 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1153
Alex Wub7b8bda2012-04-17 17:20:48 +08001154 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001155 drm_output_release_fb(output, output->current);
1156 drm_output_release_fb(output, output->next);
1157 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001158
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001159 if (ec->use_pixman) {
1160 drm_output_fini_pixman(output);
1161 if (drm_output_init_pixman(output, ec) < 0) {
1162 weston_log("failed to init output pixman state with "
1163 "new mode\n");
1164 return -1;
1165 }
1166 } else {
1167 gl_renderer_output_destroy(&output->base);
1168 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001169
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001170 if (drm_output_init_egl(output, ec) < 0) {
1171 weston_log("failed to init output egl state with "
1172 "new mode");
1173 return -1;
1174 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001175 }
1176
Alex Wub7b8bda2012-04-17 17:20:48 +08001177 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001178}
1179
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001180static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001181on_drm_input(int fd, uint32_t mask, void *data)
1182{
1183 drmEventContext evctx;
1184
1185 memset(&evctx, 0, sizeof evctx);
1186 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1187 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001188 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001189 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001190
1191 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001192}
1193
1194static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001195init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001196{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001197 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001198 uint64_t cap;
1199 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001200
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001201 sysnum = udev_device_get_sysnum(device);
1202 if (sysnum)
1203 ec->drm.id = atoi(sysnum);
1204 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001205 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001206 return -1;
1207 }
1208
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001209 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001210 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001211 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001212 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001213 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001214 udev_device_get_devnode(device));
1215 return -1;
1216 }
1217
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001218 weston_log("using %s\n", filename);
1219
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001220 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001221
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001222 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1223 if (ret == 0 && cap == 1)
1224 ec->clock = CLOCK_MONOTONIC;
1225 else
1226 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001227
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001228 return 0;
1229}
1230
1231static int
1232init_egl(struct drm_compositor *ec)
1233{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001234 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001235
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001236 if (!ec->gbm)
1237 return -1;
1238
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001239 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001240 NULL) < 0) {
1241 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001242 return -1;
1243 }
1244
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001245 return 0;
1246}
1247
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001248static int
1249init_pixman(struct drm_compositor *ec)
1250{
1251 return pixman_renderer_init(&ec->base);
1252}
1253
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001254static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001255drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001256{
1257 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001258 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001259
1260 mode = malloc(sizeof *mode);
1261 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001262 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001263
1264 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001265 mode->base.width = info->hdisplay;
1266 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001267
1268 /* Calculate higher precision (mHz) refresh rate */
1269 refresh = (info->clock * 1000000LL / info->htotal +
1270 info->vtotal / 2) / info->vtotal;
1271
1272 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1273 refresh *= 2;
1274 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1275 refresh /= 2;
1276 if (info->vscan > 1)
1277 refresh /= info->vscan;
1278
1279 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001280 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001281
1282 if (info->type & DRM_MODE_TYPE_PREFERRED)
1283 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1284
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001285 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1286
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001287 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001288}
1289
1290static int
1291drm_subpixel_to_wayland(int drm_value)
1292{
1293 switch (drm_value) {
1294 default:
1295 case DRM_MODE_SUBPIXEL_UNKNOWN:
1296 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1297 case DRM_MODE_SUBPIXEL_NONE:
1298 return WL_OUTPUT_SUBPIXEL_NONE;
1299 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1300 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1301 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1302 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1303 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1304 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1305 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1306 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1307 }
1308}
1309
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001310/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001311static uint32_t
1312drm_get_backlight(struct drm_output *output)
1313{
1314 long brightness, max_brightness, norm;
1315
1316 brightness = backlight_get_brightness(output->backlight);
1317 max_brightness = backlight_get_max_brightness(output->backlight);
1318
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001319 /* convert it on a scale of 0 to 255 */
1320 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001321
1322 return (uint32_t) norm;
1323}
1324
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001325/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001326static void
1327drm_set_backlight(struct weston_output *output_base, uint32_t value)
1328{
1329 struct drm_output *output = (struct drm_output *) output_base;
1330 long max_brightness, new_brightness;
1331
1332 if (!output->backlight)
1333 return;
1334
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001335 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001336 return;
1337
1338 max_brightness = backlight_get_max_brightness(output->backlight);
1339
1340 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001341 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001342
1343 backlight_set_brightness(output->backlight, new_brightness);
1344}
1345
1346static drmModePropertyPtr
1347drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1348{
1349 drmModePropertyPtr props;
1350 int i;
1351
1352 for (i = 0; i < connector->count_props; i++) {
1353 props = drmModeGetProperty(fd, connector->props[i]);
1354 if (!props)
1355 continue;
1356
1357 if (!strcmp(props->name, name))
1358 return props;
1359
1360 drmModeFreeProperty(props);
1361 }
1362
1363 return NULL;
1364}
1365
1366static void
1367drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1368{
1369 struct drm_output *output = (struct drm_output *) output_base;
1370 struct weston_compositor *ec = output_base->compositor;
1371 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001372
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001373 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001374 return;
1375
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001376 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1377 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001378}
1379
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001380static const char *connector_type_names[] = {
1381 "None",
1382 "VGA",
1383 "DVI",
1384 "DVI",
1385 "DVI",
1386 "Composite",
1387 "TV",
1388 "LVDS",
1389 "CTV",
1390 "DIN",
1391 "DP",
1392 "HDMI",
1393 "HDMI",
1394 "TV",
1395 "eDP",
1396};
1397
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001398static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001399find_crtc_for_connector(struct drm_compositor *ec,
1400 drmModeRes *resources, drmModeConnector *connector)
1401{
1402 drmModeEncoder *encoder;
1403 uint32_t possible_crtcs;
1404 int i, j;
1405
1406 for (j = 0; j < connector->count_encoders; j++) {
1407 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1408 if (encoder == NULL) {
1409 weston_log("Failed to get encoder.\n");
1410 return -1;
1411 }
1412 possible_crtcs = encoder->possible_crtcs;
1413 drmModeFreeEncoder(encoder);
1414
1415 for (i = 0; i < resources->count_crtcs; i++) {
1416 if (possible_crtcs & (1 << i) &&
1417 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1418 return i;
1419 }
1420 }
1421
1422 return -1;
1423}
1424
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001425/* Init output state that depends on gl or gbm */
1426static int
1427drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1428{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001429 int i, flags;
1430
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001431 output->surface = gbm_surface_create(ec->gbm,
Alexander Larsson0b135062013-05-28 16:23:36 +02001432 output->base.current->width,
1433 output->base.current->height,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001434 GBM_FORMAT_XRGB8888,
1435 GBM_BO_USE_SCANOUT |
1436 GBM_BO_USE_RENDERING);
1437 if (!output->surface) {
1438 weston_log("failed to create gbm surface\n");
1439 return -1;
1440 }
1441
1442 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001443 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001444 gbm_surface_destroy(output->surface);
1445 return -1;
1446 }
1447
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001448 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1449
1450 for (i = 0; i < 2; i++) {
1451 if (output->cursor_bo[i])
1452 continue;
1453
1454 output->cursor_bo[i] =
1455 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1456 flags);
1457 }
1458
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001459 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1460 weston_log("cursor buffers unavailable, using gl cursors\n");
1461 ec->cursors_are_broken = 1;
1462 }
1463
1464 return 0;
1465}
1466
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001467static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001468drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1469{
1470 int w = output->base.current->width;
1471 int h = output->base.current->height;
1472 unsigned int i;
1473
1474 /* FIXME error checking */
1475
1476 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001477 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001478 if (!output->dumb[i])
1479 goto err;
1480
1481 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001482 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001483 output->dumb[i]->map,
1484 output->dumb[i]->stride);
1485 if (!output->image[i])
1486 goto err;
1487 }
1488
1489 if (pixman_renderer_output_create(&output->base) < 0)
1490 goto err;
1491
1492 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001493 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001494
1495 return 0;
1496
1497err:
1498 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1499 if (output->dumb[i])
1500 drm_fb_destroy_dumb(output->dumb[i]);
1501 if (output->image[i])
1502 pixman_image_unref(output->image[i]);
1503
1504 output->dumb[i] = NULL;
1505 output->image[i] = NULL;
1506 }
1507
1508 return -1;
1509}
1510
1511static void
1512drm_output_fini_pixman(struct drm_output *output)
1513{
1514 unsigned int i;
1515
1516 pixman_renderer_output_destroy(&output->base);
1517 pixman_region32_fini(&output->previous_damage);
1518
1519 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1520 drm_fb_destroy_dumb(output->dumb[i]);
1521 pixman_image_unref(output->image[i]);
1522 output->dumb[i] = NULL;
1523 output->image[i] = NULL;
1524 }
1525}
1526
Richard Hughes2b2092a2013-04-24 14:58:02 +01001527static void
1528edid_parse_string(const uint8_t *data, char text[])
1529{
1530 int i;
1531 int replaced = 0;
1532
1533 /* this is always 12 bytes, but we can't guarantee it's null
1534 * terminated or not junk. */
1535 strncpy(text, (const char *) data, 12);
1536
1537 /* remove insane chars */
1538 for (i = 0; text[i] != '\0'; i++) {
1539 if (text[i] == '\n' ||
1540 text[i] == '\r') {
1541 text[i] = '\0';
1542 break;
1543 }
1544 }
1545
1546 /* ensure string is printable */
1547 for (i = 0; text[i] != '\0'; i++) {
1548 if (!isprint(text[i])) {
1549 text[i] = '-';
1550 replaced++;
1551 }
1552 }
1553
1554 /* if the string is random junk, ignore the string */
1555 if (replaced > 4)
1556 text[0] = '\0';
1557}
1558
1559#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1560#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1561#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1562#define EDID_OFFSET_DATA_BLOCKS 0x36
1563#define EDID_OFFSET_LAST_BLOCK 0x6c
1564#define EDID_OFFSET_PNPID 0x08
1565#define EDID_OFFSET_SERIAL 0x0c
1566
1567static int
1568edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1569{
1570 int i;
1571 uint32_t serial_number;
1572
1573 /* check header */
1574 if (length < 128)
1575 return -1;
1576 if (data[0] != 0x00 || data[1] != 0xff)
1577 return -1;
1578
1579 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1580 * /--08--\/--09--\
1581 * 7654321076543210
1582 * |\---/\---/\---/
1583 * R C1 C2 C3 */
1584 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1585 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1586 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1587 edid->pnp_id[3] = '\0';
1588
1589 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1590 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1591 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1592 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1593 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1594 if (serial_number > 0)
1595 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1596
1597 /* parse EDID data */
1598 for (i = EDID_OFFSET_DATA_BLOCKS;
1599 i <= EDID_OFFSET_LAST_BLOCK;
1600 i += 18) {
1601 /* ignore pixel clock data */
1602 if (data[i] != 0)
1603 continue;
1604 if (data[i+2] != 0)
1605 continue;
1606
1607 /* any useful blocks? */
1608 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1609 edid_parse_string(&data[i+5],
1610 edid->monitor_name);
1611 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1612 edid_parse_string(&data[i+5],
1613 edid->serial_number);
1614 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1615 edid_parse_string(&data[i+5],
1616 edid->eisa_id);
1617 }
1618 }
1619 return 0;
1620}
1621
1622static void
1623find_and_parse_output_edid(struct drm_compositor *ec,
1624 struct drm_output *output,
1625 drmModeConnector *connector)
1626{
1627 drmModePropertyBlobPtr edid_blob = NULL;
1628 drmModePropertyPtr property;
1629 int i;
1630 int rc;
1631
1632 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1633 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1634 if (!property)
1635 continue;
1636 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1637 !strcmp(property->name, "EDID")) {
1638 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1639 connector->prop_values[i]);
1640 }
1641 drmModeFreeProperty(property);
1642 }
1643 if (!edid_blob)
1644 return;
1645
1646 rc = edid_parse(&output->edid,
1647 edid_blob->data,
1648 edid_blob->length);
1649 if (!rc) {
1650 weston_log("EDID data '%s', '%s', '%s'\n",
1651 output->edid.pnp_id,
1652 output->edid.monitor_name,
1653 output->edid.serial_number);
1654 if (output->edid.pnp_id[0] != '\0')
1655 output->base.make = output->edid.pnp_id;
1656 if (output->edid.monitor_name[0] != '\0')
1657 output->base.model = output->edid.monitor_name;
1658 if (output->edid.serial_number[0] != '\0')
1659 output->base.serial_number = output->edid.serial_number;
1660 }
1661 drmModeFreePropertyBlob(edid_blob);
1662}
1663
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001664
1665
1666static int
1667parse_modeline(const char *s, drmModeModeInfo *mode)
1668{
1669 char hsync[16];
1670 char vsync[16];
1671 float fclock;
1672
1673 mode->type = DRM_MODE_TYPE_USERDEF;
1674 mode->hskew = 0;
1675 mode->vscan = 0;
1676 mode->vrefresh = 0;
1677 mode->flags = 0;
1678
1679 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
1680 &fclock,
1681 &mode->hdisplay,
1682 &mode->hsync_start,
1683 &mode->hsync_end,
1684 &mode->htotal,
1685 &mode->vdisplay,
1686 &mode->vsync_start,
1687 &mode->vsync_end,
1688 &mode->vtotal, hsync, vsync) != 11)
1689 return -1;
1690
1691 mode->clock = fclock * 1000;
1692 if (strcmp(hsync, "+hsync") == 0)
1693 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1694 else if (strcmp(hsync, "-hsync") == 0)
1695 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1696 else
1697 return -1;
1698
1699 if (strcmp(vsync, "+vsync") == 0)
1700 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1701 else if (strcmp(vsync, "-vsync") == 0)
1702 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1703 else
1704 return -1;
1705
1706 return 0;
1707}
1708
1709static uint32_t
1710parse_transform(const char *transform, const char *output_name)
1711{
1712 static const struct { const char *name; uint32_t token; } names[] = {
1713 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1714 { "90", WL_OUTPUT_TRANSFORM_90 },
1715 { "180", WL_OUTPUT_TRANSFORM_180 },
1716 { "270", WL_OUTPUT_TRANSFORM_270 },
1717 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1718 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1719 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1720 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1721 };
1722 unsigned int i;
1723
1724 for (i = 0; i < ARRAY_LENGTH(names); i++)
1725 if (strcmp(names[i].name, transform) == 0)
1726 return names[i].token;
1727
1728 weston_log("Invalid transform \"%s\" for output %s\n",
1729 transform, output_name);
1730
1731 return WL_OUTPUT_TRANSFORM_NORMAL;
1732}
1733
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001734static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001735create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001736 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001737 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001738 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001739{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001740 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001741 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1742 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001743 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001744 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001745 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001746 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001747 int i, width, height, scale;
1748 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001749 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001750 enum output_config config;
1751 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001752
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001753 i = find_crtc_for_connector(ec, resources, connector);
1754 if (i < 0) {
1755 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001756 return -1;
1757 }
1758
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001759 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001760 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001761 return -1;
1762
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001763 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001764 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1765 output->base.make = "unknown";
1766 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001767 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001768 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001769
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001770 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1771 type_name = connector_type_names[connector->connector_type];
1772 else
1773 type_name = "UNKNOWN";
1774 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001775 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001776
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001777 section = weston_config_get_section(ec->base.config, "output", "name",
1778 output->base.name);
1779 weston_config_section_get_string(section, "mode", &s, "preferred");
1780 if (strcmp(s, "off") == 0)
1781 config = OUTPUT_CONFIG_OFF;
1782 else if (strcmp(s, "preferred") == 0)
1783 config = OUTPUT_CONFIG_PREFERRED;
1784 else if (strcmp(s, "current") == 0)
1785 config = OUTPUT_CONFIG_CURRENT;
1786 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1787 config = OUTPUT_CONFIG_MODE;
1788 else if (parse_modeline(s, &modeline) == 0)
1789 config = OUTPUT_CONFIG_MODELINE;
1790 else {
1791 weston_log("Invalid mode \"%s\" for output %s\n",
1792 s, output->base.name);
1793 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001794 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001795 free(s);
1796
1797 weston_config_section_get_int(section, "scale", &scale, 1);
1798 weston_config_section_get_string(section, "transform", &s, "normal");
1799 transform = parse_transform(s, output->base.name);
1800 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001801
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001802 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001803 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001804 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001805 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001806 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001807
Matt Roper361d2ad2011-08-29 13:52:23 -07001808 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001809 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001810
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001811 /* Get the current mode on the crtc that's currently driving
1812 * this connector. */
1813 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001814 memset(&crtc_mode, 0, sizeof crtc_mode);
1815 if (encoder != NULL) {
1816 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1817 drmModeFreeEncoder(encoder);
1818 if (crtc == NULL)
1819 goto err_free;
1820 if (crtc->mode_valid)
1821 crtc_mode = crtc->mode;
1822 drmModeFreeCrtc(crtc);
1823 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001824
David Herrmann0f0d54e2011-12-08 17:05:45 +01001825 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001826 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001827 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001828 goto err_free;
1829 }
1830
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001831 if (config == OUTPUT_CONFIG_OFF) {
1832 weston_log("Disabling output %s\n", output->base.name);
1833 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1834 0, 0, 0, 0, 0, NULL);
1835 goto err_free;
1836 }
1837
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001838 preferred = NULL;
1839 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001840 configured = NULL;
1841
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001842 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001843 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001844 width == drm_mode->base.width &&
1845 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001846 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001847 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001848 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001849 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001850 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001851 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001852
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001853 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001854 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001855 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001856 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001857 }
1858
Wang Quanxianacb805a2012-07-30 18:09:46 -04001859 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001860 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001861 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001862 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001863 }
1864
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001865 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001866 configured = current;
1867
Wang Quanxianacb805a2012-07-30 18:09:46 -04001868 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001869 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001870 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001871 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001872 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001873 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001874 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001875 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001876
1877 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001878 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001879 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001880 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001881
Wang Quanxianacb805a2012-07-30 18:09:46 -04001882 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1883
John Kåre Alsaker94659272012-11-13 19:10:18 +01001884 weston_output_init(&output->base, &ec->base, x, y,
1885 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001886 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001887
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001888 if (ec->use_pixman) {
1889 if (drm_output_init_pixman(output, ec) < 0) {
1890 weston_log("Failed to init output pixman state\n");
1891 goto err_output;
1892 }
1893 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001894 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001895 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001896 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001897
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001898 output->backlight = backlight_init(drm_device,
1899 connector->connector_type);
1900 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001901 weston_log("Initialized backlight, device %s\n",
1902 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001903 output->base.set_backlight = drm_set_backlight;
1904 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001905 } else {
1906 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001907 }
1908
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001909 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1910
Richard Hughes2b2092a2013-04-24 14:58:02 +01001911 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001912 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1913 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001914
Alex Wubd3354b2012-04-17 17:20:49 +08001915 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001916 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001917 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001918 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001919 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001920 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001921 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001922
Richard Hughese7299962013-05-01 21:52:12 +01001923 output->base.gamma_size = output->original_crtc->gamma_size;
1924 output->base.set_gamma = drm_output_set_gamma;
1925
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001926 weston_plane_init(&output->cursor_plane, 0, 0);
1927 weston_plane_init(&output->fb_plane, 0, 0);
1928
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001929 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1930 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1931 &ec->base.primary_plane);
1932
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001933 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001934 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001935 wl_list_for_each(m, &output->base.mode_list, link)
1936 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1937 m->width, m->height, m->refresh / 1000.0,
1938 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1939 ", preferred" : "",
1940 m->flags & WL_OUTPUT_MODE_CURRENT ?
1941 ", current" : "",
1942 connector->count_modes == 0 ?
1943 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001944
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001945 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001946
John Kåre Alsaker94659272012-11-13 19:10:18 +01001947err_output:
1948 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001949err_free:
1950 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1951 base.link) {
1952 wl_list_remove(&drm_mode->base.link);
1953 free(drm_mode);
1954 }
1955
1956 drmModeFreeCrtc(output->original_crtc);
1957 ec->crtc_allocator &= ~(1 << output->crtc_id);
1958 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001959 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001960
David Herrmann0f0d54e2011-12-08 17:05:45 +01001961 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001962}
1963
Jesse Barnes58ef3792012-02-23 09:45:49 -05001964static void
1965create_sprites(struct drm_compositor *ec)
1966{
1967 struct drm_sprite *sprite;
1968 drmModePlaneRes *plane_res;
1969 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001970 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001971
1972 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1973 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001974 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001975 strerror(errno));
1976 return;
1977 }
1978
1979 for (i = 0; i < plane_res->count_planes; i++) {
1980 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1981 if (!plane)
1982 continue;
1983
1984 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1985 plane->count_formats));
1986 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001987 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001988 __func__);
1989 free(plane);
1990 continue;
1991 }
1992
1993 memset(sprite, 0, sizeof *sprite);
1994
1995 sprite->possible_crtcs = plane->possible_crtcs;
1996 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001997 sprite->current = NULL;
1998 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001999 sprite->compositor = ec;
2000 sprite->count_formats = plane->count_formats;
2001 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002002 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002003 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002004 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002005 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2006 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002007
2008 wl_list_insert(&ec->sprite_list, &sprite->link);
2009 }
2010
2011 free(plane_res->planes);
2012 free(plane_res);
2013}
2014
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002015static void
2016destroy_sprites(struct drm_compositor *compositor)
2017{
2018 struct drm_sprite *sprite, *next;
2019 struct drm_output *output;
2020
2021 output = container_of(compositor->base.output_list.next,
2022 struct drm_output, base.link);
2023
2024 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2025 drmModeSetPlane(compositor->drm.fd,
2026 sprite->plane_id,
2027 output->crtc_id, 0, 0,
2028 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002029 drm_output_release_fb(output, sprite->current);
2030 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002031 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002032 free(sprite);
2033 }
2034}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002035
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002036static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002037create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002038 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002039{
2040 drmModeConnector *connector;
2041 drmModeRes *resources;
2042 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002043 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002044
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002045 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002046 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002047 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002048 return -1;
2049 }
2050
Jesse Barnes58ef3792012-02-23 09:45:49 -05002051 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002052 if (!ec->crtcs) {
2053 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002054 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002055 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002056
Rob Clark4339add2012-08-09 14:18:28 -05002057 ec->min_width = resources->min_width;
2058 ec->max_width = resources->max_width;
2059 ec->min_height = resources->min_height;
2060 ec->max_height = resources->max_height;
2061
Jesse Barnes58ef3792012-02-23 09:45:49 -05002062 ec->num_crtcs = resources->count_crtcs;
2063 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2064
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002065 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002066 connector = drmModeGetConnector(ec->drm.fd,
2067 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002068 if (connector == NULL)
2069 continue;
2070
2071 if (connector->connection == DRM_MODE_CONNECTED &&
2072 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002073 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002074 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002075 connector, x, y,
2076 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002077 drmModeFreeConnector(connector);
2078 continue;
2079 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002080
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002081 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002082 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002083 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002084 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002085
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002086 drmModeFreeConnector(connector);
2087 }
2088
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002089 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002090 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002091 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002092 return -1;
2093 }
2094
2095 drmModeFreeResources(resources);
2096
2097 return 0;
2098}
2099
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002100static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002101update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002102{
2103 drmModeConnector *connector;
2104 drmModeRes *resources;
2105 struct drm_output *output, *next;
2106 int x = 0, y = 0;
2107 int x_offset = 0, y_offset = 0;
2108 uint32_t connected = 0, disconnects = 0;
2109 int i;
2110
2111 resources = drmModeGetResources(ec->drm.fd);
2112 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002113 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002114 return;
2115 }
2116
2117 /* collect new connects */
2118 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002119 int connector_id = resources->connectors[i];
2120
2121 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002122 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002123 continue;
2124
David Herrmann7551cff2011-12-08 17:05:43 +01002125 if (connector->connection != DRM_MODE_CONNECTED) {
2126 drmModeFreeConnector(connector);
2127 continue;
2128 }
2129
Benjamin Franzke117483d2011-08-30 11:38:26 +02002130 connected |= (1 << connector_id);
2131
2132 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002133 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002134 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002135 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002136
2137 /* XXX: not yet needed, we die with 0 outputs */
2138 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002139 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002140 else
2141 x = 0;
2142 y = 0;
2143 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002144 connector, x, y,
2145 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002146 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002147
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002148 }
2149 drmModeFreeConnector(connector);
2150 }
2151 drmModeFreeResources(resources);
2152
2153 disconnects = ec->connector_allocator & ~connected;
2154 if (disconnects) {
2155 wl_list_for_each_safe(output, next, &ec->base.output_list,
2156 base.link) {
2157 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002158 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002159 output->base.x - x_offset,
2160 output->base.y - y_offset);
2161 }
2162
2163 if (disconnects & (1 << output->connector_id)) {
2164 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002165 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002166 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002167 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002168 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002169 }
2170 }
2171 }
2172
2173 /* FIXME: handle zero outputs, without terminating */
2174 if (ec->connector_allocator == 0)
2175 wl_display_terminate(ec->base.wl_display);
2176}
2177
2178static int
David Herrmannd7488c22012-03-11 20:05:21 +01002179udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002180{
David Herrmannd7488c22012-03-11 20:05:21 +01002181 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002182 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002183
2184 sysnum = udev_device_get_sysnum(device);
2185 if (!sysnum || atoi(sysnum) != ec->drm.id)
2186 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002187
David Herrmann6ac52db2012-03-11 20:05:22 +01002188 val = udev_device_get_property_value(device, "HOTPLUG");
2189 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002190 return 0;
2191
David Herrmann6ac52db2012-03-11 20:05:22 +01002192 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002193}
2194
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002195static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002196udev_drm_event(int fd, uint32_t mask, void *data)
2197{
2198 struct drm_compositor *ec = data;
2199 struct udev_device *event;
2200
2201 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002202
David Herrmannd7488c22012-03-11 20:05:21 +01002203 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002204 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002205
2206 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002207
2208 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002209}
2210
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002211static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002212drm_restore(struct weston_compositor *ec)
2213{
2214 struct drm_compositor *d = (struct drm_compositor *) ec;
2215
2216 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2217 weston_log("failed to drop master: %m\n");
2218 tty_reset(d->tty);
2219}
2220
2221static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002222drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002223{
2224 struct drm_compositor *d = (struct drm_compositor *) ec;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002225 struct udev_seat *seat, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002226
Kristian Høgsberge8091032013-02-18 15:43:29 -05002227 wl_list_for_each_safe(seat, next, &ec->seat_list, base.link)
2228 udev_seat_destroy(seat);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002229
2230 wl_event_source_remove(d->udev_drm_source);
2231 wl_event_source_remove(d->drm_source);
2232
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002233 destroy_sprites(d);
2234
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002235 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002236
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002237 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002238
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002239 if (d->gbm)
2240 gbm_device_destroy(d->gbm);
2241
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002242 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002243 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002244 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002245
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002246 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002247}
2248
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002249static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002250drm_compositor_set_modes(struct drm_compositor *compositor)
2251{
2252 struct drm_output *output;
2253 struct drm_mode *drm_mode;
2254 int ret;
2255
2256 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002257 if (!output->current) {
2258 /* If something that would cause the output to
2259 * switch mode happened while in another vt, we
2260 * might not have a current drm_fb. In that case,
2261 * schedule a repaint and let drm_output_repaint
2262 * handle setting the mode. */
2263 weston_output_schedule_repaint(&output->base);
2264 continue;
2265 }
2266
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002267 drm_mode = (struct drm_mode *) output->base.current;
2268 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002269 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002270 &output->connector_id, 1,
2271 &drm_mode->mode_info);
2272 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002273 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002274 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002275 drm_mode->base.width, drm_mode->base.height,
2276 output->base.x, output->base.y);
2277 }
2278 }
2279}
2280
2281static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002282vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002283{
2284 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002285 struct udev_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002286 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002287 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002288
2289 switch (event) {
2290 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002291 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002292 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002293 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002294 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002295 wl_display_terminate(compositor->wl_display);
2296 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002297 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002298 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002299 weston_compositor_damage_all(compositor);
Kristian Høgsberg87644662013-02-18 16:50:19 -05002300 wl_list_for_each(seat, &compositor->seat_list, base.link)
2301 udev_seat_enable(seat, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002302 break;
2303 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002304 weston_log("leaving VT\n");
Kristian Høgsberg87644662013-02-18 16:50:19 -05002305 wl_list_for_each(seat, &compositor->seat_list, base.link)
2306 udev_seat_disable(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002307
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002308 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002309 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002310 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002311
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002312 /* If we have a repaint scheduled (either from a
2313 * pending pageflip or the idle handler), make sure we
2314 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002315 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002316 * further attemps at repainting. When we switch
2317 * back, we schedule a repaint, which will process
2318 * pending frame callbacks. */
2319
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002320 wl_list_for_each(output, &ec->base.output_list, base.link) {
2321 output->base.repaint_needed = 0;
2322 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002323 }
2324
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002325 output = container_of(ec->base.output_list.next,
2326 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002327
2328 wl_list_for_each(sprite, &ec->sprite_list, link)
2329 drmModeSetPlane(ec->drm.fd,
2330 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002331 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002332 0, 0, 0, 0, 0, 0, 0, 0);
2333
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002334 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002335 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002336
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002337 break;
2338 };
2339}
2340
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002341static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002342switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002343{
2344 struct drm_compositor *ec = data;
2345
Daniel Stone325fc2d2012-05-30 16:31:58 +01002346 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002347}
2348
David Herrmann0af066f2012-10-29 19:21:16 +01002349/*
2350 * Find primary GPU
2351 * Some systems may have multiple DRM devices attached to a single seat. This
2352 * function loops over all devices and tries to find a PCI device with the
2353 * boot_vga sysfs attribute set to 1.
2354 * If no such device is found, the first DRM device reported by udev is used.
2355 */
2356static struct udev_device*
2357find_primary_gpu(struct drm_compositor *ec, const char *seat)
2358{
2359 struct udev_enumerate *e;
2360 struct udev_list_entry *entry;
2361 const char *path, *device_seat, *id;
2362 struct udev_device *device, *drm_device, *pci;
2363
2364 e = udev_enumerate_new(ec->udev);
2365 udev_enumerate_add_match_subsystem(e, "drm");
2366 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2367
2368 udev_enumerate_scan_devices(e);
2369 drm_device = NULL;
2370 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2371 path = udev_list_entry_get_name(entry);
2372 device = udev_device_new_from_syspath(ec->udev, path);
2373 if (!device)
2374 continue;
2375 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2376 if (!device_seat)
2377 device_seat = default_seat;
2378 if (strcmp(device_seat, seat)) {
2379 udev_device_unref(device);
2380 continue;
2381 }
2382
2383 pci = udev_device_get_parent_with_subsystem_devtype(device,
2384 "pci", NULL);
2385 if (pci) {
2386 id = udev_device_get_sysattr_value(pci, "boot_vga");
2387 if (id && !strcmp(id, "1")) {
2388 if (drm_device)
2389 udev_device_unref(drm_device);
2390 drm_device = device;
2391 break;
2392 }
2393 }
2394
2395 if (!drm_device)
2396 drm_device = device;
2397 else
2398 udev_device_unref(device);
2399 }
2400
2401 udev_enumerate_unref(e);
2402 return drm_device;
2403}
2404
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002405static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002406planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002407{
2408 struct drm_compositor *c = data;
2409
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002410 switch (key) {
2411 case KEY_C:
2412 c->cursors_are_broken ^= 1;
2413 break;
2414 case KEY_V:
2415 c->sprites_are_broken ^= 1;
2416 break;
2417 case KEY_O:
2418 c->sprites_hidden ^= 1;
2419 break;
2420 default:
2421 break;
2422 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002423}
2424
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002425static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002426drm_compositor_create(struct wl_display *display,
Rob Bradford643641d2013-05-31 18:09:53 +01002427 int connector, const char *seat_id, int tty, int pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002428 int *argc, char *argv[],
2429 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002430{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002431 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002432 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002433 struct wl_event_loop *loop;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002434 struct udev_seat *udev_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002435 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002436 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002437
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002438 weston_log("initializing drm backend\n");
2439
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002440 ec = malloc(sizeof *ec);
2441 if (ec == NULL)
2442 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002443 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002444
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002445 /* KMS support for sprites is not complete yet, so disable the
2446 * functionality for now. */
2447 ec->sprites_are_broken = 1;
2448
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002449 ec->use_pixman = pixman;
2450
Daniel Stone725c2c32012-06-22 14:04:36 +01002451 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002452 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002453 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002454 goto err_base;
2455 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002456
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002457 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002458 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002459 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002460 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002461 goto err_compositor;
2462 }
2463
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002464 ec->udev = udev_new();
2465 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002466 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002467 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002468 }
2469
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002470 ec->base.wl_display = display;
2471 ec->tty = tty_create(&ec->base, vt_func, tty);
2472 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002473 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002474 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002475 }
2476
Rob Bradford643641d2013-05-31 18:09:53 +01002477 drm_device = find_primary_gpu(ec, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002478 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002479 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002480 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002481 }
David Herrmann0af066f2012-10-29 19:21:16 +01002482 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002483
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002484 if (init_drm(ec, drm_device) < 0) {
2485 weston_log("failed to initialize kms\n");
2486 goto err_udev_dev;
2487 }
2488
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002489 if (ec->use_pixman) {
2490 if (init_pixman(ec) < 0) {
2491 weston_log("failed to initialize pixman renderer\n");
2492 goto err_udev_dev;
2493 }
2494 } else {
2495 if (init_egl(ec) < 0) {
2496 weston_log("failed to initialize egl\n");
2497 goto err_udev_dev;
2498 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002499 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002500
2501 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002502 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002503
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002504 ec->base.focus = 1;
2505
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002506 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002507
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002508 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002509 weston_compositor_add_key_binding(&ec->base, key,
2510 MODIFIER_CTRL | MODIFIER_ALT,
2511 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002512
Jesse Barnes58ef3792012-02-23 09:45:49 -05002513 wl_list_init(&ec->sprite_list);
2514 create_sprites(ec);
2515
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002516 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002517 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002518 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002519 }
2520
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002521 path = NULL;
2522
Rob Bradford643641d2013-05-31 18:09:53 +01002523 if (udev_input_create(&ec->base, ec->udev, seat_id) == NULL) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002524 weston_log("failed to create input devices\n");
2525 goto err_sprite;
2526 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002527
2528 loop = wl_display_get_event_loop(ec->base.wl_display);
2529 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002530 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002531 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002532
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002533 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2534 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002535 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002536 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002537 }
2538 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2539 "drm", NULL);
2540 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002541 wl_event_loop_add_fd(loop,
2542 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002543 WL_EVENT_READABLE, udev_drm_event, ec);
2544
2545 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002546 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002547 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002548 }
2549
Daniel Stonea96b93c2012-06-22 14:04:37 +01002550 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002551
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002552 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002553 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002554 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002555 planes_binding, ec);
2556 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2557 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002558
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002559 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002560
2561err_udev_monitor:
2562 wl_event_source_remove(ec->udev_drm_source);
2563 udev_monitor_unref(ec->udev_monitor);
2564err_drm_source:
2565 wl_event_source_remove(ec->drm_source);
Kristian Høgsberge8091032013-02-18 15:43:29 -05002566 wl_list_for_each_safe(udev_seat, next, &ec->base.seat_list, base.link)
2567 udev_seat_destroy(udev_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002568err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002569 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002570 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002571 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002572err_udev_dev:
2573 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002574err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002575 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2576 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002577 tty_destroy(ec->tty);
2578err_udev:
2579 udev_unref(ec->udev);
2580err_compositor:
2581 weston_compositor_shutdown(&ec->base);
2582err_base:
2583 free(ec);
2584 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002585}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002586
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002587WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002588backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002589 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002590{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002591 int connector = 0, tty = 0, use_pixman = 0;
Rob Bradford643641d2013-05-31 18:09:53 +01002592 const char *seat_id = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002593
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002594 const struct weston_option drm_options[] = {
2595 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
Rob Bradford643641d2013-05-31 18:09:53 +01002596 { WESTON_OPTION_STRING, "seat", 0, &seat_id },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002597 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002598 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002599 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002600 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002601
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002602 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002603
Rob Bradford643641d2013-05-31 18:09:53 +01002604 return drm_compositor_create(display, connector, seat_id, tty, use_pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002605 argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002606}