blob: beb6ba5691ce03b8e07ea20d4b5728c22fc02f16 [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;
Rob Bradfordd355b802013-05-31 18:09:55 +0100110 struct udev_input input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400111};
112
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400113struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500114 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400115 drmModeModeInfo mode_info;
116};
117
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300118struct drm_output;
119
120struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300121 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200122 uint32_t fb_id, stride, handle, size;
123 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300124 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200125 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200126
127 /* Used by gbm fbs */
128 struct gbm_bo *bo;
129
130 /* Used by dumb fbs */
131 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300132};
133
Richard Hughes2b2092a2013-04-24 14:58:02 +0100134struct drm_edid {
135 char eisa_id[13];
136 char monitor_name[13];
137 char pnp_id[5];
138 char serial_number[13];
139};
140
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400141struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500142 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400143
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400144 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500145 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400146 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700147 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100148 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300149 drmModePropertyPtr dpms_prop;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200150
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300151 int vblank_pending;
152 int page_flip_pending;
153
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400154 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400155 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400156 struct weston_plane cursor_plane;
157 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400158 struct weston_surface *cursor_surface;
159 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300160 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200161 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200162
163 struct drm_fb *dumb[2];
164 pixman_image_t *image[2];
165 int current_image;
166 pixman_region32_t previous_damage;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400167};
168
Jesse Barnes58ef3792012-02-23 09:45:49 -0500169/*
170 * An output has a primary display plane plus zero or more sprites for
171 * blending display contents.
172 */
173struct drm_sprite {
174 struct wl_list link;
175
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400176 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500177
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200178 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300179 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500180 struct drm_compositor *compositor;
181
Jesse Barnes58ef3792012-02-23 09:45:49 -0500182 uint32_t possible_crtcs;
183 uint32_t plane_id;
184 uint32_t count_formats;
185
186 int32_t src_x, src_y;
187 uint32_t src_w, src_h;
188 uint32_t dest_x, dest_y;
189 uint32_t dest_w, dest_h;
190
191 uint32_t formats[];
192};
193
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500194static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400195
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400196static void
197drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400198
Jesse Barnes58ef3792012-02-23 09:45:49 -0500199static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500200drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
201{
202 struct weston_compositor *ec = output_base->compositor;
203 struct drm_compositor *c =(struct drm_compositor *) ec;
204 struct drm_output *output = (struct drm_output *) output_base;
205 int crtc;
206
207 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
208 if (c->crtcs[crtc] != output->crtc_id)
209 continue;
210
211 if (supported & (1 << crtc))
212 return -1;
213 }
214
215 return 0;
216}
217
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300218static void
219drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
220{
221 struct drm_fb *fb = data;
222 struct gbm_device *gbm = gbm_bo_get_device(bo);
223
224 if (fb->fb_id)
225 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
226
Pekka Paalanende685b82012-12-04 15:58:12 +0200227 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300228
229 free(data);
230}
231
232static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200233drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
234{
235 struct drm_fb *fb;
236 int ret;
237
238 struct drm_mode_create_dumb create_arg;
239 struct drm_mode_destroy_dumb destroy_arg;
240 struct drm_mode_map_dumb map_arg;
241
242 fb = calloc(1, sizeof *fb);
243 if (!fb)
244 return NULL;
245
246 create_arg.bpp = 32;
247 create_arg.width = width;
248 create_arg.height = height;
249
250 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
251 if (ret)
252 goto err_fb;
253
254 fb->handle = create_arg.handle;
255 fb->stride = create_arg.pitch;
256 fb->size = create_arg.size;
257 fb->fd = ec->drm.fd;
258
259 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
260 fb->stride, fb->handle, &fb->fb_id);
261 if (ret)
262 goto err_bo;
263
264 memset(&map_arg, 0, sizeof(map_arg));
265 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400266 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200267 if (ret)
268 goto err_add_fb;
269
270 fb->map = mmap(0, fb->size, PROT_WRITE,
271 MAP_SHARED, ec->drm.fd, map_arg.offset);
272 if (fb->map == MAP_FAILED)
273 goto err_add_fb;
274
275 return fb;
276
277err_add_fb:
278 drmModeRmFB(ec->drm.fd, fb->fb_id);
279err_bo:
280 memset(&destroy_arg, 0, sizeof(destroy_arg));
281 destroy_arg.handle = create_arg.handle;
282 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
283err_fb:
284 free(fb);
285 return NULL;
286}
287
288static void
289drm_fb_destroy_dumb(struct drm_fb *fb)
290{
291 struct drm_mode_destroy_dumb destroy_arg;
292
293 if (!fb->map)
294 return;
295
296 if (fb->fb_id)
297 drmModeRmFB(fb->fd, fb->fb_id);
298
299 weston_buffer_reference(&fb->buffer_ref, NULL);
300
301 munmap(fb->map, fb->size);
302
303 memset(&destroy_arg, 0, sizeof(destroy_arg));
304 destroy_arg.handle = fb->handle;
305 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
306
307 free(fb);
308}
309
310static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500311drm_fb_get_from_bo(struct gbm_bo *bo,
312 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300313{
314 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200315 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200316 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300317 int ret;
318
319 if (fb)
320 return fb;
321
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200322 fb = calloc(1, sizeof *fb);
323 if (!fb)
324 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300325
326 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300327
328 width = gbm_bo_get_width(bo);
329 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200330 fb->stride = gbm_bo_get_stride(bo);
331 fb->handle = gbm_bo_get_handle(bo).u32;
332 fb->size = fb->stride * height;
333 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300334
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200335 if (compositor->min_width > width || width > compositor->max_width ||
336 compositor->min_height > height ||
337 height > compositor->max_height) {
338 weston_log("bo geometry out of bounds\n");
339 goto err_free;
340 }
341
342 ret = -1;
343
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200344 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200345 handles[0] = fb->handle;
346 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200347 offsets[0] = 0;
348
349 ret = drmModeAddFB2(compositor->drm.fd, width, height,
350 format, handles, pitches, offsets,
351 &fb->fb_id, 0);
352 if (ret) {
353 weston_log("addfb2 failed: %m\n");
354 compositor->no_addfb2 = 1;
355 compositor->sprites_are_broken = 1;
356 }
357 }
358
359 if (ret)
360 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200361 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200362
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300363 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200364 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200365 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300366 }
367
368 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
369
370 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200371
372err_free:
373 free(fb);
374 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300375}
376
377static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200378drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
379{
Pekka Paalanende685b82012-12-04 15:58:12 +0200380 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200381
382 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200383
Pekka Paalanende685b82012-12-04 15:58:12 +0200384 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200385}
386
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200387static void
388drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
389{
390 if (!fb)
391 return;
392
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200393 if (fb->map &&
394 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200395 drm_fb_destroy_dumb(fb);
396 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200397 if (fb->is_client_buffer)
398 gbm_bo_destroy(fb->bo);
399 else
400 gbm_surface_release_buffer(output->surface,
401 output->current->bo);
402 }
403}
404
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500405static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200406drm_output_check_scanout_format(struct drm_output *output,
407 struct weston_surface *es, struct gbm_bo *bo)
408{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200409 uint32_t format;
410 pixman_region32_t r;
411
412 format = gbm_bo_get_format(bo);
413
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500414 switch (format) {
415 case GBM_FORMAT_XRGB8888:
416 return format;
417 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200418 /* We can only scanout an ARGB buffer if the surface's
419 * opaque region covers the whole output */
420 pixman_region32_init(&r);
421 pixman_region32_subtract(&r, &output->base.region,
422 &es->opaque);
423
424 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500425 format = GBM_FORMAT_XRGB8888;
426 else
427 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200428
429 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200430
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500431 return format;
432 default:
433 return 0;
434 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200435}
436
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400437static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400438drm_output_prepare_scanout_surface(struct weston_output *_output,
439 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500440{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400441 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500442 struct drm_compositor *c =
443 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200444 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300445 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500446 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500447
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500448 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200449 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200450 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200451 buffer->width != output->base.current->width ||
452 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200453 output->base.transform != es->buffer_transform ||
454 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400455 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500456
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400457 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200458 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500459
Rob Bradford9b101872012-09-14 23:25:41 +0100460 /* Unable to use the buffer for scanout */
461 if (!bo)
462 return NULL;
463
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500464 format = drm_output_check_scanout_format(output, es, bo);
465 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300466 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400467 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300468 }
469
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500470 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300471 if (!output->next) {
472 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400473 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300474 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500475
Pekka Paalanende685b82012-12-04 15:58:12 +0200476 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500477
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400478 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500479}
480
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500481static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200482drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400483{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200484 struct drm_compositor *c =
485 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300486 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400487
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200488 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400489
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300490 bo = gbm_surface_lock_front_buffer(output->surface);
491 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200492 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400493 return;
494 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300495
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500496 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300497 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200498 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300499 gbm_surface_release_buffer(output->surface, bo);
500 return;
501 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400502}
503
504static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200505drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
506{
507 struct weston_compositor *ec = output->base.compositor;
508 pixman_region32_t total_damage, previous_damage;
509
510 pixman_region32_init(&total_damage);
511 pixman_region32_init(&previous_damage);
512
513 pixman_region32_copy(&previous_damage, damage);
514
515 pixman_region32_union(&total_damage, damage, &output->previous_damage);
516 pixman_region32_copy(&output->previous_damage, &previous_damage);
517
518 output->current_image ^= 1;
519
520 output->next = output->dumb[output->current_image];
521 pixman_renderer_output_set_buffer(&output->base,
522 output->image[output->current_image]);
523
524 ec->renderer->repaint_output(&output->base, &total_damage);
525
526 pixman_region32_fini(&total_damage);
527 pixman_region32_fini(&previous_damage);
528}
529
530static void
531drm_output_render(struct drm_output *output, pixman_region32_t *damage)
532{
533 struct drm_compositor *c =
534 (struct drm_compositor *) output->base.compositor;
535
536 if (c->use_pixman)
537 drm_output_render_pixman(output, damage);
538 else
539 drm_output_render_gl(output, damage);
540
541 pixman_region32_subtract(&c->base.primary_plane.damage,
542 &c->base.primary_plane.damage, damage);
543}
544
545static void
Richard Hughese7299962013-05-01 21:52:12 +0100546drm_output_set_gamma(struct weston_output *output_base,
547 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
548{
549 int rc;
550 struct drm_output *output = (struct drm_output *) output_base;
551 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
552
553 /* check */
554 if (output_base->gamma_size != size)
555 return;
556 if (!output->original_crtc)
557 return;
558
559 rc = drmModeCrtcSetGamma(compositor->drm.fd,
560 output->crtc_id,
561 size, r, g, b);
562 if (rc)
563 weston_log("set gamma failed: %m\n");
564}
565
566static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500567drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400568 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100569{
570 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500571 struct drm_compositor *compositor =
572 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500573 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400574 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500575 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100576
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300577 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400578 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300579 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400580 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100581
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400582 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300583 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400584 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300585 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400586 &output->connector_id, 1,
587 &mode->mode_info);
588 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200589 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400590 return;
591 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300592 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200593 }
594
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500595 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300596 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500597 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200598 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500599 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500600 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100601
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300602 output->page_flip_pending = 1;
603
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400604 drm_output_set_cursor(output);
605
Jesse Barnes58ef3792012-02-23 09:45:49 -0500606 /*
607 * Now, update all the sprite surfaces
608 */
609 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200610 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500611 drmVBlank vbl = {
612 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
613 .request.sequence = 1,
614 };
615
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200616 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200617 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500618 continue;
619
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200620 if (s->next && !compositor->sprites_hidden)
621 fb_id = s->next->fb_id;
622
Jesse Barnes58ef3792012-02-23 09:45:49 -0500623 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200624 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500625 s->dest_x, s->dest_y,
626 s->dest_w, s->dest_h,
627 s->src_x, s->src_y,
628 s->src_w, s->src_h);
629 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200630 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500631 ret, strerror(errno));
632
Rob Clark5ca1a472012-08-08 20:27:37 -0500633 if (output->pipe > 0)
634 vbl.request.type |= DRM_VBLANK_SECONDARY;
635
Jesse Barnes58ef3792012-02-23 09:45:49 -0500636 /*
637 * Queue a vblank signal so we know when the surface
638 * becomes active on the display or has been replaced.
639 */
640 vbl.request.signal = (unsigned long)s;
641 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
642 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200643 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500644 ret, strerror(errno));
645 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300646
647 s->output = output;
648 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500649 }
650
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500651 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400652}
653
654static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200655drm_output_start_repaint_loop(struct weston_output *output_base)
656{
657 struct drm_output *output = (struct drm_output *) output_base;
658 struct drm_compositor *compositor = (struct drm_compositor *)
659 output_base->compositor;
660 uint32_t fb_id;
661
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300662 struct timespec ts;
663
664 if (!output->current) {
665 /* We can't page flip if there's no mode set */
666 uint32_t msec;
667
668 clock_gettime(compositor->clock, &ts);
669 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
670 weston_output_finish_frame(output_base, msec);
671 return;
672 }
673
674 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200675
676 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
677 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
678 weston_log("queueing pageflip failed: %m\n");
679 return;
680 }
681}
682
683static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500684vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
685 void *data)
686{
687 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300688 struct drm_output *output = s->output;
689 uint32_t msecs;
690
691 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500692
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200693 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200694 s->current = s->next;
695 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300696
697 if (!output->page_flip_pending) {
698 msecs = sec * 1000 + usec / 1000;
699 weston_output_finish_frame(&output->base, msecs);
700 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500701}
702
703static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400704page_flip_handler(int fd, unsigned int frame,
705 unsigned int sec, unsigned int usec, void *data)
706{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200707 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400708 uint32_t msecs;
709
Jonas Ådahle5a12252013-04-05 23:07:11 +0200710 /* We don't set page_flip_pending on start_repaint_loop, in that case
711 * we just want to page flip to the current buffer to get an accurate
712 * timestamp */
713 if (output->page_flip_pending) {
714 drm_output_release_fb(output, output->current);
715 output->current = output->next;
716 output->next = NULL;
717 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300718
Jonas Ådahle5a12252013-04-05 23:07:11 +0200719 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400720
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300721 if (!output->vblank_pending) {
722 msecs = sec * 1000 + usec / 1000;
723 weston_output_finish_frame(&output->base, msecs);
724 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200725}
726
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500727static uint32_t
728drm_output_check_sprite_format(struct drm_sprite *s,
729 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500730{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500731 uint32_t i, format;
732
733 format = gbm_bo_get_format(bo);
734
735 if (format == GBM_FORMAT_ARGB8888) {
736 pixman_region32_t r;
737
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500738 pixman_region32_init_rect(&r, 0, 0,
739 es->geometry.width,
740 es->geometry.height);
741 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500742
743 if (!pixman_region32_not_empty(&r))
744 format = GBM_FORMAT_XRGB8888;
745
746 pixman_region32_fini(&r);
747 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500748
749 for (i = 0; i < s->count_formats; i++)
750 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500751 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500752
753 return 0;
754}
755
756static int
757drm_surface_transform_supported(struct weston_surface *es)
758{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500759 return !es->transform.enabled ||
760 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500761}
762
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400763static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500764drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400765 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500766{
767 struct weston_compositor *ec = output_base->compositor;
768 struct drm_compositor *c =(struct drm_compositor *) ec;
769 struct drm_sprite *s;
770 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500771 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500772 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200773 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500774 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400775 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500776
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200777 if (c->gbm == NULL)
778 return NULL;
779
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200780 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200781 return NULL;
782
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200783 if (es->buffer_scale != output_base->scale)
784 return NULL;
785
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500786 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400787 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500788
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300789 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400790 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300791
Pekka Paalanende685b82012-12-04 15:58:12 +0200792 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400793 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500794
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200795 if (es->alpha != 1.0f)
796 return NULL;
797
Pekka Paalanende685b82012-12-04 15:58:12 +0200798 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500799 return NULL;
800
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400802 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500803
Jesse Barnes58ef3792012-02-23 09:45:49 -0500804 wl_list_for_each(s, &c->sprite_list, link) {
805 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
806 continue;
807
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200808 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500809 found = 1;
810 break;
811 }
812 }
813
814 /* No sprites available */
815 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400816 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500817
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400818 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200819 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400820 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400821 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400822
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500823 format = drm_output_check_sprite_format(s, es, bo);
824 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200825 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400826 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500827 }
828
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200829 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200830 if (!s->next) {
831 gbm_bo_destroy(bo);
832 return NULL;
833 }
834
Pekka Paalanende685b82012-12-04 15:58:12 +0200835 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500836
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400837 box = pixman_region32_extents(&es->transform.boundingbox);
838 s->plane.x = box->x1;
839 s->plane.y = box->y1;
840
Jesse Barnes58ef3792012-02-23 09:45:49 -0500841 /*
842 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200843 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500844 * for us already).
845 */
846 pixman_region32_init(&dest_rect);
847 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
848 &output_base->region);
849 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
850 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200851 tbox = weston_transformed_rect(output_base->width,
852 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200853 output_base->transform,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200854 output_base->scale,
855 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200856 s->dest_x = tbox.x1;
857 s->dest_y = tbox.y1;
858 s->dest_w = tbox.x2 - tbox.x1;
859 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500860 pixman_region32_fini(&dest_rect);
861
862 pixman_region32_init(&src_rect);
863 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
864 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500865 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400866
867 weston_surface_from_global_fixed(es,
868 wl_fixed_from_int(box->x1),
869 wl_fixed_from_int(box->y1),
870 &sx1, &sy1);
871 weston_surface_from_global_fixed(es,
872 wl_fixed_from_int(box->x2),
873 wl_fixed_from_int(box->y2),
874 &sx2, &sy2);
875
876 if (sx1 < 0)
877 sx1 = 0;
878 if (sy1 < 0)
879 sy1 = 0;
880 if (sx2 > wl_fixed_from_int(es->geometry.width))
881 sx2 = wl_fixed_from_int(es->geometry.width);
882 if (sy2 > wl_fixed_from_int(es->geometry.height))
883 sy2 = wl_fixed_from_int(es->geometry.height);
884
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200885 tbox.x1 = sx1;
886 tbox.y1 = sy1;
887 tbox.x2 = sx2;
888 tbox.y2 = sy2;
889
890 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
891 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200892 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200893
894 s->src_x = tbox.x1 << 8;
895 s->src_y = tbox.y1 << 8;
896 s->src_w = (tbox.x2 - tbox.x1) << 8;
897 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500898 pixman_region32_fini(&src_rect);
899
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400900 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500901}
902
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400903static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400904drm_output_prepare_cursor_surface(struct weston_output *output_base,
905 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500906{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400907 struct drm_compositor *c =
908 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400909 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400910
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200911 if (c->gbm == NULL)
912 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200913 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
914 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400915 if (output->cursor_surface)
916 return NULL;
917 if (es->output_mask != (1u << output_base->id))
918 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500919 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400920 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200921 if (es->buffer_ref.buffer == NULL ||
922 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400923 es->geometry.width > 64 || es->geometry.height > 64)
924 return NULL;
925
926 output->cursor_surface = es;
927
928 return &output->cursor_plane;
929}
930
931static void
932drm_output_set_cursor(struct drm_output *output)
933{
934 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400935 struct drm_compositor *c =
936 (struct drm_compositor *) output->base.compositor;
937 EGLint handle, stride;
938 struct gbm_bo *bo;
939 uint32_t buf[64 * 64];
940 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400941 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500942
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400943 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400944 if (es == NULL) {
945 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
946 return;
947 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500948
Pekka Paalanende685b82012-12-04 15:58:12 +0200949 if (es->buffer_ref.buffer &&
950 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400951 pixman_region32_fini(&output->cursor_plane.damage);
952 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400953 output->current_cursor ^= 1;
954 bo = output->cursor_bo[output->current_cursor];
955 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200956 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
957 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400958 for (i = 0; i < es->geometry.height; i++)
959 memcpy(buf + i * 64, s + i * stride,
960 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500961
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400962 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300963 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400964
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400965 handle = gbm_bo_get_handle(bo).s32;
966 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500967 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300968 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500969 c->cursors_are_broken = 1;
970 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400971 }
972
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200973 x = (es->geometry.x - output->base.x) * output->base.scale;
974 y = (es->geometry.y - output->base.y) * output->base.scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400975 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500976 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400977 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500978 c->cursors_are_broken = 1;
979 }
980
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400981 output->cursor_plane.x = x;
982 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400983 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500984}
985
Jesse Barnes58ef3792012-02-23 09:45:49 -0500986static void
987drm_assign_planes(struct weston_output *output)
988{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400989 struct drm_compositor *c =
990 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400991 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500992 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400993 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500994
995 /*
996 * Find a surface for each sprite in the output using some heuristics:
997 * 1) size
998 * 2) frequency of update
999 * 3) opacity (though some hw might support alpha blending)
1000 * 4) clipping (this can be fixed with color keys)
1001 *
1002 * The idea is to save on blitting since this should save power.
1003 * If we can get a large video surface on the sprite for example,
1004 * the main display surface may not need to update at all, and
1005 * the client buffer can be used directly for the sprite surface
1006 * as we do for flipping full screen surfaces.
1007 */
1008 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001009 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001010 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001011 /* test whether this buffer can ever go into a plane:
1012 * non-shm, or small enough to be a cursor
1013 */
1014 if ((es->buffer_ref.buffer &&
1015 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
1016 (es->geometry.width <= 64 && es->geometry.height <= 64))
1017 es->keep_buffer = 1;
1018 else
1019 es->keep_buffer = 0;
1020
Jesse Barnes58ef3792012-02-23 09:45:49 -05001021 pixman_region32_init(&surface_overlap);
1022 pixman_region32_intersect(&surface_overlap, &overlap,
1023 &es->transform.boundingbox);
1024
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001025 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001026 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001027 next_plane = primary;
1028 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001029 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001030 if (next_plane == NULL)
1031 next_plane = drm_output_prepare_scanout_surface(output, es);
1032 if (next_plane == NULL)
1033 next_plane = drm_output_prepare_overlay_surface(output, es);
1034 if (next_plane == NULL)
1035 next_plane = primary;
1036 weston_surface_move_to_plane(es, next_plane);
1037 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001038 pixman_region32_union(&overlap, &overlap,
1039 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001040
Jesse Barnes58ef3792012-02-23 09:45:49 -05001041 pixman_region32_fini(&surface_overlap);
1042 }
1043 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001044}
1045
Matt Roper361d2ad2011-08-29 13:52:23 -07001046static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001047drm_output_fini_pixman(struct drm_output *output);
1048
1049static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001050drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001051{
1052 struct drm_output *output = (struct drm_output *) output_base;
1053 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001054 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001055 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001056
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001057 if (output->backlight)
1058 backlight_destroy(output->backlight);
1059
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001060 drmModeFreeProperty(output->dpms_prop);
1061
Matt Roper361d2ad2011-08-29 13:52:23 -07001062 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001063 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001064
1065 /* Restore original CRTC state */
1066 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001067 origcrtc->x, origcrtc->y,
1068 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001069 drmModeFreeCrtc(origcrtc);
1070
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001071 c->crtc_allocator &= ~(1 << output->crtc_id);
1072 c->connector_allocator &= ~(1 << output->connector_id);
1073
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001074 if (c->use_pixman) {
1075 drm_output_fini_pixman(output);
1076 } else {
1077 gl_renderer_output_destroy(output_base);
1078 gbm_surface_destroy(output->surface);
1079 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001080
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001081 weston_plane_release(&output->fb_plane);
1082 weston_plane_release(&output->cursor_plane);
1083
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001084 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001085 wl_list_remove(&output->base.link);
1086
Matt Roper361d2ad2011-08-29 13:52:23 -07001087 free(output);
1088}
1089
Alex Wub7b8bda2012-04-17 17:20:48 +08001090static struct drm_mode *
1091choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1092{
1093 struct drm_mode *tmp_mode = NULL, *mode;
1094
1095 if (output->base.current->width == target_mode->width &&
1096 output->base.current->height == target_mode->height &&
1097 (output->base.current->refresh == target_mode->refresh ||
1098 target_mode->refresh == 0))
1099 return (struct drm_mode *)output->base.current;
1100
1101 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1102 if (mode->mode_info.hdisplay == target_mode->width &&
1103 mode->mode_info.vdisplay == target_mode->height) {
1104 if (mode->mode_info.vrefresh == target_mode->refresh ||
1105 target_mode->refresh == 0) {
1106 return mode;
1107 } else if (!tmp_mode)
1108 tmp_mode = mode;
1109 }
1110 }
1111
1112 return tmp_mode;
1113}
1114
1115static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001116drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001117static int
1118drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001119
1120static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001121drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1122{
1123 struct drm_output *output;
1124 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001125 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001126
1127 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001128 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001129 return -1;
1130 }
1131
1132 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001133 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001134 return -1;
1135 }
1136
1137 ec = (struct drm_compositor *)output_base->compositor;
1138 output = (struct drm_output *)output_base;
1139 drm_mode = choose_mode (output, mode);
1140
1141 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001142 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001143 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001144 }
1145
1146 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001147 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001148
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001149 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001150
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001151 output->base.current = &drm_mode->base;
1152 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001153 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1154
Alex Wub7b8bda2012-04-17 17:20:48 +08001155 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001156 drm_output_release_fb(output, output->current);
1157 drm_output_release_fb(output, output->next);
1158 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001159
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001160 if (ec->use_pixman) {
1161 drm_output_fini_pixman(output);
1162 if (drm_output_init_pixman(output, ec) < 0) {
1163 weston_log("failed to init output pixman state with "
1164 "new mode\n");
1165 return -1;
1166 }
1167 } else {
1168 gl_renderer_output_destroy(&output->base);
1169 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001170
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001171 if (drm_output_init_egl(output, ec) < 0) {
1172 weston_log("failed to init output egl state with "
1173 "new mode");
1174 return -1;
1175 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001176 }
1177
Alex Wub7b8bda2012-04-17 17:20:48 +08001178 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001179}
1180
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001181static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001182on_drm_input(int fd, uint32_t mask, void *data)
1183{
1184 drmEventContext evctx;
1185
1186 memset(&evctx, 0, sizeof evctx);
1187 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1188 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001189 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001190 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001191
1192 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001193}
1194
1195static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001196init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001197{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001198 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001199 uint64_t cap;
1200 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001201
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001202 sysnum = udev_device_get_sysnum(device);
1203 if (sysnum)
1204 ec->drm.id = atoi(sysnum);
1205 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001206 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001207 return -1;
1208 }
1209
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001210 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001211 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001212 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001213 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001214 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001215 udev_device_get_devnode(device));
1216 return -1;
1217 }
1218
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001219 weston_log("using %s\n", filename);
1220
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001221 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001222
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001223 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1224 if (ret == 0 && cap == 1)
1225 ec->clock = CLOCK_MONOTONIC;
1226 else
1227 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001228
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001229 return 0;
1230}
1231
1232static int
1233init_egl(struct drm_compositor *ec)
1234{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001235 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001236
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001237 if (!ec->gbm)
1238 return -1;
1239
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001240 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001241 NULL) < 0) {
1242 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001243 return -1;
1244 }
1245
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001246 return 0;
1247}
1248
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001249static int
1250init_pixman(struct drm_compositor *ec)
1251{
1252 return pixman_renderer_init(&ec->base);
1253}
1254
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001255static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001256drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001257{
1258 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001259 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001260
1261 mode = malloc(sizeof *mode);
1262 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001263 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001264
1265 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001266 mode->base.width = info->hdisplay;
1267 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001268
1269 /* Calculate higher precision (mHz) refresh rate */
1270 refresh = (info->clock * 1000000LL / info->htotal +
1271 info->vtotal / 2) / info->vtotal;
1272
1273 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1274 refresh *= 2;
1275 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1276 refresh /= 2;
1277 if (info->vscan > 1)
1278 refresh /= info->vscan;
1279
1280 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001281 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001282
1283 if (info->type & DRM_MODE_TYPE_PREFERRED)
1284 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1285
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001286 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1287
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001288 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001289}
1290
1291static int
1292drm_subpixel_to_wayland(int drm_value)
1293{
1294 switch (drm_value) {
1295 default:
1296 case DRM_MODE_SUBPIXEL_UNKNOWN:
1297 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1298 case DRM_MODE_SUBPIXEL_NONE:
1299 return WL_OUTPUT_SUBPIXEL_NONE;
1300 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1301 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1302 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1303 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1304 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1305 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1306 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1307 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1308 }
1309}
1310
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001311/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001312static uint32_t
1313drm_get_backlight(struct drm_output *output)
1314{
1315 long brightness, max_brightness, norm;
1316
1317 brightness = backlight_get_brightness(output->backlight);
1318 max_brightness = backlight_get_max_brightness(output->backlight);
1319
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001320 /* convert it on a scale of 0 to 255 */
1321 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001322
1323 return (uint32_t) norm;
1324}
1325
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001326/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001327static void
1328drm_set_backlight(struct weston_output *output_base, uint32_t value)
1329{
1330 struct drm_output *output = (struct drm_output *) output_base;
1331 long max_brightness, new_brightness;
1332
1333 if (!output->backlight)
1334 return;
1335
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001336 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001337 return;
1338
1339 max_brightness = backlight_get_max_brightness(output->backlight);
1340
1341 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001342 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001343
1344 backlight_set_brightness(output->backlight, new_brightness);
1345}
1346
1347static drmModePropertyPtr
1348drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1349{
1350 drmModePropertyPtr props;
1351 int i;
1352
1353 for (i = 0; i < connector->count_props; i++) {
1354 props = drmModeGetProperty(fd, connector->props[i]);
1355 if (!props)
1356 continue;
1357
1358 if (!strcmp(props->name, name))
1359 return props;
1360
1361 drmModeFreeProperty(props);
1362 }
1363
1364 return NULL;
1365}
1366
1367static void
1368drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1369{
1370 struct drm_output *output = (struct drm_output *) output_base;
1371 struct weston_compositor *ec = output_base->compositor;
1372 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001373
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001374 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001375 return;
1376
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001377 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1378 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001379}
1380
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001381static const char *connector_type_names[] = {
1382 "None",
1383 "VGA",
1384 "DVI",
1385 "DVI",
1386 "DVI",
1387 "Composite",
1388 "TV",
1389 "LVDS",
1390 "CTV",
1391 "DIN",
1392 "DP",
1393 "HDMI",
1394 "HDMI",
1395 "TV",
1396 "eDP",
1397};
1398
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001399static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001400find_crtc_for_connector(struct drm_compositor *ec,
1401 drmModeRes *resources, drmModeConnector *connector)
1402{
1403 drmModeEncoder *encoder;
1404 uint32_t possible_crtcs;
1405 int i, j;
1406
1407 for (j = 0; j < connector->count_encoders; j++) {
1408 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1409 if (encoder == NULL) {
1410 weston_log("Failed to get encoder.\n");
1411 return -1;
1412 }
1413 possible_crtcs = encoder->possible_crtcs;
1414 drmModeFreeEncoder(encoder);
1415
1416 for (i = 0; i < resources->count_crtcs; i++) {
1417 if (possible_crtcs & (1 << i) &&
1418 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1419 return i;
1420 }
1421 }
1422
1423 return -1;
1424}
1425
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001426/* Init output state that depends on gl or gbm */
1427static int
1428drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1429{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001430 int i, flags;
1431
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001432 output->surface = gbm_surface_create(ec->gbm,
Alexander Larsson0b135062013-05-28 16:23:36 +02001433 output->base.current->width,
1434 output->base.current->height,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001435 GBM_FORMAT_XRGB8888,
1436 GBM_BO_USE_SCANOUT |
1437 GBM_BO_USE_RENDERING);
1438 if (!output->surface) {
1439 weston_log("failed to create gbm surface\n");
1440 return -1;
1441 }
1442
1443 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001444 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001445 gbm_surface_destroy(output->surface);
1446 return -1;
1447 }
1448
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001449 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1450
1451 for (i = 0; i < 2; i++) {
1452 if (output->cursor_bo[i])
1453 continue;
1454
1455 output->cursor_bo[i] =
1456 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1457 flags);
1458 }
1459
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001460 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1461 weston_log("cursor buffers unavailable, using gl cursors\n");
1462 ec->cursors_are_broken = 1;
1463 }
1464
1465 return 0;
1466}
1467
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001468static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001469drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1470{
1471 int w = output->base.current->width;
1472 int h = output->base.current->height;
1473 unsigned int i;
1474
1475 /* FIXME error checking */
1476
1477 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001478 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001479 if (!output->dumb[i])
1480 goto err;
1481
1482 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001483 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001484 output->dumb[i]->map,
1485 output->dumb[i]->stride);
1486 if (!output->image[i])
1487 goto err;
1488 }
1489
1490 if (pixman_renderer_output_create(&output->base) < 0)
1491 goto err;
1492
1493 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001494 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001495
1496 return 0;
1497
1498err:
1499 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1500 if (output->dumb[i])
1501 drm_fb_destroy_dumb(output->dumb[i]);
1502 if (output->image[i])
1503 pixman_image_unref(output->image[i]);
1504
1505 output->dumb[i] = NULL;
1506 output->image[i] = NULL;
1507 }
1508
1509 return -1;
1510}
1511
1512static void
1513drm_output_fini_pixman(struct drm_output *output)
1514{
1515 unsigned int i;
1516
1517 pixman_renderer_output_destroy(&output->base);
1518 pixman_region32_fini(&output->previous_damage);
1519
1520 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1521 drm_fb_destroy_dumb(output->dumb[i]);
1522 pixman_image_unref(output->image[i]);
1523 output->dumb[i] = NULL;
1524 output->image[i] = NULL;
1525 }
1526}
1527
Richard Hughes2b2092a2013-04-24 14:58:02 +01001528static void
1529edid_parse_string(const uint8_t *data, char text[])
1530{
1531 int i;
1532 int replaced = 0;
1533
1534 /* this is always 12 bytes, but we can't guarantee it's null
1535 * terminated or not junk. */
1536 strncpy(text, (const char *) data, 12);
1537
1538 /* remove insane chars */
1539 for (i = 0; text[i] != '\0'; i++) {
1540 if (text[i] == '\n' ||
1541 text[i] == '\r') {
1542 text[i] = '\0';
1543 break;
1544 }
1545 }
1546
1547 /* ensure string is printable */
1548 for (i = 0; text[i] != '\0'; i++) {
1549 if (!isprint(text[i])) {
1550 text[i] = '-';
1551 replaced++;
1552 }
1553 }
1554
1555 /* if the string is random junk, ignore the string */
1556 if (replaced > 4)
1557 text[0] = '\0';
1558}
1559
1560#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1561#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1562#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1563#define EDID_OFFSET_DATA_BLOCKS 0x36
1564#define EDID_OFFSET_LAST_BLOCK 0x6c
1565#define EDID_OFFSET_PNPID 0x08
1566#define EDID_OFFSET_SERIAL 0x0c
1567
1568static int
1569edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1570{
1571 int i;
1572 uint32_t serial_number;
1573
1574 /* check header */
1575 if (length < 128)
1576 return -1;
1577 if (data[0] != 0x00 || data[1] != 0xff)
1578 return -1;
1579
1580 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1581 * /--08--\/--09--\
1582 * 7654321076543210
1583 * |\---/\---/\---/
1584 * R C1 C2 C3 */
1585 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1586 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1587 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1588 edid->pnp_id[3] = '\0';
1589
1590 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1591 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1592 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1593 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1594 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1595 if (serial_number > 0)
1596 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1597
1598 /* parse EDID data */
1599 for (i = EDID_OFFSET_DATA_BLOCKS;
1600 i <= EDID_OFFSET_LAST_BLOCK;
1601 i += 18) {
1602 /* ignore pixel clock data */
1603 if (data[i] != 0)
1604 continue;
1605 if (data[i+2] != 0)
1606 continue;
1607
1608 /* any useful blocks? */
1609 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1610 edid_parse_string(&data[i+5],
1611 edid->monitor_name);
1612 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1613 edid_parse_string(&data[i+5],
1614 edid->serial_number);
1615 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1616 edid_parse_string(&data[i+5],
1617 edid->eisa_id);
1618 }
1619 }
1620 return 0;
1621}
1622
1623static void
1624find_and_parse_output_edid(struct drm_compositor *ec,
1625 struct drm_output *output,
1626 drmModeConnector *connector)
1627{
1628 drmModePropertyBlobPtr edid_blob = NULL;
1629 drmModePropertyPtr property;
1630 int i;
1631 int rc;
1632
1633 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1634 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1635 if (!property)
1636 continue;
1637 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1638 !strcmp(property->name, "EDID")) {
1639 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1640 connector->prop_values[i]);
1641 }
1642 drmModeFreeProperty(property);
1643 }
1644 if (!edid_blob)
1645 return;
1646
1647 rc = edid_parse(&output->edid,
1648 edid_blob->data,
1649 edid_blob->length);
1650 if (!rc) {
1651 weston_log("EDID data '%s', '%s', '%s'\n",
1652 output->edid.pnp_id,
1653 output->edid.monitor_name,
1654 output->edid.serial_number);
1655 if (output->edid.pnp_id[0] != '\0')
1656 output->base.make = output->edid.pnp_id;
1657 if (output->edid.monitor_name[0] != '\0')
1658 output->base.model = output->edid.monitor_name;
1659 if (output->edid.serial_number[0] != '\0')
1660 output->base.serial_number = output->edid.serial_number;
1661 }
1662 drmModeFreePropertyBlob(edid_blob);
1663}
1664
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001665
1666
1667static int
1668parse_modeline(const char *s, drmModeModeInfo *mode)
1669{
1670 char hsync[16];
1671 char vsync[16];
1672 float fclock;
1673
1674 mode->type = DRM_MODE_TYPE_USERDEF;
1675 mode->hskew = 0;
1676 mode->vscan = 0;
1677 mode->vrefresh = 0;
1678 mode->flags = 0;
1679
1680 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
1681 &fclock,
1682 &mode->hdisplay,
1683 &mode->hsync_start,
1684 &mode->hsync_end,
1685 &mode->htotal,
1686 &mode->vdisplay,
1687 &mode->vsync_start,
1688 &mode->vsync_end,
1689 &mode->vtotal, hsync, vsync) != 11)
1690 return -1;
1691
1692 mode->clock = fclock * 1000;
1693 if (strcmp(hsync, "+hsync") == 0)
1694 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1695 else if (strcmp(hsync, "-hsync") == 0)
1696 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1697 else
1698 return -1;
1699
1700 if (strcmp(vsync, "+vsync") == 0)
1701 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1702 else if (strcmp(vsync, "-vsync") == 0)
1703 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1704 else
1705 return -1;
1706
1707 return 0;
1708}
1709
1710static uint32_t
1711parse_transform(const char *transform, const char *output_name)
1712{
1713 static const struct { const char *name; uint32_t token; } names[] = {
1714 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1715 { "90", WL_OUTPUT_TRANSFORM_90 },
1716 { "180", WL_OUTPUT_TRANSFORM_180 },
1717 { "270", WL_OUTPUT_TRANSFORM_270 },
1718 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1719 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1720 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1721 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1722 };
1723 unsigned int i;
1724
1725 for (i = 0; i < ARRAY_LENGTH(names); i++)
1726 if (strcmp(names[i].name, transform) == 0)
1727 return names[i].token;
1728
1729 weston_log("Invalid transform \"%s\" for output %s\n",
1730 transform, output_name);
1731
1732 return WL_OUTPUT_TRANSFORM_NORMAL;
1733}
1734
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001735static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001736create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001737 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001738 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001739 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001740{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001741 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001742 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1743 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001744 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001745 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001746 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001747 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001748 int i, width, height, scale;
1749 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001750 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001751 enum output_config config;
1752 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001753
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001754 i = find_crtc_for_connector(ec, resources, connector);
1755 if (i < 0) {
1756 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001757 return -1;
1758 }
1759
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001760 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001761 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001762 return -1;
1763
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001764 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001765 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1766 output->base.make = "unknown";
1767 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001768 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001769 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001770
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001771 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1772 type_name = connector_type_names[connector->connector_type];
1773 else
1774 type_name = "UNKNOWN";
1775 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001776 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001777
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001778 section = weston_config_get_section(ec->base.config, "output", "name",
1779 output->base.name);
1780 weston_config_section_get_string(section, "mode", &s, "preferred");
1781 if (strcmp(s, "off") == 0)
1782 config = OUTPUT_CONFIG_OFF;
1783 else if (strcmp(s, "preferred") == 0)
1784 config = OUTPUT_CONFIG_PREFERRED;
1785 else if (strcmp(s, "current") == 0)
1786 config = OUTPUT_CONFIG_CURRENT;
1787 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1788 config = OUTPUT_CONFIG_MODE;
1789 else if (parse_modeline(s, &modeline) == 0)
1790 config = OUTPUT_CONFIG_MODELINE;
1791 else {
1792 weston_log("Invalid mode \"%s\" for output %s\n",
1793 s, output->base.name);
1794 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001795 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001796 free(s);
1797
1798 weston_config_section_get_int(section, "scale", &scale, 1);
1799 weston_config_section_get_string(section, "transform", &s, "normal");
1800 transform = parse_transform(s, output->base.name);
1801 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001802
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001803 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001804 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001805 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001806 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001807 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001808
Matt Roper361d2ad2011-08-29 13:52:23 -07001809 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001810 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001811
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001812 /* Get the current mode on the crtc that's currently driving
1813 * this connector. */
1814 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001815 memset(&crtc_mode, 0, sizeof crtc_mode);
1816 if (encoder != NULL) {
1817 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1818 drmModeFreeEncoder(encoder);
1819 if (crtc == NULL)
1820 goto err_free;
1821 if (crtc->mode_valid)
1822 crtc_mode = crtc->mode;
1823 drmModeFreeCrtc(crtc);
1824 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001825
David Herrmann0f0d54e2011-12-08 17:05:45 +01001826 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001827 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001828 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001829 goto err_free;
1830 }
1831
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001832 if (config == OUTPUT_CONFIG_OFF) {
1833 weston_log("Disabling output %s\n", output->base.name);
1834 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1835 0, 0, 0, 0, 0, NULL);
1836 goto err_free;
1837 }
1838
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001839 preferred = NULL;
1840 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001841 configured = NULL;
1842
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001843 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001844 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001845 width == drm_mode->base.width &&
1846 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001847 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001848 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001849 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001850 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001851 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001852 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001853
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001854 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001855 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001856 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001857 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001858 }
1859
Wang Quanxianacb805a2012-07-30 18:09:46 -04001860 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001861 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001862 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001863 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001864 }
1865
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001866 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001867 configured = current;
1868
Wang Quanxianacb805a2012-07-30 18:09:46 -04001869 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001870 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001871 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001872 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001873 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001874 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001875 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001876 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001877
1878 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001879 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001880 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001881 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001882
Wang Quanxianacb805a2012-07-30 18:09:46 -04001883 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1884
John Kåre Alsaker94659272012-11-13 19:10:18 +01001885 weston_output_init(&output->base, &ec->base, x, y,
1886 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001887 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001888
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001889 if (ec->use_pixman) {
1890 if (drm_output_init_pixman(output, ec) < 0) {
1891 weston_log("Failed to init output pixman state\n");
1892 goto err_output;
1893 }
1894 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001895 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001896 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001897 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001898
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001899 output->backlight = backlight_init(drm_device,
1900 connector->connector_type);
1901 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001902 weston_log("Initialized backlight, device %s\n",
1903 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001904 output->base.set_backlight = drm_set_backlight;
1905 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001906 } else {
1907 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001908 }
1909
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001910 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1911
Richard Hughes2b2092a2013-04-24 14:58:02 +01001912 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001913 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1914 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001915
Alex Wubd3354b2012-04-17 17:20:49 +08001916 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001917 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001918 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001919 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001920 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001921 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001922 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001923
Richard Hughese7299962013-05-01 21:52:12 +01001924 output->base.gamma_size = output->original_crtc->gamma_size;
1925 output->base.set_gamma = drm_output_set_gamma;
1926
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001927 weston_plane_init(&output->cursor_plane, 0, 0);
1928 weston_plane_init(&output->fb_plane, 0, 0);
1929
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001930 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1931 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1932 &ec->base.primary_plane);
1933
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001934 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001935 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001936 wl_list_for_each(m, &output->base.mode_list, link)
1937 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1938 m->width, m->height, m->refresh / 1000.0,
1939 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1940 ", preferred" : "",
1941 m->flags & WL_OUTPUT_MODE_CURRENT ?
1942 ", current" : "",
1943 connector->count_modes == 0 ?
1944 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001945
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001946 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001947
John Kåre Alsaker94659272012-11-13 19:10:18 +01001948err_output:
1949 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001950err_free:
1951 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1952 base.link) {
1953 wl_list_remove(&drm_mode->base.link);
1954 free(drm_mode);
1955 }
1956
1957 drmModeFreeCrtc(output->original_crtc);
1958 ec->crtc_allocator &= ~(1 << output->crtc_id);
1959 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001960 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001961
David Herrmann0f0d54e2011-12-08 17:05:45 +01001962 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001963}
1964
Jesse Barnes58ef3792012-02-23 09:45:49 -05001965static void
1966create_sprites(struct drm_compositor *ec)
1967{
1968 struct drm_sprite *sprite;
1969 drmModePlaneRes *plane_res;
1970 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001971 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001972
1973 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1974 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001975 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001976 strerror(errno));
1977 return;
1978 }
1979
1980 for (i = 0; i < plane_res->count_planes; i++) {
1981 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1982 if (!plane)
1983 continue;
1984
1985 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1986 plane->count_formats));
1987 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001988 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001989 __func__);
1990 free(plane);
1991 continue;
1992 }
1993
1994 memset(sprite, 0, sizeof *sprite);
1995
1996 sprite->possible_crtcs = plane->possible_crtcs;
1997 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001998 sprite->current = NULL;
1999 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002000 sprite->compositor = ec;
2001 sprite->count_formats = plane->count_formats;
2002 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002003 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002004 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002005 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002006 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2007 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002008
2009 wl_list_insert(&ec->sprite_list, &sprite->link);
2010 }
2011
2012 free(plane_res->planes);
2013 free(plane_res);
2014}
2015
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002016static void
2017destroy_sprites(struct drm_compositor *compositor)
2018{
2019 struct drm_sprite *sprite, *next;
2020 struct drm_output *output;
2021
2022 output = container_of(compositor->base.output_list.next,
2023 struct drm_output, base.link);
2024
2025 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2026 drmModeSetPlane(compositor->drm.fd,
2027 sprite->plane_id,
2028 output->crtc_id, 0, 0,
2029 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002030 drm_output_release_fb(output, sprite->current);
2031 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002032 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002033 free(sprite);
2034 }
2035}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002036
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002037static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002038create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002039 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002040{
2041 drmModeConnector *connector;
2042 drmModeRes *resources;
2043 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002044 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002045
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002046 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002047 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002048 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002049 return -1;
2050 }
2051
Jesse Barnes58ef3792012-02-23 09:45:49 -05002052 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002053 if (!ec->crtcs) {
2054 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002055 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002056 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002057
Rob Clark4339add2012-08-09 14:18:28 -05002058 ec->min_width = resources->min_width;
2059 ec->max_width = resources->max_width;
2060 ec->min_height = resources->min_height;
2061 ec->max_height = resources->max_height;
2062
Jesse Barnes58ef3792012-02-23 09:45:49 -05002063 ec->num_crtcs = resources->count_crtcs;
2064 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2065
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002066 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002067 connector = drmModeGetConnector(ec->drm.fd,
2068 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002069 if (connector == NULL)
2070 continue;
2071
2072 if (connector->connection == DRM_MODE_CONNECTED &&
2073 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002074 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002075 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002076 connector, x, y,
2077 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002078 drmModeFreeConnector(connector);
2079 continue;
2080 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002081
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002082 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002083 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002084 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002085 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002086
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002087 drmModeFreeConnector(connector);
2088 }
2089
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002090 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002091 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002092 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002093 return -1;
2094 }
2095
2096 drmModeFreeResources(resources);
2097
2098 return 0;
2099}
2100
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002101static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002102update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002103{
2104 drmModeConnector *connector;
2105 drmModeRes *resources;
2106 struct drm_output *output, *next;
2107 int x = 0, y = 0;
2108 int x_offset = 0, y_offset = 0;
2109 uint32_t connected = 0, disconnects = 0;
2110 int i;
2111
2112 resources = drmModeGetResources(ec->drm.fd);
2113 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002114 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002115 return;
2116 }
2117
2118 /* collect new connects */
2119 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002120 int connector_id = resources->connectors[i];
2121
2122 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002123 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002124 continue;
2125
David Herrmann7551cff2011-12-08 17:05:43 +01002126 if (connector->connection != DRM_MODE_CONNECTED) {
2127 drmModeFreeConnector(connector);
2128 continue;
2129 }
2130
Benjamin Franzke117483d2011-08-30 11:38:26 +02002131 connected |= (1 << connector_id);
2132
2133 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002134 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002135 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002136 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002137
2138 /* XXX: not yet needed, we die with 0 outputs */
2139 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002140 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002141 else
2142 x = 0;
2143 y = 0;
2144 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002145 connector, x, y,
2146 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002147 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002148
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002149 }
2150 drmModeFreeConnector(connector);
2151 }
2152 drmModeFreeResources(resources);
2153
2154 disconnects = ec->connector_allocator & ~connected;
2155 if (disconnects) {
2156 wl_list_for_each_safe(output, next, &ec->base.output_list,
2157 base.link) {
2158 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002159 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002160 output->base.x - x_offset,
2161 output->base.y - y_offset);
2162 }
2163
2164 if (disconnects & (1 << output->connector_id)) {
2165 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002166 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002167 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002168 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002169 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002170 }
2171 }
2172 }
2173
2174 /* FIXME: handle zero outputs, without terminating */
2175 if (ec->connector_allocator == 0)
2176 wl_display_terminate(ec->base.wl_display);
2177}
2178
2179static int
David Herrmannd7488c22012-03-11 20:05:21 +01002180udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002181{
David Herrmannd7488c22012-03-11 20:05:21 +01002182 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002183 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002184
2185 sysnum = udev_device_get_sysnum(device);
2186 if (!sysnum || atoi(sysnum) != ec->drm.id)
2187 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002188
David Herrmann6ac52db2012-03-11 20:05:22 +01002189 val = udev_device_get_property_value(device, "HOTPLUG");
2190 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002191 return 0;
2192
David Herrmann6ac52db2012-03-11 20:05:22 +01002193 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002194}
2195
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002196static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002197udev_drm_event(int fd, uint32_t mask, void *data)
2198{
2199 struct drm_compositor *ec = data;
2200 struct udev_device *event;
2201
2202 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002203
David Herrmannd7488c22012-03-11 20:05:21 +01002204 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002205 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002206
2207 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002208
2209 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002210}
2211
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002212static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002213drm_restore(struct weston_compositor *ec)
2214{
2215 struct drm_compositor *d = (struct drm_compositor *) ec;
2216
2217 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2218 weston_log("failed to drop master: %m\n");
2219 tty_reset(d->tty);
2220}
2221
2222static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002223drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002224{
2225 struct drm_compositor *d = (struct drm_compositor *) ec;
2226
Rob Bradfordd355b802013-05-31 18:09:55 +01002227 udev_input_destroy(&d->input);
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øgsberg85fd3272012-02-23 21:45:32 -05002284 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002285 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002286
2287 switch (event) {
2288 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002289 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002290 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002291 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002292 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002293 wl_display_terminate(compositor->wl_display);
2294 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002295 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002296 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002297 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002298 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002299 break;
2300 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002301 weston_log("leaving VT\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002302 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002303
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002304 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002305 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002306 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002307
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002308 /* If we have a repaint scheduled (either from a
2309 * pending pageflip or the idle handler), make sure we
2310 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002311 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002312 * further attemps at repainting. When we switch
2313 * back, we schedule a repaint, which will process
2314 * pending frame callbacks. */
2315
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002316 wl_list_for_each(output, &ec->base.output_list, base.link) {
2317 output->base.repaint_needed = 0;
2318 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002319 }
2320
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002321 output = container_of(ec->base.output_list.next,
2322 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002323
2324 wl_list_for_each(sprite, &ec->sprite_list, link)
2325 drmModeSetPlane(ec->drm.fd,
2326 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002327 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002328 0, 0, 0, 0, 0, 0, 0, 0);
2329
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002330 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002331 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002332
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002333 break;
2334 };
2335}
2336
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002337static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002338switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002339{
2340 struct drm_compositor *ec = data;
2341
Daniel Stone325fc2d2012-05-30 16:31:58 +01002342 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002343}
2344
David Herrmann0af066f2012-10-29 19:21:16 +01002345/*
2346 * Find primary GPU
2347 * Some systems may have multiple DRM devices attached to a single seat. This
2348 * function loops over all devices and tries to find a PCI device with the
2349 * boot_vga sysfs attribute set to 1.
2350 * If no such device is found, the first DRM device reported by udev is used.
2351 */
2352static struct udev_device*
2353find_primary_gpu(struct drm_compositor *ec, const char *seat)
2354{
2355 struct udev_enumerate *e;
2356 struct udev_list_entry *entry;
2357 const char *path, *device_seat, *id;
2358 struct udev_device *device, *drm_device, *pci;
2359
2360 e = udev_enumerate_new(ec->udev);
2361 udev_enumerate_add_match_subsystem(e, "drm");
2362 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2363
2364 udev_enumerate_scan_devices(e);
2365 drm_device = NULL;
2366 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2367 path = udev_list_entry_get_name(entry);
2368 device = udev_device_new_from_syspath(ec->udev, path);
2369 if (!device)
2370 continue;
2371 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2372 if (!device_seat)
2373 device_seat = default_seat;
2374 if (strcmp(device_seat, seat)) {
2375 udev_device_unref(device);
2376 continue;
2377 }
2378
2379 pci = udev_device_get_parent_with_subsystem_devtype(device,
2380 "pci", NULL);
2381 if (pci) {
2382 id = udev_device_get_sysattr_value(pci, "boot_vga");
2383 if (id && !strcmp(id, "1")) {
2384 if (drm_device)
2385 udev_device_unref(drm_device);
2386 drm_device = device;
2387 break;
2388 }
2389 }
2390
2391 if (!drm_device)
2392 drm_device = device;
2393 else
2394 udev_device_unref(device);
2395 }
2396
2397 udev_enumerate_unref(e);
2398 return drm_device;
2399}
2400
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002401static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002402planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002403{
2404 struct drm_compositor *c = data;
2405
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002406 switch (key) {
2407 case KEY_C:
2408 c->cursors_are_broken ^= 1;
2409 break;
2410 case KEY_V:
2411 c->sprites_are_broken ^= 1;
2412 break;
2413 case KEY_O:
2414 c->sprites_hidden ^= 1;
2415 break;
2416 default:
2417 break;
2418 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002419}
2420
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002421static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002422drm_compositor_create(struct wl_display *display,
Rob Bradford643641d2013-05-31 18:09:53 +01002423 int connector, const char *seat_id, int tty, int pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002424 int *argc, char *argv[],
2425 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002426{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002427 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002428 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002429 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002430 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002431 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002432
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002433 weston_log("initializing drm backend\n");
2434
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002435 ec = malloc(sizeof *ec);
2436 if (ec == NULL)
2437 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002438 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002439
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002440 /* KMS support for sprites is not complete yet, so disable the
2441 * functionality for now. */
2442 ec->sprites_are_broken = 1;
2443
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002444 ec->use_pixman = pixman;
2445
Daniel Stone725c2c32012-06-22 14:04:36 +01002446 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002447 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002448 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002449 goto err_base;
2450 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002451
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002452 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002453 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002454 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002455 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002456 goto err_compositor;
2457 }
2458
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002459 ec->udev = udev_new();
2460 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002461 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002462 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002463 }
2464
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002465 ec->base.wl_display = display;
2466 ec->tty = tty_create(&ec->base, vt_func, tty);
2467 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002468 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002469 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002470 }
2471
Rob Bradford643641d2013-05-31 18:09:53 +01002472 drm_device = find_primary_gpu(ec, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002473 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002474 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002475 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002476 }
David Herrmann0af066f2012-10-29 19:21:16 +01002477 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002478
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002479 if (init_drm(ec, drm_device) < 0) {
2480 weston_log("failed to initialize kms\n");
2481 goto err_udev_dev;
2482 }
2483
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002484 if (ec->use_pixman) {
2485 if (init_pixman(ec) < 0) {
2486 weston_log("failed to initialize pixman renderer\n");
2487 goto err_udev_dev;
2488 }
2489 } else {
2490 if (init_egl(ec) < 0) {
2491 weston_log("failed to initialize egl\n");
2492 goto err_udev_dev;
2493 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002494 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002495
2496 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002497 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002498
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002499 ec->base.focus = 1;
2500
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002501 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002502
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002503 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002504 weston_compositor_add_key_binding(&ec->base, key,
2505 MODIFIER_CTRL | MODIFIER_ALT,
2506 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002507
Jesse Barnes58ef3792012-02-23 09:45:49 -05002508 wl_list_init(&ec->sprite_list);
2509 create_sprites(ec);
2510
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002511 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002512 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002513 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002514 }
2515
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002516 path = NULL;
2517
Rob Bradfordd355b802013-05-31 18:09:55 +01002518 if (udev_input_init(&ec->input, &ec->base, ec->udev, seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002519 weston_log("failed to create input devices\n");
2520 goto err_sprite;
2521 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002522
2523 loop = wl_display_get_event_loop(ec->base.wl_display);
2524 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002525 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002526 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002527
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002528 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2529 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002530 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002531 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002532 }
2533 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2534 "drm", NULL);
2535 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002536 wl_event_loop_add_fd(loop,
2537 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002538 WL_EVENT_READABLE, udev_drm_event, ec);
2539
2540 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002541 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002542 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002543 }
2544
Daniel Stonea96b93c2012-06-22 14:04:37 +01002545 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002546
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002547 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002548 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002549 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002550 planes_binding, ec);
2551 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2552 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002553
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002554 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002555
2556err_udev_monitor:
2557 wl_event_source_remove(ec->udev_drm_source);
2558 udev_monitor_unref(ec->udev_monitor);
2559err_drm_source:
2560 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002561 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002562err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002563 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002564 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002565 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002566err_udev_dev:
2567 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002568err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002569 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2570 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002571 tty_destroy(ec->tty);
2572err_udev:
2573 udev_unref(ec->udev);
2574err_compositor:
2575 weston_compositor_shutdown(&ec->base);
2576err_base:
2577 free(ec);
2578 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002579}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002580
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002581WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002582backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002583 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002584{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002585 int connector = 0, tty = 0, use_pixman = 0;
Rob Bradford643641d2013-05-31 18:09:53 +01002586 const char *seat_id = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002587
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002588 const struct weston_option drm_options[] = {
2589 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
Rob Bradford643641d2013-05-31 18:09:53 +01002590 { WESTON_OPTION_STRING, "seat", 0, &seat_id },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002591 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002592 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002593 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002594 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002595
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002596 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002597
Rob Bradford643641d2013-05-31 18:09:53 +01002598 return drm_compositor_create(display, connector, seat_id, tty, use_pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002599 argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002600}