blob: 3f584a66ef74a4e6f812c8893305b18ad34315f7 [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"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050050#include "udev-seat.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;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300458 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500459 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500460
Jason Ekstranda7af7042013-10-12 22:38:11 -0500461 if (ev->geometry.x != output->base.x ||
462 ev->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200463 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200464 buffer->width != output->base.current_mode->width ||
465 buffer->height != output->base.current_mode->height ||
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100466 output->base.transform != ev->surface->buffer_viewport.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500467 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400468 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500469
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400470 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700471 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500472
Rob Bradford9b101872012-09-14 23:25:41 +0100473 /* Unable to use the buffer for scanout */
474 if (!bo)
475 return NULL;
476
Jason Ekstranda7af7042013-10-12 22:38:11 -0500477 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500478 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300479 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400480 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300481 }
482
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500483 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300484 if (!output->next) {
485 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400486 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300487 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500488
Pekka Paalanende685b82012-12-04 15:58:12 +0200489 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500490
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400491 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500492}
493
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500494static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200495drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400496{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200497 struct drm_compositor *c =
498 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300499 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400500
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200501 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400502
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300503 bo = gbm_surface_lock_front_buffer(output->surface);
504 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200505 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400506 return;
507 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300508
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000509 output->next = drm_fb_get_from_bo(bo, c, output->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300510 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200511 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300512 gbm_surface_release_buffer(output->surface, bo);
513 return;
514 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400515}
516
517static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200518drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
519{
520 struct weston_compositor *ec = output->base.compositor;
521 pixman_region32_t total_damage, previous_damage;
522
523 pixman_region32_init(&total_damage);
524 pixman_region32_init(&previous_damage);
525
526 pixman_region32_copy(&previous_damage, damage);
527
528 pixman_region32_union(&total_damage, damage, &output->previous_damage);
529 pixman_region32_copy(&output->previous_damage, &previous_damage);
530
531 output->current_image ^= 1;
532
533 output->next = output->dumb[output->current_image];
534 pixman_renderer_output_set_buffer(&output->base,
535 output->image[output->current_image]);
536
537 ec->renderer->repaint_output(&output->base, &total_damage);
538
539 pixman_region32_fini(&total_damage);
540 pixman_region32_fini(&previous_damage);
541}
542
543static void
544drm_output_render(struct drm_output *output, pixman_region32_t *damage)
545{
546 struct drm_compositor *c =
547 (struct drm_compositor *) output->base.compositor;
548
549 if (c->use_pixman)
550 drm_output_render_pixman(output, damage);
551 else
552 drm_output_render_gl(output, damage);
553
554 pixman_region32_subtract(&c->base.primary_plane.damage,
555 &c->base.primary_plane.damage, damage);
556}
557
558static void
Richard Hughese7299962013-05-01 21:52:12 +0100559drm_output_set_gamma(struct weston_output *output_base,
560 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
561{
562 int rc;
563 struct drm_output *output = (struct drm_output *) output_base;
564 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
565
566 /* check */
567 if (output_base->gamma_size != size)
568 return;
569 if (!output->original_crtc)
570 return;
571
572 rc = drmModeCrtcSetGamma(compositor->drm.fd,
573 output->crtc_id,
574 size, r, g, b);
575 if (rc)
576 weston_log("set gamma failed: %m\n");
577}
578
David Herrmann1edf44c2013-10-22 17:11:26 +0200579static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500580drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400581 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100582{
583 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500584 struct drm_compositor *compositor =
585 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500586 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400587 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500588 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100589
Xiong Zhangabd5d472013-10-11 14:43:07 +0800590 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200591 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800592
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300593 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400594 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300595 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200596 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100597
Hardeningff39efa2013-09-18 23:56:35 +0200598 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200599 if (!output->current ||
600 output->current->stride != output->next->stride) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400601 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300602 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400603 &output->connector_id, 1,
604 &mode->mode_info);
605 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200606 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200607 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400608 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300609 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200610 }
611
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500612 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300613 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500614 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200615 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200616 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500617 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100618
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300619 output->page_flip_pending = 1;
620
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400621 drm_output_set_cursor(output);
622
Jesse Barnes58ef3792012-02-23 09:45:49 -0500623 /*
624 * Now, update all the sprite surfaces
625 */
626 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200627 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500628 drmVBlank vbl = {
629 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
630 .request.sequence = 1,
631 };
632
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200633 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200634 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500635 continue;
636
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200637 if (s->next && !compositor->sprites_hidden)
638 fb_id = s->next->fb_id;
639
Jesse Barnes58ef3792012-02-23 09:45:49 -0500640 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200641 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500642 s->dest_x, s->dest_y,
643 s->dest_w, s->dest_h,
644 s->src_x, s->src_y,
645 s->src_w, s->src_h);
646 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200647 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500648 ret, strerror(errno));
649
Rob Clark5ca1a472012-08-08 20:27:37 -0500650 if (output->pipe > 0)
651 vbl.request.type |= DRM_VBLANK_SECONDARY;
652
Jesse Barnes58ef3792012-02-23 09:45:49 -0500653 /*
654 * Queue a vblank signal so we know when the surface
655 * becomes active on the display or has been replaced.
656 */
657 vbl.request.signal = (unsigned long)s;
658 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
659 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200660 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500661 ret, strerror(errno));
662 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300663
664 s->output = output;
665 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500666 }
667
David Herrmann1edf44c2013-10-22 17:11:26 +0200668 return 0;
669
670err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800671 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200672 if (output->next) {
673 drm_output_release_fb(output, output->next);
674 output->next = NULL;
675 }
676
677 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400678}
679
680static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200681drm_output_start_repaint_loop(struct weston_output *output_base)
682{
683 struct drm_output *output = (struct drm_output *) output_base;
684 struct drm_compositor *compositor = (struct drm_compositor *)
685 output_base->compositor;
686 uint32_t fb_id;
David Herrmann3c688c52013-10-22 17:11:25 +0200687 uint32_t msec;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300688 struct timespec ts;
689
Xiong Zhangabd5d472013-10-11 14:43:07 +0800690 if (output->destroy_pending)
691 return;
692
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300693 if (!output->current) {
694 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200695 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300696 }
697
698 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200699
700 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
701 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
702 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200703 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200704 }
David Herrmann3c688c52013-10-22 17:11:25 +0200705
706 return;
707
708finish_frame:
709 /* if we cannot page-flip, immediately finish frame */
710 clock_gettime(compositor->clock, &ts);
711 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
712 weston_output_finish_frame(output_base, msec);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200713}
714
715static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500716vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
717 void *data)
718{
719 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300720 struct drm_output *output = s->output;
721 uint32_t msecs;
722
723 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500724
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200725 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200726 s->current = s->next;
727 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300728
729 if (!output->page_flip_pending) {
730 msecs = sec * 1000 + usec / 1000;
731 weston_output_finish_frame(&output->base, msecs);
732 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500733}
734
735static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800736drm_output_destroy(struct weston_output *output_base);
737
738static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400739page_flip_handler(int fd, unsigned int frame,
740 unsigned int sec, unsigned int usec, void *data)
741{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200742 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400743 uint32_t msecs;
744
Jonas Ådahle5a12252013-04-05 23:07:11 +0200745 /* We don't set page_flip_pending on start_repaint_loop, in that case
746 * we just want to page flip to the current buffer to get an accurate
747 * timestamp */
748 if (output->page_flip_pending) {
749 drm_output_release_fb(output, output->current);
750 output->current = output->next;
751 output->next = NULL;
752 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300753
Jonas Ådahle5a12252013-04-05 23:07:11 +0200754 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400755
Xiong Zhangabd5d472013-10-11 14:43:07 +0800756 if (output->destroy_pending)
757 drm_output_destroy(&output->base);
758 else if (!output->vblank_pending) {
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300759 msecs = sec * 1000 + usec / 1000;
760 weston_output_finish_frame(&output->base, msecs);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300761
762 /* We can't call this from frame_notify, because the output's
763 * repaint needed flag is cleared just after that */
764 if (output->recorder)
765 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300766 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200767}
768
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500769static uint32_t
770drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500771 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500772{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500773 uint32_t i, format;
774
775 format = gbm_bo_get_format(bo);
776
777 if (format == GBM_FORMAT_ARGB8888) {
778 pixman_region32_t r;
779
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500780 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600781 ev->surface->width,
782 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500783 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500784
785 if (!pixman_region32_not_empty(&r))
786 format = GBM_FORMAT_XRGB8888;
787
788 pixman_region32_fini(&r);
789 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500790
791 for (i = 0; i < s->count_formats; i++)
792 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500793 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500794
795 return 0;
796}
797
798static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500799drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500800{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500801 return !ev->transform.enabled ||
802 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500803}
804
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400805static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500806drm_output_prepare_overlay_view(struct weston_output *output_base,
807 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500808{
809 struct weston_compositor *ec = output_base->compositor;
810 struct drm_compositor *c =(struct drm_compositor *) ec;
811 struct drm_sprite *s;
812 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500813 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500814 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200815 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500816 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400817 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500818
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200819 if (c->gbm == NULL)
820 return NULL;
821
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100822 if (ev->surface->buffer_viewport.transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200823 return NULL;
824
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100825 if (ev->surface->buffer_viewport.scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200826 return NULL;
827
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500828 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400829 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500830
Jason Ekstranda7af7042013-10-12 22:38:11 -0500831 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400832 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300833
Jason Ekstranda7af7042013-10-12 22:38:11 -0500834 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400835 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500836
Jason Ekstranda7af7042013-10-12 22:38:11 -0500837 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200838 return NULL;
839
Jason Ekstranda7af7042013-10-12 22:38:11 -0500840 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500841 return NULL;
842
Jason Ekstranda7af7042013-10-12 22:38:11 -0500843 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400844 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500845
Jesse Barnes58ef3792012-02-23 09:45:49 -0500846 wl_list_for_each(s, &c->sprite_list, link) {
847 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
848 continue;
849
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200850 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500851 found = 1;
852 break;
853 }
854 }
855
856 /* No sprites available */
857 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400858 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500859
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400860 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500861 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700862 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400863 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400864 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400865
Jason Ekstranda7af7042013-10-12 22:38:11 -0500866 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500867 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200868 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400869 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500870 }
871
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200872 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200873 if (!s->next) {
874 gbm_bo_destroy(bo);
875 return NULL;
876 }
877
Jason Ekstranda7af7042013-10-12 22:38:11 -0500878 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500879
Jason Ekstranda7af7042013-10-12 22:38:11 -0500880 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400881 s->plane.x = box->x1;
882 s->plane.y = box->y1;
883
Jesse Barnes58ef3792012-02-23 09:45:49 -0500884 /*
885 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200886 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500887 * for us already).
888 */
889 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500890 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500891 &output_base->region);
892 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
893 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200894 tbox = weston_transformed_rect(output_base->width,
895 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200896 output_base->transform,
Hardeningff39efa2013-09-18 23:56:35 +0200897 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200898 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200899 s->dest_x = tbox.x1;
900 s->dest_y = tbox.y1;
901 s->dest_w = tbox.x2 - tbox.x1;
902 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500903 pixman_region32_fini(&dest_rect);
904
905 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500906 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500907 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500908 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400909
Jason Ekstranda7af7042013-10-12 22:38:11 -0500910 weston_view_from_global_fixed(ev,
911 wl_fixed_from_int(box->x1),
912 wl_fixed_from_int(box->y1),
913 &sx1, &sy1);
914 weston_view_from_global_fixed(ev,
915 wl_fixed_from_int(box->x2),
916 wl_fixed_from_int(box->y2),
917 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400918
919 if (sx1 < 0)
920 sx1 = 0;
921 if (sy1 < 0)
922 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600923 if (sx2 > wl_fixed_from_int(ev->surface->width))
924 sx2 = wl_fixed_from_int(ev->surface->width);
925 if (sy2 > wl_fixed_from_int(ev->surface->height))
926 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400927
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200928 tbox.x1 = sx1;
929 tbox.y1 = sy1;
930 tbox.x2 = sx2;
931 tbox.y2 = sy2;
932
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600933 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
934 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100935 ev->surface->buffer_viewport.transform,
936 ev->surface->buffer_viewport.scale,
937 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200938
939 s->src_x = tbox.x1 << 8;
940 s->src_y = tbox.y1 << 8;
941 s->src_w = (tbox.x2 - tbox.x1) << 8;
942 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500943 pixman_region32_fini(&src_rect);
944
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400945 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500946}
947
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400948static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500949drm_output_prepare_cursor_view(struct weston_output *output_base,
950 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500951{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400952 struct drm_compositor *c =
953 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400954 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400955
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200956 if (c->gbm == NULL)
957 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200958 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
959 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500960 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400961 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500962 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400963 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500964 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400965 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500966 if (ev->surface->buffer_ref.buffer == NULL ||
967 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600968 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400969 return NULL;
970
Jason Ekstranda7af7042013-10-12 22:38:11 -0500971 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400972
973 return &output->cursor_plane;
974}
975
976static void
977drm_output_set_cursor(struct drm_output *output)
978{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500979 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +0000980 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400981 struct drm_compositor *c =
982 (struct drm_compositor *) output->base.compositor;
983 EGLint handle, stride;
984 struct gbm_bo *bo;
985 uint32_t buf[64 * 64];
986 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400987 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500988
Jason Ekstranda7af7042013-10-12 22:38:11 -0500989 output->cursor_view = NULL;
990 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400991 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
992 return;
993 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500994
Neil Robertse5051712013-11-13 15:44:06 +0000995 buffer = ev->surface->buffer_ref.buffer;
996
997 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +0200998 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400999 pixman_region32_fini(&output->cursor_plane.damage);
1000 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001001 output->current_cursor ^= 1;
1002 bo = output->cursor_bo[output->current_cursor];
1003 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001004 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1005 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1006 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001007 for (i = 0; i < ev->surface->height; i++)
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001008 memcpy(buf + i * 64, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001009 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001010 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001011
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001012 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001013 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001014
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001015 handle = gbm_bo_get_handle(bo).s32;
1016 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -05001017 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001018 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001019 c->cursors_are_broken = 1;
1020 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001021 }
1022
Jason Ekstranda7af7042013-10-12 22:38:11 -05001023 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1024 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001025 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001026 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001027 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001028 c->cursors_are_broken = 1;
1029 }
1030
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001031 output->cursor_plane.x = x;
1032 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001033 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001034}
1035
Jesse Barnes58ef3792012-02-23 09:45:49 -05001036static void
1037drm_assign_planes(struct weston_output *output)
1038{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001039 struct drm_compositor *c =
1040 (struct drm_compositor *) output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001041 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001042 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001043 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001044
1045 /*
1046 * Find a surface for each sprite in the output using some heuristics:
1047 * 1) size
1048 * 2) frequency of update
1049 * 3) opacity (though some hw might support alpha blending)
1050 * 4) clipping (this can be fixed with color keys)
1051 *
1052 * The idea is to save on blitting since this should save power.
1053 * If we can get a large video surface on the sprite for example,
1054 * the main display surface may not need to update at all, and
1055 * the client buffer can be used directly for the sprite surface
1056 * as we do for flipping full screen surfaces.
1057 */
1058 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001059 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001060
Jason Ekstranda7af7042013-10-12 22:38:11 -05001061 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001062 struct weston_surface *es = ev->surface;
1063
1064 /* Test whether this buffer can ever go into a plane:
1065 * non-shm, or small enough to be a cursor.
1066 *
1067 * Also, keep a reference when using the pixman renderer.
1068 * That makes it possible to do a seamless switch to the GL
1069 * renderer and since the pixman renderer keeps a reference
1070 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001071 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001072 if (c->use_pixman ||
1073 (es->buffer_ref.buffer &&
1074 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001075 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001076 es->keep_buffer = 1;
1077 else
1078 es->keep_buffer = 0;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001079
Jesse Barnes58ef3792012-02-23 09:45:49 -05001080 pixman_region32_init(&surface_overlap);
1081 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001082 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001083
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001084 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001085 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001086 next_plane = primary;
1087 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001088 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001089 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001090 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001091 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001092 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001093 if (next_plane == NULL)
1094 next_plane = primary;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001095 weston_view_move_to_plane(ev, next_plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001096 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001097 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001098 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001099
Jesse Barnes58ef3792012-02-23 09:45:49 -05001100 pixman_region32_fini(&surface_overlap);
1101 }
1102 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001103}
1104
Matt Roper361d2ad2011-08-29 13:52:23 -07001105static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001106drm_output_fini_pixman(struct drm_output *output);
1107
1108static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001109drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001110{
1111 struct drm_output *output = (struct drm_output *) output_base;
1112 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001113 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001114 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001115
Xiong Zhangabd5d472013-10-11 14:43:07 +08001116 if (output->page_flip_pending) {
1117 output->destroy_pending = 1;
1118 weston_log("destroy output while page flip pending\n");
1119 return;
1120 }
1121
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001122 if (output->backlight)
1123 backlight_destroy(output->backlight);
1124
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001125 drmModeFreeProperty(output->dpms_prop);
1126
Matt Roper361d2ad2011-08-29 13:52:23 -07001127 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001128 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001129
1130 /* Restore original CRTC state */
1131 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001132 origcrtc->x, origcrtc->y,
1133 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001134 drmModeFreeCrtc(origcrtc);
1135
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001136 c->crtc_allocator &= ~(1 << output->crtc_id);
1137 c->connector_allocator &= ~(1 << output->connector_id);
1138
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001139 if (c->use_pixman) {
1140 drm_output_fini_pixman(output);
1141 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001142 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001143 gbm_surface_destroy(output->surface);
1144 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001145
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001146 weston_plane_release(&output->fb_plane);
1147 weston_plane_release(&output->cursor_plane);
1148
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001149 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001150
Matt Roper361d2ad2011-08-29 13:52:23 -07001151 free(output);
1152}
1153
Alex Wub7b8bda2012-04-17 17:20:48 +08001154static struct drm_mode *
1155choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1156{
1157 struct drm_mode *tmp_mode = NULL, *mode;
1158
Hardeningff39efa2013-09-18 23:56:35 +02001159 if (output->base.current_mode->width == target_mode->width &&
1160 output->base.current_mode->height == target_mode->height &&
1161 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001162 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001163 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001164
1165 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1166 if (mode->mode_info.hdisplay == target_mode->width &&
1167 mode->mode_info.vdisplay == target_mode->height) {
1168 if (mode->mode_info.vrefresh == target_mode->refresh ||
1169 target_mode->refresh == 0) {
1170 return mode;
1171 } else if (!tmp_mode)
1172 tmp_mode = mode;
1173 }
1174 }
1175
1176 return tmp_mode;
1177}
1178
1179static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001180drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001181static int
1182drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001183
1184static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001185drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1186{
1187 struct drm_output *output;
1188 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001189 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001190
1191 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001192 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001193 return -1;
1194 }
1195
1196 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001197 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001198 return -1;
1199 }
1200
1201 ec = (struct drm_compositor *)output_base->compositor;
1202 output = (struct drm_output *)output_base;
1203 drm_mode = choose_mode (output, mode);
1204
1205 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001206 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001207 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001208 }
1209
Hardeningff39efa2013-09-18 23:56:35 +02001210 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001211 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001212
Hardeningff39efa2013-09-18 23:56:35 +02001213 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001214
Hardeningff39efa2013-09-18 23:56:35 +02001215 output->base.current_mode = &drm_mode->base;
1216 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001217 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1218
Alex Wub7b8bda2012-04-17 17:20:48 +08001219 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001220 drm_output_release_fb(output, output->current);
1221 drm_output_release_fb(output, output->next);
1222 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001223
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001224 if (ec->use_pixman) {
1225 drm_output_fini_pixman(output);
1226 if (drm_output_init_pixman(output, ec) < 0) {
1227 weston_log("failed to init output pixman state with "
1228 "new mode\n");
1229 return -1;
1230 }
1231 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001232 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001233 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001234
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001235 if (drm_output_init_egl(output, ec) < 0) {
1236 weston_log("failed to init output egl state with "
1237 "new mode");
1238 return -1;
1239 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001240 }
1241
Alex Wub7b8bda2012-04-17 17:20:48 +08001242 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001243}
1244
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001245static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001246on_drm_input(int fd, uint32_t mask, void *data)
1247{
1248 drmEventContext evctx;
1249
1250 memset(&evctx, 0, sizeof evctx);
1251 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1252 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001253 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001254 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001255
1256 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001257}
1258
1259static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001260init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001261{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001262 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001263 uint64_t cap;
1264 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001265
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001266 sysnum = udev_device_get_sysnum(device);
1267 if (sysnum)
1268 ec->drm.id = atoi(sysnum);
1269 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001270 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001271 return -1;
1272 }
1273
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001274 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001275 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001276 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001277 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001278 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001279 udev_device_get_devnode(device));
1280 return -1;
1281 }
1282
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001283 weston_log("using %s\n", filename);
1284
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001285 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001286 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001287
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001288 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1289 if (ret == 0 && cap == 1)
1290 ec->clock = CLOCK_MONOTONIC;
1291 else
1292 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001293
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001294 return 0;
1295}
1296
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001297static struct gbm_device *
1298create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001299{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001300 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001301
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001302 gl_renderer = weston_load_module("gl-renderer.so",
1303 "gl_renderer_interface");
1304 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001305 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001306
1307 /* GBM will load a dri driver, but even though they need symbols from
1308 * libglapi, in some version of Mesa they are not linked to it. Since
1309 * only the gl-renderer module links to it, the call above won't make
1310 * these symbols globally available, and loading the DRI driver fails.
1311 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1312 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1313
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001314 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001315
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001316 return gbm;
1317}
1318
1319static int
1320drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1321{
1322 EGLint format;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001323
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001324 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001325 if (gl_renderer->create(&ec->base, ec->gbm,
1326 gl_renderer->opaque_attribs, &format) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001327 return -1;
1328 }
1329
1330 return 0;
1331}
1332
1333static int
1334init_egl(struct drm_compositor *ec)
1335{
1336 ec->gbm = create_gbm_device(ec->drm.fd);
1337
1338 if (!ec->gbm)
1339 return -1;
1340
1341 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001342 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001343 return -1;
1344 }
1345
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001346 return 0;
1347}
1348
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001349static int
1350init_pixman(struct drm_compositor *ec)
1351{
1352 return pixman_renderer_init(&ec->base);
1353}
1354
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001355static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001356drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001357{
1358 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001359 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001360
1361 mode = malloc(sizeof *mode);
1362 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001363 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001364
1365 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001366 mode->base.width = info->hdisplay;
1367 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001368
1369 /* Calculate higher precision (mHz) refresh rate */
1370 refresh = (info->clock * 1000000LL / info->htotal +
1371 info->vtotal / 2) / info->vtotal;
1372
1373 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1374 refresh *= 2;
1375 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1376 refresh /= 2;
1377 if (info->vscan > 1)
1378 refresh /= info->vscan;
1379
1380 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001381 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001382
1383 if (info->type & DRM_MODE_TYPE_PREFERRED)
1384 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1385
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001386 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1387
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001388 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001389}
1390
1391static int
1392drm_subpixel_to_wayland(int drm_value)
1393{
1394 switch (drm_value) {
1395 default:
1396 case DRM_MODE_SUBPIXEL_UNKNOWN:
1397 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1398 case DRM_MODE_SUBPIXEL_NONE:
1399 return WL_OUTPUT_SUBPIXEL_NONE;
1400 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1401 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1402 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1403 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1404 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1405 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1406 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1407 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1408 }
1409}
1410
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001411/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001412static uint32_t
1413drm_get_backlight(struct drm_output *output)
1414{
1415 long brightness, max_brightness, norm;
1416
1417 brightness = backlight_get_brightness(output->backlight);
1418 max_brightness = backlight_get_max_brightness(output->backlight);
1419
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001420 /* convert it on a scale of 0 to 255 */
1421 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001422
1423 return (uint32_t) norm;
1424}
1425
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001426/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001427static void
1428drm_set_backlight(struct weston_output *output_base, uint32_t value)
1429{
1430 struct drm_output *output = (struct drm_output *) output_base;
1431 long max_brightness, new_brightness;
1432
1433 if (!output->backlight)
1434 return;
1435
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001436 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001437 return;
1438
1439 max_brightness = backlight_get_max_brightness(output->backlight);
1440
1441 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001442 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001443
1444 backlight_set_brightness(output->backlight, new_brightness);
1445}
1446
1447static drmModePropertyPtr
1448drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1449{
1450 drmModePropertyPtr props;
1451 int i;
1452
1453 for (i = 0; i < connector->count_props; i++) {
1454 props = drmModeGetProperty(fd, connector->props[i]);
1455 if (!props)
1456 continue;
1457
1458 if (!strcmp(props->name, name))
1459 return props;
1460
1461 drmModeFreeProperty(props);
1462 }
1463
1464 return NULL;
1465}
1466
1467static void
1468drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1469{
1470 struct drm_output *output = (struct drm_output *) output_base;
1471 struct weston_compositor *ec = output_base->compositor;
1472 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001473
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001474 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001475 return;
1476
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001477 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1478 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001479}
1480
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001481static const char *connector_type_names[] = {
1482 "None",
1483 "VGA",
1484 "DVI",
1485 "DVI",
1486 "DVI",
1487 "Composite",
1488 "TV",
1489 "LVDS",
1490 "CTV",
1491 "DIN",
1492 "DP",
1493 "HDMI",
1494 "HDMI",
1495 "TV",
1496 "eDP",
1497};
1498
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001499static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001500find_crtc_for_connector(struct drm_compositor *ec,
1501 drmModeRes *resources, drmModeConnector *connector)
1502{
1503 drmModeEncoder *encoder;
1504 uint32_t possible_crtcs;
1505 int i, j;
1506
1507 for (j = 0; j < connector->count_encoders; j++) {
1508 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1509 if (encoder == NULL) {
1510 weston_log("Failed to get encoder.\n");
1511 return -1;
1512 }
1513 possible_crtcs = encoder->possible_crtcs;
1514 drmModeFreeEncoder(encoder);
1515
1516 for (i = 0; i < resources->count_crtcs; i++) {
1517 if (possible_crtcs & (1 << i) &&
1518 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1519 return i;
1520 }
1521 }
1522
1523 return -1;
1524}
1525
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001526/* Init output state that depends on gl or gbm */
1527static int
1528drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1529{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001530 EGLint format = output->format;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001531 int i, flags;
1532
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001533 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001534 output->base.current_mode->width,
1535 output->base.current_mode->height,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001536 format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001537 GBM_BO_USE_SCANOUT |
1538 GBM_BO_USE_RENDERING);
1539 if (!output->surface) {
1540 weston_log("failed to create gbm surface\n");
1541 return -1;
1542 }
1543
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001544 if (gl_renderer->output_create(&output->base, output->surface,
1545 gl_renderer->opaque_attribs,
1546 &format) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001547 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001548 gbm_surface_destroy(output->surface);
1549 return -1;
1550 }
1551
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001552 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1553
1554 for (i = 0; i < 2; i++) {
1555 if (output->cursor_bo[i])
1556 continue;
1557
1558 output->cursor_bo[i] =
1559 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1560 flags);
1561 }
1562
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001563 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1564 weston_log("cursor buffers unavailable, using gl cursors\n");
1565 ec->cursors_are_broken = 1;
1566 }
1567
1568 return 0;
1569}
1570
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001571static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001572drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1573{
Hardeningff39efa2013-09-18 23:56:35 +02001574 int w = output->base.current_mode->width;
1575 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001576 unsigned int i;
1577
1578 /* FIXME error checking */
1579
1580 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001581 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001582 if (!output->dumb[i])
1583 goto err;
1584
1585 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001586 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001587 output->dumb[i]->map,
1588 output->dumb[i]->stride);
1589 if (!output->image[i])
1590 goto err;
1591 }
1592
1593 if (pixman_renderer_output_create(&output->base) < 0)
1594 goto err;
1595
1596 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001597 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001598
1599 return 0;
1600
1601err:
1602 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1603 if (output->dumb[i])
1604 drm_fb_destroy_dumb(output->dumb[i]);
1605 if (output->image[i])
1606 pixman_image_unref(output->image[i]);
1607
1608 output->dumb[i] = NULL;
1609 output->image[i] = NULL;
1610 }
1611
1612 return -1;
1613}
1614
1615static void
1616drm_output_fini_pixman(struct drm_output *output)
1617{
1618 unsigned int i;
1619
1620 pixman_renderer_output_destroy(&output->base);
1621 pixman_region32_fini(&output->previous_damage);
1622
1623 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1624 drm_fb_destroy_dumb(output->dumb[i]);
1625 pixman_image_unref(output->image[i]);
1626 output->dumb[i] = NULL;
1627 output->image[i] = NULL;
1628 }
1629}
1630
Richard Hughes2b2092a2013-04-24 14:58:02 +01001631static void
1632edid_parse_string(const uint8_t *data, char text[])
1633{
1634 int i;
1635 int replaced = 0;
1636
1637 /* this is always 12 bytes, but we can't guarantee it's null
1638 * terminated or not junk. */
1639 strncpy(text, (const char *) data, 12);
1640
1641 /* remove insane chars */
1642 for (i = 0; text[i] != '\0'; i++) {
1643 if (text[i] == '\n' ||
1644 text[i] == '\r') {
1645 text[i] = '\0';
1646 break;
1647 }
1648 }
1649
1650 /* ensure string is printable */
1651 for (i = 0; text[i] != '\0'; i++) {
1652 if (!isprint(text[i])) {
1653 text[i] = '-';
1654 replaced++;
1655 }
1656 }
1657
1658 /* if the string is random junk, ignore the string */
1659 if (replaced > 4)
1660 text[0] = '\0';
1661}
1662
1663#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1664#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1665#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1666#define EDID_OFFSET_DATA_BLOCKS 0x36
1667#define EDID_OFFSET_LAST_BLOCK 0x6c
1668#define EDID_OFFSET_PNPID 0x08
1669#define EDID_OFFSET_SERIAL 0x0c
1670
1671static int
1672edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1673{
1674 int i;
1675 uint32_t serial_number;
1676
1677 /* check header */
1678 if (length < 128)
1679 return -1;
1680 if (data[0] != 0x00 || data[1] != 0xff)
1681 return -1;
1682
1683 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1684 * /--08--\/--09--\
1685 * 7654321076543210
1686 * |\---/\---/\---/
1687 * R C1 C2 C3 */
1688 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1689 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1690 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1691 edid->pnp_id[3] = '\0';
1692
1693 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1694 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1695 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1696 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1697 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1698 if (serial_number > 0)
1699 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1700
1701 /* parse EDID data */
1702 for (i = EDID_OFFSET_DATA_BLOCKS;
1703 i <= EDID_OFFSET_LAST_BLOCK;
1704 i += 18) {
1705 /* ignore pixel clock data */
1706 if (data[i] != 0)
1707 continue;
1708 if (data[i+2] != 0)
1709 continue;
1710
1711 /* any useful blocks? */
1712 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1713 edid_parse_string(&data[i+5],
1714 edid->monitor_name);
1715 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1716 edid_parse_string(&data[i+5],
1717 edid->serial_number);
1718 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1719 edid_parse_string(&data[i+5],
1720 edid->eisa_id);
1721 }
1722 }
1723 return 0;
1724}
1725
1726static void
1727find_and_parse_output_edid(struct drm_compositor *ec,
1728 struct drm_output *output,
1729 drmModeConnector *connector)
1730{
1731 drmModePropertyBlobPtr edid_blob = NULL;
1732 drmModePropertyPtr property;
1733 int i;
1734 int rc;
1735
1736 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1737 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1738 if (!property)
1739 continue;
1740 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1741 !strcmp(property->name, "EDID")) {
1742 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1743 connector->prop_values[i]);
1744 }
1745 drmModeFreeProperty(property);
1746 }
1747 if (!edid_blob)
1748 return;
1749
1750 rc = edid_parse(&output->edid,
1751 edid_blob->data,
1752 edid_blob->length);
1753 if (!rc) {
1754 weston_log("EDID data '%s', '%s', '%s'\n",
1755 output->edid.pnp_id,
1756 output->edid.monitor_name,
1757 output->edid.serial_number);
1758 if (output->edid.pnp_id[0] != '\0')
1759 output->base.make = output->edid.pnp_id;
1760 if (output->edid.monitor_name[0] != '\0')
1761 output->base.model = output->edid.monitor_name;
1762 if (output->edid.serial_number[0] != '\0')
1763 output->base.serial_number = output->edid.serial_number;
1764 }
1765 drmModeFreePropertyBlob(edid_blob);
1766}
1767
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001768
1769
1770static int
1771parse_modeline(const char *s, drmModeModeInfo *mode)
1772{
1773 char hsync[16];
1774 char vsync[16];
1775 float fclock;
1776
1777 mode->type = DRM_MODE_TYPE_USERDEF;
1778 mode->hskew = 0;
1779 mode->vscan = 0;
1780 mode->vrefresh = 0;
1781 mode->flags = 0;
1782
Rob Bradford307e09e2013-07-26 16:29:40 +01001783 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001784 &fclock,
1785 &mode->hdisplay,
1786 &mode->hsync_start,
1787 &mode->hsync_end,
1788 &mode->htotal,
1789 &mode->vdisplay,
1790 &mode->vsync_start,
1791 &mode->vsync_end,
1792 &mode->vtotal, hsync, vsync) != 11)
1793 return -1;
1794
1795 mode->clock = fclock * 1000;
1796 if (strcmp(hsync, "+hsync") == 0)
1797 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1798 else if (strcmp(hsync, "-hsync") == 0)
1799 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1800 else
1801 return -1;
1802
1803 if (strcmp(vsync, "+vsync") == 0)
1804 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1805 else if (strcmp(vsync, "-vsync") == 0)
1806 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1807 else
1808 return -1;
1809
1810 return 0;
1811}
1812
1813static uint32_t
1814parse_transform(const char *transform, const char *output_name)
1815{
1816 static const struct { const char *name; uint32_t token; } names[] = {
1817 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1818 { "90", WL_OUTPUT_TRANSFORM_90 },
1819 { "180", WL_OUTPUT_TRANSFORM_180 },
1820 { "270", WL_OUTPUT_TRANSFORM_270 },
1821 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1822 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1823 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1824 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1825 };
1826 unsigned int i;
1827
1828 for (i = 0; i < ARRAY_LENGTH(names); i++)
1829 if (strcmp(names[i].name, transform) == 0)
1830 return names[i].token;
1831
1832 weston_log("Invalid transform \"%s\" for output %s\n",
1833 transform, output_name);
1834
1835 return WL_OUTPUT_TRANSFORM_NORMAL;
1836}
1837
Rob Bradford66bd9f52013-06-25 18:56:42 +01001838static void
1839setup_output_seat_constraint(struct drm_compositor *ec,
1840 struct weston_output *output,
1841 const char *s)
1842{
1843 if (strcmp(s, "") != 0) {
1844 struct udev_seat *seat;
1845
1846 seat = udev_seat_get_named(&ec->base, s);
1847 if (seat)
1848 seat->base.output = output;
1849
1850 if (seat && seat->base.pointer)
1851 weston_pointer_clamp(seat->base.pointer,
1852 &seat->base.pointer->x,
1853 &seat->base.pointer->y);
1854 }
1855}
1856
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001857static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001858get_gbm_format_from_section(struct weston_config_section *section,
1859 uint32_t default_value,
1860 uint32_t *format)
1861{
1862 char *s;
1863 int ret = 0;
1864
1865 weston_config_section_get_string(section,
1866 "gbm-format", &s, NULL);
1867
1868 if (s == NULL)
1869 *format = default_value;
1870 else if (strcmp(s, "xrgb8888") == 0)
1871 *format = GBM_FORMAT_XRGB8888;
1872 else if (strcmp(s, "rgb565") == 0)
1873 *format = GBM_FORMAT_RGB565;
1874 else if (strcmp(s, "xrgb2101010") == 0)
1875 *format = GBM_FORMAT_XRGB2101010;
1876 else {
1877 weston_log("fatal: unrecognized pixel format: %s\n", s);
1878 ret = -1;
1879 }
1880
1881 free(s);
1882
1883 return ret;
1884}
1885
1886static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001887create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001888 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001889 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001890 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001891{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001892 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001893 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001894 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001895 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001896 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001897 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001898 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001899 int i, width, height, scale;
1900 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001901 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001902 enum output_config config;
1903 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001904
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001905 i = find_crtc_for_connector(ec, resources, connector);
1906 if (i < 0) {
1907 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001908 return -1;
1909 }
1910
Peter Huttererf3d62272013-08-08 11:57:05 +10001911 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001912 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001913 return -1;
1914
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001915 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1916 output->base.make = "unknown";
1917 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001918 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001919 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001920
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001921 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1922 type_name = connector_type_names[connector->connector_type];
1923 else
1924 type_name = "UNKNOWN";
1925 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001926 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001927
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001928 section = weston_config_get_section(ec->base.config, "output", "name",
1929 output->base.name);
1930 weston_config_section_get_string(section, "mode", &s, "preferred");
1931 if (strcmp(s, "off") == 0)
1932 config = OUTPUT_CONFIG_OFF;
1933 else if (strcmp(s, "preferred") == 0)
1934 config = OUTPUT_CONFIG_PREFERRED;
1935 else if (strcmp(s, "current") == 0)
1936 config = OUTPUT_CONFIG_CURRENT;
1937 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1938 config = OUTPUT_CONFIG_MODE;
1939 else if (parse_modeline(s, &modeline) == 0)
1940 config = OUTPUT_CONFIG_MODELINE;
1941 else {
1942 weston_log("Invalid mode \"%s\" for output %s\n",
1943 s, output->base.name);
1944 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001945 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001946 free(s);
1947
1948 weston_config_section_get_int(section, "scale", &scale, 1);
1949 weston_config_section_get_string(section, "transform", &s, "normal");
1950 transform = parse_transform(s, output->base.name);
1951 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001952
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001953 if (get_gbm_format_from_section(section,
1954 ec->format,
1955 &output->format) == -1)
1956 output->format = ec->format;
1957
Rob Bradford66bd9f52013-06-25 18:56:42 +01001958 weston_config_section_get_string(section, "seat", &s, "");
1959 setup_output_seat_constraint(ec, &output->base, s);
1960 free(s);
1961
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001962 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001963 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001964 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001965 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001966 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001967
Matt Roper361d2ad2011-08-29 13:52:23 -07001968 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001969 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001970
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001971 /* Get the current mode on the crtc that's currently driving
1972 * this connector. */
1973 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001974 memset(&crtc_mode, 0, sizeof crtc_mode);
1975 if (encoder != NULL) {
1976 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1977 drmModeFreeEncoder(encoder);
1978 if (crtc == NULL)
1979 goto err_free;
1980 if (crtc->mode_valid)
1981 crtc_mode = crtc->mode;
1982 drmModeFreeCrtc(crtc);
1983 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001984
David Herrmann0f0d54e2011-12-08 17:05:45 +01001985 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001986 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001987 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001988 goto err_free;
1989 }
1990
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001991 if (config == OUTPUT_CONFIG_OFF) {
1992 weston_log("Disabling output %s\n", output->base.name);
1993 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1994 0, 0, 0, 0, 0, NULL);
1995 goto err_free;
1996 }
1997
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001998 preferred = NULL;
1999 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002000 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002001 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002002
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002003 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002004 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002005 width == drm_mode->base.width &&
2006 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002007 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002008 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002009 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002010 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002011 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002012 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002013 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002014
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002015 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002016 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002017 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002018 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002019 }
2020
Wang Quanxianacb805a2012-07-30 18:09:46 -04002021 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002022 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002023 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002024 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002025 }
2026
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002027 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002028 configured = current;
2029
Wang Quanxianacb805a2012-07-30 18:09:46 -04002030 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002031 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002032 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002033 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002034 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002035 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002036 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002037 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002038 else if (best)
2039 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002040
Hardeningff39efa2013-09-18 23:56:35 +02002041 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002042 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002043 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002044 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002045
Hardeningff39efa2013-09-18 23:56:35 +02002046 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002047
John Kåre Alsaker94659272012-11-13 19:10:18 +01002048 weston_output_init(&output->base, &ec->base, x, y,
2049 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002050 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002051
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002052 if (ec->use_pixman) {
2053 if (drm_output_init_pixman(output, ec) < 0) {
2054 weston_log("Failed to init output pixman state\n");
2055 goto err_output;
2056 }
2057 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002058 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002059 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002060 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002061
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002062 output->backlight = backlight_init(drm_device,
2063 connector->connector_type);
2064 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002065 weston_log("Initialized backlight, device %s\n",
2066 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002067 output->base.set_backlight = drm_set_backlight;
2068 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002069 } else {
2070 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002071 }
2072
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002073 wl_list_insert(ec->base.output_list.prev, &output->base.link);
2074
Richard Hughes2b2092a2013-04-24 14:58:02 +01002075 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002076 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2077 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002078
Jonas Ådahle5a12252013-04-05 23:07:11 +02002079 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002080 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002081 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002082 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002083 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002084 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002085
Richard Hughese7299962013-05-01 21:52:12 +01002086 output->base.gamma_size = output->original_crtc->gamma_size;
2087 output->base.set_gamma = drm_output_set_gamma;
2088
Xiong Zhang97116532013-10-23 13:58:31 +08002089 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2090 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002091
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002092 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2093 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2094 &ec->base.primary_plane);
2095
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002096 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002097 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002098 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002099 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002100 m->width, m->height, m->refresh / 1000.0,
2101 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2102 ", preferred" : "",
2103 m->flags & WL_OUTPUT_MODE_CURRENT ?
2104 ", current" : "",
2105 connector->count_modes == 0 ?
2106 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002107
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002108 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002109
John Kåre Alsaker94659272012-11-13 19:10:18 +01002110err_output:
2111 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002112err_free:
2113 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2114 base.link) {
2115 wl_list_remove(&drm_mode->base.link);
2116 free(drm_mode);
2117 }
2118
2119 drmModeFreeCrtc(output->original_crtc);
2120 ec->crtc_allocator &= ~(1 << output->crtc_id);
2121 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002122 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002123
David Herrmann0f0d54e2011-12-08 17:05:45 +01002124 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002125}
2126
Jesse Barnes58ef3792012-02-23 09:45:49 -05002127static void
2128create_sprites(struct drm_compositor *ec)
2129{
2130 struct drm_sprite *sprite;
2131 drmModePlaneRes *plane_res;
2132 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002133 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002134
2135 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2136 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002137 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002138 strerror(errno));
2139 return;
2140 }
2141
2142 for (i = 0; i < plane_res->count_planes; i++) {
2143 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2144 if (!plane)
2145 continue;
2146
Peter Huttererf3d62272013-08-08 11:57:05 +10002147 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002148 plane->count_formats));
2149 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002150 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002151 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002152 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002153 continue;
2154 }
2155
Jesse Barnes58ef3792012-02-23 09:45:49 -05002156 sprite->possible_crtcs = plane->possible_crtcs;
2157 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002158 sprite->current = NULL;
2159 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002160 sprite->compositor = ec;
2161 sprite->count_formats = plane->count_formats;
2162 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002163 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002164 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002165 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002166 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2167 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002168
2169 wl_list_insert(&ec->sprite_list, &sprite->link);
2170 }
2171
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002172 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002173}
2174
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002175static void
2176destroy_sprites(struct drm_compositor *compositor)
2177{
2178 struct drm_sprite *sprite, *next;
2179 struct drm_output *output;
2180
2181 output = container_of(compositor->base.output_list.next,
2182 struct drm_output, base.link);
2183
2184 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2185 drmModeSetPlane(compositor->drm.fd,
2186 sprite->plane_id,
2187 output->crtc_id, 0, 0,
2188 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002189 drm_output_release_fb(output, sprite->current);
2190 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002191 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002192 free(sprite);
2193 }
2194}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002195
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002196static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002197create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002198 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002199{
2200 drmModeConnector *connector;
2201 drmModeRes *resources;
2202 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002203 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002204
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002205 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002206 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002207 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002208 return -1;
2209 }
2210
Jesse Barnes58ef3792012-02-23 09:45:49 -05002211 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002212 if (!ec->crtcs) {
2213 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002214 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002215 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002216
Rob Clark4339add2012-08-09 14:18:28 -05002217 ec->min_width = resources->min_width;
2218 ec->max_width = resources->max_width;
2219 ec->min_height = resources->min_height;
2220 ec->max_height = resources->max_height;
2221
Jesse Barnes58ef3792012-02-23 09:45:49 -05002222 ec->num_crtcs = resources->count_crtcs;
2223 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2224
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002225 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002226 connector = drmModeGetConnector(ec->drm.fd,
2227 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002228 if (connector == NULL)
2229 continue;
2230
2231 if (connector->connection == DRM_MODE_CONNECTED &&
2232 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002233 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002234 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002235 connector, x, y,
2236 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002237 drmModeFreeConnector(connector);
2238 continue;
2239 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002240
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002241 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002242 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002243 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002244 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002245
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002246 drmModeFreeConnector(connector);
2247 }
2248
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002249 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002250 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002251 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002252 return -1;
2253 }
2254
2255 drmModeFreeResources(resources);
2256
2257 return 0;
2258}
2259
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002260static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002261update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002262{
2263 drmModeConnector *connector;
2264 drmModeRes *resources;
2265 struct drm_output *output, *next;
2266 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002267 uint32_t connected = 0, disconnects = 0;
2268 int i;
2269
2270 resources = drmModeGetResources(ec->drm.fd);
2271 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002272 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002273 return;
2274 }
2275
2276 /* collect new connects */
2277 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002278 int connector_id = resources->connectors[i];
2279
2280 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002281 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002282 continue;
2283
David Herrmann7551cff2011-12-08 17:05:43 +01002284 if (connector->connection != DRM_MODE_CONNECTED) {
2285 drmModeFreeConnector(connector);
2286 continue;
2287 }
2288
Benjamin Franzke117483d2011-08-30 11:38:26 +02002289 connected |= (1 << connector_id);
2290
2291 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002292 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002293 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002294 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002295
2296 /* XXX: not yet needed, we die with 0 outputs */
2297 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002298 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002299 else
2300 x = 0;
2301 y = 0;
2302 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002303 connector, x, y,
2304 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002305 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002306
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002307 }
2308 drmModeFreeConnector(connector);
2309 }
2310 drmModeFreeResources(resources);
2311
2312 disconnects = ec->connector_allocator & ~connected;
2313 if (disconnects) {
2314 wl_list_for_each_safe(output, next, &ec->base.output_list,
2315 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002316 if (disconnects & (1 << output->connector_id)) {
2317 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002318 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002319 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002320 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002321 }
2322 }
2323 }
2324
2325 /* FIXME: handle zero outputs, without terminating */
2326 if (ec->connector_allocator == 0)
2327 wl_display_terminate(ec->base.wl_display);
2328}
2329
2330static int
David Herrmannd7488c22012-03-11 20:05:21 +01002331udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002332{
David Herrmannd7488c22012-03-11 20:05:21 +01002333 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002334 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002335
2336 sysnum = udev_device_get_sysnum(device);
2337 if (!sysnum || atoi(sysnum) != ec->drm.id)
2338 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002339
David Herrmann6ac52db2012-03-11 20:05:22 +01002340 val = udev_device_get_property_value(device, "HOTPLUG");
2341 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002342 return 0;
2343
David Herrmann6ac52db2012-03-11 20:05:22 +01002344 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002345}
2346
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002347static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002348udev_drm_event(int fd, uint32_t mask, void *data)
2349{
2350 struct drm_compositor *ec = data;
2351 struct udev_device *event;
2352
2353 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002354
David Herrmannd7488c22012-03-11 20:05:21 +01002355 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002356 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002357
2358 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002359
2360 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002361}
2362
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002363static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002364drm_restore(struct weston_compositor *ec)
2365{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002366 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002367}
2368
2369static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002370drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002371{
2372 struct drm_compositor *d = (struct drm_compositor *) ec;
2373
Rob Bradfordd355b802013-05-31 18:09:55 +01002374 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002375
2376 wl_event_source_remove(d->udev_drm_source);
2377 wl_event_source_remove(d->drm_source);
2378
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002379 destroy_sprites(d);
2380
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002381 weston_compositor_shutdown(ec);
2382
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002383 if (d->gbm)
2384 gbm_device_destroy(d->gbm);
2385
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002386 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002387
Rob Bradford45c15b82013-07-26 16:29:35 +01002388 close(d->drm.fd);
2389
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002390 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002391}
2392
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002393static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002394drm_compositor_set_modes(struct drm_compositor *compositor)
2395{
2396 struct drm_output *output;
2397 struct drm_mode *drm_mode;
2398 int ret;
2399
2400 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002401 if (!output->current) {
2402 /* If something that would cause the output to
2403 * switch mode happened while in another vt, we
2404 * might not have a current drm_fb. In that case,
2405 * schedule a repaint and let drm_output_repaint
2406 * handle setting the mode. */
2407 weston_output_schedule_repaint(&output->base);
2408 continue;
2409 }
2410
Hardeningff39efa2013-09-18 23:56:35 +02002411 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002412 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002413 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002414 &output->connector_id, 1,
2415 &drm_mode->mode_info);
2416 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002417 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002418 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002419 drm_mode->base.width, drm_mode->base.height,
2420 output->base.x, output->base.y);
2421 }
2422 }
2423}
2424
2425static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002426session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002427{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002428 struct weston_compositor *compositor = data;
2429 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002430 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002431 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002432
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002433 if (ec->base.session_active) {
2434 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002435 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002436 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002437 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002438 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002439 } else {
2440 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002441 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002442
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002443 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002444 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002445
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002446 /* If we have a repaint scheduled (either from a
2447 * pending pageflip or the idle handler), make sure we
2448 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002449 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002450 * further attemps at repainting. When we switch
2451 * back, we schedule a repaint, which will process
2452 * pending frame callbacks. */
2453
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002454 wl_list_for_each(output, &ec->base.output_list, base.link) {
2455 output->base.repaint_needed = 0;
2456 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002457 }
2458
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002459 output = container_of(ec->base.output_list.next,
2460 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002461
2462 wl_list_for_each(sprite, &ec->sprite_list, link)
2463 drmModeSetPlane(ec->drm.fd,
2464 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002465 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002466 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002467 };
2468}
2469
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002470static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002471switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002472{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002473 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002474
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002475 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002476}
2477
David Herrmann0af066f2012-10-29 19:21:16 +01002478/*
2479 * Find primary GPU
2480 * Some systems may have multiple DRM devices attached to a single seat. This
2481 * function loops over all devices and tries to find a PCI device with the
2482 * boot_vga sysfs attribute set to 1.
2483 * If no such device is found, the first DRM device reported by udev is used.
2484 */
2485static struct udev_device*
2486find_primary_gpu(struct drm_compositor *ec, const char *seat)
2487{
2488 struct udev_enumerate *e;
2489 struct udev_list_entry *entry;
2490 const char *path, *device_seat, *id;
2491 struct udev_device *device, *drm_device, *pci;
2492
2493 e = udev_enumerate_new(ec->udev);
2494 udev_enumerate_add_match_subsystem(e, "drm");
2495 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2496
2497 udev_enumerate_scan_devices(e);
2498 drm_device = NULL;
2499 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2500 path = udev_list_entry_get_name(entry);
2501 device = udev_device_new_from_syspath(ec->udev, path);
2502 if (!device)
2503 continue;
2504 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2505 if (!device_seat)
2506 device_seat = default_seat;
2507 if (strcmp(device_seat, seat)) {
2508 udev_device_unref(device);
2509 continue;
2510 }
2511
2512 pci = udev_device_get_parent_with_subsystem_devtype(device,
2513 "pci", NULL);
2514 if (pci) {
2515 id = udev_device_get_sysattr_value(pci, "boot_vga");
2516 if (id && !strcmp(id, "1")) {
2517 if (drm_device)
2518 udev_device_unref(drm_device);
2519 drm_device = device;
2520 break;
2521 }
2522 }
2523
2524 if (!drm_device)
2525 drm_device = device;
2526 else
2527 udev_device_unref(device);
2528 }
2529
2530 udev_enumerate_unref(e);
2531 return drm_device;
2532}
2533
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002534static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002535planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002536{
2537 struct drm_compositor *c = data;
2538
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002539 switch (key) {
2540 case KEY_C:
2541 c->cursors_are_broken ^= 1;
2542 break;
2543 case KEY_V:
2544 c->sprites_are_broken ^= 1;
2545 break;
2546 case KEY_O:
2547 c->sprites_hidden ^= 1;
2548 break;
2549 default:
2550 break;
2551 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002552}
2553
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002554#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002555static void
2556recorder_frame_notify(struct wl_listener *listener, void *data)
2557{
2558 struct drm_output *output;
2559 struct drm_compositor *c;
2560 int fd, ret;
2561
2562 output = container_of(listener, struct drm_output,
2563 recorder_frame_listener);
2564 c = (struct drm_compositor *) output->base.compositor;
2565
2566 if (!output->recorder)
2567 return;
2568
2569 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2570 DRM_CLOEXEC, &fd);
2571 if (ret) {
2572 weston_log("[libva recorder] "
2573 "failed to create prime fd for front buffer\n");
2574 return;
2575 }
2576
2577 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002578}
2579
2580static void *
2581create_recorder(struct drm_compositor *c, int width, int height,
2582 const char *filename)
2583{
2584 int fd;
2585 drm_magic_t magic;
2586
2587 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2588 if (fd < 0)
2589 return NULL;
2590
2591 drmGetMagic(fd, &magic);
2592 drmAuthMagic(c->drm.fd, magic);
2593
2594 return vaapi_recorder_create(fd, width, height, filename);
2595}
2596
2597static void
2598recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2599 void *data)
2600{
2601 struct drm_compositor *c = data;
2602 struct drm_output *output;
2603 int width, height;
2604
2605 output = container_of(c->base.output_list.next,
2606 struct drm_output, base.link);
2607
2608 if (!output->recorder) {
Hardeningff39efa2013-09-18 23:56:35 +02002609 width = output->base.current_mode->width;
2610 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002611
2612 output->recorder =
2613 create_recorder(c, width, height, "capture.h264");
2614 if (!output->recorder) {
2615 weston_log("failed to create vaapi recorder\n");
2616 return;
2617 }
2618
2619 output->base.disable_planes++;
2620
2621 output->recorder_frame_listener.notify = recorder_frame_notify;
2622 wl_signal_add(&output->base.frame_signal,
2623 &output->recorder_frame_listener);
2624
2625 weston_output_schedule_repaint(&output->base);
2626
2627 weston_log("[libva recorder] initialized\n");
2628 } else {
2629 vaapi_recorder_destroy(output->recorder);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002630 output->recorder = NULL;
2631
2632 output->base.disable_planes--;
2633
2634 wl_list_remove(&output->recorder_frame_listener.link);
2635 weston_log("[libva recorder] done\n");
2636 }
2637}
2638#else
2639static void
2640recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2641 void *data)
2642{
2643 weston_log("Compiled without libva support\n");
2644}
2645#endif
2646
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002647static void
2648switch_to_gl_renderer(struct drm_compositor *c)
2649{
2650 struct drm_output *output;
2651
2652 if (!c->use_pixman)
2653 return;
2654
2655 weston_log("Switching to GL renderer\n");
2656
2657 c->gbm = create_gbm_device(c->drm.fd);
2658 if (!c->gbm) {
2659 weston_log("Failed to create gbm device. "
2660 "Aborting renderer switch\n");
2661 return;
2662 }
2663
2664 wl_list_for_each(output, &c->base.output_list, base.link)
2665 pixman_renderer_output_destroy(&output->base);
2666
2667 c->base.renderer->destroy(&c->base);
2668
2669 if (drm_compositor_create_gl_renderer(c) < 0) {
2670 gbm_device_destroy(c->gbm);
2671 weston_log("Failed to create GL renderer. Quitting.\n");
2672 /* FIXME: we need a function to shutdown cleanly */
2673 assert(0);
2674 }
2675
2676 wl_list_for_each(output, &c->base.output_list, base.link)
2677 drm_output_init_egl(output, c);
2678
2679 c->use_pixman = 0;
2680}
2681
2682static void
2683renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2684 void *data)
2685{
2686 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2687
2688 switch_to_gl_renderer(c);
2689}
2690
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002691static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002692drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002693 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002694 int *argc, char *argv[],
2695 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002696{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002697 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002698 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002699 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002700 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002701 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002702 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002703
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002704 weston_log("initializing drm backend\n");
2705
Peter Huttererf3d62272013-08-08 11:57:05 +10002706 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002707 if (ec == NULL)
2708 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002709
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002710 /* KMS support for sprites is not complete yet, so disable the
2711 * functionality for now. */
2712 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002713
2714 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002715 if (get_gbm_format_from_section(section,
2716 GBM_FORMAT_XRGB8888,
2717 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002718 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002719
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002720 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002721
Daniel Stone725c2c32012-06-22 14:04:36 +01002722 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002723 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002724 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002725 goto err_base;
2726 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002727
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002728 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002729 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
2730 param->seat_id);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002731 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002732 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002733 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002734 goto err_compositor;
2735 }
2736
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002737 ec->udev = udev_new();
2738 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002739 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002740 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002741 }
2742
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002743 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002744 ec->session_listener.notify = session_notify;
2745 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002746
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002747 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002748 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002749 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002750 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002751 }
David Herrmann0af066f2012-10-29 19:21:16 +01002752 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002753
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002754 if (init_drm(ec, drm_device) < 0) {
2755 weston_log("failed to initialize kms\n");
2756 goto err_udev_dev;
2757 }
2758
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002759 if (ec->use_pixman) {
2760 if (init_pixman(ec) < 0) {
2761 weston_log("failed to initialize pixman renderer\n");
2762 goto err_udev_dev;
2763 }
2764 } else {
2765 if (init_egl(ec) < 0) {
2766 weston_log("failed to initialize egl\n");
2767 goto err_udev_dev;
2768 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002769 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002770
2771 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002772 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002773
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002774 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002775
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002776 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002777 weston_compositor_add_key_binding(&ec->base, key,
2778 MODIFIER_CTRL | MODIFIER_ALT,
2779 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002780
Jesse Barnes58ef3792012-02-23 09:45:49 -05002781 wl_list_init(&ec->sprite_list);
2782 create_sprites(ec);
2783
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002784 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002785 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002786 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002787 }
2788
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002789 path = NULL;
2790
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002791 if (udev_input_init(&ec->input,
2792 &ec->base, ec->udev, param->seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002793 weston_log("failed to create input devices\n");
2794 goto err_sprite;
2795 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002796
2797 loop = wl_display_get_event_loop(ec->base.wl_display);
2798 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002799 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002800 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002801
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002802 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2803 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002804 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002805 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002806 }
2807 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2808 "drm", NULL);
2809 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002810 wl_event_loop_add_fd(loop,
2811 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002812 WL_EVENT_READABLE, udev_drm_event, ec);
2813
2814 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002815 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002816 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002817 }
2818
Daniel Stonea96b93c2012-06-22 14:04:37 +01002819 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002820
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002821 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002822 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002823 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002824 planes_binding, ec);
2825 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2826 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002827 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2828 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002829 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2830 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002831
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002832 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002833
2834err_udev_monitor:
2835 wl_event_source_remove(ec->udev_drm_source);
2836 udev_monitor_unref(ec->udev_monitor);
2837err_drm_source:
2838 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002839 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002840err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002841 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002842 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002843 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002844err_udev_dev:
2845 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002846err_launcher:
2847 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002848err_udev:
2849 udev_unref(ec->udev);
2850err_compositor:
2851 weston_compositor_shutdown(&ec->base);
2852err_base:
2853 free(ec);
2854 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002855}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002856
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002857WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002858backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002859 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002860{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002861 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002862
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002863 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002864 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2865 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2866 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002867 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002868 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002869 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002870
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002871 param.seat_id = default_seat;
2872
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002873 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002874
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002875 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002876}