blob: 77caddf33207d6dd4ad88db0c2a20a936ffa2761 [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
Daniel Stonec228e232013-05-22 18:03:19 +030024#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040025
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010028#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040029#include <string.h>
30#include <fcntl.h>
31#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040032#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070033#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030034#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020035#include <sys/mman.h>
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030036#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030037#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040038
Benjamin Franzkec649a922011-03-02 11:56:04 +010039#include <xf86drm.h>
40#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050041#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010042
Benjamin Franzke060cf802011-04-30 09:32:11 +020043#include <gbm.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040044#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020045
Kristian Høgsberg36d5fac2014-01-27 23:02:35 -080046#include "libbacklight.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040047#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010048#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020049#include "pixman-renderer.h"
Jonas Ådahle0de3c22014-03-12 22:08:42 +010050#include "udev-input.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010051#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030052#include "vaapi-recorder.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040053
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030054#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
55#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
56#endif
57
Kristian Høgsberg061c4252012-06-28 11:28:15 -040058static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060059
60enum output_config {
61 OUTPUT_CONFIG_INVALID = 0,
62 OUTPUT_CONFIG_OFF,
63 OUTPUT_CONFIG_PREFERRED,
64 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060065 OUTPUT_CONFIG_MODE,
66 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060067};
68
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040069struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050070 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040071
72 struct udev *udev;
73 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010075 struct udev_monitor *udev_monitor;
76 struct wl_event_source *udev_drm_source;
77
Benjamin Franzke2af7f102011-03-02 11:14:59 +010078 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010079 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010080 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030081 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010082 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020083 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050084 uint32_t *crtcs;
85 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050086 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010087 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -070088 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -070089 uint32_t format;
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;
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000150 uint32_t format;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200151
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300152 int vblank_pending;
153 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800154 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300155
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400156 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400157 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400158 struct weston_plane cursor_plane;
159 struct weston_plane fb_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500160 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400161 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300162 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200163 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200164
165 struct drm_fb *dumb[2];
166 pixman_image_t *image[2];
167 int current_image;
168 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300169
170 struct vaapi_recorder *recorder;
171 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400172};
173
Jesse Barnes58ef3792012-02-23 09:45:49 -0500174/*
175 * An output has a primary display plane plus zero or more sprites for
176 * blending display contents.
177 */
178struct drm_sprite {
179 struct wl_list link;
180
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400181 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500182
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200183 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300184 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500185 struct drm_compositor *compositor;
186
Jesse Barnes58ef3792012-02-23 09:45:49 -0500187 uint32_t possible_crtcs;
188 uint32_t plane_id;
189 uint32_t count_formats;
190
191 int32_t src_x, src_y;
192 uint32_t src_w, src_h;
193 uint32_t dest_x, dest_y;
194 uint32_t dest_w, dest_h;
195
196 uint32_t formats[];
197};
198
Kristian Høgsbergd8e98332013-10-16 16:15:11 -0700199struct drm_parameters {
200 int connector;
201 int tty;
202 int use_pixman;
203 const char *seat_id;
204};
205
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300206static struct gl_renderer_interface *gl_renderer;
207
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500208static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400209
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400210static void
211drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400212
Jesse Barnes58ef3792012-02-23 09:45:49 -0500213static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500214drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
215{
216 struct weston_compositor *ec = output_base->compositor;
217 struct drm_compositor *c =(struct drm_compositor *) ec;
218 struct drm_output *output = (struct drm_output *) output_base;
219 int crtc;
220
221 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
222 if (c->crtcs[crtc] != output->crtc_id)
223 continue;
224
225 if (supported & (1 << crtc))
226 return -1;
227 }
228
229 return 0;
230}
231
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300232static void
233drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
234{
235 struct drm_fb *fb = data;
236 struct gbm_device *gbm = gbm_bo_get_device(bo);
237
238 if (fb->fb_id)
239 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
240
Pekka Paalanende685b82012-12-04 15:58:12 +0200241 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300242
243 free(data);
244}
245
246static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200247drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
248{
249 struct drm_fb *fb;
250 int ret;
251
252 struct drm_mode_create_dumb create_arg;
253 struct drm_mode_destroy_dumb destroy_arg;
254 struct drm_mode_map_dumb map_arg;
255
Peter Huttererf3d62272013-08-08 11:57:05 +1000256 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200257 if (!fb)
258 return NULL;
259
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700260 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200261 create_arg.bpp = 32;
262 create_arg.width = width;
263 create_arg.height = height;
264
265 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
266 if (ret)
267 goto err_fb;
268
269 fb->handle = create_arg.handle;
270 fb->stride = create_arg.pitch;
271 fb->size = create_arg.size;
272 fb->fd = ec->drm.fd;
273
274 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
275 fb->stride, fb->handle, &fb->fb_id);
276 if (ret)
277 goto err_bo;
278
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700279 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200280 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400281 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200282 if (ret)
283 goto err_add_fb;
284
285 fb->map = mmap(0, fb->size, PROT_WRITE,
286 MAP_SHARED, ec->drm.fd, map_arg.offset);
287 if (fb->map == MAP_FAILED)
288 goto err_add_fb;
289
290 return fb;
291
292err_add_fb:
293 drmModeRmFB(ec->drm.fd, fb->fb_id);
294err_bo:
295 memset(&destroy_arg, 0, sizeof(destroy_arg));
296 destroy_arg.handle = create_arg.handle;
297 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
298err_fb:
299 free(fb);
300 return NULL;
301}
302
303static void
304drm_fb_destroy_dumb(struct drm_fb *fb)
305{
306 struct drm_mode_destroy_dumb destroy_arg;
307
308 if (!fb->map)
309 return;
310
311 if (fb->fb_id)
312 drmModeRmFB(fb->fd, fb->fb_id);
313
314 weston_buffer_reference(&fb->buffer_ref, NULL);
315
316 munmap(fb->map, fb->size);
317
318 memset(&destroy_arg, 0, sizeof(destroy_arg));
319 destroy_arg.handle = fb->handle;
320 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
321
322 free(fb);
323}
324
325static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500326drm_fb_get_from_bo(struct gbm_bo *bo,
327 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300328{
329 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200330 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200331 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300332 int ret;
333
334 if (fb)
335 return fb;
336
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200337 fb = calloc(1, sizeof *fb);
338 if (!fb)
339 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300340
341 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300342
343 width = gbm_bo_get_width(bo);
344 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200345 fb->stride = gbm_bo_get_stride(bo);
346 fb->handle = gbm_bo_get_handle(bo).u32;
347 fb->size = fb->stride * height;
348 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300349
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200350 if (compositor->min_width > width || width > compositor->max_width ||
351 compositor->min_height > height ||
352 height > compositor->max_height) {
353 weston_log("bo geometry out of bounds\n");
354 goto err_free;
355 }
356
357 ret = -1;
358
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200359 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200360 handles[0] = fb->handle;
361 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200362 offsets[0] = 0;
363
364 ret = drmModeAddFB2(compositor->drm.fd, width, height,
365 format, handles, pitches, offsets,
366 &fb->fb_id, 0);
367 if (ret) {
368 weston_log("addfb2 failed: %m\n");
369 compositor->no_addfb2 = 1;
370 compositor->sprites_are_broken = 1;
371 }
372 }
373
374 if (ret)
375 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200376 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200377
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300378 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200379 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200380 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300381 }
382
383 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
384
385 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200386
387err_free:
388 free(fb);
389 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300390}
391
392static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500393drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200394{
Pekka Paalanende685b82012-12-04 15:58:12 +0200395 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200396
397 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200398
Pekka Paalanende685b82012-12-04 15:58:12 +0200399 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200400}
401
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200402static void
403drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
404{
405 if (!fb)
406 return;
407
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200408 if (fb->map &&
409 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200410 drm_fb_destroy_dumb(fb);
411 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200412 if (fb->is_client_buffer)
413 gbm_bo_destroy(fb->bo);
414 else
415 gbm_surface_release_buffer(output->surface,
Jason Ekstrand3ec57f52013-11-14 20:52:35 -0600416 fb->bo);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200417 }
418}
419
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500420static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200421drm_output_check_scanout_format(struct drm_output *output,
422 struct weston_surface *es, struct gbm_bo *bo)
423{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200424 uint32_t format;
425 pixman_region32_t r;
426
427 format = gbm_bo_get_format(bo);
428
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700429 if (format == GBM_FORMAT_ARGB8888) {
430 /* We can scanout an ARGB buffer if the surface's
431 * opaque region covers the whole output, but we have
432 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -0800433 pixman_region32_init_rect(&r, 0, 0,
434 output->base.width,
435 output->base.height);
436 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200437
438 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500439 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200440
441 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500442 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700443
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000444 if (output->format == format)
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700445 return format;
446
447 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200448}
449
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400450static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500451drm_output_prepare_scanout_view(struct weston_output *_output,
452 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500453{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400454 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500455 struct drm_compositor *c =
456 (struct drm_compositor *) output->base.compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500457 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200458 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300459 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500460 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500461
Jason Ekstranda7af7042013-10-12 22:38:11 -0500462 if (ev->geometry.x != output->base.x ||
463 ev->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200464 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200465 buffer->width != output->base.current_mode->width ||
466 buffer->height != output->base.current_mode->height ||
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200467 output->base.transform != viewport->buffer.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500468 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400469 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500470
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400471 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700472 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500473
Rob Bradford9b101872012-09-14 23:25:41 +0100474 /* Unable to use the buffer for scanout */
475 if (!bo)
476 return NULL;
477
Jason Ekstranda7af7042013-10-12 22:38:11 -0500478 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500479 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300480 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400481 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300482 }
483
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500484 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300485 if (!output->next) {
486 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400487 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300488 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500489
Pekka Paalanende685b82012-12-04 15:58:12 +0200490 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500491
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400492 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500493}
494
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500495static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200496drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400497{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200498 struct drm_compositor *c =
499 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300500 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400501
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200502 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400503
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300504 bo = gbm_surface_lock_front_buffer(output->surface);
505 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200506 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400507 return;
508 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300509
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000510 output->next = drm_fb_get_from_bo(bo, c, output->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300511 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200512 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300513 gbm_surface_release_buffer(output->surface, bo);
514 return;
515 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400516}
517
518static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200519drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
520{
521 struct weston_compositor *ec = output->base.compositor;
522 pixman_region32_t total_damage, previous_damage;
523
524 pixman_region32_init(&total_damage);
525 pixman_region32_init(&previous_damage);
526
527 pixman_region32_copy(&previous_damage, damage);
528
529 pixman_region32_union(&total_damage, damage, &output->previous_damage);
530 pixman_region32_copy(&output->previous_damage, &previous_damage);
531
532 output->current_image ^= 1;
533
534 output->next = output->dumb[output->current_image];
535 pixman_renderer_output_set_buffer(&output->base,
536 output->image[output->current_image]);
537
538 ec->renderer->repaint_output(&output->base, &total_damage);
539
540 pixman_region32_fini(&total_damage);
541 pixman_region32_fini(&previous_damage);
542}
543
544static void
545drm_output_render(struct drm_output *output, pixman_region32_t *damage)
546{
547 struct drm_compositor *c =
548 (struct drm_compositor *) output->base.compositor;
549
550 if (c->use_pixman)
551 drm_output_render_pixman(output, damage);
552 else
553 drm_output_render_gl(output, damage);
554
555 pixman_region32_subtract(&c->base.primary_plane.damage,
556 &c->base.primary_plane.damage, damage);
557}
558
559static void
Richard Hughese7299962013-05-01 21:52:12 +0100560drm_output_set_gamma(struct weston_output *output_base,
561 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
562{
563 int rc;
564 struct drm_output *output = (struct drm_output *) output_base;
565 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
566
567 /* check */
568 if (output_base->gamma_size != size)
569 return;
570 if (!output->original_crtc)
571 return;
572
573 rc = drmModeCrtcSetGamma(compositor->drm.fd,
574 output->crtc_id,
575 size, r, g, b);
576 if (rc)
577 weston_log("set gamma failed: %m\n");
578}
579
David Herrmann1edf44c2013-10-22 17:11:26 +0200580static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500581drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400582 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100583{
584 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500585 struct drm_compositor *compositor =
586 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500587 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400588 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500589 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100590
Xiong Zhangabd5d472013-10-11 14:43:07 +0800591 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200592 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800593
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300594 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400595 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300596 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200597 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100598
Hardeningff39efa2013-09-18 23:56:35 +0200599 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200600 if (!output->current ||
601 output->current->stride != output->next->stride) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400602 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300603 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400604 &output->connector_id, 1,
605 &mode->mode_info);
606 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200607 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200608 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400609 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300610 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200611 }
612
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500613 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300614 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500615 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200616 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200617 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500618 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100619
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300620 output->page_flip_pending = 1;
621
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400622 drm_output_set_cursor(output);
623
Jesse Barnes58ef3792012-02-23 09:45:49 -0500624 /*
625 * Now, update all the sprite surfaces
626 */
627 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200628 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500629 drmVBlank vbl = {
630 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
631 .request.sequence = 1,
632 };
633
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200634 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200635 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500636 continue;
637
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200638 if (s->next && !compositor->sprites_hidden)
639 fb_id = s->next->fb_id;
640
Jesse Barnes58ef3792012-02-23 09:45:49 -0500641 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200642 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500643 s->dest_x, s->dest_y,
644 s->dest_w, s->dest_h,
645 s->src_x, s->src_y,
646 s->src_w, s->src_h);
647 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200648 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500649 ret, strerror(errno));
650
Rob Clark5ca1a472012-08-08 20:27:37 -0500651 if (output->pipe > 0)
652 vbl.request.type |= DRM_VBLANK_SECONDARY;
653
Jesse Barnes58ef3792012-02-23 09:45:49 -0500654 /*
655 * Queue a vblank signal so we know when the surface
656 * becomes active on the display or has been replaced.
657 */
658 vbl.request.signal = (unsigned long)s;
659 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
660 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200661 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500662 ret, strerror(errno));
663 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300664
665 s->output = output;
666 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500667 }
668
David Herrmann1edf44c2013-10-22 17:11:26 +0200669 return 0;
670
671err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800672 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200673 if (output->next) {
674 drm_output_release_fb(output, output->next);
675 output->next = NULL;
676 }
677
678 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400679}
680
681static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200682drm_output_start_repaint_loop(struct weston_output *output_base)
683{
684 struct drm_output *output = (struct drm_output *) output_base;
685 struct drm_compositor *compositor = (struct drm_compositor *)
686 output_base->compositor;
687 uint32_t fb_id;
David Herrmann3c688c52013-10-22 17:11:25 +0200688 uint32_t msec;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300689 struct timespec ts;
690
Xiong Zhangabd5d472013-10-11 14:43:07 +0800691 if (output->destroy_pending)
692 return;
693
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300694 if (!output->current) {
695 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200696 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300697 }
698
699 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200700
701 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
702 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
703 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200704 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200705 }
David Herrmann3c688c52013-10-22 17:11:25 +0200706
707 return;
708
709finish_frame:
710 /* if we cannot page-flip, immediately finish frame */
711 clock_gettime(compositor->clock, &ts);
712 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
713 weston_output_finish_frame(output_base, msec);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200714}
715
716static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500717vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
718 void *data)
719{
720 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300721 struct drm_output *output = s->output;
722 uint32_t msecs;
723
724 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500725
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200726 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200727 s->current = s->next;
728 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300729
730 if (!output->page_flip_pending) {
731 msecs = sec * 1000 + usec / 1000;
732 weston_output_finish_frame(&output->base, msecs);
733 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500734}
735
736static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800737drm_output_destroy(struct weston_output *output_base);
738
739static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400740page_flip_handler(int fd, unsigned int frame,
741 unsigned int sec, unsigned int usec, void *data)
742{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200743 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400744 uint32_t msecs;
745
Jonas Ådahle5a12252013-04-05 23:07:11 +0200746 /* We don't set page_flip_pending on start_repaint_loop, in that case
747 * we just want to page flip to the current buffer to get an accurate
748 * timestamp */
749 if (output->page_flip_pending) {
750 drm_output_release_fb(output, output->current);
751 output->current = output->next;
752 output->next = NULL;
753 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300754
Jonas Ådahle5a12252013-04-05 23:07:11 +0200755 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400756
Xiong Zhangabd5d472013-10-11 14:43:07 +0800757 if (output->destroy_pending)
758 drm_output_destroy(&output->base);
759 else if (!output->vblank_pending) {
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300760 msecs = sec * 1000 + usec / 1000;
761 weston_output_finish_frame(&output->base, msecs);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300762
763 /* We can't call this from frame_notify, because the output's
764 * repaint needed flag is cleared just after that */
765 if (output->recorder)
766 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300767 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200768}
769
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500770static uint32_t
771drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500772 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500773{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500774 uint32_t i, format;
775
776 format = gbm_bo_get_format(bo);
777
778 if (format == GBM_FORMAT_ARGB8888) {
779 pixman_region32_t r;
780
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500781 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600782 ev->surface->width,
783 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500784 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500785
786 if (!pixman_region32_not_empty(&r))
787 format = GBM_FORMAT_XRGB8888;
788
789 pixman_region32_fini(&r);
790 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500791
792 for (i = 0; i < s->count_formats; i++)
793 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500794 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500795
796 return 0;
797}
798
799static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500800drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500802 return !ev->transform.enabled ||
803 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500804}
805
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400806static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500807drm_output_prepare_overlay_view(struct weston_output *output_base,
808 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500809{
810 struct weston_compositor *ec = output_base->compositor;
811 struct drm_compositor *c =(struct drm_compositor *) ec;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200812 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500813 struct drm_sprite *s;
814 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500815 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500816 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200817 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500818 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400819 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500820
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200821 if (c->gbm == NULL)
822 return NULL;
823
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200824 if (viewport->buffer.transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200825 return NULL;
826
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200827 if (viewport->buffer.scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200828 return NULL;
829
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500830 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400831 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500832
Jason Ekstranda7af7042013-10-12 22:38:11 -0500833 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400834 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300835
Jason Ekstranda7af7042013-10-12 22:38:11 -0500836 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400837 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500838
Jason Ekstranda7af7042013-10-12 22:38:11 -0500839 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200840 return NULL;
841
Jason Ekstranda7af7042013-10-12 22:38:11 -0500842 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500843 return NULL;
844
Jason Ekstranda7af7042013-10-12 22:38:11 -0500845 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400846 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500847
Jesse Barnes58ef3792012-02-23 09:45:49 -0500848 wl_list_for_each(s, &c->sprite_list, link) {
849 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
850 continue;
851
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200852 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500853 found = 1;
854 break;
855 }
856 }
857
858 /* No sprites available */
859 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400860 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500861
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400862 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500863 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700864 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400865 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400866 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400867
Jason Ekstranda7af7042013-10-12 22:38:11 -0500868 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500869 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200870 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400871 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500872 }
873
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200874 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200875 if (!s->next) {
876 gbm_bo_destroy(bo);
877 return NULL;
878 }
879
Jason Ekstranda7af7042013-10-12 22:38:11 -0500880 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500881
Jason Ekstranda7af7042013-10-12 22:38:11 -0500882 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400883 s->plane.x = box->x1;
884 s->plane.y = box->y1;
885
Jesse Barnes58ef3792012-02-23 09:45:49 -0500886 /*
887 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200888 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500889 * for us already).
890 */
891 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500892 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500893 &output_base->region);
894 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
895 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200896 tbox = weston_transformed_rect(output_base->width,
897 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200898 output_base->transform,
Hardeningff39efa2013-09-18 23:56:35 +0200899 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200900 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200901 s->dest_x = tbox.x1;
902 s->dest_y = tbox.y1;
903 s->dest_w = tbox.x2 - tbox.x1;
904 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500905 pixman_region32_fini(&dest_rect);
906
907 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500908 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500909 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500910 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400911
Jason Ekstranda7af7042013-10-12 22:38:11 -0500912 weston_view_from_global_fixed(ev,
913 wl_fixed_from_int(box->x1),
914 wl_fixed_from_int(box->y1),
915 &sx1, &sy1);
916 weston_view_from_global_fixed(ev,
917 wl_fixed_from_int(box->x2),
918 wl_fixed_from_int(box->y2),
919 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400920
921 if (sx1 < 0)
922 sx1 = 0;
923 if (sy1 < 0)
924 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600925 if (sx2 > wl_fixed_from_int(ev->surface->width))
926 sx2 = wl_fixed_from_int(ev->surface->width);
927 if (sy2 > wl_fixed_from_int(ev->surface->height))
928 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400929
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200930 tbox.x1 = sx1;
931 tbox.y1 = sy1;
932 tbox.x2 = sx2;
933 tbox.y2 = sy2;
934
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600935 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
936 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200937 viewport->buffer.transform,
938 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100939 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200940
941 s->src_x = tbox.x1 << 8;
942 s->src_y = tbox.y1 << 8;
943 s->src_w = (tbox.x2 - tbox.x1) << 8;
944 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500945 pixman_region32_fini(&src_rect);
946
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400947 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500948}
949
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400950static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500951drm_output_prepare_cursor_view(struct weston_output *output_base,
952 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500953{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400954 struct drm_compositor *c =
955 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400956 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400957
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200958 if (c->gbm == NULL)
959 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200960 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
961 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500962 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400963 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500964 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400965 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500966 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400967 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500968 if (ev->surface->buffer_ref.buffer == NULL ||
969 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600970 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400971 return NULL;
972
Jason Ekstranda7af7042013-10-12 22:38:11 -0500973 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400974
975 return &output->cursor_plane;
976}
977
978static void
979drm_output_set_cursor(struct drm_output *output)
980{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500981 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +0000982 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400983 struct drm_compositor *c =
984 (struct drm_compositor *) output->base.compositor;
985 EGLint handle, stride;
986 struct gbm_bo *bo;
987 uint32_t buf[64 * 64];
988 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400989 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500990
Jason Ekstranda7af7042013-10-12 22:38:11 -0500991 output->cursor_view = NULL;
992 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400993 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
994 return;
995 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500996
Neil Robertse5051712013-11-13 15:44:06 +0000997 buffer = ev->surface->buffer_ref.buffer;
998
999 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001000 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001001 pixman_region32_fini(&output->cursor_plane.damage);
1002 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001003 output->current_cursor ^= 1;
1004 bo = output->cursor_bo[output->current_cursor];
1005 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001006 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1007 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1008 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001009 for (i = 0; i < ev->surface->height; i++)
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001010 memcpy(buf + i * 64, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001011 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001012 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001013
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001014 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001015 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001016
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001017 handle = gbm_bo_get_handle(bo).s32;
1018 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -05001019 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001020 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001021 c->cursors_are_broken = 1;
1022 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001023 }
1024
Jason Ekstranda7af7042013-10-12 22:38:11 -05001025 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1026 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001027 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001028 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001029 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001030 c->cursors_are_broken = 1;
1031 }
1032
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001033 output->cursor_plane.x = x;
1034 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001035 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001036}
1037
Jesse Barnes58ef3792012-02-23 09:45:49 -05001038static void
1039drm_assign_planes(struct weston_output *output)
1040{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001041 struct drm_compositor *c =
1042 (struct drm_compositor *) output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001043 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001044 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001045 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001046
1047 /*
1048 * Find a surface for each sprite in the output using some heuristics:
1049 * 1) size
1050 * 2) frequency of update
1051 * 3) opacity (though some hw might support alpha blending)
1052 * 4) clipping (this can be fixed with color keys)
1053 *
1054 * The idea is to save on blitting since this should save power.
1055 * If we can get a large video surface on the sprite for example,
1056 * the main display surface may not need to update at all, and
1057 * the client buffer can be used directly for the sprite surface
1058 * as we do for flipping full screen surfaces.
1059 */
1060 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001061 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001062
Jason Ekstranda7af7042013-10-12 22:38:11 -05001063 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001064 struct weston_surface *es = ev->surface;
1065
1066 /* Test whether this buffer can ever go into a plane:
1067 * non-shm, or small enough to be a cursor.
1068 *
1069 * Also, keep a reference when using the pixman renderer.
1070 * That makes it possible to do a seamless switch to the GL
1071 * renderer and since the pixman renderer keeps a reference
1072 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001073 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001074 if (c->use_pixman ||
1075 (es->buffer_ref.buffer &&
1076 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001077 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001078 es->keep_buffer = 1;
1079 else
1080 es->keep_buffer = 0;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001081
Jesse Barnes58ef3792012-02-23 09:45:49 -05001082 pixman_region32_init(&surface_overlap);
1083 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001084 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001085
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001086 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001087 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001088 next_plane = primary;
1089 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001090 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001091 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001092 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001093 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001094 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001095 if (next_plane == NULL)
1096 next_plane = primary;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001097 weston_view_move_to_plane(ev, next_plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001098 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001099 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001100 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001101
Jesse Barnes58ef3792012-02-23 09:45:49 -05001102 pixman_region32_fini(&surface_overlap);
1103 }
1104 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001105}
1106
Matt Roper361d2ad2011-08-29 13:52:23 -07001107static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001108drm_output_fini_pixman(struct drm_output *output);
1109
1110static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001111drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001112{
1113 struct drm_output *output = (struct drm_output *) output_base;
1114 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001115 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001116 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001117
Xiong Zhangabd5d472013-10-11 14:43:07 +08001118 if (output->page_flip_pending) {
1119 output->destroy_pending = 1;
1120 weston_log("destroy output while page flip pending\n");
1121 return;
1122 }
1123
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001124 if (output->backlight)
1125 backlight_destroy(output->backlight);
1126
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001127 drmModeFreeProperty(output->dpms_prop);
1128
Matt Roper361d2ad2011-08-29 13:52:23 -07001129 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001130 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001131
1132 /* Restore original CRTC state */
1133 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001134 origcrtc->x, origcrtc->y,
1135 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001136 drmModeFreeCrtc(origcrtc);
1137
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001138 c->crtc_allocator &= ~(1 << output->crtc_id);
1139 c->connector_allocator &= ~(1 << output->connector_id);
1140
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001141 if (c->use_pixman) {
1142 drm_output_fini_pixman(output);
1143 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001144 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001145 gbm_surface_destroy(output->surface);
1146 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001147
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001148 weston_plane_release(&output->fb_plane);
1149 weston_plane_release(&output->cursor_plane);
1150
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001151 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001152
Matt Roper361d2ad2011-08-29 13:52:23 -07001153 free(output);
1154}
1155
Alex Wub7b8bda2012-04-17 17:20:48 +08001156static struct drm_mode *
1157choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1158{
1159 struct drm_mode *tmp_mode = NULL, *mode;
1160
Hardeningff39efa2013-09-18 23:56:35 +02001161 if (output->base.current_mode->width == target_mode->width &&
1162 output->base.current_mode->height == target_mode->height &&
1163 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001164 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001165 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001166
1167 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1168 if (mode->mode_info.hdisplay == target_mode->width &&
1169 mode->mode_info.vdisplay == target_mode->height) {
1170 if (mode->mode_info.vrefresh == target_mode->refresh ||
1171 target_mode->refresh == 0) {
1172 return mode;
1173 } else if (!tmp_mode)
1174 tmp_mode = mode;
1175 }
1176 }
1177
1178 return tmp_mode;
1179}
1180
1181static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001182drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001183static int
1184drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001185
1186static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001187drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1188{
1189 struct drm_output *output;
1190 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001191 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001192
1193 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001194 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001195 return -1;
1196 }
1197
1198 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001199 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001200 return -1;
1201 }
1202
1203 ec = (struct drm_compositor *)output_base->compositor;
1204 output = (struct drm_output *)output_base;
1205 drm_mode = choose_mode (output, mode);
1206
1207 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001208 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001209 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001210 }
1211
Hardeningff39efa2013-09-18 23:56:35 +02001212 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001213 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001214
Hardeningff39efa2013-09-18 23:56:35 +02001215 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001216
Hardeningff39efa2013-09-18 23:56:35 +02001217 output->base.current_mode = &drm_mode->base;
1218 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001219 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1220
Alex Wub7b8bda2012-04-17 17:20:48 +08001221 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001222 drm_output_release_fb(output, output->current);
1223 drm_output_release_fb(output, output->next);
1224 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001225
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001226 if (ec->use_pixman) {
1227 drm_output_fini_pixman(output);
1228 if (drm_output_init_pixman(output, ec) < 0) {
1229 weston_log("failed to init output pixman state with "
1230 "new mode\n");
1231 return -1;
1232 }
1233 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001234 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001235 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001236
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001237 if (drm_output_init_egl(output, ec) < 0) {
1238 weston_log("failed to init output egl state with "
1239 "new mode");
1240 return -1;
1241 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001242 }
1243
Alex Wub7b8bda2012-04-17 17:20:48 +08001244 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001245}
1246
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001247static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001248on_drm_input(int fd, uint32_t mask, void *data)
1249{
1250 drmEventContext evctx;
1251
1252 memset(&evctx, 0, sizeof evctx);
1253 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1254 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001255 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001256 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001257
1258 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001259}
1260
1261static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001262init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001263{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001264 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001265 uint64_t cap;
1266 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001267
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001268 sysnum = udev_device_get_sysnum(device);
1269 if (sysnum)
1270 ec->drm.id = atoi(sysnum);
1271 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001272 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001273 return -1;
1274 }
1275
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001276 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001277 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001278 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001279 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001280 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001281 udev_device_get_devnode(device));
1282 return -1;
1283 }
1284
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001285 weston_log("using %s\n", filename);
1286
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001287 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001288 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001289
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001290 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1291 if (ret == 0 && cap == 1)
1292 ec->clock = CLOCK_MONOTONIC;
1293 else
1294 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001295
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001296 return 0;
1297}
1298
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001299static struct gbm_device *
1300create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001301{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001302 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001303
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001304 gl_renderer = weston_load_module("gl-renderer.so",
1305 "gl_renderer_interface");
1306 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001307 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001308
1309 /* GBM will load a dri driver, but even though they need symbols from
1310 * libglapi, in some version of Mesa they are not linked to it. Since
1311 * only the gl-renderer module links to it, the call above won't make
1312 * these symbols globally available, and loading the DRI driver fails.
1313 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1314 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1315
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001316 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001317
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001318 return gbm;
1319}
1320
1321static int
1322drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1323{
1324 EGLint format;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001325
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001326 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001327 if (gl_renderer->create(&ec->base, ec->gbm,
1328 gl_renderer->opaque_attribs, &format) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001329 return -1;
1330 }
1331
1332 return 0;
1333}
1334
1335static int
1336init_egl(struct drm_compositor *ec)
1337{
1338 ec->gbm = create_gbm_device(ec->drm.fd);
1339
1340 if (!ec->gbm)
1341 return -1;
1342
1343 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001344 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001345 return -1;
1346 }
1347
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001348 return 0;
1349}
1350
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001351static int
1352init_pixman(struct drm_compositor *ec)
1353{
1354 return pixman_renderer_init(&ec->base);
1355}
1356
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001357static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001358drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001359{
1360 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001361 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001362
1363 mode = malloc(sizeof *mode);
1364 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001365 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001366
1367 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001368 mode->base.width = info->hdisplay;
1369 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001370
1371 /* Calculate higher precision (mHz) refresh rate */
1372 refresh = (info->clock * 1000000LL / info->htotal +
1373 info->vtotal / 2) / info->vtotal;
1374
1375 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1376 refresh *= 2;
1377 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1378 refresh /= 2;
1379 if (info->vscan > 1)
1380 refresh /= info->vscan;
1381
1382 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001383 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001384
1385 if (info->type & DRM_MODE_TYPE_PREFERRED)
1386 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1387
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001388 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1389
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001390 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001391}
1392
1393static int
1394drm_subpixel_to_wayland(int drm_value)
1395{
1396 switch (drm_value) {
1397 default:
1398 case DRM_MODE_SUBPIXEL_UNKNOWN:
1399 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1400 case DRM_MODE_SUBPIXEL_NONE:
1401 return WL_OUTPUT_SUBPIXEL_NONE;
1402 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1403 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1404 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1405 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1406 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1407 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1408 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1409 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1410 }
1411}
1412
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001413/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001414static uint32_t
1415drm_get_backlight(struct drm_output *output)
1416{
1417 long brightness, max_brightness, norm;
1418
1419 brightness = backlight_get_brightness(output->backlight);
1420 max_brightness = backlight_get_max_brightness(output->backlight);
1421
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001422 /* convert it on a scale of 0 to 255 */
1423 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001424
1425 return (uint32_t) norm;
1426}
1427
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001428/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001429static void
1430drm_set_backlight(struct weston_output *output_base, uint32_t value)
1431{
1432 struct drm_output *output = (struct drm_output *) output_base;
1433 long max_brightness, new_brightness;
1434
1435 if (!output->backlight)
1436 return;
1437
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001438 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001439 return;
1440
1441 max_brightness = backlight_get_max_brightness(output->backlight);
1442
1443 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001444 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001445
1446 backlight_set_brightness(output->backlight, new_brightness);
1447}
1448
1449static drmModePropertyPtr
1450drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1451{
1452 drmModePropertyPtr props;
1453 int i;
1454
1455 for (i = 0; i < connector->count_props; i++) {
1456 props = drmModeGetProperty(fd, connector->props[i]);
1457 if (!props)
1458 continue;
1459
1460 if (!strcmp(props->name, name))
1461 return props;
1462
1463 drmModeFreeProperty(props);
1464 }
1465
1466 return NULL;
1467}
1468
1469static void
1470drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1471{
1472 struct drm_output *output = (struct drm_output *) output_base;
1473 struct weston_compositor *ec = output_base->compositor;
1474 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001475
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001476 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001477 return;
1478
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001479 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1480 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001481}
1482
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001483static const char *connector_type_names[] = {
1484 "None",
1485 "VGA",
1486 "DVI",
1487 "DVI",
1488 "DVI",
1489 "Composite",
1490 "TV",
1491 "LVDS",
1492 "CTV",
1493 "DIN",
1494 "DP",
1495 "HDMI",
1496 "HDMI",
1497 "TV",
1498 "eDP",
1499};
1500
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001501static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001502find_crtc_for_connector(struct drm_compositor *ec,
1503 drmModeRes *resources, drmModeConnector *connector)
1504{
1505 drmModeEncoder *encoder;
1506 uint32_t possible_crtcs;
1507 int i, j;
1508
1509 for (j = 0; j < connector->count_encoders; j++) {
1510 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1511 if (encoder == NULL) {
1512 weston_log("Failed to get encoder.\n");
1513 return -1;
1514 }
1515 possible_crtcs = encoder->possible_crtcs;
1516 drmModeFreeEncoder(encoder);
1517
1518 for (i = 0; i < resources->count_crtcs; i++) {
1519 if (possible_crtcs & (1 << i) &&
1520 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1521 return i;
1522 }
1523 }
1524
1525 return -1;
1526}
1527
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001528/* Init output state that depends on gl or gbm */
1529static int
1530drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1531{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001532 EGLint format = output->format;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001533 int i, flags;
1534
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001535 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001536 output->base.current_mode->width,
1537 output->base.current_mode->height,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001538 format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001539 GBM_BO_USE_SCANOUT |
1540 GBM_BO_USE_RENDERING);
1541 if (!output->surface) {
1542 weston_log("failed to create gbm surface\n");
1543 return -1;
1544 }
1545
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001546 if (gl_renderer->output_create(&output->base, output->surface,
1547 gl_renderer->opaque_attribs,
1548 &format) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001549 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001550 gbm_surface_destroy(output->surface);
1551 return -1;
1552 }
1553
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001554 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1555
1556 for (i = 0; i < 2; i++) {
1557 if (output->cursor_bo[i])
1558 continue;
1559
1560 output->cursor_bo[i] =
1561 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1562 flags);
1563 }
1564
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001565 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1566 weston_log("cursor buffers unavailable, using gl cursors\n");
1567 ec->cursors_are_broken = 1;
1568 }
1569
1570 return 0;
1571}
1572
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001573static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001574drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1575{
Hardeningff39efa2013-09-18 23:56:35 +02001576 int w = output->base.current_mode->width;
1577 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001578 unsigned int i;
1579
1580 /* FIXME error checking */
1581
1582 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001583 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001584 if (!output->dumb[i])
1585 goto err;
1586
1587 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001588 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001589 output->dumb[i]->map,
1590 output->dumb[i]->stride);
1591 if (!output->image[i])
1592 goto err;
1593 }
1594
1595 if (pixman_renderer_output_create(&output->base) < 0)
1596 goto err;
1597
1598 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001599 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001600
1601 return 0;
1602
1603err:
1604 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1605 if (output->dumb[i])
1606 drm_fb_destroy_dumb(output->dumb[i]);
1607 if (output->image[i])
1608 pixman_image_unref(output->image[i]);
1609
1610 output->dumb[i] = NULL;
1611 output->image[i] = NULL;
1612 }
1613
1614 return -1;
1615}
1616
1617static void
1618drm_output_fini_pixman(struct drm_output *output)
1619{
1620 unsigned int i;
1621
1622 pixman_renderer_output_destroy(&output->base);
1623 pixman_region32_fini(&output->previous_damage);
1624
1625 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1626 drm_fb_destroy_dumb(output->dumb[i]);
1627 pixman_image_unref(output->image[i]);
1628 output->dumb[i] = NULL;
1629 output->image[i] = NULL;
1630 }
1631}
1632
Richard Hughes2b2092a2013-04-24 14:58:02 +01001633static void
1634edid_parse_string(const uint8_t *data, char text[])
1635{
1636 int i;
1637 int replaced = 0;
1638
1639 /* this is always 12 bytes, but we can't guarantee it's null
1640 * terminated or not junk. */
1641 strncpy(text, (const char *) data, 12);
1642
1643 /* remove insane chars */
1644 for (i = 0; text[i] != '\0'; i++) {
1645 if (text[i] == '\n' ||
1646 text[i] == '\r') {
1647 text[i] = '\0';
1648 break;
1649 }
1650 }
1651
1652 /* ensure string is printable */
1653 for (i = 0; text[i] != '\0'; i++) {
1654 if (!isprint(text[i])) {
1655 text[i] = '-';
1656 replaced++;
1657 }
1658 }
1659
1660 /* if the string is random junk, ignore the string */
1661 if (replaced > 4)
1662 text[0] = '\0';
1663}
1664
1665#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1666#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1667#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1668#define EDID_OFFSET_DATA_BLOCKS 0x36
1669#define EDID_OFFSET_LAST_BLOCK 0x6c
1670#define EDID_OFFSET_PNPID 0x08
1671#define EDID_OFFSET_SERIAL 0x0c
1672
1673static int
1674edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1675{
1676 int i;
1677 uint32_t serial_number;
1678
1679 /* check header */
1680 if (length < 128)
1681 return -1;
1682 if (data[0] != 0x00 || data[1] != 0xff)
1683 return -1;
1684
1685 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1686 * /--08--\/--09--\
1687 * 7654321076543210
1688 * |\---/\---/\---/
1689 * R C1 C2 C3 */
1690 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1691 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1692 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1693 edid->pnp_id[3] = '\0';
1694
1695 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1696 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1697 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1698 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1699 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1700 if (serial_number > 0)
1701 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1702
1703 /* parse EDID data */
1704 for (i = EDID_OFFSET_DATA_BLOCKS;
1705 i <= EDID_OFFSET_LAST_BLOCK;
1706 i += 18) {
1707 /* ignore pixel clock data */
1708 if (data[i] != 0)
1709 continue;
1710 if (data[i+2] != 0)
1711 continue;
1712
1713 /* any useful blocks? */
1714 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1715 edid_parse_string(&data[i+5],
1716 edid->monitor_name);
1717 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1718 edid_parse_string(&data[i+5],
1719 edid->serial_number);
1720 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1721 edid_parse_string(&data[i+5],
1722 edid->eisa_id);
1723 }
1724 }
1725 return 0;
1726}
1727
1728static void
1729find_and_parse_output_edid(struct drm_compositor *ec,
1730 struct drm_output *output,
1731 drmModeConnector *connector)
1732{
1733 drmModePropertyBlobPtr edid_blob = NULL;
1734 drmModePropertyPtr property;
1735 int i;
1736 int rc;
1737
1738 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1739 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1740 if (!property)
1741 continue;
1742 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1743 !strcmp(property->name, "EDID")) {
1744 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1745 connector->prop_values[i]);
1746 }
1747 drmModeFreeProperty(property);
1748 }
1749 if (!edid_blob)
1750 return;
1751
1752 rc = edid_parse(&output->edid,
1753 edid_blob->data,
1754 edid_blob->length);
1755 if (!rc) {
1756 weston_log("EDID data '%s', '%s', '%s'\n",
1757 output->edid.pnp_id,
1758 output->edid.monitor_name,
1759 output->edid.serial_number);
1760 if (output->edid.pnp_id[0] != '\0')
1761 output->base.make = output->edid.pnp_id;
1762 if (output->edid.monitor_name[0] != '\0')
1763 output->base.model = output->edid.monitor_name;
1764 if (output->edid.serial_number[0] != '\0')
1765 output->base.serial_number = output->edid.serial_number;
1766 }
1767 drmModeFreePropertyBlob(edid_blob);
1768}
1769
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001770
1771
1772static int
1773parse_modeline(const char *s, drmModeModeInfo *mode)
1774{
1775 char hsync[16];
1776 char vsync[16];
1777 float fclock;
1778
1779 mode->type = DRM_MODE_TYPE_USERDEF;
1780 mode->hskew = 0;
1781 mode->vscan = 0;
1782 mode->vrefresh = 0;
1783 mode->flags = 0;
1784
Rob Bradford307e09e2013-07-26 16:29:40 +01001785 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001786 &fclock,
1787 &mode->hdisplay,
1788 &mode->hsync_start,
1789 &mode->hsync_end,
1790 &mode->htotal,
1791 &mode->vdisplay,
1792 &mode->vsync_start,
1793 &mode->vsync_end,
1794 &mode->vtotal, hsync, vsync) != 11)
1795 return -1;
1796
1797 mode->clock = fclock * 1000;
1798 if (strcmp(hsync, "+hsync") == 0)
1799 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1800 else if (strcmp(hsync, "-hsync") == 0)
1801 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1802 else
1803 return -1;
1804
1805 if (strcmp(vsync, "+vsync") == 0)
1806 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1807 else if (strcmp(vsync, "-vsync") == 0)
1808 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1809 else
1810 return -1;
1811
1812 return 0;
1813}
1814
1815static uint32_t
1816parse_transform(const char *transform, const char *output_name)
1817{
1818 static const struct { const char *name; uint32_t token; } names[] = {
1819 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1820 { "90", WL_OUTPUT_TRANSFORM_90 },
1821 { "180", WL_OUTPUT_TRANSFORM_180 },
1822 { "270", WL_OUTPUT_TRANSFORM_270 },
1823 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1824 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1825 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1826 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1827 };
1828 unsigned int i;
1829
1830 for (i = 0; i < ARRAY_LENGTH(names); i++)
1831 if (strcmp(names[i].name, transform) == 0)
1832 return names[i].token;
1833
1834 weston_log("Invalid transform \"%s\" for output %s\n",
1835 transform, output_name);
1836
1837 return WL_OUTPUT_TRANSFORM_NORMAL;
1838}
1839
Rob Bradford66bd9f52013-06-25 18:56:42 +01001840static void
1841setup_output_seat_constraint(struct drm_compositor *ec,
1842 struct weston_output *output,
1843 const char *s)
1844{
1845 if (strcmp(s, "") != 0) {
1846 struct udev_seat *seat;
1847
Jonas Ådahl58e15862014-03-12 22:08:40 +01001848 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001849 if (seat)
1850 seat->base.output = output;
1851
1852 if (seat && seat->base.pointer)
1853 weston_pointer_clamp(seat->base.pointer,
1854 &seat->base.pointer->x,
1855 &seat->base.pointer->y);
1856 }
1857}
1858
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001859static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001860get_gbm_format_from_section(struct weston_config_section *section,
1861 uint32_t default_value,
1862 uint32_t *format)
1863{
1864 char *s;
1865 int ret = 0;
1866
1867 weston_config_section_get_string(section,
1868 "gbm-format", &s, NULL);
1869
1870 if (s == NULL)
1871 *format = default_value;
1872 else if (strcmp(s, "xrgb8888") == 0)
1873 *format = GBM_FORMAT_XRGB8888;
1874 else if (strcmp(s, "rgb565") == 0)
1875 *format = GBM_FORMAT_RGB565;
1876 else if (strcmp(s, "xrgb2101010") == 0)
1877 *format = GBM_FORMAT_XRGB2101010;
1878 else {
1879 weston_log("fatal: unrecognized pixel format: %s\n", s);
1880 ret = -1;
1881 }
1882
1883 free(s);
1884
1885 return ret;
1886}
1887
1888static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001889create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001890 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001891 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001892 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001893{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001894 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001895 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001896 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001897 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001898 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001899 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001900 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001901 int i, width, height, scale;
1902 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001903 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001904 enum output_config config;
1905 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001906
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001907 i = find_crtc_for_connector(ec, resources, connector);
1908 if (i < 0) {
1909 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001910 return -1;
1911 }
1912
Peter Huttererf3d62272013-08-08 11:57:05 +10001913 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001914 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001915 return -1;
1916
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001917 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1918 output->base.make = "unknown";
1919 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001920 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001921 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001922
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001923 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1924 type_name = connector_type_names[connector->connector_type];
1925 else
1926 type_name = "UNKNOWN";
1927 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001928 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001929
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001930 section = weston_config_get_section(ec->base.config, "output", "name",
1931 output->base.name);
1932 weston_config_section_get_string(section, "mode", &s, "preferred");
1933 if (strcmp(s, "off") == 0)
1934 config = OUTPUT_CONFIG_OFF;
1935 else if (strcmp(s, "preferred") == 0)
1936 config = OUTPUT_CONFIG_PREFERRED;
1937 else if (strcmp(s, "current") == 0)
1938 config = OUTPUT_CONFIG_CURRENT;
1939 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1940 config = OUTPUT_CONFIG_MODE;
1941 else if (parse_modeline(s, &modeline) == 0)
1942 config = OUTPUT_CONFIG_MODELINE;
1943 else {
1944 weston_log("Invalid mode \"%s\" for output %s\n",
1945 s, output->base.name);
1946 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001947 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001948 free(s);
1949
1950 weston_config_section_get_int(section, "scale", &scale, 1);
1951 weston_config_section_get_string(section, "transform", &s, "normal");
1952 transform = parse_transform(s, output->base.name);
1953 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001954
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001955 if (get_gbm_format_from_section(section,
1956 ec->format,
1957 &output->format) == -1)
1958 output->format = ec->format;
1959
Rob Bradford66bd9f52013-06-25 18:56:42 +01001960 weston_config_section_get_string(section, "seat", &s, "");
1961 setup_output_seat_constraint(ec, &output->base, s);
1962 free(s);
1963
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001964 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001965 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001966 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001967 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001968 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001969
Matt Roper361d2ad2011-08-29 13:52:23 -07001970 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001971 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001972
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001973 /* Get the current mode on the crtc that's currently driving
1974 * this connector. */
1975 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001976 memset(&crtc_mode, 0, sizeof crtc_mode);
1977 if (encoder != NULL) {
1978 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1979 drmModeFreeEncoder(encoder);
1980 if (crtc == NULL)
1981 goto err_free;
1982 if (crtc->mode_valid)
1983 crtc_mode = crtc->mode;
1984 drmModeFreeCrtc(crtc);
1985 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001986
David Herrmann0f0d54e2011-12-08 17:05:45 +01001987 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001988 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001989 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001990 goto err_free;
1991 }
1992
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001993 if (config == OUTPUT_CONFIG_OFF) {
1994 weston_log("Disabling output %s\n", output->base.name);
1995 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1996 0, 0, 0, 0, 0, NULL);
1997 goto err_free;
1998 }
1999
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002000 preferred = NULL;
2001 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002002 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002003 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002004
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002005 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002006 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002007 width == drm_mode->base.width &&
2008 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002009 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002010 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002011 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002012 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002013 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002014 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002015 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002016
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002017 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002018 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002019 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002020 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002021 }
2022
Wang Quanxianacb805a2012-07-30 18:09:46 -04002023 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002024 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002025 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002026 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002027 }
2028
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002029 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002030 configured = current;
2031
Wang Quanxianacb805a2012-07-30 18:09:46 -04002032 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002033 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002034 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002035 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002036 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002037 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002038 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002039 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002040 else if (best)
2041 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002042
Hardeningff39efa2013-09-18 23:56:35 +02002043 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002044 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002045 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002046 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002047
Hardeningff39efa2013-09-18 23:56:35 +02002048 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002049
John Kåre Alsaker94659272012-11-13 19:10:18 +01002050 weston_output_init(&output->base, &ec->base, x, y,
2051 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002052 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002053
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002054 if (ec->use_pixman) {
2055 if (drm_output_init_pixman(output, ec) < 0) {
2056 weston_log("Failed to init output pixman state\n");
2057 goto err_output;
2058 }
2059 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002060 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002061 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002062 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002063
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002064 output->backlight = backlight_init(drm_device,
2065 connector->connector_type);
2066 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002067 weston_log("Initialized backlight, device %s\n",
2068 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002069 output->base.set_backlight = drm_set_backlight;
2070 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002071 } else {
2072 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002073 }
2074
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002075 wl_list_insert(ec->base.output_list.prev, &output->base.link);
2076
Richard Hughes2b2092a2013-04-24 14:58:02 +01002077 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002078 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2079 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002080
Jonas Ådahle5a12252013-04-05 23:07:11 +02002081 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002082 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002083 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002084 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002085 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002086 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002087
Richard Hughese7299962013-05-01 21:52:12 +01002088 output->base.gamma_size = output->original_crtc->gamma_size;
2089 output->base.set_gamma = drm_output_set_gamma;
2090
Xiong Zhang97116532013-10-23 13:58:31 +08002091 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2092 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002093
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002094 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2095 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2096 &ec->base.primary_plane);
2097
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002098 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002099 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002100 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002101 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002102 m->width, m->height, m->refresh / 1000.0,
2103 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2104 ", preferred" : "",
2105 m->flags & WL_OUTPUT_MODE_CURRENT ?
2106 ", current" : "",
2107 connector->count_modes == 0 ?
2108 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002109
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002110 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002111
John Kåre Alsaker94659272012-11-13 19:10:18 +01002112err_output:
2113 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002114err_free:
2115 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2116 base.link) {
2117 wl_list_remove(&drm_mode->base.link);
2118 free(drm_mode);
2119 }
2120
2121 drmModeFreeCrtc(output->original_crtc);
2122 ec->crtc_allocator &= ~(1 << output->crtc_id);
2123 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002124 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002125
David Herrmann0f0d54e2011-12-08 17:05:45 +01002126 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002127}
2128
Jesse Barnes58ef3792012-02-23 09:45:49 -05002129static void
2130create_sprites(struct drm_compositor *ec)
2131{
2132 struct drm_sprite *sprite;
2133 drmModePlaneRes *plane_res;
2134 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002135 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002136
2137 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2138 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002139 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002140 strerror(errno));
2141 return;
2142 }
2143
2144 for (i = 0; i < plane_res->count_planes; i++) {
2145 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2146 if (!plane)
2147 continue;
2148
Peter Huttererf3d62272013-08-08 11:57:05 +10002149 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002150 plane->count_formats));
2151 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002152 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002153 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002154 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002155 continue;
2156 }
2157
Jesse Barnes58ef3792012-02-23 09:45:49 -05002158 sprite->possible_crtcs = plane->possible_crtcs;
2159 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002160 sprite->current = NULL;
2161 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002162 sprite->compositor = ec;
2163 sprite->count_formats = plane->count_formats;
2164 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002165 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002166 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002167 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002168 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2169 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002170
2171 wl_list_insert(&ec->sprite_list, &sprite->link);
2172 }
2173
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002174 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002175}
2176
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002177static void
2178destroy_sprites(struct drm_compositor *compositor)
2179{
2180 struct drm_sprite *sprite, *next;
2181 struct drm_output *output;
2182
2183 output = container_of(compositor->base.output_list.next,
2184 struct drm_output, base.link);
2185
2186 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2187 drmModeSetPlane(compositor->drm.fd,
2188 sprite->plane_id,
2189 output->crtc_id, 0, 0,
2190 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002191 drm_output_release_fb(output, sprite->current);
2192 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002193 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002194 free(sprite);
2195 }
2196}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002197
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002198static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002199create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002200 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002201{
2202 drmModeConnector *connector;
2203 drmModeRes *resources;
2204 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002205 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002206
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002207 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002208 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002209 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002210 return -1;
2211 }
2212
Jesse Barnes58ef3792012-02-23 09:45:49 -05002213 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002214 if (!ec->crtcs) {
2215 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002216 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002217 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002218
Rob Clark4339add2012-08-09 14:18:28 -05002219 ec->min_width = resources->min_width;
2220 ec->max_width = resources->max_width;
2221 ec->min_height = resources->min_height;
2222 ec->max_height = resources->max_height;
2223
Jesse Barnes58ef3792012-02-23 09:45:49 -05002224 ec->num_crtcs = resources->count_crtcs;
2225 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2226
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002227 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002228 connector = drmModeGetConnector(ec->drm.fd,
2229 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002230 if (connector == NULL)
2231 continue;
2232
2233 if (connector->connection == DRM_MODE_CONNECTED &&
2234 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002235 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002236 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002237 connector, x, y,
2238 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002239 drmModeFreeConnector(connector);
2240 continue;
2241 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002242
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002243 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002244 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002245 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002246 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002247
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002248 drmModeFreeConnector(connector);
2249 }
2250
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002251 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002252 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002253 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002254 return -1;
2255 }
2256
2257 drmModeFreeResources(resources);
2258
2259 return 0;
2260}
2261
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002262static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002263update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002264{
2265 drmModeConnector *connector;
2266 drmModeRes *resources;
2267 struct drm_output *output, *next;
2268 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002269 uint32_t connected = 0, disconnects = 0;
2270 int i;
2271
2272 resources = drmModeGetResources(ec->drm.fd);
2273 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002274 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002275 return;
2276 }
2277
2278 /* collect new connects */
2279 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002280 int connector_id = resources->connectors[i];
2281
2282 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002283 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002284 continue;
2285
David Herrmann7551cff2011-12-08 17:05:43 +01002286 if (connector->connection != DRM_MODE_CONNECTED) {
2287 drmModeFreeConnector(connector);
2288 continue;
2289 }
2290
Benjamin Franzke117483d2011-08-30 11:38:26 +02002291 connected |= (1 << connector_id);
2292
2293 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002294 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002295 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002296 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002297
2298 /* XXX: not yet needed, we die with 0 outputs */
2299 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002300 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002301 else
2302 x = 0;
2303 y = 0;
2304 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002305 connector, x, y,
2306 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002307 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002308
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002309 }
2310 drmModeFreeConnector(connector);
2311 }
2312 drmModeFreeResources(resources);
2313
2314 disconnects = ec->connector_allocator & ~connected;
2315 if (disconnects) {
2316 wl_list_for_each_safe(output, next, &ec->base.output_list,
2317 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002318 if (disconnects & (1 << output->connector_id)) {
2319 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002320 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002321 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002322 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002323 }
2324 }
2325 }
2326
2327 /* FIXME: handle zero outputs, without terminating */
2328 if (ec->connector_allocator == 0)
2329 wl_display_terminate(ec->base.wl_display);
2330}
2331
2332static int
David Herrmannd7488c22012-03-11 20:05:21 +01002333udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002334{
David Herrmannd7488c22012-03-11 20:05:21 +01002335 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002336 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002337
2338 sysnum = udev_device_get_sysnum(device);
2339 if (!sysnum || atoi(sysnum) != ec->drm.id)
2340 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002341
David Herrmann6ac52db2012-03-11 20:05:22 +01002342 val = udev_device_get_property_value(device, "HOTPLUG");
2343 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002344 return 0;
2345
David Herrmann6ac52db2012-03-11 20:05:22 +01002346 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002347}
2348
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002349static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002350udev_drm_event(int fd, uint32_t mask, void *data)
2351{
2352 struct drm_compositor *ec = data;
2353 struct udev_device *event;
2354
2355 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002356
David Herrmannd7488c22012-03-11 20:05:21 +01002357 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002358 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002359
2360 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002361
2362 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002363}
2364
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002365static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002366drm_restore(struct weston_compositor *ec)
2367{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002368 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002369}
2370
2371static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002372drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002373{
2374 struct drm_compositor *d = (struct drm_compositor *) ec;
2375
Rob Bradfordd355b802013-05-31 18:09:55 +01002376 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002377
2378 wl_event_source_remove(d->udev_drm_source);
2379 wl_event_source_remove(d->drm_source);
2380
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002381 destroy_sprites(d);
2382
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002383 weston_compositor_shutdown(ec);
2384
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002385 if (d->gbm)
2386 gbm_device_destroy(d->gbm);
2387
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002388 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002389
Rob Bradford45c15b82013-07-26 16:29:35 +01002390 close(d->drm.fd);
2391
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002392 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002393}
2394
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002395static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002396drm_compositor_set_modes(struct drm_compositor *compositor)
2397{
2398 struct drm_output *output;
2399 struct drm_mode *drm_mode;
2400 int ret;
2401
2402 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002403 if (!output->current) {
2404 /* If something that would cause the output to
2405 * switch mode happened while in another vt, we
2406 * might not have a current drm_fb. In that case,
2407 * schedule a repaint and let drm_output_repaint
2408 * handle setting the mode. */
2409 weston_output_schedule_repaint(&output->base);
2410 continue;
2411 }
2412
Hardeningff39efa2013-09-18 23:56:35 +02002413 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002414 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002415 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002416 &output->connector_id, 1,
2417 &drm_mode->mode_info);
2418 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002419 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002420 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002421 drm_mode->base.width, drm_mode->base.height,
2422 output->base.x, output->base.y);
2423 }
2424 }
2425}
2426
2427static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002428session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002429{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002430 struct weston_compositor *compositor = data;
2431 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002432 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002433 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002434
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002435 if (ec->base.session_active) {
2436 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002437 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002438 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002439 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002440 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002441 } else {
2442 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002443 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002444
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002445 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002446 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002447
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002448 /* If we have a repaint scheduled (either from a
2449 * pending pageflip or the idle handler), make sure we
2450 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002451 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002452 * further attemps at repainting. When we switch
2453 * back, we schedule a repaint, which will process
2454 * pending frame callbacks. */
2455
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002456 wl_list_for_each(output, &ec->base.output_list, base.link) {
2457 output->base.repaint_needed = 0;
2458 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002459 }
2460
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002461 output = container_of(ec->base.output_list.next,
2462 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002463
2464 wl_list_for_each(sprite, &ec->sprite_list, link)
2465 drmModeSetPlane(ec->drm.fd,
2466 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002467 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002468 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002469 };
2470}
2471
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002472static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002473switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002474{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002475 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002476
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002477 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002478}
2479
David Herrmann0af066f2012-10-29 19:21:16 +01002480/*
2481 * Find primary GPU
2482 * Some systems may have multiple DRM devices attached to a single seat. This
2483 * function loops over all devices and tries to find a PCI device with the
2484 * boot_vga sysfs attribute set to 1.
2485 * If no such device is found, the first DRM device reported by udev is used.
2486 */
2487static struct udev_device*
2488find_primary_gpu(struct drm_compositor *ec, const char *seat)
2489{
2490 struct udev_enumerate *e;
2491 struct udev_list_entry *entry;
2492 const char *path, *device_seat, *id;
2493 struct udev_device *device, *drm_device, *pci;
2494
2495 e = udev_enumerate_new(ec->udev);
2496 udev_enumerate_add_match_subsystem(e, "drm");
2497 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2498
2499 udev_enumerate_scan_devices(e);
2500 drm_device = NULL;
2501 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2502 path = udev_list_entry_get_name(entry);
2503 device = udev_device_new_from_syspath(ec->udev, path);
2504 if (!device)
2505 continue;
2506 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2507 if (!device_seat)
2508 device_seat = default_seat;
2509 if (strcmp(device_seat, seat)) {
2510 udev_device_unref(device);
2511 continue;
2512 }
2513
2514 pci = udev_device_get_parent_with_subsystem_devtype(device,
2515 "pci", NULL);
2516 if (pci) {
2517 id = udev_device_get_sysattr_value(pci, "boot_vga");
2518 if (id && !strcmp(id, "1")) {
2519 if (drm_device)
2520 udev_device_unref(drm_device);
2521 drm_device = device;
2522 break;
2523 }
2524 }
2525
2526 if (!drm_device)
2527 drm_device = device;
2528 else
2529 udev_device_unref(device);
2530 }
2531
2532 udev_enumerate_unref(e);
2533 return drm_device;
2534}
2535
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002536static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002537planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002538{
2539 struct drm_compositor *c = data;
2540
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002541 switch (key) {
2542 case KEY_C:
2543 c->cursors_are_broken ^= 1;
2544 break;
2545 case KEY_V:
2546 c->sprites_are_broken ^= 1;
2547 break;
2548 case KEY_O:
2549 c->sprites_hidden ^= 1;
2550 break;
2551 default:
2552 break;
2553 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002554}
2555
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002556#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002557static void
2558recorder_frame_notify(struct wl_listener *listener, void *data)
2559{
2560 struct drm_output *output;
2561 struct drm_compositor *c;
2562 int fd, ret;
2563
2564 output = container_of(listener, struct drm_output,
2565 recorder_frame_listener);
2566 c = (struct drm_compositor *) output->base.compositor;
2567
2568 if (!output->recorder)
2569 return;
2570
2571 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2572 DRM_CLOEXEC, &fd);
2573 if (ret) {
2574 weston_log("[libva recorder] "
2575 "failed to create prime fd for front buffer\n");
2576 return;
2577 }
2578
2579 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002580}
2581
2582static void *
2583create_recorder(struct drm_compositor *c, int width, int height,
2584 const char *filename)
2585{
2586 int fd;
2587 drm_magic_t magic;
2588
2589 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2590 if (fd < 0)
2591 return NULL;
2592
2593 drmGetMagic(fd, &magic);
2594 drmAuthMagic(c->drm.fd, magic);
2595
2596 return vaapi_recorder_create(fd, width, height, filename);
2597}
2598
2599static void
2600recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2601 void *data)
2602{
2603 struct drm_compositor *c = data;
2604 struct drm_output *output;
2605 int width, height;
2606
2607 output = container_of(c->base.output_list.next,
2608 struct drm_output, base.link);
2609
2610 if (!output->recorder) {
Hardeningff39efa2013-09-18 23:56:35 +02002611 width = output->base.current_mode->width;
2612 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002613
2614 output->recorder =
2615 create_recorder(c, width, height, "capture.h264");
2616 if (!output->recorder) {
2617 weston_log("failed to create vaapi recorder\n");
2618 return;
2619 }
2620
2621 output->base.disable_planes++;
2622
2623 output->recorder_frame_listener.notify = recorder_frame_notify;
2624 wl_signal_add(&output->base.frame_signal,
2625 &output->recorder_frame_listener);
2626
2627 weston_output_schedule_repaint(&output->base);
2628
2629 weston_log("[libva recorder] initialized\n");
2630 } else {
2631 vaapi_recorder_destroy(output->recorder);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002632 output->recorder = NULL;
2633
2634 output->base.disable_planes--;
2635
2636 wl_list_remove(&output->recorder_frame_listener.link);
2637 weston_log("[libva recorder] done\n");
2638 }
2639}
2640#else
2641static void
2642recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2643 void *data)
2644{
2645 weston_log("Compiled without libva support\n");
2646}
2647#endif
2648
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002649static void
2650switch_to_gl_renderer(struct drm_compositor *c)
2651{
2652 struct drm_output *output;
2653
2654 if (!c->use_pixman)
2655 return;
2656
2657 weston_log("Switching to GL renderer\n");
2658
2659 c->gbm = create_gbm_device(c->drm.fd);
2660 if (!c->gbm) {
2661 weston_log("Failed to create gbm device. "
2662 "Aborting renderer switch\n");
2663 return;
2664 }
2665
2666 wl_list_for_each(output, &c->base.output_list, base.link)
2667 pixman_renderer_output_destroy(&output->base);
2668
2669 c->base.renderer->destroy(&c->base);
2670
2671 if (drm_compositor_create_gl_renderer(c) < 0) {
2672 gbm_device_destroy(c->gbm);
2673 weston_log("Failed to create GL renderer. Quitting.\n");
2674 /* FIXME: we need a function to shutdown cleanly */
2675 assert(0);
2676 }
2677
2678 wl_list_for_each(output, &c->base.output_list, base.link)
2679 drm_output_init_egl(output, c);
2680
2681 c->use_pixman = 0;
2682}
2683
2684static void
2685renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2686 void *data)
2687{
2688 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2689
2690 switch_to_gl_renderer(c);
2691}
2692
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002693static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002694drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002695 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002696 int *argc, char *argv[],
2697 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002698{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002699 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002700 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002701 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002702 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002703 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002704 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002705
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002706 weston_log("initializing drm backend\n");
2707
Peter Huttererf3d62272013-08-08 11:57:05 +10002708 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002709 if (ec == NULL)
2710 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002711
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002712 /* KMS support for sprites is not complete yet, so disable the
2713 * functionality for now. */
2714 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002715
2716 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002717 if (get_gbm_format_from_section(section,
2718 GBM_FORMAT_XRGB8888,
2719 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002720 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002721
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002722 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002723
Daniel Stone725c2c32012-06-22 14:04:36 +01002724 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002725 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002726 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002727 goto err_base;
2728 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002729
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002730 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002731 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
2732 param->seat_id);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002733 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002734 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002735 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002736 goto err_compositor;
2737 }
2738
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002739 ec->udev = udev_new();
2740 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002741 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002742 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002743 }
2744
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002745 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002746 ec->session_listener.notify = session_notify;
2747 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002748
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002749 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002750 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002751 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002752 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002753 }
David Herrmann0af066f2012-10-29 19:21:16 +01002754 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002755
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002756 if (init_drm(ec, drm_device) < 0) {
2757 weston_log("failed to initialize kms\n");
2758 goto err_udev_dev;
2759 }
2760
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002761 if (ec->use_pixman) {
2762 if (init_pixman(ec) < 0) {
2763 weston_log("failed to initialize pixman renderer\n");
2764 goto err_udev_dev;
2765 }
2766 } else {
2767 if (init_egl(ec) < 0) {
2768 weston_log("failed to initialize egl\n");
2769 goto err_udev_dev;
2770 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002771 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002772
2773 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002774 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002775
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002776 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002777
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002778 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002779 weston_compositor_add_key_binding(&ec->base, key,
2780 MODIFIER_CTRL | MODIFIER_ALT,
2781 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002782
Jesse Barnes58ef3792012-02-23 09:45:49 -05002783 wl_list_init(&ec->sprite_list);
2784 create_sprites(ec);
2785
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002786 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002787 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002788 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002789 }
2790
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002791 path = NULL;
2792
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002793 if (udev_input_init(&ec->input,
2794 &ec->base, ec->udev, param->seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002795 weston_log("failed to create input devices\n");
2796 goto err_sprite;
2797 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002798
2799 loop = wl_display_get_event_loop(ec->base.wl_display);
2800 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002801 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002802 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002803
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002804 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2805 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002806 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002807 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002808 }
2809 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2810 "drm", NULL);
2811 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002812 wl_event_loop_add_fd(loop,
2813 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002814 WL_EVENT_READABLE, udev_drm_event, ec);
2815
2816 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002817 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002818 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002819 }
2820
Daniel Stonea96b93c2012-06-22 14:04:37 +01002821 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002822
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002823 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002824 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002825 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002826 planes_binding, ec);
2827 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2828 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002829 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2830 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002831 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2832 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002833
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002834 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002835
2836err_udev_monitor:
2837 wl_event_source_remove(ec->udev_drm_source);
2838 udev_monitor_unref(ec->udev_monitor);
2839err_drm_source:
2840 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002841 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002842err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002843 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002844 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002845 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002846err_udev_dev:
2847 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002848err_launcher:
2849 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002850err_udev:
2851 udev_unref(ec->udev);
2852err_compositor:
2853 weston_compositor_shutdown(&ec->base);
2854err_base:
2855 free(ec);
2856 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002857}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002858
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002859WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002860backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002861 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002862{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002863 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002864
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002865 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002866 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2867 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2868 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002869 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002870 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002871 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002872
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002873 param.seat_id = default_seat;
2874
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002875 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002876
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002877 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002878}