blob: 5cb0fab942a7c433213c08083d28139ab73b835f [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>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020044#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040045#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020046
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;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200150
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300151 int vblank_pending;
152 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800153 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300154
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400155 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400156 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400157 struct weston_plane cursor_plane;
158 struct weston_plane fb_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500159 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400160 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300161 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200162 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200163
164 struct drm_fb *dumb[2];
165 pixman_image_t *image[2];
166 int current_image;
167 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300168
169 struct vaapi_recorder *recorder;
170 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400171};
172
Jesse Barnes58ef3792012-02-23 09:45:49 -0500173/*
174 * An output has a primary display plane plus zero or more sprites for
175 * blending display contents.
176 */
177struct drm_sprite {
178 struct wl_list link;
179
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400180 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500181
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200182 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300183 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500184 struct drm_compositor *compositor;
185
Jesse Barnes58ef3792012-02-23 09:45:49 -0500186 uint32_t possible_crtcs;
187 uint32_t plane_id;
188 uint32_t count_formats;
189
190 int32_t src_x, src_y;
191 uint32_t src_w, src_h;
192 uint32_t dest_x, dest_y;
193 uint32_t dest_w, dest_h;
194
195 uint32_t formats[];
196};
197
Kristian Høgsbergd8e98332013-10-16 16:15:11 -0700198struct drm_parameters {
199 int connector;
200 int tty;
201 int use_pixman;
202 const char *seat_id;
203};
204
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300205static struct gl_renderer_interface *gl_renderer;
206
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500207static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400208
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400209static void
210drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400211
Jesse Barnes58ef3792012-02-23 09:45:49 -0500212static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500213drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
214{
215 struct weston_compositor *ec = output_base->compositor;
216 struct drm_compositor *c =(struct drm_compositor *) ec;
217 struct drm_output *output = (struct drm_output *) output_base;
218 int crtc;
219
220 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
221 if (c->crtcs[crtc] != output->crtc_id)
222 continue;
223
224 if (supported & (1 << crtc))
225 return -1;
226 }
227
228 return 0;
229}
230
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300231static void
232drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
233{
234 struct drm_fb *fb = data;
235 struct gbm_device *gbm = gbm_bo_get_device(bo);
236
237 if (fb->fb_id)
238 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
239
Pekka Paalanende685b82012-12-04 15:58:12 +0200240 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300241
242 free(data);
243}
244
245static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200246drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
247{
248 struct drm_fb *fb;
249 int ret;
250
251 struct drm_mode_create_dumb create_arg;
252 struct drm_mode_destroy_dumb destroy_arg;
253 struct drm_mode_map_dumb map_arg;
254
Peter Huttererf3d62272013-08-08 11:57:05 +1000255 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200256 if (!fb)
257 return NULL;
258
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700259 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200260 create_arg.bpp = 32;
261 create_arg.width = width;
262 create_arg.height = height;
263
264 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
265 if (ret)
266 goto err_fb;
267
268 fb->handle = create_arg.handle;
269 fb->stride = create_arg.pitch;
270 fb->size = create_arg.size;
271 fb->fd = ec->drm.fd;
272
273 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
274 fb->stride, fb->handle, &fb->fb_id);
275 if (ret)
276 goto err_bo;
277
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700278 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200279 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400280 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200281 if (ret)
282 goto err_add_fb;
283
284 fb->map = mmap(0, fb->size, PROT_WRITE,
285 MAP_SHARED, ec->drm.fd, map_arg.offset);
286 if (fb->map == MAP_FAILED)
287 goto err_add_fb;
288
289 return fb;
290
291err_add_fb:
292 drmModeRmFB(ec->drm.fd, fb->fb_id);
293err_bo:
294 memset(&destroy_arg, 0, sizeof(destroy_arg));
295 destroy_arg.handle = create_arg.handle;
296 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
297err_fb:
298 free(fb);
299 return NULL;
300}
301
302static void
303drm_fb_destroy_dumb(struct drm_fb *fb)
304{
305 struct drm_mode_destroy_dumb destroy_arg;
306
307 if (!fb->map)
308 return;
309
310 if (fb->fb_id)
311 drmModeRmFB(fb->fd, fb->fb_id);
312
313 weston_buffer_reference(&fb->buffer_ref, NULL);
314
315 munmap(fb->map, fb->size);
316
317 memset(&destroy_arg, 0, sizeof(destroy_arg));
318 destroy_arg.handle = fb->handle;
319 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
320
321 free(fb);
322}
323
324static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500325drm_fb_get_from_bo(struct gbm_bo *bo,
326 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300327{
328 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200329 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200330 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300331 int ret;
332
333 if (fb)
334 return fb;
335
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200336 fb = calloc(1, sizeof *fb);
337 if (!fb)
338 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300339
340 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300341
342 width = gbm_bo_get_width(bo);
343 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200344 fb->stride = gbm_bo_get_stride(bo);
345 fb->handle = gbm_bo_get_handle(bo).u32;
346 fb->size = fb->stride * height;
347 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300348
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200349 if (compositor->min_width > width || width > compositor->max_width ||
350 compositor->min_height > height ||
351 height > compositor->max_height) {
352 weston_log("bo geometry out of bounds\n");
353 goto err_free;
354 }
355
356 ret = -1;
357
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200358 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200359 handles[0] = fb->handle;
360 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200361 offsets[0] = 0;
362
363 ret = drmModeAddFB2(compositor->drm.fd, width, height,
364 format, handles, pitches, offsets,
365 &fb->fb_id, 0);
366 if (ret) {
367 weston_log("addfb2 failed: %m\n");
368 compositor->no_addfb2 = 1;
369 compositor->sprites_are_broken = 1;
370 }
371 }
372
373 if (ret)
374 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200375 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300377 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200378 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200379 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300380 }
381
382 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
383
384 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200385
386err_free:
387 free(fb);
388 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300389}
390
391static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500392drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200393{
Pekka Paalanende685b82012-12-04 15:58:12 +0200394 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200395
396 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200397
Pekka Paalanende685b82012-12-04 15:58:12 +0200398 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200399}
400
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200401static void
402drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
403{
404 if (!fb)
405 return;
406
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200407 if (fb->map &&
408 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200409 drm_fb_destroy_dumb(fb);
410 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200411 if (fb->is_client_buffer)
412 gbm_bo_destroy(fb->bo);
413 else
414 gbm_surface_release_buffer(output->surface,
415 output->current->bo);
416 }
417}
418
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500419static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200420drm_output_check_scanout_format(struct drm_output *output,
421 struct weston_surface *es, struct gbm_bo *bo)
422{
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700423 struct drm_compositor *c =
424 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200425 uint32_t format;
426 pixman_region32_t r;
427
428 format = gbm_bo_get_format(bo);
429
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700430 if (format == GBM_FORMAT_ARGB8888) {
431 /* We can scanout an ARGB buffer if the surface's
432 * opaque region covers the whole output, but we have
433 * to use XRGB as the KMS format code. */
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200434 pixman_region32_init(&r);
435 pixman_region32_subtract(&r, &output->base.region,
436 &es->opaque);
437
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
444 if (c->format == format)
445 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 ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500466 output->base.transform != ev->surface->buffer_transform ||
467 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
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700509 output->next = drm_fb_get_from_bo(bo, c, c->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:
671 if (output->next) {
672 drm_output_release_fb(output, output->next);
673 output->next = NULL;
674 }
675
676 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400677}
678
679static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200680drm_output_start_repaint_loop(struct weston_output *output_base)
681{
682 struct drm_output *output = (struct drm_output *) output_base;
683 struct drm_compositor *compositor = (struct drm_compositor *)
684 output_base->compositor;
685 uint32_t fb_id;
David Herrmann3c688c52013-10-22 17:11:25 +0200686 uint32_t msec;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300687 struct timespec ts;
688
Xiong Zhangabd5d472013-10-11 14:43:07 +0800689 if (output->destroy_pending)
690 return;
691
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300692 if (!output->current) {
693 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200694 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300695 }
696
697 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200698
699 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
700 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
701 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200702 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200703 }
David Herrmann3c688c52013-10-22 17:11:25 +0200704
705 return;
706
707finish_frame:
708 /* if we cannot page-flip, immediately finish frame */
709 clock_gettime(compositor->clock, &ts);
710 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
711 weston_output_finish_frame(output_base, msec);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200712}
713
714static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500715vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
716 void *data)
717{
718 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300719 struct drm_output *output = s->output;
720 uint32_t msecs;
721
722 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500723
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200724 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200725 s->current = s->next;
726 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300727
728 if (!output->page_flip_pending) {
729 msecs = sec * 1000 + usec / 1000;
730 weston_output_finish_frame(&output->base, msecs);
731 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500732}
733
734static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800735drm_output_destroy(struct weston_output *output_base);
736
737static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400738page_flip_handler(int fd, unsigned int frame,
739 unsigned int sec, unsigned int usec, void *data)
740{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200741 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400742 uint32_t msecs;
743
Jonas Ådahle5a12252013-04-05 23:07:11 +0200744 /* We don't set page_flip_pending on start_repaint_loop, in that case
745 * we just want to page flip to the current buffer to get an accurate
746 * timestamp */
747 if (output->page_flip_pending) {
748 drm_output_release_fb(output, output->current);
749 output->current = output->next;
750 output->next = NULL;
751 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300752
Jonas Ådahle5a12252013-04-05 23:07:11 +0200753 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400754
Xiong Zhangabd5d472013-10-11 14:43:07 +0800755 if (output->destroy_pending)
756 drm_output_destroy(&output->base);
757 else if (!output->vblank_pending) {
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300758 msecs = sec * 1000 + usec / 1000;
759 weston_output_finish_frame(&output->base, msecs);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300760
761 /* We can't call this from frame_notify, because the output's
762 * repaint needed flag is cleared just after that */
763 if (output->recorder)
764 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300765 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200766}
767
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500768static uint32_t
769drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500770 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500771{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500772 uint32_t i, format;
773
774 format = gbm_bo_get_format(bo);
775
776 if (format == GBM_FORMAT_ARGB8888) {
777 pixman_region32_t r;
778
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500779 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500780 ev->geometry.width,
781 ev->geometry.height);
782 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500783
784 if (!pixman_region32_not_empty(&r))
785 format = GBM_FORMAT_XRGB8888;
786
787 pixman_region32_fini(&r);
788 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500789
790 for (i = 0; i < s->count_formats; i++)
791 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500792 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500793
794 return 0;
795}
796
797static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500798drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500799{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500800 return !ev->transform.enabled ||
801 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500802}
803
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400804static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500805drm_output_prepare_overlay_view(struct weston_output *output_base,
806 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500807{
808 struct weston_compositor *ec = output_base->compositor;
809 struct drm_compositor *c =(struct drm_compositor *) ec;
810 struct drm_sprite *s;
811 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500812 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500813 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200814 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500815 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400816 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500817
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200818 if (c->gbm == NULL)
819 return NULL;
820
Jason Ekstranda7af7042013-10-12 22:38:11 -0500821 if (ev->surface->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200822 return NULL;
823
Jason Ekstranda7af7042013-10-12 22:38:11 -0500824 if (ev->surface->buffer_scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200825 return NULL;
826
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500827 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400828 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500829
Jason Ekstranda7af7042013-10-12 22:38:11 -0500830 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400831 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300832
Jason Ekstranda7af7042013-10-12 22:38:11 -0500833 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400834 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500835
Jason Ekstranda7af7042013-10-12 22:38:11 -0500836 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200837 return NULL;
838
Jason Ekstranda7af7042013-10-12 22:38:11 -0500839 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500840 return NULL;
841
Jason Ekstranda7af7042013-10-12 22:38:11 -0500842 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400843 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500844
Jesse Barnes58ef3792012-02-23 09:45:49 -0500845 wl_list_for_each(s, &c->sprite_list, link) {
846 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
847 continue;
848
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200849 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500850 found = 1;
851 break;
852 }
853 }
854
855 /* No sprites available */
856 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400857 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500858
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400859 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500860 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700861 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400862 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400863 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400864
Jason Ekstranda7af7042013-10-12 22:38:11 -0500865 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500866 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200867 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400868 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500869 }
870
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200871 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200872 if (!s->next) {
873 gbm_bo_destroy(bo);
874 return NULL;
875 }
876
Jason Ekstranda7af7042013-10-12 22:38:11 -0500877 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500878
Jason Ekstranda7af7042013-10-12 22:38:11 -0500879 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400880 s->plane.x = box->x1;
881 s->plane.y = box->y1;
882
Jesse Barnes58ef3792012-02-23 09:45:49 -0500883 /*
884 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200885 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500886 * for us already).
887 */
888 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500889 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500890 &output_base->region);
891 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
892 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200893 tbox = weston_transformed_rect(output_base->width,
894 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200895 output_base->transform,
Hardeningff39efa2013-09-18 23:56:35 +0200896 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200897 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200898 s->dest_x = tbox.x1;
899 s->dest_y = tbox.y1;
900 s->dest_w = tbox.x2 - tbox.x1;
901 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500902 pixman_region32_fini(&dest_rect);
903
904 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500905 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500906 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500907 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400908
Jason Ekstranda7af7042013-10-12 22:38:11 -0500909 weston_view_from_global_fixed(ev,
910 wl_fixed_from_int(box->x1),
911 wl_fixed_from_int(box->y1),
912 &sx1, &sy1);
913 weston_view_from_global_fixed(ev,
914 wl_fixed_from_int(box->x2),
915 wl_fixed_from_int(box->y2),
916 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400917
918 if (sx1 < 0)
919 sx1 = 0;
920 if (sy1 < 0)
921 sy1 = 0;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500922 if (sx2 > wl_fixed_from_int(ev->geometry.width))
923 sx2 = wl_fixed_from_int(ev->geometry.width);
924 if (sy2 > wl_fixed_from_int(ev->geometry.height))
925 sy2 = wl_fixed_from_int(ev->geometry.height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400926
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200927 tbox.x1 = sx1;
928 tbox.y1 = sy1;
929 tbox.x2 = sx2;
930 tbox.y2 = sy2;
931
Jason Ekstranda7af7042013-10-12 22:38:11 -0500932 tbox = weston_transformed_rect(wl_fixed_from_int(ev->geometry.width),
933 wl_fixed_from_int(ev->geometry.height),
934 ev->surface->buffer_transform,
935 ev->surface->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200936
937 s->src_x = tbox.x1 << 8;
938 s->src_y = tbox.y1 << 8;
939 s->src_w = (tbox.x2 - tbox.x1) << 8;
940 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500941 pixman_region32_fini(&src_rect);
942
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400943 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500944}
945
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400946static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500947drm_output_prepare_cursor_view(struct weston_output *output_base,
948 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500949{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400950 struct drm_compositor *c =
951 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400952 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400953
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200954 if (c->gbm == NULL)
955 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200956 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
957 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500958 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400959 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500960 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400961 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500962 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400963 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500964 if (ev->surface->buffer_ref.buffer == NULL ||
965 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
966 ev->geometry.width > 64 || ev->geometry.height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400967 return NULL;
968
Jason Ekstranda7af7042013-10-12 22:38:11 -0500969 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400970
971 return &output->cursor_plane;
972}
973
974static void
975drm_output_set_cursor(struct drm_output *output)
976{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500977 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +0000978 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400979 struct drm_compositor *c =
980 (struct drm_compositor *) output->base.compositor;
981 EGLint handle, stride;
982 struct gbm_bo *bo;
983 uint32_t buf[64 * 64];
984 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400985 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500986
Jason Ekstranda7af7042013-10-12 22:38:11 -0500987 output->cursor_view = NULL;
988 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400989 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
990 return;
991 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500992
Neil Robertse5051712013-11-13 15:44:06 +0000993 buffer = ev->surface->buffer_ref.buffer;
994
995 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +0200996 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400997 pixman_region32_fini(&output->cursor_plane.damage);
998 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400999 output->current_cursor ^= 1;
1000 bo = output->cursor_bo[output->current_cursor];
1001 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001002 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1003 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1004 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001005 for (i = 0; i < ev->geometry.height; i++)
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001006 memcpy(buf + i * 64, s + i * stride,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001007 ev->geometry.width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001008 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001009
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001010 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001011 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001012
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001013 handle = gbm_bo_get_handle(bo).s32;
1014 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -05001015 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001016 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001017 c->cursors_are_broken = 1;
1018 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001019 }
1020
Jason Ekstranda7af7042013-10-12 22:38:11 -05001021 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1022 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001023 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001024 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001025 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001026 c->cursors_are_broken = 1;
1027 }
1028
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001029 output->cursor_plane.x = x;
1030 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001031 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001032}
1033
Jesse Barnes58ef3792012-02-23 09:45:49 -05001034static void
1035drm_assign_planes(struct weston_output *output)
1036{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001037 struct drm_compositor *c =
1038 (struct drm_compositor *) output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001039 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001040 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001041 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001042
1043 /*
1044 * Find a surface for each sprite in the output using some heuristics:
1045 * 1) size
1046 * 2) frequency of update
1047 * 3) opacity (though some hw might support alpha blending)
1048 * 4) clipping (this can be fixed with color keys)
1049 *
1050 * The idea is to save on blitting since this should save power.
1051 * If we can get a large video surface on the sprite for example,
1052 * the main display surface may not need to update at all, and
1053 * the client buffer can be used directly for the sprite surface
1054 * as we do for flipping full screen surfaces.
1055 */
1056 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001057 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001058
1059 /* Flag all visible surfaces as keep_buffer = 1 */
1060 wl_list_for_each(ev, &c->base.view_list, link)
1061 ev->surface->keep_buffer = 1;
1062
1063 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001064 /* test whether this buffer can ever go into a plane:
1065 * non-shm, or small enough to be a cursor
1066 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001067 if (!ev->surface->buffer_ref.buffer ||
1068 (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) &&
1069 (ev->geometry.width > 64 || ev->geometry.height > 64)))
1070 ev->surface->keep_buffer = 0;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001071
Jesse Barnes58ef3792012-02-23 09:45:49 -05001072 pixman_region32_init(&surface_overlap);
1073 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001074 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001075
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001076 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001077 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001078 next_plane = primary;
1079 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001080 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001081 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001082 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001083 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001084 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001085 if (next_plane == NULL)
1086 next_plane = primary;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001087 weston_view_move_to_plane(ev, next_plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001088 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001089 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001090 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001091
Jesse Barnes58ef3792012-02-23 09:45:49 -05001092 pixman_region32_fini(&surface_overlap);
1093 }
1094 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001095}
1096
Matt Roper361d2ad2011-08-29 13:52:23 -07001097static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001098drm_output_fini_pixman(struct drm_output *output);
1099
1100static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001101drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001102{
1103 struct drm_output *output = (struct drm_output *) output_base;
1104 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001105 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001106 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001107
Xiong Zhangabd5d472013-10-11 14:43:07 +08001108 if (output->page_flip_pending) {
1109 output->destroy_pending = 1;
1110 weston_log("destroy output while page flip pending\n");
1111 return;
1112 }
1113
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001114 if (output->backlight)
1115 backlight_destroy(output->backlight);
1116
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001117 drmModeFreeProperty(output->dpms_prop);
1118
Matt Roper361d2ad2011-08-29 13:52:23 -07001119 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001120 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001121
1122 /* Restore original CRTC state */
1123 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001124 origcrtc->x, origcrtc->y,
1125 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001126 drmModeFreeCrtc(origcrtc);
1127
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001128 c->crtc_allocator &= ~(1 << output->crtc_id);
1129 c->connector_allocator &= ~(1 << output->connector_id);
1130
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001131 if (c->use_pixman) {
1132 drm_output_fini_pixman(output);
1133 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001134 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001135 gbm_surface_destroy(output->surface);
1136 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001137
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001138 weston_plane_release(&output->fb_plane);
1139 weston_plane_release(&output->cursor_plane);
1140
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001141 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001142 wl_list_remove(&output->base.link);
1143
Matt Roper361d2ad2011-08-29 13:52:23 -07001144 free(output);
1145}
1146
Alex Wub7b8bda2012-04-17 17:20:48 +08001147static struct drm_mode *
1148choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1149{
1150 struct drm_mode *tmp_mode = NULL, *mode;
1151
Hardeningff39efa2013-09-18 23:56:35 +02001152 if (output->base.current_mode->width == target_mode->width &&
1153 output->base.current_mode->height == target_mode->height &&
1154 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001155 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001156 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001157
1158 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1159 if (mode->mode_info.hdisplay == target_mode->width &&
1160 mode->mode_info.vdisplay == target_mode->height) {
1161 if (mode->mode_info.vrefresh == target_mode->refresh ||
1162 target_mode->refresh == 0) {
1163 return mode;
1164 } else if (!tmp_mode)
1165 tmp_mode = mode;
1166 }
1167 }
1168
1169 return tmp_mode;
1170}
1171
1172static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001173drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001174static int
1175drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001176
1177static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001178drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1179{
1180 struct drm_output *output;
1181 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001182 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001183
1184 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001185 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001186 return -1;
1187 }
1188
1189 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001190 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001191 return -1;
1192 }
1193
1194 ec = (struct drm_compositor *)output_base->compositor;
1195 output = (struct drm_output *)output_base;
1196 drm_mode = choose_mode (output, mode);
1197
1198 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001199 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001200 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001201 }
1202
Hardeningff39efa2013-09-18 23:56:35 +02001203 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001204 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001205
Hardeningff39efa2013-09-18 23:56:35 +02001206 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001207
Hardeningff39efa2013-09-18 23:56:35 +02001208 output->base.current_mode = &drm_mode->base;
1209 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001210 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1211
Alex Wub7b8bda2012-04-17 17:20:48 +08001212 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001213 drm_output_release_fb(output, output->current);
1214 drm_output_release_fb(output, output->next);
1215 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001216
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001217 if (ec->use_pixman) {
1218 drm_output_fini_pixman(output);
1219 if (drm_output_init_pixman(output, ec) < 0) {
1220 weston_log("failed to init output pixman state with "
1221 "new mode\n");
1222 return -1;
1223 }
1224 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001225 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001226 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001227
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001228 if (drm_output_init_egl(output, ec) < 0) {
1229 weston_log("failed to init output egl state with "
1230 "new mode");
1231 return -1;
1232 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001233 }
1234
Alex Wub7b8bda2012-04-17 17:20:48 +08001235 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001236}
1237
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001238static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001239on_drm_input(int fd, uint32_t mask, void *data)
1240{
1241 drmEventContext evctx;
1242
1243 memset(&evctx, 0, sizeof evctx);
1244 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1245 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001246 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001247 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001248
1249 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001250}
1251
1252static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001253init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001254{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001255 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001256 uint64_t cap;
1257 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001258
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001259 sysnum = udev_device_get_sysnum(device);
1260 if (sysnum)
1261 ec->drm.id = atoi(sysnum);
1262 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001263 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001264 return -1;
1265 }
1266
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001267 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001268 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001269 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001270 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001271 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001272 udev_device_get_devnode(device));
1273 return -1;
1274 }
1275
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001276 weston_log("using %s\n", filename);
1277
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001278 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001279 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001280
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001281 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1282 if (ret == 0 && cap == 1)
1283 ec->clock = CLOCK_MONOTONIC;
1284 else
1285 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001286
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001287 return 0;
1288}
1289
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001290static struct gbm_device *
1291create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001292{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001293 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001294
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001295 gl_renderer = weston_load_module("gl-renderer.so",
1296 "gl_renderer_interface");
1297 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001298 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001299
1300 /* GBM will load a dri driver, but even though they need symbols from
1301 * libglapi, in some version of Mesa they are not linked to it. Since
1302 * only the gl-renderer module links to it, the call above won't make
1303 * these symbols globally available, and loading the DRI driver fails.
1304 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1305 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1306
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001307 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001308
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001309 return gbm;
1310}
1311
1312static int
1313drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1314{
1315 EGLint format;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001316
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001317 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001318 if (gl_renderer->create(&ec->base, ec->gbm,
1319 gl_renderer->opaque_attribs, &format) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001320 return -1;
1321 }
1322
1323 return 0;
1324}
1325
1326static int
1327init_egl(struct drm_compositor *ec)
1328{
1329 ec->gbm = create_gbm_device(ec->drm.fd);
1330
1331 if (!ec->gbm)
1332 return -1;
1333
1334 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001335 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001336 return -1;
1337 }
1338
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001339 return 0;
1340}
1341
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001342static int
1343init_pixman(struct drm_compositor *ec)
1344{
1345 return pixman_renderer_init(&ec->base);
1346}
1347
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001348static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001349drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001350{
1351 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001352 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001353
1354 mode = malloc(sizeof *mode);
1355 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001356 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001357
1358 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001359 mode->base.width = info->hdisplay;
1360 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001361
1362 /* Calculate higher precision (mHz) refresh rate */
1363 refresh = (info->clock * 1000000LL / info->htotal +
1364 info->vtotal / 2) / info->vtotal;
1365
1366 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1367 refresh *= 2;
1368 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1369 refresh /= 2;
1370 if (info->vscan > 1)
1371 refresh /= info->vscan;
1372
1373 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001374 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001375
1376 if (info->type & DRM_MODE_TYPE_PREFERRED)
1377 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1378
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001379 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1380
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001381 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001382}
1383
1384static int
1385drm_subpixel_to_wayland(int drm_value)
1386{
1387 switch (drm_value) {
1388 default:
1389 case DRM_MODE_SUBPIXEL_UNKNOWN:
1390 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1391 case DRM_MODE_SUBPIXEL_NONE:
1392 return WL_OUTPUT_SUBPIXEL_NONE;
1393 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1394 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1395 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1396 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1397 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1398 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1399 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1400 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1401 }
1402}
1403
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001404/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001405static uint32_t
1406drm_get_backlight(struct drm_output *output)
1407{
1408 long brightness, max_brightness, norm;
1409
1410 brightness = backlight_get_brightness(output->backlight);
1411 max_brightness = backlight_get_max_brightness(output->backlight);
1412
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001413 /* convert it on a scale of 0 to 255 */
1414 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001415
1416 return (uint32_t) norm;
1417}
1418
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001419/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001420static void
1421drm_set_backlight(struct weston_output *output_base, uint32_t value)
1422{
1423 struct drm_output *output = (struct drm_output *) output_base;
1424 long max_brightness, new_brightness;
1425
1426 if (!output->backlight)
1427 return;
1428
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001429 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001430 return;
1431
1432 max_brightness = backlight_get_max_brightness(output->backlight);
1433
1434 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001435 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001436
1437 backlight_set_brightness(output->backlight, new_brightness);
1438}
1439
1440static drmModePropertyPtr
1441drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1442{
1443 drmModePropertyPtr props;
1444 int i;
1445
1446 for (i = 0; i < connector->count_props; i++) {
1447 props = drmModeGetProperty(fd, connector->props[i]);
1448 if (!props)
1449 continue;
1450
1451 if (!strcmp(props->name, name))
1452 return props;
1453
1454 drmModeFreeProperty(props);
1455 }
1456
1457 return NULL;
1458}
1459
1460static void
1461drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1462{
1463 struct drm_output *output = (struct drm_output *) output_base;
1464 struct weston_compositor *ec = output_base->compositor;
1465 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001466
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001467 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001468 return;
1469
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001470 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1471 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001472}
1473
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001474static const char *connector_type_names[] = {
1475 "None",
1476 "VGA",
1477 "DVI",
1478 "DVI",
1479 "DVI",
1480 "Composite",
1481 "TV",
1482 "LVDS",
1483 "CTV",
1484 "DIN",
1485 "DP",
1486 "HDMI",
1487 "HDMI",
1488 "TV",
1489 "eDP",
1490};
1491
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001492static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001493find_crtc_for_connector(struct drm_compositor *ec,
1494 drmModeRes *resources, drmModeConnector *connector)
1495{
1496 drmModeEncoder *encoder;
1497 uint32_t possible_crtcs;
1498 int i, j;
1499
1500 for (j = 0; j < connector->count_encoders; j++) {
1501 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1502 if (encoder == NULL) {
1503 weston_log("Failed to get encoder.\n");
1504 return -1;
1505 }
1506 possible_crtcs = encoder->possible_crtcs;
1507 drmModeFreeEncoder(encoder);
1508
1509 for (i = 0; i < resources->count_crtcs; i++) {
1510 if (possible_crtcs & (1 << i) &&
1511 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1512 return i;
1513 }
1514 }
1515
1516 return -1;
1517}
1518
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001519/* Init output state that depends on gl or gbm */
1520static int
1521drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1522{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001523 int i, flags;
1524
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001525 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001526 output->base.current_mode->width,
1527 output->base.current_mode->height,
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07001528 ec->format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001529 GBM_BO_USE_SCANOUT |
1530 GBM_BO_USE_RENDERING);
1531 if (!output->surface) {
1532 weston_log("failed to create gbm surface\n");
1533 return -1;
1534 }
1535
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001536 if (gl_renderer->output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001537 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001538 gbm_surface_destroy(output->surface);
1539 return -1;
1540 }
1541
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001542 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1543
1544 for (i = 0; i < 2; i++) {
1545 if (output->cursor_bo[i])
1546 continue;
1547
1548 output->cursor_bo[i] =
1549 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1550 flags);
1551 }
1552
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001553 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1554 weston_log("cursor buffers unavailable, using gl cursors\n");
1555 ec->cursors_are_broken = 1;
1556 }
1557
1558 return 0;
1559}
1560
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001561static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001562drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1563{
Hardeningff39efa2013-09-18 23:56:35 +02001564 int w = output->base.current_mode->width;
1565 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001566 unsigned int i;
1567
1568 /* FIXME error checking */
1569
1570 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001571 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001572 if (!output->dumb[i])
1573 goto err;
1574
1575 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001576 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001577 output->dumb[i]->map,
1578 output->dumb[i]->stride);
1579 if (!output->image[i])
1580 goto err;
1581 }
1582
1583 if (pixman_renderer_output_create(&output->base) < 0)
1584 goto err;
1585
1586 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001587 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001588
1589 return 0;
1590
1591err:
1592 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1593 if (output->dumb[i])
1594 drm_fb_destroy_dumb(output->dumb[i]);
1595 if (output->image[i])
1596 pixman_image_unref(output->image[i]);
1597
1598 output->dumb[i] = NULL;
1599 output->image[i] = NULL;
1600 }
1601
1602 return -1;
1603}
1604
1605static void
1606drm_output_fini_pixman(struct drm_output *output)
1607{
1608 unsigned int i;
1609
1610 pixman_renderer_output_destroy(&output->base);
1611 pixman_region32_fini(&output->previous_damage);
1612
1613 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1614 drm_fb_destroy_dumb(output->dumb[i]);
1615 pixman_image_unref(output->image[i]);
1616 output->dumb[i] = NULL;
1617 output->image[i] = NULL;
1618 }
1619}
1620
Richard Hughes2b2092a2013-04-24 14:58:02 +01001621static void
1622edid_parse_string(const uint8_t *data, char text[])
1623{
1624 int i;
1625 int replaced = 0;
1626
1627 /* this is always 12 bytes, but we can't guarantee it's null
1628 * terminated or not junk. */
1629 strncpy(text, (const char *) data, 12);
1630
1631 /* remove insane chars */
1632 for (i = 0; text[i] != '\0'; i++) {
1633 if (text[i] == '\n' ||
1634 text[i] == '\r') {
1635 text[i] = '\0';
1636 break;
1637 }
1638 }
1639
1640 /* ensure string is printable */
1641 for (i = 0; text[i] != '\0'; i++) {
1642 if (!isprint(text[i])) {
1643 text[i] = '-';
1644 replaced++;
1645 }
1646 }
1647
1648 /* if the string is random junk, ignore the string */
1649 if (replaced > 4)
1650 text[0] = '\0';
1651}
1652
1653#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1654#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1655#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1656#define EDID_OFFSET_DATA_BLOCKS 0x36
1657#define EDID_OFFSET_LAST_BLOCK 0x6c
1658#define EDID_OFFSET_PNPID 0x08
1659#define EDID_OFFSET_SERIAL 0x0c
1660
1661static int
1662edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1663{
1664 int i;
1665 uint32_t serial_number;
1666
1667 /* check header */
1668 if (length < 128)
1669 return -1;
1670 if (data[0] != 0x00 || data[1] != 0xff)
1671 return -1;
1672
1673 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1674 * /--08--\/--09--\
1675 * 7654321076543210
1676 * |\---/\---/\---/
1677 * R C1 C2 C3 */
1678 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1679 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1680 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1681 edid->pnp_id[3] = '\0';
1682
1683 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1684 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1685 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1686 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1687 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1688 if (serial_number > 0)
1689 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1690
1691 /* parse EDID data */
1692 for (i = EDID_OFFSET_DATA_BLOCKS;
1693 i <= EDID_OFFSET_LAST_BLOCK;
1694 i += 18) {
1695 /* ignore pixel clock data */
1696 if (data[i] != 0)
1697 continue;
1698 if (data[i+2] != 0)
1699 continue;
1700
1701 /* any useful blocks? */
1702 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1703 edid_parse_string(&data[i+5],
1704 edid->monitor_name);
1705 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1706 edid_parse_string(&data[i+5],
1707 edid->serial_number);
1708 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1709 edid_parse_string(&data[i+5],
1710 edid->eisa_id);
1711 }
1712 }
1713 return 0;
1714}
1715
1716static void
1717find_and_parse_output_edid(struct drm_compositor *ec,
1718 struct drm_output *output,
1719 drmModeConnector *connector)
1720{
1721 drmModePropertyBlobPtr edid_blob = NULL;
1722 drmModePropertyPtr property;
1723 int i;
1724 int rc;
1725
1726 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1727 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1728 if (!property)
1729 continue;
1730 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1731 !strcmp(property->name, "EDID")) {
1732 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1733 connector->prop_values[i]);
1734 }
1735 drmModeFreeProperty(property);
1736 }
1737 if (!edid_blob)
1738 return;
1739
1740 rc = edid_parse(&output->edid,
1741 edid_blob->data,
1742 edid_blob->length);
1743 if (!rc) {
1744 weston_log("EDID data '%s', '%s', '%s'\n",
1745 output->edid.pnp_id,
1746 output->edid.monitor_name,
1747 output->edid.serial_number);
1748 if (output->edid.pnp_id[0] != '\0')
1749 output->base.make = output->edid.pnp_id;
1750 if (output->edid.monitor_name[0] != '\0')
1751 output->base.model = output->edid.monitor_name;
1752 if (output->edid.serial_number[0] != '\0')
1753 output->base.serial_number = output->edid.serial_number;
1754 }
1755 drmModeFreePropertyBlob(edid_blob);
1756}
1757
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001758
1759
1760static int
1761parse_modeline(const char *s, drmModeModeInfo *mode)
1762{
1763 char hsync[16];
1764 char vsync[16];
1765 float fclock;
1766
1767 mode->type = DRM_MODE_TYPE_USERDEF;
1768 mode->hskew = 0;
1769 mode->vscan = 0;
1770 mode->vrefresh = 0;
1771 mode->flags = 0;
1772
Rob Bradford307e09e2013-07-26 16:29:40 +01001773 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001774 &fclock,
1775 &mode->hdisplay,
1776 &mode->hsync_start,
1777 &mode->hsync_end,
1778 &mode->htotal,
1779 &mode->vdisplay,
1780 &mode->vsync_start,
1781 &mode->vsync_end,
1782 &mode->vtotal, hsync, vsync) != 11)
1783 return -1;
1784
1785 mode->clock = fclock * 1000;
1786 if (strcmp(hsync, "+hsync") == 0)
1787 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1788 else if (strcmp(hsync, "-hsync") == 0)
1789 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1790 else
1791 return -1;
1792
1793 if (strcmp(vsync, "+vsync") == 0)
1794 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1795 else if (strcmp(vsync, "-vsync") == 0)
1796 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1797 else
1798 return -1;
1799
1800 return 0;
1801}
1802
1803static uint32_t
1804parse_transform(const char *transform, const char *output_name)
1805{
1806 static const struct { const char *name; uint32_t token; } names[] = {
1807 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1808 { "90", WL_OUTPUT_TRANSFORM_90 },
1809 { "180", WL_OUTPUT_TRANSFORM_180 },
1810 { "270", WL_OUTPUT_TRANSFORM_270 },
1811 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1812 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1813 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1814 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1815 };
1816 unsigned int i;
1817
1818 for (i = 0; i < ARRAY_LENGTH(names); i++)
1819 if (strcmp(names[i].name, transform) == 0)
1820 return names[i].token;
1821
1822 weston_log("Invalid transform \"%s\" for output %s\n",
1823 transform, output_name);
1824
1825 return WL_OUTPUT_TRANSFORM_NORMAL;
1826}
1827
Rob Bradford66bd9f52013-06-25 18:56:42 +01001828static void
1829setup_output_seat_constraint(struct drm_compositor *ec,
1830 struct weston_output *output,
1831 const char *s)
1832{
1833 if (strcmp(s, "") != 0) {
1834 struct udev_seat *seat;
1835
1836 seat = udev_seat_get_named(&ec->base, s);
1837 if (seat)
1838 seat->base.output = output;
1839
1840 if (seat && seat->base.pointer)
1841 weston_pointer_clamp(seat->base.pointer,
1842 &seat->base.pointer->x,
1843 &seat->base.pointer->y);
1844 }
1845}
1846
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001847static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001848create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001849 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001850 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001851 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001852{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001853 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001854 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1855 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001856 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001857 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001858 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001859 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001860 int i, width, height, scale;
1861 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001862 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001863 enum output_config config;
1864 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001865
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001866 i = find_crtc_for_connector(ec, resources, connector);
1867 if (i < 0) {
1868 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001869 return -1;
1870 }
1871
Peter Huttererf3d62272013-08-08 11:57:05 +10001872 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001873 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001874 return -1;
1875
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001876 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1877 output->base.make = "unknown";
1878 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001879 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001880 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001881
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001882 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1883 type_name = connector_type_names[connector->connector_type];
1884 else
1885 type_name = "UNKNOWN";
1886 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001887 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001888
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001889 section = weston_config_get_section(ec->base.config, "output", "name",
1890 output->base.name);
1891 weston_config_section_get_string(section, "mode", &s, "preferred");
1892 if (strcmp(s, "off") == 0)
1893 config = OUTPUT_CONFIG_OFF;
1894 else if (strcmp(s, "preferred") == 0)
1895 config = OUTPUT_CONFIG_PREFERRED;
1896 else if (strcmp(s, "current") == 0)
1897 config = OUTPUT_CONFIG_CURRENT;
1898 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1899 config = OUTPUT_CONFIG_MODE;
1900 else if (parse_modeline(s, &modeline) == 0)
1901 config = OUTPUT_CONFIG_MODELINE;
1902 else {
1903 weston_log("Invalid mode \"%s\" for output %s\n",
1904 s, output->base.name);
1905 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001906 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001907 free(s);
1908
1909 weston_config_section_get_int(section, "scale", &scale, 1);
1910 weston_config_section_get_string(section, "transform", &s, "normal");
1911 transform = parse_transform(s, output->base.name);
1912 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001913
Rob Bradford66bd9f52013-06-25 18:56:42 +01001914 weston_config_section_get_string(section, "seat", &s, "");
1915 setup_output_seat_constraint(ec, &output->base, s);
1916 free(s);
1917
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001918 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001919 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001920 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001921 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001922 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001923
Matt Roper361d2ad2011-08-29 13:52:23 -07001924 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001925 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001926
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001927 /* Get the current mode on the crtc that's currently driving
1928 * this connector. */
1929 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001930 memset(&crtc_mode, 0, sizeof crtc_mode);
1931 if (encoder != NULL) {
1932 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1933 drmModeFreeEncoder(encoder);
1934 if (crtc == NULL)
1935 goto err_free;
1936 if (crtc->mode_valid)
1937 crtc_mode = crtc->mode;
1938 drmModeFreeCrtc(crtc);
1939 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001940
David Herrmann0f0d54e2011-12-08 17:05:45 +01001941 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001942 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001943 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001944 goto err_free;
1945 }
1946
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001947 if (config == OUTPUT_CONFIG_OFF) {
1948 weston_log("Disabling output %s\n", output->base.name);
1949 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1950 0, 0, 0, 0, 0, NULL);
1951 goto err_free;
1952 }
1953
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001954 preferred = NULL;
1955 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001956 configured = NULL;
1957
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001958 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001959 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001960 width == drm_mode->base.width &&
1961 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001962 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001963 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001964 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001965 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001966 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001967 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001968
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001969 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001970 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001971 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001972 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001973 }
1974
Wang Quanxianacb805a2012-07-30 18:09:46 -04001975 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001976 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001977 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001978 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001979 }
1980
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001981 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001982 configured = current;
1983
Wang Quanxianacb805a2012-07-30 18:09:46 -04001984 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02001985 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001986 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02001987 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001988 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02001989 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001990 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02001991 output->base.current_mode = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001992
Hardeningff39efa2013-09-18 23:56:35 +02001993 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001994 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001995 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001996 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001997
Hardeningff39efa2013-09-18 23:56:35 +02001998 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001999
John Kåre Alsaker94659272012-11-13 19:10:18 +01002000 weston_output_init(&output->base, &ec->base, x, y,
2001 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002002 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002003
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002004 if (ec->use_pixman) {
2005 if (drm_output_init_pixman(output, ec) < 0) {
2006 weston_log("Failed to init output pixman state\n");
2007 goto err_output;
2008 }
2009 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002010 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002011 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002012 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002013
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002014 output->backlight = backlight_init(drm_device,
2015 connector->connector_type);
2016 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002017 weston_log("Initialized backlight, device %s\n",
2018 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002019 output->base.set_backlight = drm_set_backlight;
2020 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002021 } else {
2022 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002023 }
2024
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002025 wl_list_insert(ec->base.output_list.prev, &output->base.link);
2026
Richard Hughes2b2092a2013-04-24 14:58:02 +01002027 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002028 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2029 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002030
Jonas Ådahle5a12252013-04-05 23:07:11 +02002031 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002032 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002033 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002034 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002035 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002036 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002037
Richard Hughese7299962013-05-01 21:52:12 +01002038 output->base.gamma_size = output->original_crtc->gamma_size;
2039 output->base.set_gamma = drm_output_set_gamma;
2040
Xiong Zhang97116532013-10-23 13:58:31 +08002041 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2042 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002043
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002044 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2045 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2046 &ec->base.primary_plane);
2047
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002048 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002049 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002050 wl_list_for_each(m, &output->base.mode_list, link)
2051 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
2052 m->width, m->height, m->refresh / 1000.0,
2053 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2054 ", preferred" : "",
2055 m->flags & WL_OUTPUT_MODE_CURRENT ?
2056 ", current" : "",
2057 connector->count_modes == 0 ?
2058 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002059
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002060 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002061
John Kåre Alsaker94659272012-11-13 19:10:18 +01002062err_output:
2063 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002064err_free:
2065 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2066 base.link) {
2067 wl_list_remove(&drm_mode->base.link);
2068 free(drm_mode);
2069 }
2070
2071 drmModeFreeCrtc(output->original_crtc);
2072 ec->crtc_allocator &= ~(1 << output->crtc_id);
2073 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002074 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002075
David Herrmann0f0d54e2011-12-08 17:05:45 +01002076 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002077}
2078
Jesse Barnes58ef3792012-02-23 09:45:49 -05002079static void
2080create_sprites(struct drm_compositor *ec)
2081{
2082 struct drm_sprite *sprite;
2083 drmModePlaneRes *plane_res;
2084 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002085 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002086
2087 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2088 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002089 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002090 strerror(errno));
2091 return;
2092 }
2093
2094 for (i = 0; i < plane_res->count_planes; i++) {
2095 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2096 if (!plane)
2097 continue;
2098
Peter Huttererf3d62272013-08-08 11:57:05 +10002099 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002100 plane->count_formats));
2101 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002102 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002103 __func__);
2104 free(plane);
2105 continue;
2106 }
2107
Jesse Barnes58ef3792012-02-23 09:45:49 -05002108 sprite->possible_crtcs = plane->possible_crtcs;
2109 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002110 sprite->current = NULL;
2111 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002112 sprite->compositor = ec;
2113 sprite->count_formats = plane->count_formats;
2114 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002115 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002116 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002117 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002118 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2119 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002120
2121 wl_list_insert(&ec->sprite_list, &sprite->link);
2122 }
2123
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002124 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002125}
2126
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002127static void
2128destroy_sprites(struct drm_compositor *compositor)
2129{
2130 struct drm_sprite *sprite, *next;
2131 struct drm_output *output;
2132
2133 output = container_of(compositor->base.output_list.next,
2134 struct drm_output, base.link);
2135
2136 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2137 drmModeSetPlane(compositor->drm.fd,
2138 sprite->plane_id,
2139 output->crtc_id, 0, 0,
2140 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002141 drm_output_release_fb(output, sprite->current);
2142 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002143 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002144 free(sprite);
2145 }
2146}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002147
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002148static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002149create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002150 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002151{
2152 drmModeConnector *connector;
2153 drmModeRes *resources;
2154 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002155 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002156
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002157 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002158 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002159 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002160 return -1;
2161 }
2162
Jesse Barnes58ef3792012-02-23 09:45:49 -05002163 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002164 if (!ec->crtcs) {
2165 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002166 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002167 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002168
Rob Clark4339add2012-08-09 14:18:28 -05002169 ec->min_width = resources->min_width;
2170 ec->max_width = resources->max_width;
2171 ec->min_height = resources->min_height;
2172 ec->max_height = resources->max_height;
2173
Jesse Barnes58ef3792012-02-23 09:45:49 -05002174 ec->num_crtcs = resources->count_crtcs;
2175 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2176
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002177 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002178 connector = drmModeGetConnector(ec->drm.fd,
2179 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002180 if (connector == NULL)
2181 continue;
2182
2183 if (connector->connection == DRM_MODE_CONNECTED &&
2184 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002185 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002186 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002187 connector, x, y,
2188 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002189 drmModeFreeConnector(connector);
2190 continue;
2191 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002192
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002193 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002194 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002195 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002196 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002197
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002198 drmModeFreeConnector(connector);
2199 }
2200
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002201 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002202 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002203 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002204 return -1;
2205 }
2206
2207 drmModeFreeResources(resources);
2208
2209 return 0;
2210}
2211
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002212static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002213update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002214{
2215 drmModeConnector *connector;
2216 drmModeRes *resources;
2217 struct drm_output *output, *next;
2218 int x = 0, y = 0;
2219 int x_offset = 0, y_offset = 0;
2220 uint32_t connected = 0, disconnects = 0;
2221 int i;
2222
2223 resources = drmModeGetResources(ec->drm.fd);
2224 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002225 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002226 return;
2227 }
2228
2229 /* collect new connects */
2230 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002231 int connector_id = resources->connectors[i];
2232
2233 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002234 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002235 continue;
2236
David Herrmann7551cff2011-12-08 17:05:43 +01002237 if (connector->connection != DRM_MODE_CONNECTED) {
2238 drmModeFreeConnector(connector);
2239 continue;
2240 }
2241
Benjamin Franzke117483d2011-08-30 11:38:26 +02002242 connected |= (1 << connector_id);
2243
2244 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002245 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002246 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002247 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002248
2249 /* XXX: not yet needed, we die with 0 outputs */
2250 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002251 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002252 else
2253 x = 0;
2254 y = 0;
2255 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002256 connector, x, y,
2257 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002258 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002259
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002260 }
2261 drmModeFreeConnector(connector);
2262 }
2263 drmModeFreeResources(resources);
2264
2265 disconnects = ec->connector_allocator & ~connected;
2266 if (disconnects) {
2267 wl_list_for_each_safe(output, next, &ec->base.output_list,
2268 base.link) {
2269 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002270 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002271 output->base.x - x_offset,
2272 output->base.y - y_offset);
2273 }
2274
2275 if (disconnects & (1 << output->connector_id)) {
2276 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002277 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002278 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002279 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002280 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002281 }
2282 }
2283 }
2284
2285 /* FIXME: handle zero outputs, without terminating */
2286 if (ec->connector_allocator == 0)
2287 wl_display_terminate(ec->base.wl_display);
2288}
2289
2290static int
David Herrmannd7488c22012-03-11 20:05:21 +01002291udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002292{
David Herrmannd7488c22012-03-11 20:05:21 +01002293 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002294 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002295
2296 sysnum = udev_device_get_sysnum(device);
2297 if (!sysnum || atoi(sysnum) != ec->drm.id)
2298 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002299
David Herrmann6ac52db2012-03-11 20:05:22 +01002300 val = udev_device_get_property_value(device, "HOTPLUG");
2301 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002302 return 0;
2303
David Herrmann6ac52db2012-03-11 20:05:22 +01002304 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002305}
2306
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002307static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002308udev_drm_event(int fd, uint32_t mask, void *data)
2309{
2310 struct drm_compositor *ec = data;
2311 struct udev_device *event;
2312
2313 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002314
David Herrmannd7488c22012-03-11 20:05:21 +01002315 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002316 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002317
2318 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002319
2320 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002321}
2322
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002323static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002324drm_restore(struct weston_compositor *ec)
2325{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002326 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002327}
2328
2329static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002330drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002331{
2332 struct drm_compositor *d = (struct drm_compositor *) ec;
2333
Rob Bradfordd355b802013-05-31 18:09:55 +01002334 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002335
2336 wl_event_source_remove(d->udev_drm_source);
2337 wl_event_source_remove(d->drm_source);
2338
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002339 destroy_sprites(d);
2340
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002341 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002342
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002343 weston_compositor_shutdown(ec);
2344
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002345 if (d->gbm)
2346 gbm_device_destroy(d->gbm);
2347
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002348 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002349
Rob Bradford45c15b82013-07-26 16:29:35 +01002350 close(d->drm.fd);
2351
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002352 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002353}
2354
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002355static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002356drm_compositor_set_modes(struct drm_compositor *compositor)
2357{
2358 struct drm_output *output;
2359 struct drm_mode *drm_mode;
2360 int ret;
2361
2362 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002363 if (!output->current) {
2364 /* If something that would cause the output to
2365 * switch mode happened while in another vt, we
2366 * might not have a current drm_fb. In that case,
2367 * schedule a repaint and let drm_output_repaint
2368 * handle setting the mode. */
2369 weston_output_schedule_repaint(&output->base);
2370 continue;
2371 }
2372
Hardeningff39efa2013-09-18 23:56:35 +02002373 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002374 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002375 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002376 &output->connector_id, 1,
2377 &drm_mode->mode_info);
2378 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002379 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002380 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002381 drm_mode->base.width, drm_mode->base.height,
2382 output->base.x, output->base.y);
2383 }
2384 }
2385}
2386
2387static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002388session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002389{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002390 struct weston_compositor *compositor = data;
2391 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002392 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002393 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002394
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002395 if (ec->base.session_active) {
2396 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002397 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002398 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002399 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002400 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002401 } else {
2402 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002403 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002404
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002405 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002406 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002407
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002408 /* If we have a repaint scheduled (either from a
2409 * pending pageflip or the idle handler), make sure we
2410 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002411 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002412 * further attemps at repainting. When we switch
2413 * back, we schedule a repaint, which will process
2414 * pending frame callbacks. */
2415
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002416 wl_list_for_each(output, &ec->base.output_list, base.link) {
2417 output->base.repaint_needed = 0;
2418 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002419 }
2420
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002421 output = container_of(ec->base.output_list.next,
2422 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002423
2424 wl_list_for_each(sprite, &ec->sprite_list, link)
2425 drmModeSetPlane(ec->drm.fd,
2426 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002427 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002428 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002429 };
2430}
2431
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002432static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002433switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002434{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002435 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002436
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002437 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002438}
2439
David Herrmann0af066f2012-10-29 19:21:16 +01002440/*
2441 * Find primary GPU
2442 * Some systems may have multiple DRM devices attached to a single seat. This
2443 * function loops over all devices and tries to find a PCI device with the
2444 * boot_vga sysfs attribute set to 1.
2445 * If no such device is found, the first DRM device reported by udev is used.
2446 */
2447static struct udev_device*
2448find_primary_gpu(struct drm_compositor *ec, const char *seat)
2449{
2450 struct udev_enumerate *e;
2451 struct udev_list_entry *entry;
2452 const char *path, *device_seat, *id;
2453 struct udev_device *device, *drm_device, *pci;
2454
2455 e = udev_enumerate_new(ec->udev);
2456 udev_enumerate_add_match_subsystem(e, "drm");
2457 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2458
2459 udev_enumerate_scan_devices(e);
2460 drm_device = NULL;
2461 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2462 path = udev_list_entry_get_name(entry);
2463 device = udev_device_new_from_syspath(ec->udev, path);
2464 if (!device)
2465 continue;
2466 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2467 if (!device_seat)
2468 device_seat = default_seat;
2469 if (strcmp(device_seat, seat)) {
2470 udev_device_unref(device);
2471 continue;
2472 }
2473
2474 pci = udev_device_get_parent_with_subsystem_devtype(device,
2475 "pci", NULL);
2476 if (pci) {
2477 id = udev_device_get_sysattr_value(pci, "boot_vga");
2478 if (id && !strcmp(id, "1")) {
2479 if (drm_device)
2480 udev_device_unref(drm_device);
2481 drm_device = device;
2482 break;
2483 }
2484 }
2485
2486 if (!drm_device)
2487 drm_device = device;
2488 else
2489 udev_device_unref(device);
2490 }
2491
2492 udev_enumerate_unref(e);
2493 return drm_device;
2494}
2495
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002496static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002497planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002498{
2499 struct drm_compositor *c = data;
2500
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002501 switch (key) {
2502 case KEY_C:
2503 c->cursors_are_broken ^= 1;
2504 break;
2505 case KEY_V:
2506 c->sprites_are_broken ^= 1;
2507 break;
2508 case KEY_O:
2509 c->sprites_hidden ^= 1;
2510 break;
2511 default:
2512 break;
2513 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002514}
2515
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002516#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002517static void
2518recorder_frame_notify(struct wl_listener *listener, void *data)
2519{
2520 struct drm_output *output;
2521 struct drm_compositor *c;
2522 int fd, ret;
2523
2524 output = container_of(listener, struct drm_output,
2525 recorder_frame_listener);
2526 c = (struct drm_compositor *) output->base.compositor;
2527
2528 if (!output->recorder)
2529 return;
2530
2531 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2532 DRM_CLOEXEC, &fd);
2533 if (ret) {
2534 weston_log("[libva recorder] "
2535 "failed to create prime fd for front buffer\n");
2536 return;
2537 }
2538
2539 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002540}
2541
2542static void *
2543create_recorder(struct drm_compositor *c, int width, int height,
2544 const char *filename)
2545{
2546 int fd;
2547 drm_magic_t magic;
2548
2549 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2550 if (fd < 0)
2551 return NULL;
2552
2553 drmGetMagic(fd, &magic);
2554 drmAuthMagic(c->drm.fd, magic);
2555
2556 return vaapi_recorder_create(fd, width, height, filename);
2557}
2558
2559static void
2560recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2561 void *data)
2562{
2563 struct drm_compositor *c = data;
2564 struct drm_output *output;
2565 int width, height;
2566
2567 output = container_of(c->base.output_list.next,
2568 struct drm_output, base.link);
2569
2570 if (!output->recorder) {
Hardeningff39efa2013-09-18 23:56:35 +02002571 width = output->base.current_mode->width;
2572 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002573
2574 output->recorder =
2575 create_recorder(c, width, height, "capture.h264");
2576 if (!output->recorder) {
2577 weston_log("failed to create vaapi recorder\n");
2578 return;
2579 }
2580
2581 output->base.disable_planes++;
2582
2583 output->recorder_frame_listener.notify = recorder_frame_notify;
2584 wl_signal_add(&output->base.frame_signal,
2585 &output->recorder_frame_listener);
2586
2587 weston_output_schedule_repaint(&output->base);
2588
2589 weston_log("[libva recorder] initialized\n");
2590 } else {
2591 vaapi_recorder_destroy(output->recorder);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002592 output->recorder = NULL;
2593
2594 output->base.disable_planes--;
2595
2596 wl_list_remove(&output->recorder_frame_listener.link);
2597 weston_log("[libva recorder] done\n");
2598 }
2599}
2600#else
2601static void
2602recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2603 void *data)
2604{
2605 weston_log("Compiled without libva support\n");
2606}
2607#endif
2608
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002609static void
2610switch_to_gl_renderer(struct drm_compositor *c)
2611{
2612 struct drm_output *output;
2613
2614 if (!c->use_pixman)
2615 return;
2616
2617 weston_log("Switching to GL renderer\n");
2618
2619 c->gbm = create_gbm_device(c->drm.fd);
2620 if (!c->gbm) {
2621 weston_log("Failed to create gbm device. "
2622 "Aborting renderer switch\n");
2623 return;
2624 }
2625
2626 wl_list_for_each(output, &c->base.output_list, base.link)
2627 pixman_renderer_output_destroy(&output->base);
2628
2629 c->base.renderer->destroy(&c->base);
2630
2631 if (drm_compositor_create_gl_renderer(c) < 0) {
2632 gbm_device_destroy(c->gbm);
2633 weston_log("Failed to create GL renderer. Quitting.\n");
2634 /* FIXME: we need a function to shutdown cleanly */
2635 assert(0);
2636 }
2637
2638 wl_list_for_each(output, &c->base.output_list, base.link)
2639 drm_output_init_egl(output, c);
2640
2641 c->use_pixman = 0;
2642}
2643
2644static void
2645renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2646 void *data)
2647{
2648 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2649
2650 switch_to_gl_renderer(c);
2651}
2652
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002653static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002654drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002655 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002656 int *argc, char *argv[],
2657 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002658{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002659 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002660 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002661 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002662 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002663 const char *path;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002664 char *s;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002665 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002666
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002667 weston_log("initializing drm backend\n");
2668
Peter Huttererf3d62272013-08-08 11:57:05 +10002669 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002670 if (ec == NULL)
2671 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002672
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002673 /* KMS support for sprites is not complete yet, so disable the
2674 * functionality for now. */
2675 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002676
2677 section = weston_config_get_section(config, "core", NULL, NULL);
2678 weston_config_section_get_string(section,
2679 "gbm-format", &s, "xrgb8888");
2680 if (strcmp(s, "xrgb8888") == 0)
2681 ec->format = GBM_FORMAT_XRGB8888;
2682 else if (strcmp(s, "rgb565") == 0)
2683 ec->format = GBM_FORMAT_RGB565;
2684 else if (strcmp(s, "xrgb2101010") == 0)
2685 ec->format = GBM_FORMAT_XRGB2101010;
2686 else {
2687 weston_log("fatal: unrecognized pixel format: %s\n", s);
2688 free(s);
2689 goto err_base;
2690 }
2691 free(s);
2692
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002693 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002694
Daniel Stone725c2c32012-06-22 14:04:36 +01002695 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002696 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002697 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002698 goto err_base;
2699 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002700
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002701 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002702 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
2703 param->seat_id);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002704 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002705 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002706 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002707 goto err_compositor;
2708 }
2709
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002710 ec->udev = udev_new();
2711 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002712 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002713 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002714 }
2715
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002716 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002717 ec->session_listener.notify = session_notify;
2718 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002719
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002720 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002721 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002722 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002723 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002724 }
David Herrmann0af066f2012-10-29 19:21:16 +01002725 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002726
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002727 if (init_drm(ec, drm_device) < 0) {
2728 weston_log("failed to initialize kms\n");
2729 goto err_udev_dev;
2730 }
2731
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002732 if (ec->use_pixman) {
2733 if (init_pixman(ec) < 0) {
2734 weston_log("failed to initialize pixman renderer\n");
2735 goto err_udev_dev;
2736 }
2737 } else {
2738 if (init_egl(ec) < 0) {
2739 weston_log("failed to initialize egl\n");
2740 goto err_udev_dev;
2741 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002742 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002743
2744 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002745 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002746
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002747 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002748
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002749 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002750 weston_compositor_add_key_binding(&ec->base, key,
2751 MODIFIER_CTRL | MODIFIER_ALT,
2752 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002753
Jesse Barnes58ef3792012-02-23 09:45:49 -05002754 wl_list_init(&ec->sprite_list);
2755 create_sprites(ec);
2756
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002757 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002758 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002759 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002760 }
2761
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002762 path = NULL;
2763
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002764 if (udev_input_init(&ec->input,
2765 &ec->base, ec->udev, param->seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002766 weston_log("failed to create input devices\n");
2767 goto err_sprite;
2768 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002769
2770 loop = wl_display_get_event_loop(ec->base.wl_display);
2771 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002772 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002773 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002774
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002775 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2776 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002777 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002778 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002779 }
2780 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2781 "drm", NULL);
2782 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002783 wl_event_loop_add_fd(loop,
2784 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002785 WL_EVENT_READABLE, udev_drm_event, ec);
2786
2787 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002788 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002789 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002790 }
2791
Daniel Stonea96b93c2012-06-22 14:04:37 +01002792 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002793
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002794 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002795 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002796 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002797 planes_binding, ec);
2798 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2799 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002800 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2801 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002802 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2803 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002804
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002805 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002806
2807err_udev_monitor:
2808 wl_event_source_remove(ec->udev_drm_source);
2809 udev_monitor_unref(ec->udev_monitor);
2810err_drm_source:
2811 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002812 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002813err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002814 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002815 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002816 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002817err_udev_dev:
2818 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002819err_launcher:
2820 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002821err_udev:
2822 udev_unref(ec->udev);
2823err_compositor:
2824 weston_compositor_shutdown(&ec->base);
2825err_base:
2826 free(ec);
2827 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002828}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002829
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002830WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002831backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002832 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002833{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002834 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002835
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002836 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002837 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2838 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2839 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002840 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002841 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002842 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002843
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002844 param.seat_id = default_seat;
2845
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002846 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002847
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002848 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002849}