blob: 44413081ac3bfa0d8cc7a1533e779f6274f07b96 [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;
Neil Robertsf37f82c2014-05-01 18:00:41 +0100956 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400957 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400958
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200959 if (c->gbm == NULL)
960 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200961 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
962 return NULL;
Neil Robertsf37f82c2014-05-01 18:00:41 +0100963 if (viewport->buffer.scale != output_base->current_scale)
964 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500965 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400966 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500967 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400968 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500969 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400970 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500971 if (ev->surface->buffer_ref.buffer == NULL ||
972 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600973 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400974 return NULL;
975
Jason Ekstranda7af7042013-10-12 22:38:11 -0500976 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400977
978 return &output->cursor_plane;
979}
980
981static void
982drm_output_set_cursor(struct drm_output *output)
983{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500984 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +0000985 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400986 struct drm_compositor *c =
987 (struct drm_compositor *) output->base.compositor;
988 EGLint handle, stride;
989 struct gbm_bo *bo;
990 uint32_t buf[64 * 64];
991 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400992 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500993
Jason Ekstranda7af7042013-10-12 22:38:11 -0500994 output->cursor_view = NULL;
995 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400996 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
997 return;
998 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500999
Neil Robertse5051712013-11-13 15:44:06 +00001000 buffer = ev->surface->buffer_ref.buffer;
1001
1002 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001003 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001004 pixman_region32_fini(&output->cursor_plane.damage);
1005 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001006 output->current_cursor ^= 1;
1007 bo = output->cursor_bo[output->current_cursor];
1008 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001009 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1010 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1011 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001012 for (i = 0; i < ev->surface->height; i++)
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001013 memcpy(buf + i * 64, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001014 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001015 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001016
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001017 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001018 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001019
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001020 handle = gbm_bo_get_handle(bo).s32;
1021 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -05001022 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001023 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001024 c->cursors_are_broken = 1;
1025 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001026 }
1027
Jason Ekstranda7af7042013-10-12 22:38:11 -05001028 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1029 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001030 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001031 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001032 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001033 c->cursors_are_broken = 1;
1034 }
1035
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001036 output->cursor_plane.x = x;
1037 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001038 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001039}
1040
Jesse Barnes58ef3792012-02-23 09:45:49 -05001041static void
1042drm_assign_planes(struct weston_output *output)
1043{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001044 struct drm_compositor *c =
1045 (struct drm_compositor *) output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001046 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001047 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001048 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001049
1050 /*
1051 * Find a surface for each sprite in the output using some heuristics:
1052 * 1) size
1053 * 2) frequency of update
1054 * 3) opacity (though some hw might support alpha blending)
1055 * 4) clipping (this can be fixed with color keys)
1056 *
1057 * The idea is to save on blitting since this should save power.
1058 * If we can get a large video surface on the sprite for example,
1059 * the main display surface may not need to update at all, and
1060 * the client buffer can be used directly for the sprite surface
1061 * as we do for flipping full screen surfaces.
1062 */
1063 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001064 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001065
Jason Ekstranda7af7042013-10-12 22:38:11 -05001066 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001067 struct weston_surface *es = ev->surface;
1068
1069 /* Test whether this buffer can ever go into a plane:
1070 * non-shm, or small enough to be a cursor.
1071 *
1072 * Also, keep a reference when using the pixman renderer.
1073 * That makes it possible to do a seamless switch to the GL
1074 * renderer and since the pixman renderer keeps a reference
1075 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001076 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001077 if (c->use_pixman ||
1078 (es->buffer_ref.buffer &&
1079 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001080 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001081 es->keep_buffer = 1;
1082 else
1083 es->keep_buffer = 0;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001084
Jesse Barnes58ef3792012-02-23 09:45:49 -05001085 pixman_region32_init(&surface_overlap);
1086 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001087 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001088
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001089 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001090 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001091 next_plane = primary;
1092 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001093 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001094 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001095 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001096 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001097 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001098 if (next_plane == NULL)
1099 next_plane = primary;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001100 weston_view_move_to_plane(ev, next_plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001101 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001102 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001103 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001104
Jesse Barnes58ef3792012-02-23 09:45:49 -05001105 pixman_region32_fini(&surface_overlap);
1106 }
1107 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001108}
1109
Matt Roper361d2ad2011-08-29 13:52:23 -07001110static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001111drm_output_fini_pixman(struct drm_output *output);
1112
1113static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001114drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001115{
1116 struct drm_output *output = (struct drm_output *) output_base;
1117 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001118 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001119 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001120
Xiong Zhangabd5d472013-10-11 14:43:07 +08001121 if (output->page_flip_pending) {
1122 output->destroy_pending = 1;
1123 weston_log("destroy output while page flip pending\n");
1124 return;
1125 }
1126
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001127 if (output->backlight)
1128 backlight_destroy(output->backlight);
1129
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001130 drmModeFreeProperty(output->dpms_prop);
1131
Matt Roper361d2ad2011-08-29 13:52:23 -07001132 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001133 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001134
1135 /* Restore original CRTC state */
1136 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001137 origcrtc->x, origcrtc->y,
1138 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001139 drmModeFreeCrtc(origcrtc);
1140
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001141 c->crtc_allocator &= ~(1 << output->crtc_id);
1142 c->connector_allocator &= ~(1 << output->connector_id);
1143
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001144 if (c->use_pixman) {
1145 drm_output_fini_pixman(output);
1146 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001147 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001148 gbm_surface_destroy(output->surface);
1149 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001150
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001151 weston_plane_release(&output->fb_plane);
1152 weston_plane_release(&output->cursor_plane);
1153
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001154 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001155
Matt Roper361d2ad2011-08-29 13:52:23 -07001156 free(output);
1157}
1158
Alex Wub7b8bda2012-04-17 17:20:48 +08001159static struct drm_mode *
1160choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1161{
1162 struct drm_mode *tmp_mode = NULL, *mode;
1163
Hardeningff39efa2013-09-18 23:56:35 +02001164 if (output->base.current_mode->width == target_mode->width &&
1165 output->base.current_mode->height == target_mode->height &&
1166 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001167 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001168 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001169
1170 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1171 if (mode->mode_info.hdisplay == target_mode->width &&
1172 mode->mode_info.vdisplay == target_mode->height) {
1173 if (mode->mode_info.vrefresh == target_mode->refresh ||
1174 target_mode->refresh == 0) {
1175 return mode;
1176 } else if (!tmp_mode)
1177 tmp_mode = mode;
1178 }
1179 }
1180
1181 return tmp_mode;
1182}
1183
1184static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001185drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001186static int
1187drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001188
1189static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001190drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1191{
1192 struct drm_output *output;
1193 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001194 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001195
1196 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001197 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001198 return -1;
1199 }
1200
1201 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001202 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001203 return -1;
1204 }
1205
1206 ec = (struct drm_compositor *)output_base->compositor;
1207 output = (struct drm_output *)output_base;
1208 drm_mode = choose_mode (output, mode);
1209
1210 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001211 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001212 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001213 }
1214
Hardeningff39efa2013-09-18 23:56:35 +02001215 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001216 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001217
Hardeningff39efa2013-09-18 23:56:35 +02001218 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001219
Hardeningff39efa2013-09-18 23:56:35 +02001220 output->base.current_mode = &drm_mode->base;
1221 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001222 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1223
Alex Wub7b8bda2012-04-17 17:20:48 +08001224 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001225 drm_output_release_fb(output, output->current);
1226 drm_output_release_fb(output, output->next);
1227 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001228
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001229 if (ec->use_pixman) {
1230 drm_output_fini_pixman(output);
1231 if (drm_output_init_pixman(output, ec) < 0) {
1232 weston_log("failed to init output pixman state with "
1233 "new mode\n");
1234 return -1;
1235 }
1236 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001237 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001238 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001239
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001240 if (drm_output_init_egl(output, ec) < 0) {
1241 weston_log("failed to init output egl state with "
1242 "new mode");
1243 return -1;
1244 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001245 }
1246
Alex Wub7b8bda2012-04-17 17:20:48 +08001247 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001248}
1249
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001250static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001251on_drm_input(int fd, uint32_t mask, void *data)
1252{
1253 drmEventContext evctx;
1254
1255 memset(&evctx, 0, sizeof evctx);
1256 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1257 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001258 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001259 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001260
1261 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001262}
1263
1264static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001265init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001266{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001267 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001268 uint64_t cap;
1269 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001270
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001271 sysnum = udev_device_get_sysnum(device);
1272 if (sysnum)
1273 ec->drm.id = atoi(sysnum);
1274 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001275 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001276 return -1;
1277 }
1278
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001279 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001280 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001281 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001282 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001283 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001284 udev_device_get_devnode(device));
1285 return -1;
1286 }
1287
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001288 weston_log("using %s\n", filename);
1289
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001290 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001291 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001292
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001293 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1294 if (ret == 0 && cap == 1)
1295 ec->clock = CLOCK_MONOTONIC;
1296 else
1297 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001298
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001299 return 0;
1300}
1301
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001302static struct gbm_device *
1303create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001304{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001305 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001306
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001307 gl_renderer = weston_load_module("gl-renderer.so",
1308 "gl_renderer_interface");
1309 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001310 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001311
1312 /* GBM will load a dri driver, but even though they need symbols from
1313 * libglapi, in some version of Mesa they are not linked to it. Since
1314 * only the gl-renderer module links to it, the call above won't make
1315 * these symbols globally available, and loading the DRI driver fails.
1316 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1317 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1318
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001319 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001320
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001321 return gbm;
1322}
1323
1324static int
1325drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1326{
1327 EGLint format;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001328
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001329 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001330 if (gl_renderer->create(&ec->base, ec->gbm,
1331 gl_renderer->opaque_attribs, &format) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001332 return -1;
1333 }
1334
1335 return 0;
1336}
1337
1338static int
1339init_egl(struct drm_compositor *ec)
1340{
1341 ec->gbm = create_gbm_device(ec->drm.fd);
1342
1343 if (!ec->gbm)
1344 return -1;
1345
1346 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001347 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001348 return -1;
1349 }
1350
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001351 return 0;
1352}
1353
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001354static int
1355init_pixman(struct drm_compositor *ec)
1356{
1357 return pixman_renderer_init(&ec->base);
1358}
1359
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001360static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001361drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001362{
1363 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001364 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001365
1366 mode = malloc(sizeof *mode);
1367 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001368 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001369
1370 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001371 mode->base.width = info->hdisplay;
1372 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001373
1374 /* Calculate higher precision (mHz) refresh rate */
1375 refresh = (info->clock * 1000000LL / info->htotal +
1376 info->vtotal / 2) / info->vtotal;
1377
1378 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1379 refresh *= 2;
1380 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1381 refresh /= 2;
1382 if (info->vscan > 1)
1383 refresh /= info->vscan;
1384
1385 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001386 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001387
1388 if (info->type & DRM_MODE_TYPE_PREFERRED)
1389 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1390
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001391 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1392
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001393 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001394}
1395
1396static int
1397drm_subpixel_to_wayland(int drm_value)
1398{
1399 switch (drm_value) {
1400 default:
1401 case DRM_MODE_SUBPIXEL_UNKNOWN:
1402 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1403 case DRM_MODE_SUBPIXEL_NONE:
1404 return WL_OUTPUT_SUBPIXEL_NONE;
1405 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1406 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1407 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1408 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1409 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1410 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1411 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1412 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1413 }
1414}
1415
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001416/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001417static uint32_t
1418drm_get_backlight(struct drm_output *output)
1419{
1420 long brightness, max_brightness, norm;
1421
1422 brightness = backlight_get_brightness(output->backlight);
1423 max_brightness = backlight_get_max_brightness(output->backlight);
1424
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001425 /* convert it on a scale of 0 to 255 */
1426 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001427
1428 return (uint32_t) norm;
1429}
1430
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001431/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001432static void
1433drm_set_backlight(struct weston_output *output_base, uint32_t value)
1434{
1435 struct drm_output *output = (struct drm_output *) output_base;
1436 long max_brightness, new_brightness;
1437
1438 if (!output->backlight)
1439 return;
1440
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001441 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001442 return;
1443
1444 max_brightness = backlight_get_max_brightness(output->backlight);
1445
1446 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001447 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001448
1449 backlight_set_brightness(output->backlight, new_brightness);
1450}
1451
1452static drmModePropertyPtr
1453drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1454{
1455 drmModePropertyPtr props;
1456 int i;
1457
1458 for (i = 0; i < connector->count_props; i++) {
1459 props = drmModeGetProperty(fd, connector->props[i]);
1460 if (!props)
1461 continue;
1462
1463 if (!strcmp(props->name, name))
1464 return props;
1465
1466 drmModeFreeProperty(props);
1467 }
1468
1469 return NULL;
1470}
1471
1472static void
1473drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1474{
1475 struct drm_output *output = (struct drm_output *) output_base;
1476 struct weston_compositor *ec = output_base->compositor;
1477 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001478
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001479 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001480 return;
1481
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001482 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1483 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001484}
1485
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001486static const char *connector_type_names[] = {
1487 "None",
1488 "VGA",
1489 "DVI",
1490 "DVI",
1491 "DVI",
1492 "Composite",
1493 "TV",
1494 "LVDS",
1495 "CTV",
1496 "DIN",
1497 "DP",
1498 "HDMI",
1499 "HDMI",
1500 "TV",
1501 "eDP",
1502};
1503
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001504static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001505find_crtc_for_connector(struct drm_compositor *ec,
1506 drmModeRes *resources, drmModeConnector *connector)
1507{
1508 drmModeEncoder *encoder;
1509 uint32_t possible_crtcs;
1510 int i, j;
1511
1512 for (j = 0; j < connector->count_encoders; j++) {
1513 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1514 if (encoder == NULL) {
1515 weston_log("Failed to get encoder.\n");
1516 return -1;
1517 }
1518 possible_crtcs = encoder->possible_crtcs;
1519 drmModeFreeEncoder(encoder);
1520
1521 for (i = 0; i < resources->count_crtcs; i++) {
1522 if (possible_crtcs & (1 << i) &&
1523 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1524 return i;
1525 }
1526 }
1527
1528 return -1;
1529}
1530
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001531/* Init output state that depends on gl or gbm */
1532static int
1533drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1534{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001535 EGLint format = output->format;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001536 int i, flags;
1537
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001538 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001539 output->base.current_mode->width,
1540 output->base.current_mode->height,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001541 format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001542 GBM_BO_USE_SCANOUT |
1543 GBM_BO_USE_RENDERING);
1544 if (!output->surface) {
1545 weston_log("failed to create gbm surface\n");
1546 return -1;
1547 }
1548
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001549 if (gl_renderer->output_create(&output->base, output->surface,
1550 gl_renderer->opaque_attribs,
1551 &format) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001552 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001553 gbm_surface_destroy(output->surface);
1554 return -1;
1555 }
1556
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001557 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1558
1559 for (i = 0; i < 2; i++) {
1560 if (output->cursor_bo[i])
1561 continue;
1562
1563 output->cursor_bo[i] =
1564 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1565 flags);
1566 }
1567
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001568 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1569 weston_log("cursor buffers unavailable, using gl cursors\n");
1570 ec->cursors_are_broken = 1;
1571 }
1572
1573 return 0;
1574}
1575
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001576static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001577drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1578{
Hardeningff39efa2013-09-18 23:56:35 +02001579 int w = output->base.current_mode->width;
1580 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001581 unsigned int i;
1582
1583 /* FIXME error checking */
1584
1585 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001586 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001587 if (!output->dumb[i])
1588 goto err;
1589
1590 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001591 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001592 output->dumb[i]->map,
1593 output->dumb[i]->stride);
1594 if (!output->image[i])
1595 goto err;
1596 }
1597
1598 if (pixman_renderer_output_create(&output->base) < 0)
1599 goto err;
1600
1601 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001602 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001603
1604 return 0;
1605
1606err:
1607 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1608 if (output->dumb[i])
1609 drm_fb_destroy_dumb(output->dumb[i]);
1610 if (output->image[i])
1611 pixman_image_unref(output->image[i]);
1612
1613 output->dumb[i] = NULL;
1614 output->image[i] = NULL;
1615 }
1616
1617 return -1;
1618}
1619
1620static void
1621drm_output_fini_pixman(struct drm_output *output)
1622{
1623 unsigned int i;
1624
1625 pixman_renderer_output_destroy(&output->base);
1626 pixman_region32_fini(&output->previous_damage);
1627
1628 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1629 drm_fb_destroy_dumb(output->dumb[i]);
1630 pixman_image_unref(output->image[i]);
1631 output->dumb[i] = NULL;
1632 output->image[i] = NULL;
1633 }
1634}
1635
Richard Hughes2b2092a2013-04-24 14:58:02 +01001636static void
1637edid_parse_string(const uint8_t *data, char text[])
1638{
1639 int i;
1640 int replaced = 0;
1641
1642 /* this is always 12 bytes, but we can't guarantee it's null
1643 * terminated or not junk. */
1644 strncpy(text, (const char *) data, 12);
1645
1646 /* remove insane chars */
1647 for (i = 0; text[i] != '\0'; i++) {
1648 if (text[i] == '\n' ||
1649 text[i] == '\r') {
1650 text[i] = '\0';
1651 break;
1652 }
1653 }
1654
1655 /* ensure string is printable */
1656 for (i = 0; text[i] != '\0'; i++) {
1657 if (!isprint(text[i])) {
1658 text[i] = '-';
1659 replaced++;
1660 }
1661 }
1662
1663 /* if the string is random junk, ignore the string */
1664 if (replaced > 4)
1665 text[0] = '\0';
1666}
1667
1668#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1669#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1670#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1671#define EDID_OFFSET_DATA_BLOCKS 0x36
1672#define EDID_OFFSET_LAST_BLOCK 0x6c
1673#define EDID_OFFSET_PNPID 0x08
1674#define EDID_OFFSET_SERIAL 0x0c
1675
1676static int
1677edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1678{
1679 int i;
1680 uint32_t serial_number;
1681
1682 /* check header */
1683 if (length < 128)
1684 return -1;
1685 if (data[0] != 0x00 || data[1] != 0xff)
1686 return -1;
1687
1688 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1689 * /--08--\/--09--\
1690 * 7654321076543210
1691 * |\---/\---/\---/
1692 * R C1 C2 C3 */
1693 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1694 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1695 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1696 edid->pnp_id[3] = '\0';
1697
1698 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1699 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1700 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1701 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1702 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1703 if (serial_number > 0)
1704 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1705
1706 /* parse EDID data */
1707 for (i = EDID_OFFSET_DATA_BLOCKS;
1708 i <= EDID_OFFSET_LAST_BLOCK;
1709 i += 18) {
1710 /* ignore pixel clock data */
1711 if (data[i] != 0)
1712 continue;
1713 if (data[i+2] != 0)
1714 continue;
1715
1716 /* any useful blocks? */
1717 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1718 edid_parse_string(&data[i+5],
1719 edid->monitor_name);
1720 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1721 edid_parse_string(&data[i+5],
1722 edid->serial_number);
1723 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1724 edid_parse_string(&data[i+5],
1725 edid->eisa_id);
1726 }
1727 }
1728 return 0;
1729}
1730
1731static void
1732find_and_parse_output_edid(struct drm_compositor *ec,
1733 struct drm_output *output,
1734 drmModeConnector *connector)
1735{
1736 drmModePropertyBlobPtr edid_blob = NULL;
1737 drmModePropertyPtr property;
1738 int i;
1739 int rc;
1740
1741 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1742 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1743 if (!property)
1744 continue;
1745 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1746 !strcmp(property->name, "EDID")) {
1747 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1748 connector->prop_values[i]);
1749 }
1750 drmModeFreeProperty(property);
1751 }
1752 if (!edid_blob)
1753 return;
1754
1755 rc = edid_parse(&output->edid,
1756 edid_blob->data,
1757 edid_blob->length);
1758 if (!rc) {
1759 weston_log("EDID data '%s', '%s', '%s'\n",
1760 output->edid.pnp_id,
1761 output->edid.monitor_name,
1762 output->edid.serial_number);
1763 if (output->edid.pnp_id[0] != '\0')
1764 output->base.make = output->edid.pnp_id;
1765 if (output->edid.monitor_name[0] != '\0')
1766 output->base.model = output->edid.monitor_name;
1767 if (output->edid.serial_number[0] != '\0')
1768 output->base.serial_number = output->edid.serial_number;
1769 }
1770 drmModeFreePropertyBlob(edid_blob);
1771}
1772
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001773
1774
1775static int
1776parse_modeline(const char *s, drmModeModeInfo *mode)
1777{
1778 char hsync[16];
1779 char vsync[16];
1780 float fclock;
1781
1782 mode->type = DRM_MODE_TYPE_USERDEF;
1783 mode->hskew = 0;
1784 mode->vscan = 0;
1785 mode->vrefresh = 0;
1786 mode->flags = 0;
1787
Rob Bradford307e09e2013-07-26 16:29:40 +01001788 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001789 &fclock,
1790 &mode->hdisplay,
1791 &mode->hsync_start,
1792 &mode->hsync_end,
1793 &mode->htotal,
1794 &mode->vdisplay,
1795 &mode->vsync_start,
1796 &mode->vsync_end,
1797 &mode->vtotal, hsync, vsync) != 11)
1798 return -1;
1799
1800 mode->clock = fclock * 1000;
1801 if (strcmp(hsync, "+hsync") == 0)
1802 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1803 else if (strcmp(hsync, "-hsync") == 0)
1804 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1805 else
1806 return -1;
1807
1808 if (strcmp(vsync, "+vsync") == 0)
1809 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1810 else if (strcmp(vsync, "-vsync") == 0)
1811 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1812 else
1813 return -1;
1814
1815 return 0;
1816}
1817
1818static uint32_t
1819parse_transform(const char *transform, const char *output_name)
1820{
1821 static const struct { const char *name; uint32_t token; } names[] = {
1822 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1823 { "90", WL_OUTPUT_TRANSFORM_90 },
1824 { "180", WL_OUTPUT_TRANSFORM_180 },
1825 { "270", WL_OUTPUT_TRANSFORM_270 },
1826 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1827 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1828 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1829 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1830 };
1831 unsigned int i;
1832
1833 for (i = 0; i < ARRAY_LENGTH(names); i++)
1834 if (strcmp(names[i].name, transform) == 0)
1835 return names[i].token;
1836
1837 weston_log("Invalid transform \"%s\" for output %s\n",
1838 transform, output_name);
1839
1840 return WL_OUTPUT_TRANSFORM_NORMAL;
1841}
1842
Rob Bradford66bd9f52013-06-25 18:56:42 +01001843static void
1844setup_output_seat_constraint(struct drm_compositor *ec,
1845 struct weston_output *output,
1846 const char *s)
1847{
1848 if (strcmp(s, "") != 0) {
1849 struct udev_seat *seat;
1850
Jonas Ådahl58e15862014-03-12 22:08:40 +01001851 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001852 if (seat)
1853 seat->base.output = output;
1854
1855 if (seat && seat->base.pointer)
1856 weston_pointer_clamp(seat->base.pointer,
1857 &seat->base.pointer->x,
1858 &seat->base.pointer->y);
1859 }
1860}
1861
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001862static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001863get_gbm_format_from_section(struct weston_config_section *section,
1864 uint32_t default_value,
1865 uint32_t *format)
1866{
1867 char *s;
1868 int ret = 0;
1869
1870 weston_config_section_get_string(section,
1871 "gbm-format", &s, NULL);
1872
1873 if (s == NULL)
1874 *format = default_value;
1875 else if (strcmp(s, "xrgb8888") == 0)
1876 *format = GBM_FORMAT_XRGB8888;
1877 else if (strcmp(s, "rgb565") == 0)
1878 *format = GBM_FORMAT_RGB565;
1879 else if (strcmp(s, "xrgb2101010") == 0)
1880 *format = GBM_FORMAT_XRGB2101010;
1881 else {
1882 weston_log("fatal: unrecognized pixel format: %s\n", s);
1883 ret = -1;
1884 }
1885
1886 free(s);
1887
1888 return ret;
1889}
1890
1891static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001892create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001893 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001894 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001895 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001896{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001897 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001898 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001899 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001900 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001901 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001902 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001903 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001904 int i, width, height, scale;
1905 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001906 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001907 enum output_config config;
1908 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001909
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001910 i = find_crtc_for_connector(ec, resources, connector);
1911 if (i < 0) {
1912 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001913 return -1;
1914 }
1915
Peter Huttererf3d62272013-08-08 11:57:05 +10001916 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001917 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001918 return -1;
1919
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001920 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1921 output->base.make = "unknown";
1922 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001923 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001924 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001925
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001926 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1927 type_name = connector_type_names[connector->connector_type];
1928 else
1929 type_name = "UNKNOWN";
1930 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001931 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001932
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001933 section = weston_config_get_section(ec->base.config, "output", "name",
1934 output->base.name);
1935 weston_config_section_get_string(section, "mode", &s, "preferred");
1936 if (strcmp(s, "off") == 0)
1937 config = OUTPUT_CONFIG_OFF;
1938 else if (strcmp(s, "preferred") == 0)
1939 config = OUTPUT_CONFIG_PREFERRED;
1940 else if (strcmp(s, "current") == 0)
1941 config = OUTPUT_CONFIG_CURRENT;
1942 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1943 config = OUTPUT_CONFIG_MODE;
1944 else if (parse_modeline(s, &modeline) == 0)
1945 config = OUTPUT_CONFIG_MODELINE;
1946 else {
1947 weston_log("Invalid mode \"%s\" for output %s\n",
1948 s, output->base.name);
1949 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001950 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001951 free(s);
1952
1953 weston_config_section_get_int(section, "scale", &scale, 1);
1954 weston_config_section_get_string(section, "transform", &s, "normal");
1955 transform = parse_transform(s, output->base.name);
1956 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001957
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001958 if (get_gbm_format_from_section(section,
1959 ec->format,
1960 &output->format) == -1)
1961 output->format = ec->format;
1962
Rob Bradford66bd9f52013-06-25 18:56:42 +01001963 weston_config_section_get_string(section, "seat", &s, "");
1964 setup_output_seat_constraint(ec, &output->base, s);
1965 free(s);
1966
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001967 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001968 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001969 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001970 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001971 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001972
Matt Roper361d2ad2011-08-29 13:52:23 -07001973 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001974 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001975
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001976 /* Get the current mode on the crtc that's currently driving
1977 * this connector. */
1978 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001979 memset(&crtc_mode, 0, sizeof crtc_mode);
1980 if (encoder != NULL) {
1981 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1982 drmModeFreeEncoder(encoder);
1983 if (crtc == NULL)
1984 goto err_free;
1985 if (crtc->mode_valid)
1986 crtc_mode = crtc->mode;
1987 drmModeFreeCrtc(crtc);
1988 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001989
David Herrmann0f0d54e2011-12-08 17:05:45 +01001990 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001991 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001992 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001993 goto err_free;
1994 }
1995
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001996 if (config == OUTPUT_CONFIG_OFF) {
1997 weston_log("Disabling output %s\n", output->base.name);
1998 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1999 0, 0, 0, 0, 0, NULL);
2000 goto err_free;
2001 }
2002
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002003 preferred = NULL;
2004 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002005 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002006 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002007
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002008 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002009 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002010 width == drm_mode->base.width &&
2011 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002012 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002013 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002014 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002015 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002016 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002017 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002018 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002019
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002020 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002021 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002022 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002023 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002024 }
2025
Wang Quanxianacb805a2012-07-30 18:09:46 -04002026 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002027 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002028 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002029 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002030 }
2031
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002032 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002033 configured = current;
2034
Wang Quanxianacb805a2012-07-30 18:09:46 -04002035 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002036 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002037 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002038 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002039 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002040 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002041 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002042 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002043 else if (best)
2044 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002045
Hardeningff39efa2013-09-18 23:56:35 +02002046 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002047 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002048 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002049 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002050
Hardeningff39efa2013-09-18 23:56:35 +02002051 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002052
John Kåre Alsaker94659272012-11-13 19:10:18 +01002053 weston_output_init(&output->base, &ec->base, x, y,
2054 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002055 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002056
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002057 if (ec->use_pixman) {
2058 if (drm_output_init_pixman(output, ec) < 0) {
2059 weston_log("Failed to init output pixman state\n");
2060 goto err_output;
2061 }
2062 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002063 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002064 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002065 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002066
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002067 output->backlight = backlight_init(drm_device,
2068 connector->connector_type);
2069 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002070 weston_log("Initialized backlight, device %s\n",
2071 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002072 output->base.set_backlight = drm_set_backlight;
2073 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002074 } else {
2075 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002076 }
2077
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002078 wl_list_insert(ec->base.output_list.prev, &output->base.link);
2079
Richard Hughes2b2092a2013-04-24 14:58:02 +01002080 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002081 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2082 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002083
Jonas Ådahle5a12252013-04-05 23:07:11 +02002084 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002085 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002086 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002087 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002088 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002089 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002090
Richard Hughese7299962013-05-01 21:52:12 +01002091 output->base.gamma_size = output->original_crtc->gamma_size;
2092 output->base.set_gamma = drm_output_set_gamma;
2093
Xiong Zhang97116532013-10-23 13:58:31 +08002094 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2095 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002096
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002097 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2098 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2099 &ec->base.primary_plane);
2100
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002101 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002102 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002103 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002104 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002105 m->width, m->height, m->refresh / 1000.0,
2106 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2107 ", preferred" : "",
2108 m->flags & WL_OUTPUT_MODE_CURRENT ?
2109 ", current" : "",
2110 connector->count_modes == 0 ?
2111 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002112
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002113 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002114
John Kåre Alsaker94659272012-11-13 19:10:18 +01002115err_output:
2116 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002117err_free:
2118 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2119 base.link) {
2120 wl_list_remove(&drm_mode->base.link);
2121 free(drm_mode);
2122 }
2123
2124 drmModeFreeCrtc(output->original_crtc);
2125 ec->crtc_allocator &= ~(1 << output->crtc_id);
2126 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002127 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002128
David Herrmann0f0d54e2011-12-08 17:05:45 +01002129 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002130}
2131
Jesse Barnes58ef3792012-02-23 09:45:49 -05002132static void
2133create_sprites(struct drm_compositor *ec)
2134{
2135 struct drm_sprite *sprite;
2136 drmModePlaneRes *plane_res;
2137 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002138 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002139
2140 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2141 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002142 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002143 strerror(errno));
2144 return;
2145 }
2146
2147 for (i = 0; i < plane_res->count_planes; i++) {
2148 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2149 if (!plane)
2150 continue;
2151
Peter Huttererf3d62272013-08-08 11:57:05 +10002152 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002153 plane->count_formats));
2154 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002155 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002156 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002157 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002158 continue;
2159 }
2160
Jesse Barnes58ef3792012-02-23 09:45:49 -05002161 sprite->possible_crtcs = plane->possible_crtcs;
2162 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002163 sprite->current = NULL;
2164 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002165 sprite->compositor = ec;
2166 sprite->count_formats = plane->count_formats;
2167 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002168 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002169 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002170 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002171 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2172 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002173
2174 wl_list_insert(&ec->sprite_list, &sprite->link);
2175 }
2176
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002177 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002178}
2179
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002180static void
2181destroy_sprites(struct drm_compositor *compositor)
2182{
2183 struct drm_sprite *sprite, *next;
2184 struct drm_output *output;
2185
2186 output = container_of(compositor->base.output_list.next,
2187 struct drm_output, base.link);
2188
2189 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2190 drmModeSetPlane(compositor->drm.fd,
2191 sprite->plane_id,
2192 output->crtc_id, 0, 0,
2193 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002194 drm_output_release_fb(output, sprite->current);
2195 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002196 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002197 free(sprite);
2198 }
2199}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002200
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002201static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002202create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002203 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002204{
2205 drmModeConnector *connector;
2206 drmModeRes *resources;
2207 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002208 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002209
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002210 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002211 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002212 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002213 return -1;
2214 }
2215
Jesse Barnes58ef3792012-02-23 09:45:49 -05002216 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002217 if (!ec->crtcs) {
2218 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002219 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002220 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002221
Rob Clark4339add2012-08-09 14:18:28 -05002222 ec->min_width = resources->min_width;
2223 ec->max_width = resources->max_width;
2224 ec->min_height = resources->min_height;
2225 ec->max_height = resources->max_height;
2226
Jesse Barnes58ef3792012-02-23 09:45:49 -05002227 ec->num_crtcs = resources->count_crtcs;
2228 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2229
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002230 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002231 connector = drmModeGetConnector(ec->drm.fd,
2232 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002233 if (connector == NULL)
2234 continue;
2235
2236 if (connector->connection == DRM_MODE_CONNECTED &&
2237 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002238 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002239 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002240 connector, x, y,
2241 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002242 drmModeFreeConnector(connector);
2243 continue;
2244 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002245
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002246 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002247 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002248 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002249 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002250
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002251 drmModeFreeConnector(connector);
2252 }
2253
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002254 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002255 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002256 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002257 return -1;
2258 }
2259
2260 drmModeFreeResources(resources);
2261
2262 return 0;
2263}
2264
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002265static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002266update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002267{
2268 drmModeConnector *connector;
2269 drmModeRes *resources;
2270 struct drm_output *output, *next;
2271 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002272 uint32_t connected = 0, disconnects = 0;
2273 int i;
2274
2275 resources = drmModeGetResources(ec->drm.fd);
2276 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002277 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002278 return;
2279 }
2280
2281 /* collect new connects */
2282 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002283 int connector_id = resources->connectors[i];
2284
2285 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002286 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002287 continue;
2288
David Herrmann7551cff2011-12-08 17:05:43 +01002289 if (connector->connection != DRM_MODE_CONNECTED) {
2290 drmModeFreeConnector(connector);
2291 continue;
2292 }
2293
Benjamin Franzke117483d2011-08-30 11:38:26 +02002294 connected |= (1 << connector_id);
2295
2296 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002297 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002298 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002299 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002300
2301 /* XXX: not yet needed, we die with 0 outputs */
2302 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002303 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002304 else
2305 x = 0;
2306 y = 0;
2307 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002308 connector, x, y,
2309 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002310 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002311
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002312 }
2313 drmModeFreeConnector(connector);
2314 }
2315 drmModeFreeResources(resources);
2316
2317 disconnects = ec->connector_allocator & ~connected;
2318 if (disconnects) {
2319 wl_list_for_each_safe(output, next, &ec->base.output_list,
2320 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002321 if (disconnects & (1 << output->connector_id)) {
2322 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002323 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002324 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002325 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002326 }
2327 }
2328 }
2329
2330 /* FIXME: handle zero outputs, without terminating */
2331 if (ec->connector_allocator == 0)
2332 wl_display_terminate(ec->base.wl_display);
2333}
2334
2335static int
David Herrmannd7488c22012-03-11 20:05:21 +01002336udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002337{
David Herrmannd7488c22012-03-11 20:05:21 +01002338 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002339 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002340
2341 sysnum = udev_device_get_sysnum(device);
2342 if (!sysnum || atoi(sysnum) != ec->drm.id)
2343 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002344
David Herrmann6ac52db2012-03-11 20:05:22 +01002345 val = udev_device_get_property_value(device, "HOTPLUG");
2346 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002347 return 0;
2348
David Herrmann6ac52db2012-03-11 20:05:22 +01002349 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002350}
2351
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002352static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002353udev_drm_event(int fd, uint32_t mask, void *data)
2354{
2355 struct drm_compositor *ec = data;
2356 struct udev_device *event;
2357
2358 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002359
David Herrmannd7488c22012-03-11 20:05:21 +01002360 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002361 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002362
2363 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002364
2365 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002366}
2367
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002368static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002369drm_restore(struct weston_compositor *ec)
2370{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002371 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002372}
2373
2374static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002375drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002376{
2377 struct drm_compositor *d = (struct drm_compositor *) ec;
2378
Rob Bradfordd355b802013-05-31 18:09:55 +01002379 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002380
2381 wl_event_source_remove(d->udev_drm_source);
2382 wl_event_source_remove(d->drm_source);
2383
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002384 destroy_sprites(d);
2385
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002386 weston_compositor_shutdown(ec);
2387
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002388 if (d->gbm)
2389 gbm_device_destroy(d->gbm);
2390
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002391 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002392
Rob Bradford45c15b82013-07-26 16:29:35 +01002393 close(d->drm.fd);
2394
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002395 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002396}
2397
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002398static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002399drm_compositor_set_modes(struct drm_compositor *compositor)
2400{
2401 struct drm_output *output;
2402 struct drm_mode *drm_mode;
2403 int ret;
2404
2405 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002406 if (!output->current) {
2407 /* If something that would cause the output to
2408 * switch mode happened while in another vt, we
2409 * might not have a current drm_fb. In that case,
2410 * schedule a repaint and let drm_output_repaint
2411 * handle setting the mode. */
2412 weston_output_schedule_repaint(&output->base);
2413 continue;
2414 }
2415
Hardeningff39efa2013-09-18 23:56:35 +02002416 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002417 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002418 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002419 &output->connector_id, 1,
2420 &drm_mode->mode_info);
2421 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002422 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002423 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002424 drm_mode->base.width, drm_mode->base.height,
2425 output->base.x, output->base.y);
2426 }
2427 }
2428}
2429
2430static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002431session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002432{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002433 struct weston_compositor *compositor = data;
2434 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002435 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002436 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002437
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002438 if (ec->base.session_active) {
2439 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002440 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002441 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002442 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002443 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002444 } else {
2445 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002446 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002447
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002448 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002449 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002450
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002451 /* If we have a repaint scheduled (either from a
2452 * pending pageflip or the idle handler), make sure we
2453 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002454 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002455 * further attemps at repainting. When we switch
2456 * back, we schedule a repaint, which will process
2457 * pending frame callbacks. */
2458
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002459 wl_list_for_each(output, &ec->base.output_list, base.link) {
2460 output->base.repaint_needed = 0;
2461 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002462 }
2463
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002464 output = container_of(ec->base.output_list.next,
2465 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002466
2467 wl_list_for_each(sprite, &ec->sprite_list, link)
2468 drmModeSetPlane(ec->drm.fd,
2469 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002470 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002471 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002472 };
2473}
2474
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002475static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002476switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002477{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002478 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002479
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002480 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002481}
2482
David Herrmann0af066f2012-10-29 19:21:16 +01002483/*
2484 * Find primary GPU
2485 * Some systems may have multiple DRM devices attached to a single seat. This
2486 * function loops over all devices and tries to find a PCI device with the
2487 * boot_vga sysfs attribute set to 1.
2488 * If no such device is found, the first DRM device reported by udev is used.
2489 */
2490static struct udev_device*
2491find_primary_gpu(struct drm_compositor *ec, const char *seat)
2492{
2493 struct udev_enumerate *e;
2494 struct udev_list_entry *entry;
2495 const char *path, *device_seat, *id;
2496 struct udev_device *device, *drm_device, *pci;
2497
2498 e = udev_enumerate_new(ec->udev);
2499 udev_enumerate_add_match_subsystem(e, "drm");
2500 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2501
2502 udev_enumerate_scan_devices(e);
2503 drm_device = NULL;
2504 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2505 path = udev_list_entry_get_name(entry);
2506 device = udev_device_new_from_syspath(ec->udev, path);
2507 if (!device)
2508 continue;
2509 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2510 if (!device_seat)
2511 device_seat = default_seat;
2512 if (strcmp(device_seat, seat)) {
2513 udev_device_unref(device);
2514 continue;
2515 }
2516
2517 pci = udev_device_get_parent_with_subsystem_devtype(device,
2518 "pci", NULL);
2519 if (pci) {
2520 id = udev_device_get_sysattr_value(pci, "boot_vga");
2521 if (id && !strcmp(id, "1")) {
2522 if (drm_device)
2523 udev_device_unref(drm_device);
2524 drm_device = device;
2525 break;
2526 }
2527 }
2528
2529 if (!drm_device)
2530 drm_device = device;
2531 else
2532 udev_device_unref(device);
2533 }
2534
2535 udev_enumerate_unref(e);
2536 return drm_device;
2537}
2538
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002539static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002540planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002541{
2542 struct drm_compositor *c = data;
2543
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002544 switch (key) {
2545 case KEY_C:
2546 c->cursors_are_broken ^= 1;
2547 break;
2548 case KEY_V:
2549 c->sprites_are_broken ^= 1;
2550 break;
2551 case KEY_O:
2552 c->sprites_hidden ^= 1;
2553 break;
2554 default:
2555 break;
2556 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002557}
2558
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002559#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002560static void
2561recorder_frame_notify(struct wl_listener *listener, void *data)
2562{
2563 struct drm_output *output;
2564 struct drm_compositor *c;
2565 int fd, ret;
2566
2567 output = container_of(listener, struct drm_output,
2568 recorder_frame_listener);
2569 c = (struct drm_compositor *) output->base.compositor;
2570
2571 if (!output->recorder)
2572 return;
2573
2574 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2575 DRM_CLOEXEC, &fd);
2576 if (ret) {
2577 weston_log("[libva recorder] "
2578 "failed to create prime fd for front buffer\n");
2579 return;
2580 }
2581
Ander Conselvan de Oliveiraa61b9492014-04-16 12:05:12 +03002582 vaapi_recorder_frame(output->recorder, fd, output->current->stride);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002583}
2584
2585static void *
2586create_recorder(struct drm_compositor *c, int width, int height,
2587 const char *filename)
2588{
2589 int fd;
2590 drm_magic_t magic;
2591
2592 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2593 if (fd < 0)
2594 return NULL;
2595
2596 drmGetMagic(fd, &magic);
2597 drmAuthMagic(c->drm.fd, magic);
2598
2599 return vaapi_recorder_create(fd, width, height, filename);
2600}
2601
2602static void
2603recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2604 void *data)
2605{
2606 struct drm_compositor *c = data;
2607 struct drm_output *output;
2608 int width, height;
2609
2610 output = container_of(c->base.output_list.next,
2611 struct drm_output, base.link);
2612
2613 if (!output->recorder) {
Hardeningff39efa2013-09-18 23:56:35 +02002614 width = output->base.current_mode->width;
2615 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002616
2617 output->recorder =
2618 create_recorder(c, width, height, "capture.h264");
2619 if (!output->recorder) {
2620 weston_log("failed to create vaapi recorder\n");
2621 return;
2622 }
2623
2624 output->base.disable_planes++;
2625
2626 output->recorder_frame_listener.notify = recorder_frame_notify;
2627 wl_signal_add(&output->base.frame_signal,
2628 &output->recorder_frame_listener);
2629
2630 weston_output_schedule_repaint(&output->base);
2631
2632 weston_log("[libva recorder] initialized\n");
2633 } else {
2634 vaapi_recorder_destroy(output->recorder);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002635 output->recorder = NULL;
2636
2637 output->base.disable_planes--;
2638
2639 wl_list_remove(&output->recorder_frame_listener.link);
2640 weston_log("[libva recorder] done\n");
2641 }
2642}
2643#else
2644static void
2645recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2646 void *data)
2647{
2648 weston_log("Compiled without libva support\n");
2649}
2650#endif
2651
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002652static void
2653switch_to_gl_renderer(struct drm_compositor *c)
2654{
2655 struct drm_output *output;
2656
2657 if (!c->use_pixman)
2658 return;
2659
2660 weston_log("Switching to GL renderer\n");
2661
2662 c->gbm = create_gbm_device(c->drm.fd);
2663 if (!c->gbm) {
2664 weston_log("Failed to create gbm device. "
2665 "Aborting renderer switch\n");
2666 return;
2667 }
2668
2669 wl_list_for_each(output, &c->base.output_list, base.link)
2670 pixman_renderer_output_destroy(&output->base);
2671
2672 c->base.renderer->destroy(&c->base);
2673
2674 if (drm_compositor_create_gl_renderer(c) < 0) {
2675 gbm_device_destroy(c->gbm);
2676 weston_log("Failed to create GL renderer. Quitting.\n");
2677 /* FIXME: we need a function to shutdown cleanly */
2678 assert(0);
2679 }
2680
2681 wl_list_for_each(output, &c->base.output_list, base.link)
2682 drm_output_init_egl(output, c);
2683
2684 c->use_pixman = 0;
2685}
2686
2687static void
2688renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2689 void *data)
2690{
2691 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2692
2693 switch_to_gl_renderer(c);
2694}
2695
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002696static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002697drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002698 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002699 int *argc, char *argv[],
2700 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002701{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002702 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002703 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002704 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002705 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002706 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002707 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002708
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002709 weston_log("initializing drm backend\n");
2710
Peter Huttererf3d62272013-08-08 11:57:05 +10002711 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002712 if (ec == NULL)
2713 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002714
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002715 /* KMS support for sprites is not complete yet, so disable the
2716 * functionality for now. */
2717 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002718
2719 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002720 if (get_gbm_format_from_section(section,
2721 GBM_FORMAT_XRGB8888,
2722 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002723 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002724
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002725 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002726
Daniel Stone725c2c32012-06-22 14:04:36 +01002727 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002728 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002729 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002730 goto err_base;
2731 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002732
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002733 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002734 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
2735 param->seat_id);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002736 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002737 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002738 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002739 goto err_compositor;
2740 }
2741
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002742 ec->udev = udev_new();
2743 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002744 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002745 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002746 }
2747
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002748 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002749 ec->session_listener.notify = session_notify;
2750 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002751
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002752 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002753 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002754 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002755 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002756 }
David Herrmann0af066f2012-10-29 19:21:16 +01002757 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002758
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002759 if (init_drm(ec, drm_device) < 0) {
2760 weston_log("failed to initialize kms\n");
2761 goto err_udev_dev;
2762 }
2763
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002764 if (ec->use_pixman) {
2765 if (init_pixman(ec) < 0) {
2766 weston_log("failed to initialize pixman renderer\n");
2767 goto err_udev_dev;
2768 }
2769 } else {
2770 if (init_egl(ec) < 0) {
2771 weston_log("failed to initialize egl\n");
2772 goto err_udev_dev;
2773 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002774 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002775
2776 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002777 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002778
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002779 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002780
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002781 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002782 weston_compositor_add_key_binding(&ec->base, key,
2783 MODIFIER_CTRL | MODIFIER_ALT,
2784 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002785
Jesse Barnes58ef3792012-02-23 09:45:49 -05002786 wl_list_init(&ec->sprite_list);
2787 create_sprites(ec);
2788
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002789 if (udev_input_init(&ec->input,
2790 &ec->base, ec->udev, param->seat_id) < 0) {
2791 weston_log("failed to create input devices\n");
2792 goto err_sprite;
2793 }
2794
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002795 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002796 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002797 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002798 }
2799
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002800 /* A this point we have some idea of whether or not we have a working
2801 * cursor plane. */
2802 if (!ec->cursors_are_broken)
2803 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2804
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002805 path = NULL;
2806
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002807 loop = wl_display_get_event_loop(ec->base.wl_display);
2808 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002809 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002810 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002811
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002812 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2813 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002814 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002815 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002816 }
2817 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2818 "drm", NULL);
2819 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002820 wl_event_loop_add_fd(loop,
2821 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002822 WL_EVENT_READABLE, udev_drm_event, ec);
2823
2824 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002825 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002826 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002827 }
2828
Daniel Stonea96b93c2012-06-22 14:04:37 +01002829 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002830
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002831 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002832 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002833 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002834 planes_binding, ec);
2835 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2836 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002837 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2838 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002839 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2840 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002841
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002842 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002843
2844err_udev_monitor:
2845 wl_event_source_remove(ec->udev_drm_source);
2846 udev_monitor_unref(ec->udev_monitor);
2847err_drm_source:
2848 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002849err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002850 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002851err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002852 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002853 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002854 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002855err_udev_dev:
2856 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002857err_launcher:
2858 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002859err_udev:
2860 udev_unref(ec->udev);
2861err_compositor:
2862 weston_compositor_shutdown(&ec->base);
2863err_base:
2864 free(ec);
2865 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002866}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002867
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002868WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002869backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002870 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002871{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002872 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002873
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002874 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002875 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2876 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2877 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002878 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002879 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002880 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002881
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002882 param.seat_id = default_seat;
2883
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002884 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002885
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002886 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002887}