blob: 27d4d02081282b3152417cfbf6a3d669aaec5c27 [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 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200591 }
592
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500593 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300594 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500595 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200596 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500597 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500598 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100599
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300600 output->page_flip_pending = 1;
601
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400602 drm_output_set_cursor(output);
603
Jesse Barnes58ef3792012-02-23 09:45:49 -0500604 /*
605 * Now, update all the sprite surfaces
606 */
607 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200608 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500609 drmVBlank vbl = {
610 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
611 .request.sequence = 1,
612 };
613
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200614 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200615 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500616 continue;
617
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200618 if (s->next && !compositor->sprites_hidden)
619 fb_id = s->next->fb_id;
620
Jesse Barnes58ef3792012-02-23 09:45:49 -0500621 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200622 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500623 s->dest_x, s->dest_y,
624 s->dest_w, s->dest_h,
625 s->src_x, s->src_y,
626 s->src_w, s->src_h);
627 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200628 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500629 ret, strerror(errno));
630
Rob Clark5ca1a472012-08-08 20:27:37 -0500631 if (output->pipe > 0)
632 vbl.request.type |= DRM_VBLANK_SECONDARY;
633
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634 /*
635 * Queue a vblank signal so we know when the surface
636 * becomes active on the display or has been replaced.
637 */
638 vbl.request.signal = (unsigned long)s;
639 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
640 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200641 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500642 ret, strerror(errno));
643 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300644
645 s->output = output;
646 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500647 }
648
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500649 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400650}
651
652static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200653drm_output_start_repaint_loop(struct weston_output *output_base)
654{
655 struct drm_output *output = (struct drm_output *) output_base;
656 struct drm_compositor *compositor = (struct drm_compositor *)
657 output_base->compositor;
658 uint32_t fb_id;
659
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300660 struct timespec ts;
661
662 if (!output->current) {
663 /* We can't page flip if there's no mode set */
664 uint32_t msec;
665
666 clock_gettime(compositor->clock, &ts);
667 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
668 weston_output_finish_frame(output_base, msec);
669 return;
670 }
671
672 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200673
674 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
675 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
676 weston_log("queueing pageflip failed: %m\n");
677 return;
678 }
679}
680
681static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500682vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
683 void *data)
684{
685 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300686 struct drm_output *output = s->output;
687 uint32_t msecs;
688
689 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500690
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200691 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200692 s->current = s->next;
693 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300694
695 if (!output->page_flip_pending) {
696 msecs = sec * 1000 + usec / 1000;
697 weston_output_finish_frame(&output->base, msecs);
698 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500699}
700
701static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400702page_flip_handler(int fd, unsigned int frame,
703 unsigned int sec, unsigned int usec, void *data)
704{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200705 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400706 uint32_t msecs;
707
Jonas Ådahle5a12252013-04-05 23:07:11 +0200708 /* We don't set page_flip_pending on start_repaint_loop, in that case
709 * we just want to page flip to the current buffer to get an accurate
710 * timestamp */
711 if (output->page_flip_pending) {
712 drm_output_release_fb(output, output->current);
713 output->current = output->next;
714 output->next = NULL;
715 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300716
Jonas Ådahle5a12252013-04-05 23:07:11 +0200717 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400718
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300719 if (!output->vblank_pending) {
720 msecs = sec * 1000 + usec / 1000;
721 weston_output_finish_frame(&output->base, msecs);
722 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200723}
724
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500725static uint32_t
726drm_output_check_sprite_format(struct drm_sprite *s,
727 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500728{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500729 uint32_t i, format;
730
731 format = gbm_bo_get_format(bo);
732
733 if (format == GBM_FORMAT_ARGB8888) {
734 pixman_region32_t r;
735
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500736 pixman_region32_init_rect(&r, 0, 0,
737 es->geometry.width,
738 es->geometry.height);
739 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500740
741 if (!pixman_region32_not_empty(&r))
742 format = GBM_FORMAT_XRGB8888;
743
744 pixman_region32_fini(&r);
745 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500746
747 for (i = 0; i < s->count_formats; i++)
748 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500749 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500750
751 return 0;
752}
753
754static int
755drm_surface_transform_supported(struct weston_surface *es)
756{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500757 return !es->transform.enabled ||
758 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500759}
760
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400761static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500762drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400763 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500764{
765 struct weston_compositor *ec = output_base->compositor;
766 struct drm_compositor *c =(struct drm_compositor *) ec;
767 struct drm_sprite *s;
768 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500769 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500770 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200771 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500772 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400773 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500774
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200775 if (c->gbm == NULL)
776 return NULL;
777
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200778 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200779 return NULL;
780
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200781 if (es->buffer_scale != output_base->scale)
782 return NULL;
783
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500784 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400785 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500786
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300787 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400788 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300789
Pekka Paalanende685b82012-12-04 15:58:12 +0200790 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400791 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500792
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200793 if (es->alpha != 1.0f)
794 return NULL;
795
Pekka Paalanende685b82012-12-04 15:58:12 +0200796 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500797 return NULL;
798
Jesse Barnes58ef3792012-02-23 09:45:49 -0500799 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400800 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801
Jesse Barnes58ef3792012-02-23 09:45:49 -0500802 wl_list_for_each(s, &c->sprite_list, link) {
803 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
804 continue;
805
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200806 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500807 found = 1;
808 break;
809 }
810 }
811
812 /* No sprites available */
813 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400814 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500815
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400816 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200817 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400818 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400819 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400820
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500821 format = drm_output_check_sprite_format(s, es, bo);
822 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200823 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400824 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500825 }
826
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200827 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200828 if (!s->next) {
829 gbm_bo_destroy(bo);
830 return NULL;
831 }
832
Pekka Paalanende685b82012-12-04 15:58:12 +0200833 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500834
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400835 box = pixman_region32_extents(&es->transform.boundingbox);
836 s->plane.x = box->x1;
837 s->plane.y = box->y1;
838
Jesse Barnes58ef3792012-02-23 09:45:49 -0500839 /*
840 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200841 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500842 * for us already).
843 */
844 pixman_region32_init(&dest_rect);
845 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
846 &output_base->region);
847 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
848 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200849 tbox = weston_transformed_rect(output_base->width,
850 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200851 output_base->transform,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200852 output_base->scale,
853 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200854 s->dest_x = tbox.x1;
855 s->dest_y = tbox.y1;
856 s->dest_w = tbox.x2 - tbox.x1;
857 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500858 pixman_region32_fini(&dest_rect);
859
860 pixman_region32_init(&src_rect);
861 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
862 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500863 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400864
865 weston_surface_from_global_fixed(es,
866 wl_fixed_from_int(box->x1),
867 wl_fixed_from_int(box->y1),
868 &sx1, &sy1);
869 weston_surface_from_global_fixed(es,
870 wl_fixed_from_int(box->x2),
871 wl_fixed_from_int(box->y2),
872 &sx2, &sy2);
873
874 if (sx1 < 0)
875 sx1 = 0;
876 if (sy1 < 0)
877 sy1 = 0;
878 if (sx2 > wl_fixed_from_int(es->geometry.width))
879 sx2 = wl_fixed_from_int(es->geometry.width);
880 if (sy2 > wl_fixed_from_int(es->geometry.height))
881 sy2 = wl_fixed_from_int(es->geometry.height);
882
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200883 tbox.x1 = sx1;
884 tbox.y1 = sy1;
885 tbox.x2 = sx2;
886 tbox.y2 = sy2;
887
888 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
889 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200890 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200891
892 s->src_x = tbox.x1 << 8;
893 s->src_y = tbox.y1 << 8;
894 s->src_w = (tbox.x2 - tbox.x1) << 8;
895 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500896 pixman_region32_fini(&src_rect);
897
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400898 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500899}
900
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400901static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400902drm_output_prepare_cursor_surface(struct weston_output *output_base,
903 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500904{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400905 struct drm_compositor *c =
906 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400907 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400908
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200909 if (c->gbm == NULL)
910 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200911 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
912 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400913 if (output->cursor_surface)
914 return NULL;
915 if (es->output_mask != (1u << output_base->id))
916 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500917 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400918 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200919 if (es->buffer_ref.buffer == NULL ||
920 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400921 es->geometry.width > 64 || es->geometry.height > 64)
922 return NULL;
923
924 output->cursor_surface = es;
925
926 return &output->cursor_plane;
927}
928
929static void
930drm_output_set_cursor(struct drm_output *output)
931{
932 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400933 struct drm_compositor *c =
934 (struct drm_compositor *) output->base.compositor;
935 EGLint handle, stride;
936 struct gbm_bo *bo;
937 uint32_t buf[64 * 64];
938 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400939 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500940
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400941 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400942 if (es == NULL) {
943 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
944 return;
945 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500946
Pekka Paalanende685b82012-12-04 15:58:12 +0200947 if (es->buffer_ref.buffer &&
948 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400949 pixman_region32_fini(&output->cursor_plane.damage);
950 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400951 output->current_cursor ^= 1;
952 bo = output->cursor_bo[output->current_cursor];
953 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200954 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
955 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400956 for (i = 0; i < es->geometry.height; i++)
957 memcpy(buf + i * 64, s + i * stride,
958 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500959
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400960 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300961 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400962
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400963 handle = gbm_bo_get_handle(bo).s32;
964 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500965 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300966 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500967 c->cursors_are_broken = 1;
968 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400969 }
970
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200971 x = (es->geometry.x - output->base.x) * output->base.scale;
972 y = (es->geometry.y - output->base.y) * output->base.scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400973 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500974 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400975 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500976 c->cursors_are_broken = 1;
977 }
978
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400979 output->cursor_plane.x = x;
980 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400981 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500982}
983
Jesse Barnes58ef3792012-02-23 09:45:49 -0500984static void
985drm_assign_planes(struct weston_output *output)
986{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400987 struct drm_compositor *c =
988 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400989 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500990 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400991 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500992
993 /*
994 * Find a surface for each sprite in the output using some heuristics:
995 * 1) size
996 * 2) frequency of update
997 * 3) opacity (though some hw might support alpha blending)
998 * 4) clipping (this can be fixed with color keys)
999 *
1000 * The idea is to save on blitting since this should save power.
1001 * If we can get a large video surface on the sprite for example,
1002 * the main display surface may not need to update at all, and
1003 * the client buffer can be used directly for the sprite surface
1004 * as we do for flipping full screen surfaces.
1005 */
1006 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001007 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001008 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001009 /* test whether this buffer can ever go into a plane:
1010 * non-shm, or small enough to be a cursor
1011 */
1012 if ((es->buffer_ref.buffer &&
1013 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
1014 (es->geometry.width <= 64 && es->geometry.height <= 64))
1015 es->keep_buffer = 1;
1016 else
1017 es->keep_buffer = 0;
1018
Jesse Barnes58ef3792012-02-23 09:45:49 -05001019 pixman_region32_init(&surface_overlap);
1020 pixman_region32_intersect(&surface_overlap, &overlap,
1021 &es->transform.boundingbox);
1022
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001023 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001024 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001025 next_plane = primary;
1026 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001027 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001028 if (next_plane == NULL)
1029 next_plane = drm_output_prepare_scanout_surface(output, es);
1030 if (next_plane == NULL)
1031 next_plane = drm_output_prepare_overlay_surface(output, es);
1032 if (next_plane == NULL)
1033 next_plane = primary;
1034 weston_surface_move_to_plane(es, next_plane);
1035 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001036 pixman_region32_union(&overlap, &overlap,
1037 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001038
Jesse Barnes58ef3792012-02-23 09:45:49 -05001039 pixman_region32_fini(&surface_overlap);
1040 }
1041 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001042}
1043
Matt Roper361d2ad2011-08-29 13:52:23 -07001044static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001045drm_output_fini_pixman(struct drm_output *output);
1046
1047static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001048drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001049{
1050 struct drm_output *output = (struct drm_output *) output_base;
1051 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001052 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001053 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001054
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001055 if (output->backlight)
1056 backlight_destroy(output->backlight);
1057
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001058 drmModeFreeProperty(output->dpms_prop);
1059
Matt Roper361d2ad2011-08-29 13:52:23 -07001060 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001061 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001062
1063 /* Restore original CRTC state */
1064 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001065 origcrtc->x, origcrtc->y,
1066 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001067 drmModeFreeCrtc(origcrtc);
1068
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001069 c->crtc_allocator &= ~(1 << output->crtc_id);
1070 c->connector_allocator &= ~(1 << output->connector_id);
1071
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001072 if (c->use_pixman) {
1073 drm_output_fini_pixman(output);
1074 } else {
1075 gl_renderer_output_destroy(output_base);
1076 gbm_surface_destroy(output->surface);
1077 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001078
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001079 weston_plane_release(&output->fb_plane);
1080 weston_plane_release(&output->cursor_plane);
1081
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001082 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001083 wl_list_remove(&output->base.link);
1084
Matt Roper361d2ad2011-08-29 13:52:23 -07001085 free(output);
1086}
1087
Alex Wub7b8bda2012-04-17 17:20:48 +08001088static struct drm_mode *
1089choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1090{
1091 struct drm_mode *tmp_mode = NULL, *mode;
1092
1093 if (output->base.current->width == target_mode->width &&
1094 output->base.current->height == target_mode->height &&
1095 (output->base.current->refresh == target_mode->refresh ||
1096 target_mode->refresh == 0))
1097 return (struct drm_mode *)output->base.current;
1098
1099 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1100 if (mode->mode_info.hdisplay == target_mode->width &&
1101 mode->mode_info.vdisplay == target_mode->height) {
1102 if (mode->mode_info.vrefresh == target_mode->refresh ||
1103 target_mode->refresh == 0) {
1104 return mode;
1105 } else if (!tmp_mode)
1106 tmp_mode = mode;
1107 }
1108 }
1109
1110 return tmp_mode;
1111}
1112
1113static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001114drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001115static int
1116drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001117
1118static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001119drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1120{
1121 struct drm_output *output;
1122 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001123 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001124
1125 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001126 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001127 return -1;
1128 }
1129
1130 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001131 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001132 return -1;
1133 }
1134
1135 ec = (struct drm_compositor *)output_base->compositor;
1136 output = (struct drm_output *)output_base;
1137 drm_mode = choose_mode (output, mode);
1138
1139 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001140 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001141 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001142 }
1143
1144 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001145 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001146
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001147 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001148
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001149 output->base.current = &drm_mode->base;
1150 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001151 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1152
Alex Wub7b8bda2012-04-17 17:20:48 +08001153 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001154 drm_output_release_fb(output, output->current);
1155 drm_output_release_fb(output, output->next);
1156 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001157
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001158 if (ec->use_pixman) {
1159 drm_output_fini_pixman(output);
1160 if (drm_output_init_pixman(output, ec) < 0) {
1161 weston_log("failed to init output pixman state with "
1162 "new mode\n");
1163 return -1;
1164 }
1165 } else {
1166 gl_renderer_output_destroy(&output->base);
1167 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001168
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001169 if (drm_output_init_egl(output, ec) < 0) {
1170 weston_log("failed to init output egl state with "
1171 "new mode");
1172 return -1;
1173 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001174 }
1175
Alex Wub7b8bda2012-04-17 17:20:48 +08001176 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001177}
1178
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001179static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001180on_drm_input(int fd, uint32_t mask, void *data)
1181{
1182 drmEventContext evctx;
1183
1184 memset(&evctx, 0, sizeof evctx);
1185 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1186 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001187 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001188 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001189
1190 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001191}
1192
1193static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001194init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001195{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001196 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001197 uint64_t cap;
1198 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001199
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001200 sysnum = udev_device_get_sysnum(device);
1201 if (sysnum)
1202 ec->drm.id = atoi(sysnum);
1203 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001204 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001205 return -1;
1206 }
1207
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001208 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001209 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001210 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001211 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001212 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001213 udev_device_get_devnode(device));
1214 return -1;
1215 }
1216
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001217 weston_log("using %s\n", filename);
1218
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001219 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001220
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001221 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1222 if (ret == 0 && cap == 1)
1223 ec->clock = CLOCK_MONOTONIC;
1224 else
1225 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001226
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001227 return 0;
1228}
1229
1230static int
1231init_egl(struct drm_compositor *ec)
1232{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001233 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001234
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001235 if (!ec->gbm)
1236 return -1;
1237
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001238 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001239 NULL) < 0) {
1240 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001241 return -1;
1242 }
1243
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001244 return 0;
1245}
1246
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001247static int
1248init_pixman(struct drm_compositor *ec)
1249{
1250 return pixman_renderer_init(&ec->base);
1251}
1252
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001253static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001254drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001255{
1256 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001257 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001258
1259 mode = malloc(sizeof *mode);
1260 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001261 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001262
1263 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001264 mode->base.width = info->hdisplay;
1265 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001266
1267 /* Calculate higher precision (mHz) refresh rate */
1268 refresh = (info->clock * 1000000LL / info->htotal +
1269 info->vtotal / 2) / info->vtotal;
1270
1271 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1272 refresh *= 2;
1273 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1274 refresh /= 2;
1275 if (info->vscan > 1)
1276 refresh /= info->vscan;
1277
1278 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001279 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001280
1281 if (info->type & DRM_MODE_TYPE_PREFERRED)
1282 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1283
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001284 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1285
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001286 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001287}
1288
1289static int
1290drm_subpixel_to_wayland(int drm_value)
1291{
1292 switch (drm_value) {
1293 default:
1294 case DRM_MODE_SUBPIXEL_UNKNOWN:
1295 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1296 case DRM_MODE_SUBPIXEL_NONE:
1297 return WL_OUTPUT_SUBPIXEL_NONE;
1298 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1299 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1300 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1301 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1302 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1303 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1304 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1305 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1306 }
1307}
1308
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001309/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001310static uint32_t
1311drm_get_backlight(struct drm_output *output)
1312{
1313 long brightness, max_brightness, norm;
1314
1315 brightness = backlight_get_brightness(output->backlight);
1316 max_brightness = backlight_get_max_brightness(output->backlight);
1317
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001318 /* convert it on a scale of 0 to 255 */
1319 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001320
1321 return (uint32_t) norm;
1322}
1323
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001324/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001325static void
1326drm_set_backlight(struct weston_output *output_base, uint32_t value)
1327{
1328 struct drm_output *output = (struct drm_output *) output_base;
1329 long max_brightness, new_brightness;
1330
1331 if (!output->backlight)
1332 return;
1333
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001334 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001335 return;
1336
1337 max_brightness = backlight_get_max_brightness(output->backlight);
1338
1339 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001340 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001341
1342 backlight_set_brightness(output->backlight, new_brightness);
1343}
1344
1345static drmModePropertyPtr
1346drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1347{
1348 drmModePropertyPtr props;
1349 int i;
1350
1351 for (i = 0; i < connector->count_props; i++) {
1352 props = drmModeGetProperty(fd, connector->props[i]);
1353 if (!props)
1354 continue;
1355
1356 if (!strcmp(props->name, name))
1357 return props;
1358
1359 drmModeFreeProperty(props);
1360 }
1361
1362 return NULL;
1363}
1364
1365static void
1366drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1367{
1368 struct drm_output *output = (struct drm_output *) output_base;
1369 struct weston_compositor *ec = output_base->compositor;
1370 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001371
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001372 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001373 return;
1374
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001375 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1376 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001377}
1378
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001379static const char *connector_type_names[] = {
1380 "None",
1381 "VGA",
1382 "DVI",
1383 "DVI",
1384 "DVI",
1385 "Composite",
1386 "TV",
1387 "LVDS",
1388 "CTV",
1389 "DIN",
1390 "DP",
1391 "HDMI",
1392 "HDMI",
1393 "TV",
1394 "eDP",
1395};
1396
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001397static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001398find_crtc_for_connector(struct drm_compositor *ec,
1399 drmModeRes *resources, drmModeConnector *connector)
1400{
1401 drmModeEncoder *encoder;
1402 uint32_t possible_crtcs;
1403 int i, j;
1404
1405 for (j = 0; j < connector->count_encoders; j++) {
1406 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1407 if (encoder == NULL) {
1408 weston_log("Failed to get encoder.\n");
1409 return -1;
1410 }
1411 possible_crtcs = encoder->possible_crtcs;
1412 drmModeFreeEncoder(encoder);
1413
1414 for (i = 0; i < resources->count_crtcs; i++) {
1415 if (possible_crtcs & (1 << i) &&
1416 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1417 return i;
1418 }
1419 }
1420
1421 return -1;
1422}
1423
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001424/* Init output state that depends on gl or gbm */
1425static int
1426drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1427{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001428 int i, flags;
1429
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001430 output->surface = gbm_surface_create(ec->gbm,
Alexander Larsson0b135062013-05-28 16:23:36 +02001431 output->base.current->width,
1432 output->base.current->height,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001433 GBM_FORMAT_XRGB8888,
1434 GBM_BO_USE_SCANOUT |
1435 GBM_BO_USE_RENDERING);
1436 if (!output->surface) {
1437 weston_log("failed to create gbm surface\n");
1438 return -1;
1439 }
1440
1441 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001442 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001443 gbm_surface_destroy(output->surface);
1444 return -1;
1445 }
1446
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001447 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1448
1449 for (i = 0; i < 2; i++) {
1450 if (output->cursor_bo[i])
1451 continue;
1452
1453 output->cursor_bo[i] =
1454 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1455 flags);
1456 }
1457
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001458 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1459 weston_log("cursor buffers unavailable, using gl cursors\n");
1460 ec->cursors_are_broken = 1;
1461 }
1462
1463 return 0;
1464}
1465
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001466static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001467drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1468{
1469 int w = output->base.current->width;
1470 int h = output->base.current->height;
1471 unsigned int i;
1472
1473 /* FIXME error checking */
1474
1475 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001476 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001477 if (!output->dumb[i])
1478 goto err;
1479
1480 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001481 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001482 output->dumb[i]->map,
1483 output->dumb[i]->stride);
1484 if (!output->image[i])
1485 goto err;
1486 }
1487
1488 if (pixman_renderer_output_create(&output->base) < 0)
1489 goto err;
1490
1491 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001492 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001493
1494 return 0;
1495
1496err:
1497 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1498 if (output->dumb[i])
1499 drm_fb_destroy_dumb(output->dumb[i]);
1500 if (output->image[i])
1501 pixman_image_unref(output->image[i]);
1502
1503 output->dumb[i] = NULL;
1504 output->image[i] = NULL;
1505 }
1506
1507 return -1;
1508}
1509
1510static void
1511drm_output_fini_pixman(struct drm_output *output)
1512{
1513 unsigned int i;
1514
1515 pixman_renderer_output_destroy(&output->base);
1516 pixman_region32_fini(&output->previous_damage);
1517
1518 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1519 drm_fb_destroy_dumb(output->dumb[i]);
1520 pixman_image_unref(output->image[i]);
1521 output->dumb[i] = NULL;
1522 output->image[i] = NULL;
1523 }
1524}
1525
Richard Hughes2b2092a2013-04-24 14:58:02 +01001526static void
1527edid_parse_string(const uint8_t *data, char text[])
1528{
1529 int i;
1530 int replaced = 0;
1531
1532 /* this is always 12 bytes, but we can't guarantee it's null
1533 * terminated or not junk. */
1534 strncpy(text, (const char *) data, 12);
1535
1536 /* remove insane chars */
1537 for (i = 0; text[i] != '\0'; i++) {
1538 if (text[i] == '\n' ||
1539 text[i] == '\r') {
1540 text[i] = '\0';
1541 break;
1542 }
1543 }
1544
1545 /* ensure string is printable */
1546 for (i = 0; text[i] != '\0'; i++) {
1547 if (!isprint(text[i])) {
1548 text[i] = '-';
1549 replaced++;
1550 }
1551 }
1552
1553 /* if the string is random junk, ignore the string */
1554 if (replaced > 4)
1555 text[0] = '\0';
1556}
1557
1558#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1559#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1560#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1561#define EDID_OFFSET_DATA_BLOCKS 0x36
1562#define EDID_OFFSET_LAST_BLOCK 0x6c
1563#define EDID_OFFSET_PNPID 0x08
1564#define EDID_OFFSET_SERIAL 0x0c
1565
1566static int
1567edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1568{
1569 int i;
1570 uint32_t serial_number;
1571
1572 /* check header */
1573 if (length < 128)
1574 return -1;
1575 if (data[0] != 0x00 || data[1] != 0xff)
1576 return -1;
1577
1578 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1579 * /--08--\/--09--\
1580 * 7654321076543210
1581 * |\---/\---/\---/
1582 * R C1 C2 C3 */
1583 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1584 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1585 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1586 edid->pnp_id[3] = '\0';
1587
1588 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1589 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1590 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1591 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1592 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1593 if (serial_number > 0)
1594 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1595
1596 /* parse EDID data */
1597 for (i = EDID_OFFSET_DATA_BLOCKS;
1598 i <= EDID_OFFSET_LAST_BLOCK;
1599 i += 18) {
1600 /* ignore pixel clock data */
1601 if (data[i] != 0)
1602 continue;
1603 if (data[i+2] != 0)
1604 continue;
1605
1606 /* any useful blocks? */
1607 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1608 edid_parse_string(&data[i+5],
1609 edid->monitor_name);
1610 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1611 edid_parse_string(&data[i+5],
1612 edid->serial_number);
1613 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1614 edid_parse_string(&data[i+5],
1615 edid->eisa_id);
1616 }
1617 }
1618 return 0;
1619}
1620
1621static void
1622find_and_parse_output_edid(struct drm_compositor *ec,
1623 struct drm_output *output,
1624 drmModeConnector *connector)
1625{
1626 drmModePropertyBlobPtr edid_blob = NULL;
1627 drmModePropertyPtr property;
1628 int i;
1629 int rc;
1630
1631 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1632 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1633 if (!property)
1634 continue;
1635 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1636 !strcmp(property->name, "EDID")) {
1637 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1638 connector->prop_values[i]);
1639 }
1640 drmModeFreeProperty(property);
1641 }
1642 if (!edid_blob)
1643 return;
1644
1645 rc = edid_parse(&output->edid,
1646 edid_blob->data,
1647 edid_blob->length);
1648 if (!rc) {
1649 weston_log("EDID data '%s', '%s', '%s'\n",
1650 output->edid.pnp_id,
1651 output->edid.monitor_name,
1652 output->edid.serial_number);
1653 if (output->edid.pnp_id[0] != '\0')
1654 output->base.make = output->edid.pnp_id;
1655 if (output->edid.monitor_name[0] != '\0')
1656 output->base.model = output->edid.monitor_name;
1657 if (output->edid.serial_number[0] != '\0')
1658 output->base.serial_number = output->edid.serial_number;
1659 }
1660 drmModeFreePropertyBlob(edid_blob);
1661}
1662
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001663
1664
1665static int
1666parse_modeline(const char *s, drmModeModeInfo *mode)
1667{
1668 char hsync[16];
1669 char vsync[16];
1670 float fclock;
1671
1672 mode->type = DRM_MODE_TYPE_USERDEF;
1673 mode->hskew = 0;
1674 mode->vscan = 0;
1675 mode->vrefresh = 0;
1676 mode->flags = 0;
1677
1678 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
1679 &fclock,
1680 &mode->hdisplay,
1681 &mode->hsync_start,
1682 &mode->hsync_end,
1683 &mode->htotal,
1684 &mode->vdisplay,
1685 &mode->vsync_start,
1686 &mode->vsync_end,
1687 &mode->vtotal, hsync, vsync) != 11)
1688 return -1;
1689
1690 mode->clock = fclock * 1000;
1691 if (strcmp(hsync, "+hsync") == 0)
1692 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1693 else if (strcmp(hsync, "-hsync") == 0)
1694 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1695 else
1696 return -1;
1697
1698 if (strcmp(vsync, "+vsync") == 0)
1699 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1700 else if (strcmp(vsync, "-vsync") == 0)
1701 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1702 else
1703 return -1;
1704
1705 return 0;
1706}
1707
1708static uint32_t
1709parse_transform(const char *transform, const char *output_name)
1710{
1711 static const struct { const char *name; uint32_t token; } names[] = {
1712 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1713 { "90", WL_OUTPUT_TRANSFORM_90 },
1714 { "180", WL_OUTPUT_TRANSFORM_180 },
1715 { "270", WL_OUTPUT_TRANSFORM_270 },
1716 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1717 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1718 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1719 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1720 };
1721 unsigned int i;
1722
1723 for (i = 0; i < ARRAY_LENGTH(names); i++)
1724 if (strcmp(names[i].name, transform) == 0)
1725 return names[i].token;
1726
1727 weston_log("Invalid transform \"%s\" for output %s\n",
1728 transform, output_name);
1729
1730 return WL_OUTPUT_TRANSFORM_NORMAL;
1731}
1732
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001733static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001734create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001735 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001736 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001737 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001738{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001739 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001740 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1741 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001742 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001743 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001744 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001745 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001746 int i, width, height, scale;
1747 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001748 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001749 enum output_config config;
1750 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001751
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001752 i = find_crtc_for_connector(ec, resources, connector);
1753 if (i < 0) {
1754 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001755 return -1;
1756 }
1757
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001758 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001759 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001760 return -1;
1761
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001762 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001763 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1764 output->base.make = "unknown";
1765 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001766 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001767 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001768
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001769 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1770 type_name = connector_type_names[connector->connector_type];
1771 else
1772 type_name = "UNKNOWN";
1773 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001774 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001775
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001776 section = weston_config_get_section(ec->base.config, "output", "name",
1777 output->base.name);
1778 weston_config_section_get_string(section, "mode", &s, "preferred");
1779 if (strcmp(s, "off") == 0)
1780 config = OUTPUT_CONFIG_OFF;
1781 else if (strcmp(s, "preferred") == 0)
1782 config = OUTPUT_CONFIG_PREFERRED;
1783 else if (strcmp(s, "current") == 0)
1784 config = OUTPUT_CONFIG_CURRENT;
1785 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1786 config = OUTPUT_CONFIG_MODE;
1787 else if (parse_modeline(s, &modeline) == 0)
1788 config = OUTPUT_CONFIG_MODELINE;
1789 else {
1790 weston_log("Invalid mode \"%s\" for output %s\n",
1791 s, output->base.name);
1792 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001793 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001794 free(s);
1795
1796 weston_config_section_get_int(section, "scale", &scale, 1);
1797 weston_config_section_get_string(section, "transform", &s, "normal");
1798 transform = parse_transform(s, output->base.name);
1799 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001800
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001801 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001802 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001803 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001804 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001805 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001806
Matt Roper361d2ad2011-08-29 13:52:23 -07001807 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001808 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001809
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001810 /* Get the current mode on the crtc that's currently driving
1811 * this connector. */
1812 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001813 memset(&crtc_mode, 0, sizeof crtc_mode);
1814 if (encoder != NULL) {
1815 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1816 drmModeFreeEncoder(encoder);
1817 if (crtc == NULL)
1818 goto err_free;
1819 if (crtc->mode_valid)
1820 crtc_mode = crtc->mode;
1821 drmModeFreeCrtc(crtc);
1822 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001823
David Herrmann0f0d54e2011-12-08 17:05:45 +01001824 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001825 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001826 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001827 goto err_free;
1828 }
1829
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001830 if (config == OUTPUT_CONFIG_OFF) {
1831 weston_log("Disabling output %s\n", output->base.name);
1832 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1833 0, 0, 0, 0, 0, NULL);
1834 goto err_free;
1835 }
1836
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001837 preferred = NULL;
1838 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001839 configured = NULL;
1840
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001841 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001842 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001843 width == drm_mode->base.width &&
1844 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001845 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001846 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001847 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001848 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001849 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001850 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001851
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001852 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001853 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001854 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001855 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001856 }
1857
Wang Quanxianacb805a2012-07-30 18:09:46 -04001858 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001859 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001860 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001861 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001862 }
1863
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001864 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001865 configured = current;
1866
Wang Quanxianacb805a2012-07-30 18:09:46 -04001867 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001868 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001869 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001870 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001871 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001872 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001873 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001874 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001875
1876 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001877 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001878 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001879 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001880
Wang Quanxianacb805a2012-07-30 18:09:46 -04001881 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1882
John Kåre Alsaker94659272012-11-13 19:10:18 +01001883 weston_output_init(&output->base, &ec->base, x, y,
1884 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001885 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001886
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001887 if (ec->use_pixman) {
1888 if (drm_output_init_pixman(output, ec) < 0) {
1889 weston_log("Failed to init output pixman state\n");
1890 goto err_output;
1891 }
1892 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001893 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001894 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001895 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001896
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001897 output->backlight = backlight_init(drm_device,
1898 connector->connector_type);
1899 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001900 weston_log("Initialized backlight, device %s\n",
1901 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001902 output->base.set_backlight = drm_set_backlight;
1903 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001904 } else {
1905 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001906 }
1907
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001908 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1909
Richard Hughes2b2092a2013-04-24 14:58:02 +01001910 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001911 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1912 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001913
Alex Wubd3354b2012-04-17 17:20:49 +08001914 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001915 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001916 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001917 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001918 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001919 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001920 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001921
Richard Hughese7299962013-05-01 21:52:12 +01001922 output->base.gamma_size = output->original_crtc->gamma_size;
1923 output->base.set_gamma = drm_output_set_gamma;
1924
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001925 weston_plane_init(&output->cursor_plane, 0, 0);
1926 weston_plane_init(&output->fb_plane, 0, 0);
1927
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001928 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1929 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1930 &ec->base.primary_plane);
1931
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001932 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001933 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001934 wl_list_for_each(m, &output->base.mode_list, link)
1935 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1936 m->width, m->height, m->refresh / 1000.0,
1937 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1938 ", preferred" : "",
1939 m->flags & WL_OUTPUT_MODE_CURRENT ?
1940 ", current" : "",
1941 connector->count_modes == 0 ?
1942 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001943
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001944 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001945
John Kåre Alsaker94659272012-11-13 19:10:18 +01001946err_output:
1947 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001948err_free:
1949 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1950 base.link) {
1951 wl_list_remove(&drm_mode->base.link);
1952 free(drm_mode);
1953 }
1954
1955 drmModeFreeCrtc(output->original_crtc);
1956 ec->crtc_allocator &= ~(1 << output->crtc_id);
1957 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001958 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001959
David Herrmann0f0d54e2011-12-08 17:05:45 +01001960 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001961}
1962
Jesse Barnes58ef3792012-02-23 09:45:49 -05001963static void
1964create_sprites(struct drm_compositor *ec)
1965{
1966 struct drm_sprite *sprite;
1967 drmModePlaneRes *plane_res;
1968 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001969 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001970
1971 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1972 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001973 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001974 strerror(errno));
1975 return;
1976 }
1977
1978 for (i = 0; i < plane_res->count_planes; i++) {
1979 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1980 if (!plane)
1981 continue;
1982
1983 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1984 plane->count_formats));
1985 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001986 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001987 __func__);
1988 free(plane);
1989 continue;
1990 }
1991
1992 memset(sprite, 0, sizeof *sprite);
1993
1994 sprite->possible_crtcs = plane->possible_crtcs;
1995 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001996 sprite->current = NULL;
1997 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001998 sprite->compositor = ec;
1999 sprite->count_formats = plane->count_formats;
2000 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002001 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002002 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002003 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002004 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2005 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002006
2007 wl_list_insert(&ec->sprite_list, &sprite->link);
2008 }
2009
2010 free(plane_res->planes);
2011 free(plane_res);
2012}
2013
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002014static void
2015destroy_sprites(struct drm_compositor *compositor)
2016{
2017 struct drm_sprite *sprite, *next;
2018 struct drm_output *output;
2019
2020 output = container_of(compositor->base.output_list.next,
2021 struct drm_output, base.link);
2022
2023 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2024 drmModeSetPlane(compositor->drm.fd,
2025 sprite->plane_id,
2026 output->crtc_id, 0, 0,
2027 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002028 drm_output_release_fb(output, sprite->current);
2029 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002030 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002031 free(sprite);
2032 }
2033}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002034
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002035static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002036create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002037 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002038{
2039 drmModeConnector *connector;
2040 drmModeRes *resources;
2041 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002042 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002043
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002044 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002045 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002046 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002047 return -1;
2048 }
2049
Jesse Barnes58ef3792012-02-23 09:45:49 -05002050 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002051 if (!ec->crtcs) {
2052 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002053 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002054 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002055
Rob Clark4339add2012-08-09 14:18:28 -05002056 ec->min_width = resources->min_width;
2057 ec->max_width = resources->max_width;
2058 ec->min_height = resources->min_height;
2059 ec->max_height = resources->max_height;
2060
Jesse Barnes58ef3792012-02-23 09:45:49 -05002061 ec->num_crtcs = resources->count_crtcs;
2062 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2063
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002064 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002065 connector = drmModeGetConnector(ec->drm.fd,
2066 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002067 if (connector == NULL)
2068 continue;
2069
2070 if (connector->connection == DRM_MODE_CONNECTED &&
2071 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002072 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002073 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002074 connector, x, y,
2075 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002076 drmModeFreeConnector(connector);
2077 continue;
2078 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002079
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002080 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002081 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002082 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002083 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002084
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002085 drmModeFreeConnector(connector);
2086 }
2087
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002088 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002089 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002090 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002091 return -1;
2092 }
2093
2094 drmModeFreeResources(resources);
2095
2096 return 0;
2097}
2098
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002099static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002100update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002101{
2102 drmModeConnector *connector;
2103 drmModeRes *resources;
2104 struct drm_output *output, *next;
2105 int x = 0, y = 0;
2106 int x_offset = 0, y_offset = 0;
2107 uint32_t connected = 0, disconnects = 0;
2108 int i;
2109
2110 resources = drmModeGetResources(ec->drm.fd);
2111 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002112 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002113 return;
2114 }
2115
2116 /* collect new connects */
2117 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002118 int connector_id = resources->connectors[i];
2119
2120 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002121 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002122 continue;
2123
David Herrmann7551cff2011-12-08 17:05:43 +01002124 if (connector->connection != DRM_MODE_CONNECTED) {
2125 drmModeFreeConnector(connector);
2126 continue;
2127 }
2128
Benjamin Franzke117483d2011-08-30 11:38:26 +02002129 connected |= (1 << connector_id);
2130
2131 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002132 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002133 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002134 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002135
2136 /* XXX: not yet needed, we die with 0 outputs */
2137 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002138 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002139 else
2140 x = 0;
2141 y = 0;
2142 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002143 connector, x, y,
2144 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002145 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002146
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002147 }
2148 drmModeFreeConnector(connector);
2149 }
2150 drmModeFreeResources(resources);
2151
2152 disconnects = ec->connector_allocator & ~connected;
2153 if (disconnects) {
2154 wl_list_for_each_safe(output, next, &ec->base.output_list,
2155 base.link) {
2156 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002157 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002158 output->base.x - x_offset,
2159 output->base.y - y_offset);
2160 }
2161
2162 if (disconnects & (1 << output->connector_id)) {
2163 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002164 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002165 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002166 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002167 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002168 }
2169 }
2170 }
2171
2172 /* FIXME: handle zero outputs, without terminating */
2173 if (ec->connector_allocator == 0)
2174 wl_display_terminate(ec->base.wl_display);
2175}
2176
2177static int
David Herrmannd7488c22012-03-11 20:05:21 +01002178udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002179{
David Herrmannd7488c22012-03-11 20:05:21 +01002180 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002181 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002182
2183 sysnum = udev_device_get_sysnum(device);
2184 if (!sysnum || atoi(sysnum) != ec->drm.id)
2185 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002186
David Herrmann6ac52db2012-03-11 20:05:22 +01002187 val = udev_device_get_property_value(device, "HOTPLUG");
2188 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002189 return 0;
2190
David Herrmann6ac52db2012-03-11 20:05:22 +01002191 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002192}
2193
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002194static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002195udev_drm_event(int fd, uint32_t mask, void *data)
2196{
2197 struct drm_compositor *ec = data;
2198 struct udev_device *event;
2199
2200 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002201
David Herrmannd7488c22012-03-11 20:05:21 +01002202 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002203 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002204
2205 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002206
2207 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002208}
2209
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002210static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002211drm_restore(struct weston_compositor *ec)
2212{
2213 struct drm_compositor *d = (struct drm_compositor *) ec;
2214
2215 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2216 weston_log("failed to drop master: %m\n");
2217 tty_reset(d->tty);
2218}
2219
2220static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002221drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002222{
2223 struct drm_compositor *d = (struct drm_compositor *) ec;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002224 struct udev_seat *seat, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002225
Kristian Høgsberge8091032013-02-18 15:43:29 -05002226 wl_list_for_each_safe(seat, next, &ec->seat_list, base.link)
2227 udev_seat_destroy(seat);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002228
2229 wl_event_source_remove(d->udev_drm_source);
2230 wl_event_source_remove(d->drm_source);
2231
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002232 destroy_sprites(d);
2233
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002234 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002235
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002236 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002237
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002238 if (d->gbm)
2239 gbm_device_destroy(d->gbm);
2240
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002241 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002242 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002243 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002244
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002245 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002246}
2247
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002248static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002249drm_compositor_set_modes(struct drm_compositor *compositor)
2250{
2251 struct drm_output *output;
2252 struct drm_mode *drm_mode;
2253 int ret;
2254
2255 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002256 if (!output->current) {
2257 /* If something that would cause the output to
2258 * switch mode happened while in another vt, we
2259 * might not have a current drm_fb. In that case,
2260 * schedule a repaint and let drm_output_repaint
2261 * handle setting the mode. */
2262 weston_output_schedule_repaint(&output->base);
2263 continue;
2264 }
2265
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002266 drm_mode = (struct drm_mode *) output->base.current;
2267 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002268 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002269 &output->connector_id, 1,
2270 &drm_mode->mode_info);
2271 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002272 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002273 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002274 drm_mode->base.width, drm_mode->base.height,
2275 output->base.x, output->base.y);
2276 }
2277 }
2278}
2279
2280static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002281vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002282{
2283 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002284 struct udev_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002285 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002286 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002287
2288 switch (event) {
2289 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002290 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002291 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002292 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002293 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002294 wl_display_terminate(compositor->wl_display);
2295 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002296 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002297 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002298 weston_compositor_damage_all(compositor);
Kristian Høgsberg87644662013-02-18 16:50:19 -05002299 wl_list_for_each(seat, &compositor->seat_list, base.link)
2300 udev_seat_enable(seat, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002301 break;
2302 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002303 weston_log("leaving VT\n");
Kristian Høgsberg87644662013-02-18 16:50:19 -05002304 wl_list_for_each(seat, &compositor->seat_list, base.link)
2305 udev_seat_disable(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002306
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002307 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002308 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002309 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002310
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002311 /* If we have a repaint scheduled (either from a
2312 * pending pageflip or the idle handler), make sure we
2313 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002314 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002315 * further attemps at repainting. When we switch
2316 * back, we schedule a repaint, which will process
2317 * pending frame callbacks. */
2318
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002319 wl_list_for_each(output, &ec->base.output_list, base.link) {
2320 output->base.repaint_needed = 0;
2321 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002322 }
2323
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002324 output = container_of(ec->base.output_list.next,
2325 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002326
2327 wl_list_for_each(sprite, &ec->sprite_list, link)
2328 drmModeSetPlane(ec->drm.fd,
2329 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002330 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002331 0, 0, 0, 0, 0, 0, 0, 0);
2332
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002333 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002334 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002335
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002336 break;
2337 };
2338}
2339
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002340static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002341switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002342{
2343 struct drm_compositor *ec = data;
2344
Daniel Stone325fc2d2012-05-30 16:31:58 +01002345 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002346}
2347
David Herrmann0af066f2012-10-29 19:21:16 +01002348/*
2349 * Find primary GPU
2350 * Some systems may have multiple DRM devices attached to a single seat. This
2351 * function loops over all devices and tries to find a PCI device with the
2352 * boot_vga sysfs attribute set to 1.
2353 * If no such device is found, the first DRM device reported by udev is used.
2354 */
2355static struct udev_device*
2356find_primary_gpu(struct drm_compositor *ec, const char *seat)
2357{
2358 struct udev_enumerate *e;
2359 struct udev_list_entry *entry;
2360 const char *path, *device_seat, *id;
2361 struct udev_device *device, *drm_device, *pci;
2362
2363 e = udev_enumerate_new(ec->udev);
2364 udev_enumerate_add_match_subsystem(e, "drm");
2365 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2366
2367 udev_enumerate_scan_devices(e);
2368 drm_device = NULL;
2369 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2370 path = udev_list_entry_get_name(entry);
2371 device = udev_device_new_from_syspath(ec->udev, path);
2372 if (!device)
2373 continue;
2374 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2375 if (!device_seat)
2376 device_seat = default_seat;
2377 if (strcmp(device_seat, seat)) {
2378 udev_device_unref(device);
2379 continue;
2380 }
2381
2382 pci = udev_device_get_parent_with_subsystem_devtype(device,
2383 "pci", NULL);
2384 if (pci) {
2385 id = udev_device_get_sysattr_value(pci, "boot_vga");
2386 if (id && !strcmp(id, "1")) {
2387 if (drm_device)
2388 udev_device_unref(drm_device);
2389 drm_device = device;
2390 break;
2391 }
2392 }
2393
2394 if (!drm_device)
2395 drm_device = device;
2396 else
2397 udev_device_unref(device);
2398 }
2399
2400 udev_enumerate_unref(e);
2401 return drm_device;
2402}
2403
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002404static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002405planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002406{
2407 struct drm_compositor *c = data;
2408
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002409 switch (key) {
2410 case KEY_C:
2411 c->cursors_are_broken ^= 1;
2412 break;
2413 case KEY_V:
2414 c->sprites_are_broken ^= 1;
2415 break;
2416 case KEY_O:
2417 c->sprites_hidden ^= 1;
2418 break;
2419 default:
2420 break;
2421 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002422}
2423
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002424static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002425drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002426 int connector, const char *seat, int tty, int pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002427 int *argc, char *argv[],
2428 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002429{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002430 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002431 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002432 struct wl_event_loop *loop;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002433 struct udev_seat *udev_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002434 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002435 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002436
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002437 weston_log("initializing drm backend\n");
2438
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002439 ec = malloc(sizeof *ec);
2440 if (ec == NULL)
2441 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002442 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002443
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002444 /* KMS support for sprites is not complete yet, so disable the
2445 * functionality for now. */
2446 ec->sprites_are_broken = 1;
2447
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002448 ec->use_pixman = pixman;
2449
Daniel Stone725c2c32012-06-22 14:04:36 +01002450 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002451 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002452 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002453 goto err_base;
2454 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002455
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002456 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002457 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002458 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002459 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002460 goto err_compositor;
2461 }
2462
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002463 ec->udev = udev_new();
2464 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002465 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002466 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002467 }
2468
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002469 ec->base.wl_display = display;
2470 ec->tty = tty_create(&ec->base, vt_func, tty);
2471 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002472 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002473 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002474 }
2475
David Herrmann0af066f2012-10-29 19:21:16 +01002476 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002477 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002478 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002479 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002480 }
David Herrmann0af066f2012-10-29 19:21:16 +01002481 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002482
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002483 if (init_drm(ec, drm_device) < 0) {
2484 weston_log("failed to initialize kms\n");
2485 goto err_udev_dev;
2486 }
2487
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002488 if (ec->use_pixman) {
2489 if (init_pixman(ec) < 0) {
2490 weston_log("failed to initialize pixman renderer\n");
2491 goto err_udev_dev;
2492 }
2493 } else {
2494 if (init_egl(ec) < 0) {
2495 weston_log("failed to initialize egl\n");
2496 goto err_udev_dev;
2497 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002498 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002499
2500 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002501 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002502
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002503 ec->base.focus = 1;
2504
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002505 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002506
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002507 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002508 weston_compositor_add_key_binding(&ec->base, key,
2509 MODIFIER_CTRL | MODIFIER_ALT,
2510 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002511
Jesse Barnes58ef3792012-02-23 09:45:49 -05002512 wl_list_init(&ec->sprite_list);
2513 create_sprites(ec);
2514
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002515 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002516 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002517 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002518 }
2519
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002520 path = NULL;
2521
Kristian Høgsberge8091032013-02-18 15:43:29 -05002522 if (udev_seat_create(&ec->base, ec->udev, seat) == NULL) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002523 weston_log("failed to create input devices\n");
2524 goto err_sprite;
2525 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002526
2527 loop = wl_display_get_event_loop(ec->base.wl_display);
2528 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002529 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002530 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002531
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002532 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2533 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002534 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002535 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002536 }
2537 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2538 "drm", NULL);
2539 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002540 wl_event_loop_add_fd(loop,
2541 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002542 WL_EVENT_READABLE, udev_drm_event, ec);
2543
2544 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002545 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002546 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002547 }
2548
Daniel Stonea96b93c2012-06-22 14:04:37 +01002549 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002550
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002551 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002552 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002553 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002554 planes_binding, ec);
2555 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2556 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002557
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002558 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002559
2560err_udev_monitor:
2561 wl_event_source_remove(ec->udev_drm_source);
2562 udev_monitor_unref(ec->udev_monitor);
2563err_drm_source:
2564 wl_event_source_remove(ec->drm_source);
Kristian Høgsberge8091032013-02-18 15:43:29 -05002565 wl_list_for_each_safe(udev_seat, next, &ec->base.seat_list, base.link)
2566 udev_seat_destroy(udev_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002567err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002568 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002569 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002570 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002571err_udev_dev:
2572 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002573err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002574 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2575 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002576 tty_destroy(ec->tty);
2577err_udev:
2578 udev_unref(ec->udev);
2579err_compositor:
2580 weston_compositor_shutdown(&ec->base);
2581err_base:
2582 free(ec);
2583 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002584}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002585
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002586WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002587backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002588 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002589{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002590 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002591 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002592
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002593 const struct weston_option drm_options[] = {
2594 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2595 { WESTON_OPTION_STRING, "seat", 0, &seat },
2596 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002597 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002598 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002599 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002600
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002601 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002602
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002603 return drm_compositor_create(display, connector, seat, tty, use_pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002604 argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002605}