blob: fbf6e499a1ce91dec47ed5683b9742f2294fa95e [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,
Jason Ekstrand3ec57f52013-11-14 20:52:35 -0600415 fb->bo);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200416 }
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 ||
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100466 output->base.transform != ev->surface->buffer_viewport.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500467 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400468 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500469
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400470 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700471 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500472
Rob Bradford9b101872012-09-14 23:25:41 +0100473 /* Unable to use the buffer for scanout */
474 if (!bo)
475 return NULL;
476
Jason Ekstranda7af7042013-10-12 22:38:11 -0500477 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500478 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300479 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400480 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300481 }
482
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500483 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300484 if (!output->next) {
485 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400486 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300487 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500488
Pekka Paalanende685b82012-12-04 15:58:12 +0200489 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500490
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400491 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500492}
493
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500494static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200495drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400496{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200497 struct drm_compositor *c =
498 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300499 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400500
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200501 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400502
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300503 bo = gbm_surface_lock_front_buffer(output->surface);
504 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200505 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400506 return;
507 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300508
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 Ekstrand918f2dd2013-12-02 21:01:53 -0600780 ev->surface->width,
781 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500782 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
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100821 if (ev->surface->buffer_viewport.transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200822 return NULL;
823
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100824 if (ev->surface->buffer_viewport.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 Ekstrand918f2dd2013-12-02 21:01:53 -0600922 if (sx2 > wl_fixed_from_int(ev->surface->width))
923 sx2 = wl_fixed_from_int(ev->surface->width);
924 if (sy2 > wl_fixed_from_int(ev->surface->height))
925 sy2 = wl_fixed_from_int(ev->surface->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 Ekstrand918f2dd2013-12-02 21:01:53 -0600932 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
933 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100934 ev->surface->buffer_viewport.transform,
935 ev->surface->buffer_viewport.scale,
936 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200937
938 s->src_x = tbox.x1 << 8;
939 s->src_y = tbox.y1 << 8;
940 s->src_w = (tbox.x2 - tbox.x1) << 8;
941 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500942 pixman_region32_fini(&src_rect);
943
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400944 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500945}
946
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400947static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500948drm_output_prepare_cursor_view(struct weston_output *output_base,
949 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500950{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400951 struct drm_compositor *c =
952 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400953 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400954
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200955 if (c->gbm == NULL)
956 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200957 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
958 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500959 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400960 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500961 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400962 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500963 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400964 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500965 if (ev->surface->buffer_ref.buffer == NULL ||
966 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600967 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400968 return NULL;
969
Jason Ekstranda7af7042013-10-12 22:38:11 -0500970 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400971
972 return &output->cursor_plane;
973}
974
975static void
976drm_output_set_cursor(struct drm_output *output)
977{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500978 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +0000979 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400980 struct drm_compositor *c =
981 (struct drm_compositor *) output->base.compositor;
982 EGLint handle, stride;
983 struct gbm_bo *bo;
984 uint32_t buf[64 * 64];
985 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400986 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500987
Jason Ekstranda7af7042013-10-12 22:38:11 -0500988 output->cursor_view = NULL;
989 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400990 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
991 return;
992 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500993
Neil Robertse5051712013-11-13 15:44:06 +0000994 buffer = ev->surface->buffer_ref.buffer;
995
996 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +0200997 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400998 pixman_region32_fini(&output->cursor_plane.damage);
999 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001000 output->current_cursor ^= 1;
1001 bo = output->cursor_bo[output->current_cursor];
1002 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001003 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1004 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1005 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001006 for (i = 0; i < ev->surface->height; i++)
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001007 memcpy(buf + i * 64, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001008 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001009 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001010
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001011 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001012 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001013
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001014 handle = gbm_bo_get_handle(bo).s32;
1015 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -05001016 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001017 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001018 c->cursors_are_broken = 1;
1019 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001020 }
1021
Jason Ekstranda7af7042013-10-12 22:38:11 -05001022 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1023 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001024 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001025 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001026 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001027 c->cursors_are_broken = 1;
1028 }
1029
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001030 output->cursor_plane.x = x;
1031 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001032 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001033}
1034
Jesse Barnes58ef3792012-02-23 09:45:49 -05001035static void
1036drm_assign_planes(struct weston_output *output)
1037{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001038 struct drm_compositor *c =
1039 (struct drm_compositor *) output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001040 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001041 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001042 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001043
1044 /*
1045 * Find a surface for each sprite in the output using some heuristics:
1046 * 1) size
1047 * 2) frequency of update
1048 * 3) opacity (though some hw might support alpha blending)
1049 * 4) clipping (this can be fixed with color keys)
1050 *
1051 * The idea is to save on blitting since this should save power.
1052 * If we can get a large video surface on the sprite for example,
1053 * the main display surface may not need to update at all, and
1054 * the client buffer can be used directly for the sprite surface
1055 * as we do for flipping full screen surfaces.
1056 */
1057 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001058 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001059
Jason Ekstranda7af7042013-10-12 22:38:11 -05001060 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001061 struct weston_surface *es = ev->surface;
1062
1063 /* Test whether this buffer can ever go into a plane:
1064 * non-shm, or small enough to be a cursor.
1065 *
1066 * Also, keep a reference when using the pixman renderer.
1067 * That makes it possible to do a seamless switch to the GL
1068 * renderer and since the pixman renderer keeps a reference
1069 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001070 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001071 if (c->use_pixman ||
1072 (es->buffer_ref.buffer &&
1073 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001074 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001075 es->keep_buffer = 1;
1076 else
1077 es->keep_buffer = 0;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001078
Jesse Barnes58ef3792012-02-23 09:45:49 -05001079 pixman_region32_init(&surface_overlap);
1080 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001081 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001082
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001083 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001084 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001085 next_plane = primary;
1086 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001087 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001088 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001089 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001090 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001091 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001092 if (next_plane == NULL)
1093 next_plane = primary;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001094 weston_view_move_to_plane(ev, next_plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001095 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001096 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001097 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001098
Jesse Barnes58ef3792012-02-23 09:45:49 -05001099 pixman_region32_fini(&surface_overlap);
1100 }
1101 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001102}
1103
Matt Roper361d2ad2011-08-29 13:52:23 -07001104static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001105drm_output_fini_pixman(struct drm_output *output);
1106
1107static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001108drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001109{
1110 struct drm_output *output = (struct drm_output *) output_base;
1111 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001112 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001113 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001114
Xiong Zhangabd5d472013-10-11 14:43:07 +08001115 if (output->page_flip_pending) {
1116 output->destroy_pending = 1;
1117 weston_log("destroy output while page flip pending\n");
1118 return;
1119 }
1120
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001121 if (output->backlight)
1122 backlight_destroy(output->backlight);
1123
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001124 drmModeFreeProperty(output->dpms_prop);
1125
Matt Roper361d2ad2011-08-29 13:52:23 -07001126 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001127 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001128
1129 /* Restore original CRTC state */
1130 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001131 origcrtc->x, origcrtc->y,
1132 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001133 drmModeFreeCrtc(origcrtc);
1134
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001135 c->crtc_allocator &= ~(1 << output->crtc_id);
1136 c->connector_allocator &= ~(1 << output->connector_id);
1137
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001138 if (c->use_pixman) {
1139 drm_output_fini_pixman(output);
1140 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001141 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001142 gbm_surface_destroy(output->surface);
1143 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001144
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001145 weston_plane_release(&output->fb_plane);
1146 weston_plane_release(&output->cursor_plane);
1147
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001148 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001149 wl_list_remove(&output->base.link);
1150
Matt Roper361d2ad2011-08-29 13:52:23 -07001151 free(output);
1152}
1153
Alex Wub7b8bda2012-04-17 17:20:48 +08001154static struct drm_mode *
1155choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1156{
1157 struct drm_mode *tmp_mode = NULL, *mode;
1158
Hardeningff39efa2013-09-18 23:56:35 +02001159 if (output->base.current_mode->width == target_mode->width &&
1160 output->base.current_mode->height == target_mode->height &&
1161 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001162 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001163 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001164
1165 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1166 if (mode->mode_info.hdisplay == target_mode->width &&
1167 mode->mode_info.vdisplay == target_mode->height) {
1168 if (mode->mode_info.vrefresh == target_mode->refresh ||
1169 target_mode->refresh == 0) {
1170 return mode;
1171 } else if (!tmp_mode)
1172 tmp_mode = mode;
1173 }
1174 }
1175
1176 return tmp_mode;
1177}
1178
1179static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001180drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001181static int
1182drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001183
1184static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001185drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1186{
1187 struct drm_output *output;
1188 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001189 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001190
1191 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001192 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001193 return -1;
1194 }
1195
1196 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001197 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001198 return -1;
1199 }
1200
1201 ec = (struct drm_compositor *)output_base->compositor;
1202 output = (struct drm_output *)output_base;
1203 drm_mode = choose_mode (output, mode);
1204
1205 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001206 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001207 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001208 }
1209
Hardeningff39efa2013-09-18 23:56:35 +02001210 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001211 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001212
Hardeningff39efa2013-09-18 23:56:35 +02001213 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001214
Hardeningff39efa2013-09-18 23:56:35 +02001215 output->base.current_mode = &drm_mode->base;
1216 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001217 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1218
Alex Wub7b8bda2012-04-17 17:20:48 +08001219 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001220 drm_output_release_fb(output, output->current);
1221 drm_output_release_fb(output, output->next);
1222 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001223
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001224 if (ec->use_pixman) {
1225 drm_output_fini_pixman(output);
1226 if (drm_output_init_pixman(output, ec) < 0) {
1227 weston_log("failed to init output pixman state with "
1228 "new mode\n");
1229 return -1;
1230 }
1231 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001232 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001233 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001234
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001235 if (drm_output_init_egl(output, ec) < 0) {
1236 weston_log("failed to init output egl state with "
1237 "new mode");
1238 return -1;
1239 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001240 }
1241
Alex Wub7b8bda2012-04-17 17:20:48 +08001242 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001243}
1244
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001245static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001246on_drm_input(int fd, uint32_t mask, void *data)
1247{
1248 drmEventContext evctx;
1249
1250 memset(&evctx, 0, sizeof evctx);
1251 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1252 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001253 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001254 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001255
1256 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001257}
1258
1259static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001260init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001261{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001262 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001263 uint64_t cap;
1264 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001265
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001266 sysnum = udev_device_get_sysnum(device);
1267 if (sysnum)
1268 ec->drm.id = atoi(sysnum);
1269 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001270 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001271 return -1;
1272 }
1273
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001274 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001275 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001276 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001277 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001278 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001279 udev_device_get_devnode(device));
1280 return -1;
1281 }
1282
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001283 weston_log("using %s\n", filename);
1284
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001285 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001286 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001287
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001288 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1289 if (ret == 0 && cap == 1)
1290 ec->clock = CLOCK_MONOTONIC;
1291 else
1292 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001293
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001294 return 0;
1295}
1296
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001297static struct gbm_device *
1298create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001299{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001300 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001301
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001302 gl_renderer = weston_load_module("gl-renderer.so",
1303 "gl_renderer_interface");
1304 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001305 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001306
1307 /* GBM will load a dri driver, but even though they need symbols from
1308 * libglapi, in some version of Mesa they are not linked to it. Since
1309 * only the gl-renderer module links to it, the call above won't make
1310 * these symbols globally available, and loading the DRI driver fails.
1311 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1312 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1313
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001314 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001315
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001316 return gbm;
1317}
1318
1319static int
1320drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1321{
1322 EGLint format;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001323
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001324 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001325 if (gl_renderer->create(&ec->base, ec->gbm,
1326 gl_renderer->opaque_attribs, &format) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001327 return -1;
1328 }
1329
1330 return 0;
1331}
1332
1333static int
1334init_egl(struct drm_compositor *ec)
1335{
1336 ec->gbm = create_gbm_device(ec->drm.fd);
1337
1338 if (!ec->gbm)
1339 return -1;
1340
1341 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001342 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001343 return -1;
1344 }
1345
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001346 return 0;
1347}
1348
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001349static int
1350init_pixman(struct drm_compositor *ec)
1351{
1352 return pixman_renderer_init(&ec->base);
1353}
1354
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001355static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001356drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001357{
1358 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001359 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001360
1361 mode = malloc(sizeof *mode);
1362 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001363 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001364
1365 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001366 mode->base.width = info->hdisplay;
1367 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001368
1369 /* Calculate higher precision (mHz) refresh rate */
1370 refresh = (info->clock * 1000000LL / info->htotal +
1371 info->vtotal / 2) / info->vtotal;
1372
1373 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1374 refresh *= 2;
1375 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1376 refresh /= 2;
1377 if (info->vscan > 1)
1378 refresh /= info->vscan;
1379
1380 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001381 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001382
1383 if (info->type & DRM_MODE_TYPE_PREFERRED)
1384 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1385
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001386 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1387
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001388 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001389}
1390
1391static int
1392drm_subpixel_to_wayland(int drm_value)
1393{
1394 switch (drm_value) {
1395 default:
1396 case DRM_MODE_SUBPIXEL_UNKNOWN:
1397 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1398 case DRM_MODE_SUBPIXEL_NONE:
1399 return WL_OUTPUT_SUBPIXEL_NONE;
1400 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1401 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1402 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1403 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1404 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1405 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1406 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1407 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1408 }
1409}
1410
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001411/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001412static uint32_t
1413drm_get_backlight(struct drm_output *output)
1414{
1415 long brightness, max_brightness, norm;
1416
1417 brightness = backlight_get_brightness(output->backlight);
1418 max_brightness = backlight_get_max_brightness(output->backlight);
1419
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001420 /* convert it on a scale of 0 to 255 */
1421 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001422
1423 return (uint32_t) norm;
1424}
1425
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001426/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001427static void
1428drm_set_backlight(struct weston_output *output_base, uint32_t value)
1429{
1430 struct drm_output *output = (struct drm_output *) output_base;
1431 long max_brightness, new_brightness;
1432
1433 if (!output->backlight)
1434 return;
1435
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001436 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001437 return;
1438
1439 max_brightness = backlight_get_max_brightness(output->backlight);
1440
1441 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001442 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001443
1444 backlight_set_brightness(output->backlight, new_brightness);
1445}
1446
1447static drmModePropertyPtr
1448drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1449{
1450 drmModePropertyPtr props;
1451 int i;
1452
1453 for (i = 0; i < connector->count_props; i++) {
1454 props = drmModeGetProperty(fd, connector->props[i]);
1455 if (!props)
1456 continue;
1457
1458 if (!strcmp(props->name, name))
1459 return props;
1460
1461 drmModeFreeProperty(props);
1462 }
1463
1464 return NULL;
1465}
1466
1467static void
1468drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1469{
1470 struct drm_output *output = (struct drm_output *) output_base;
1471 struct weston_compositor *ec = output_base->compositor;
1472 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001473
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001474 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001475 return;
1476
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001477 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1478 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001479}
1480
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001481static const char *connector_type_names[] = {
1482 "None",
1483 "VGA",
1484 "DVI",
1485 "DVI",
1486 "DVI",
1487 "Composite",
1488 "TV",
1489 "LVDS",
1490 "CTV",
1491 "DIN",
1492 "DP",
1493 "HDMI",
1494 "HDMI",
1495 "TV",
1496 "eDP",
1497};
1498
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001499static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001500find_crtc_for_connector(struct drm_compositor *ec,
1501 drmModeRes *resources, drmModeConnector *connector)
1502{
1503 drmModeEncoder *encoder;
1504 uint32_t possible_crtcs;
1505 int i, j;
1506
1507 for (j = 0; j < connector->count_encoders; j++) {
1508 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1509 if (encoder == NULL) {
1510 weston_log("Failed to get encoder.\n");
1511 return -1;
1512 }
1513 possible_crtcs = encoder->possible_crtcs;
1514 drmModeFreeEncoder(encoder);
1515
1516 for (i = 0; i < resources->count_crtcs; i++) {
1517 if (possible_crtcs & (1 << i) &&
1518 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1519 return i;
1520 }
1521 }
1522
1523 return -1;
1524}
1525
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001526/* Init output state that depends on gl or gbm */
1527static int
1528drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1529{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001530 int i, flags;
1531
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001532 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001533 output->base.current_mode->width,
1534 output->base.current_mode->height,
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07001535 ec->format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001536 GBM_BO_USE_SCANOUT |
1537 GBM_BO_USE_RENDERING);
1538 if (!output->surface) {
1539 weston_log("failed to create gbm surface\n");
1540 return -1;
1541 }
1542
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001543 if (gl_renderer->output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001544 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001545 gbm_surface_destroy(output->surface);
1546 return -1;
1547 }
1548
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001549 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1550
1551 for (i = 0; i < 2; i++) {
1552 if (output->cursor_bo[i])
1553 continue;
1554
1555 output->cursor_bo[i] =
1556 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1557 flags);
1558 }
1559
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001560 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1561 weston_log("cursor buffers unavailable, using gl cursors\n");
1562 ec->cursors_are_broken = 1;
1563 }
1564
1565 return 0;
1566}
1567
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001568static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001569drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1570{
Hardeningff39efa2013-09-18 23:56:35 +02001571 int w = output->base.current_mode->width;
1572 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001573 unsigned int i;
1574
1575 /* FIXME error checking */
1576
1577 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001578 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001579 if (!output->dumb[i])
1580 goto err;
1581
1582 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001583 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001584 output->dumb[i]->map,
1585 output->dumb[i]->stride);
1586 if (!output->image[i])
1587 goto err;
1588 }
1589
1590 if (pixman_renderer_output_create(&output->base) < 0)
1591 goto err;
1592
1593 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001594 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001595
1596 return 0;
1597
1598err:
1599 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1600 if (output->dumb[i])
1601 drm_fb_destroy_dumb(output->dumb[i]);
1602 if (output->image[i])
1603 pixman_image_unref(output->image[i]);
1604
1605 output->dumb[i] = NULL;
1606 output->image[i] = NULL;
1607 }
1608
1609 return -1;
1610}
1611
1612static void
1613drm_output_fini_pixman(struct drm_output *output)
1614{
1615 unsigned int i;
1616
1617 pixman_renderer_output_destroy(&output->base);
1618 pixman_region32_fini(&output->previous_damage);
1619
1620 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1621 drm_fb_destroy_dumb(output->dumb[i]);
1622 pixman_image_unref(output->image[i]);
1623 output->dumb[i] = NULL;
1624 output->image[i] = NULL;
1625 }
1626}
1627
Richard Hughes2b2092a2013-04-24 14:58:02 +01001628static void
1629edid_parse_string(const uint8_t *data, char text[])
1630{
1631 int i;
1632 int replaced = 0;
1633
1634 /* this is always 12 bytes, but we can't guarantee it's null
1635 * terminated or not junk. */
1636 strncpy(text, (const char *) data, 12);
1637
1638 /* remove insane chars */
1639 for (i = 0; text[i] != '\0'; i++) {
1640 if (text[i] == '\n' ||
1641 text[i] == '\r') {
1642 text[i] = '\0';
1643 break;
1644 }
1645 }
1646
1647 /* ensure string is printable */
1648 for (i = 0; text[i] != '\0'; i++) {
1649 if (!isprint(text[i])) {
1650 text[i] = '-';
1651 replaced++;
1652 }
1653 }
1654
1655 /* if the string is random junk, ignore the string */
1656 if (replaced > 4)
1657 text[0] = '\0';
1658}
1659
1660#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1661#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1662#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1663#define EDID_OFFSET_DATA_BLOCKS 0x36
1664#define EDID_OFFSET_LAST_BLOCK 0x6c
1665#define EDID_OFFSET_PNPID 0x08
1666#define EDID_OFFSET_SERIAL 0x0c
1667
1668static int
1669edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1670{
1671 int i;
1672 uint32_t serial_number;
1673
1674 /* check header */
1675 if (length < 128)
1676 return -1;
1677 if (data[0] != 0x00 || data[1] != 0xff)
1678 return -1;
1679
1680 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1681 * /--08--\/--09--\
1682 * 7654321076543210
1683 * |\---/\---/\---/
1684 * R C1 C2 C3 */
1685 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1686 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1687 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1688 edid->pnp_id[3] = '\0';
1689
1690 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1691 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1692 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1693 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1694 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1695 if (serial_number > 0)
1696 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1697
1698 /* parse EDID data */
1699 for (i = EDID_OFFSET_DATA_BLOCKS;
1700 i <= EDID_OFFSET_LAST_BLOCK;
1701 i += 18) {
1702 /* ignore pixel clock data */
1703 if (data[i] != 0)
1704 continue;
1705 if (data[i+2] != 0)
1706 continue;
1707
1708 /* any useful blocks? */
1709 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1710 edid_parse_string(&data[i+5],
1711 edid->monitor_name);
1712 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1713 edid_parse_string(&data[i+5],
1714 edid->serial_number);
1715 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1716 edid_parse_string(&data[i+5],
1717 edid->eisa_id);
1718 }
1719 }
1720 return 0;
1721}
1722
1723static void
1724find_and_parse_output_edid(struct drm_compositor *ec,
1725 struct drm_output *output,
1726 drmModeConnector *connector)
1727{
1728 drmModePropertyBlobPtr edid_blob = NULL;
1729 drmModePropertyPtr property;
1730 int i;
1731 int rc;
1732
1733 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1734 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1735 if (!property)
1736 continue;
1737 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1738 !strcmp(property->name, "EDID")) {
1739 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1740 connector->prop_values[i]);
1741 }
1742 drmModeFreeProperty(property);
1743 }
1744 if (!edid_blob)
1745 return;
1746
1747 rc = edid_parse(&output->edid,
1748 edid_blob->data,
1749 edid_blob->length);
1750 if (!rc) {
1751 weston_log("EDID data '%s', '%s', '%s'\n",
1752 output->edid.pnp_id,
1753 output->edid.monitor_name,
1754 output->edid.serial_number);
1755 if (output->edid.pnp_id[0] != '\0')
1756 output->base.make = output->edid.pnp_id;
1757 if (output->edid.monitor_name[0] != '\0')
1758 output->base.model = output->edid.monitor_name;
1759 if (output->edid.serial_number[0] != '\0')
1760 output->base.serial_number = output->edid.serial_number;
1761 }
1762 drmModeFreePropertyBlob(edid_blob);
1763}
1764
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001765
1766
1767static int
1768parse_modeline(const char *s, drmModeModeInfo *mode)
1769{
1770 char hsync[16];
1771 char vsync[16];
1772 float fclock;
1773
1774 mode->type = DRM_MODE_TYPE_USERDEF;
1775 mode->hskew = 0;
1776 mode->vscan = 0;
1777 mode->vrefresh = 0;
1778 mode->flags = 0;
1779
Rob Bradford307e09e2013-07-26 16:29:40 +01001780 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001781 &fclock,
1782 &mode->hdisplay,
1783 &mode->hsync_start,
1784 &mode->hsync_end,
1785 &mode->htotal,
1786 &mode->vdisplay,
1787 &mode->vsync_start,
1788 &mode->vsync_end,
1789 &mode->vtotal, hsync, vsync) != 11)
1790 return -1;
1791
1792 mode->clock = fclock * 1000;
1793 if (strcmp(hsync, "+hsync") == 0)
1794 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1795 else if (strcmp(hsync, "-hsync") == 0)
1796 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1797 else
1798 return -1;
1799
1800 if (strcmp(vsync, "+vsync") == 0)
1801 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1802 else if (strcmp(vsync, "-vsync") == 0)
1803 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1804 else
1805 return -1;
1806
1807 return 0;
1808}
1809
1810static uint32_t
1811parse_transform(const char *transform, const char *output_name)
1812{
1813 static const struct { const char *name; uint32_t token; } names[] = {
1814 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1815 { "90", WL_OUTPUT_TRANSFORM_90 },
1816 { "180", WL_OUTPUT_TRANSFORM_180 },
1817 { "270", WL_OUTPUT_TRANSFORM_270 },
1818 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1819 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1820 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1821 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1822 };
1823 unsigned int i;
1824
1825 for (i = 0; i < ARRAY_LENGTH(names); i++)
1826 if (strcmp(names[i].name, transform) == 0)
1827 return names[i].token;
1828
1829 weston_log("Invalid transform \"%s\" for output %s\n",
1830 transform, output_name);
1831
1832 return WL_OUTPUT_TRANSFORM_NORMAL;
1833}
1834
Rob Bradford66bd9f52013-06-25 18:56:42 +01001835static void
1836setup_output_seat_constraint(struct drm_compositor *ec,
1837 struct weston_output *output,
1838 const char *s)
1839{
1840 if (strcmp(s, "") != 0) {
1841 struct udev_seat *seat;
1842
1843 seat = udev_seat_get_named(&ec->base, s);
1844 if (seat)
1845 seat->base.output = output;
1846
1847 if (seat && seat->base.pointer)
1848 weston_pointer_clamp(seat->base.pointer,
1849 &seat->base.pointer->x,
1850 &seat->base.pointer->y);
1851 }
1852}
1853
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001854static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001855create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001856 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001857 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001858 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001859{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001860 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001861 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1862 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001863 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001864 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001865 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001866 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001867 int i, width, height, scale;
1868 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001869 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001870 enum output_config config;
1871 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001872
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001873 i = find_crtc_for_connector(ec, resources, connector);
1874 if (i < 0) {
1875 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001876 return -1;
1877 }
1878
Peter Huttererf3d62272013-08-08 11:57:05 +10001879 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001880 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001881 return -1;
1882
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001883 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1884 output->base.make = "unknown";
1885 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001886 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001887 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001888
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001889 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1890 type_name = connector_type_names[connector->connector_type];
1891 else
1892 type_name = "UNKNOWN";
1893 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001894 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001895
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001896 section = weston_config_get_section(ec->base.config, "output", "name",
1897 output->base.name);
1898 weston_config_section_get_string(section, "mode", &s, "preferred");
1899 if (strcmp(s, "off") == 0)
1900 config = OUTPUT_CONFIG_OFF;
1901 else if (strcmp(s, "preferred") == 0)
1902 config = OUTPUT_CONFIG_PREFERRED;
1903 else if (strcmp(s, "current") == 0)
1904 config = OUTPUT_CONFIG_CURRENT;
1905 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1906 config = OUTPUT_CONFIG_MODE;
1907 else if (parse_modeline(s, &modeline) == 0)
1908 config = OUTPUT_CONFIG_MODELINE;
1909 else {
1910 weston_log("Invalid mode \"%s\" for output %s\n",
1911 s, output->base.name);
1912 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001913 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001914 free(s);
1915
1916 weston_config_section_get_int(section, "scale", &scale, 1);
1917 weston_config_section_get_string(section, "transform", &s, "normal");
1918 transform = parse_transform(s, output->base.name);
1919 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001920
Rob Bradford66bd9f52013-06-25 18:56:42 +01001921 weston_config_section_get_string(section, "seat", &s, "");
1922 setup_output_seat_constraint(ec, &output->base, s);
1923 free(s);
1924
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001925 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001926 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001927 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001928 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001929 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001930
Matt Roper361d2ad2011-08-29 13:52:23 -07001931 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001932 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001933
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001934 /* Get the current mode on the crtc that's currently driving
1935 * this connector. */
1936 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001937 memset(&crtc_mode, 0, sizeof crtc_mode);
1938 if (encoder != NULL) {
1939 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1940 drmModeFreeEncoder(encoder);
1941 if (crtc == NULL)
1942 goto err_free;
1943 if (crtc->mode_valid)
1944 crtc_mode = crtc->mode;
1945 drmModeFreeCrtc(crtc);
1946 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001947
David Herrmann0f0d54e2011-12-08 17:05:45 +01001948 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001949 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001950 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001951 goto err_free;
1952 }
1953
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001954 if (config == OUTPUT_CONFIG_OFF) {
1955 weston_log("Disabling output %s\n", output->base.name);
1956 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1957 0, 0, 0, 0, 0, NULL);
1958 goto err_free;
1959 }
1960
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001961 preferred = NULL;
1962 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001963 configured = NULL;
1964
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001965 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001966 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001967 width == drm_mode->base.width &&
1968 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001969 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001970 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001971 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001972 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001973 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001974 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001975
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001976 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001977 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001978 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001979 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001980 }
1981
Wang Quanxianacb805a2012-07-30 18:09:46 -04001982 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001983 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001984 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001985 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001986 }
1987
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001988 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001989 configured = current;
1990
Wang Quanxianacb805a2012-07-30 18:09:46 -04001991 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02001992 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001993 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02001994 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001995 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02001996 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001997 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02001998 output->base.current_mode = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001999
Hardeningff39efa2013-09-18 23:56:35 +02002000 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002001 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002002 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002003 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002004
Hardeningff39efa2013-09-18 23:56:35 +02002005 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002006
John Kåre Alsaker94659272012-11-13 19:10:18 +01002007 weston_output_init(&output->base, &ec->base, x, y,
2008 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002009 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002010
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002011 if (ec->use_pixman) {
2012 if (drm_output_init_pixman(output, ec) < 0) {
2013 weston_log("Failed to init output pixman state\n");
2014 goto err_output;
2015 }
2016 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002017 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002018 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002019 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002020
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002021 output->backlight = backlight_init(drm_device,
2022 connector->connector_type);
2023 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002024 weston_log("Initialized backlight, device %s\n",
2025 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002026 output->base.set_backlight = drm_set_backlight;
2027 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002028 } else {
2029 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002030 }
2031
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002032 wl_list_insert(ec->base.output_list.prev, &output->base.link);
2033
Richard Hughes2b2092a2013-04-24 14:58:02 +01002034 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002035 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2036 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002037
Jonas Ådahle5a12252013-04-05 23:07:11 +02002038 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002039 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002040 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002041 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002042 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002043 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002044
Richard Hughese7299962013-05-01 21:52:12 +01002045 output->base.gamma_size = output->original_crtc->gamma_size;
2046 output->base.set_gamma = drm_output_set_gamma;
2047
Xiong Zhang97116532013-10-23 13:58:31 +08002048 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2049 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002050
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002051 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2052 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2053 &ec->base.primary_plane);
2054
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002055 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002056 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002057 wl_list_for_each(m, &output->base.mode_list, link)
2058 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
2059 m->width, m->height, m->refresh / 1000.0,
2060 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2061 ", preferred" : "",
2062 m->flags & WL_OUTPUT_MODE_CURRENT ?
2063 ", current" : "",
2064 connector->count_modes == 0 ?
2065 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002066
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002067 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002068
John Kåre Alsaker94659272012-11-13 19:10:18 +01002069err_output:
2070 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002071err_free:
2072 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2073 base.link) {
2074 wl_list_remove(&drm_mode->base.link);
2075 free(drm_mode);
2076 }
2077
2078 drmModeFreeCrtc(output->original_crtc);
2079 ec->crtc_allocator &= ~(1 << output->crtc_id);
2080 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002081 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002082
David Herrmann0f0d54e2011-12-08 17:05:45 +01002083 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002084}
2085
Jesse Barnes58ef3792012-02-23 09:45:49 -05002086static void
2087create_sprites(struct drm_compositor *ec)
2088{
2089 struct drm_sprite *sprite;
2090 drmModePlaneRes *plane_res;
2091 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002092 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002093
2094 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2095 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002096 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002097 strerror(errno));
2098 return;
2099 }
2100
2101 for (i = 0; i < plane_res->count_planes; i++) {
2102 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2103 if (!plane)
2104 continue;
2105
Peter Huttererf3d62272013-08-08 11:57:05 +10002106 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002107 plane->count_formats));
2108 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002109 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002110 __func__);
2111 free(plane);
2112 continue;
2113 }
2114
Jesse Barnes58ef3792012-02-23 09:45:49 -05002115 sprite->possible_crtcs = plane->possible_crtcs;
2116 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002117 sprite->current = NULL;
2118 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002119 sprite->compositor = ec;
2120 sprite->count_formats = plane->count_formats;
2121 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002122 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002123 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002124 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002125 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2126 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002127
2128 wl_list_insert(&ec->sprite_list, &sprite->link);
2129 }
2130
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002131 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002132}
2133
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002134static void
2135destroy_sprites(struct drm_compositor *compositor)
2136{
2137 struct drm_sprite *sprite, *next;
2138 struct drm_output *output;
2139
2140 output = container_of(compositor->base.output_list.next,
2141 struct drm_output, base.link);
2142
2143 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2144 drmModeSetPlane(compositor->drm.fd,
2145 sprite->plane_id,
2146 output->crtc_id, 0, 0,
2147 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002148 drm_output_release_fb(output, sprite->current);
2149 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002150 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002151 free(sprite);
2152 }
2153}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002154
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002155static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002156create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002157 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002158{
2159 drmModeConnector *connector;
2160 drmModeRes *resources;
2161 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002162 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002163
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002164 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002165 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002166 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002167 return -1;
2168 }
2169
Jesse Barnes58ef3792012-02-23 09:45:49 -05002170 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002171 if (!ec->crtcs) {
2172 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002173 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002174 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002175
Rob Clark4339add2012-08-09 14:18:28 -05002176 ec->min_width = resources->min_width;
2177 ec->max_width = resources->max_width;
2178 ec->min_height = resources->min_height;
2179 ec->max_height = resources->max_height;
2180
Jesse Barnes58ef3792012-02-23 09:45:49 -05002181 ec->num_crtcs = resources->count_crtcs;
2182 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2183
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002184 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002185 connector = drmModeGetConnector(ec->drm.fd,
2186 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002187 if (connector == NULL)
2188 continue;
2189
2190 if (connector->connection == DRM_MODE_CONNECTED &&
2191 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002192 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002193 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002194 connector, x, y,
2195 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002196 drmModeFreeConnector(connector);
2197 continue;
2198 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002199
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002200 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002201 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002202 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002203 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002204
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002205 drmModeFreeConnector(connector);
2206 }
2207
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002208 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002209 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002210 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002211 return -1;
2212 }
2213
2214 drmModeFreeResources(resources);
2215
2216 return 0;
2217}
2218
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002219static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002220update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002221{
2222 drmModeConnector *connector;
2223 drmModeRes *resources;
2224 struct drm_output *output, *next;
2225 int x = 0, y = 0;
2226 int x_offset = 0, y_offset = 0;
2227 uint32_t connected = 0, disconnects = 0;
2228 int i;
2229
2230 resources = drmModeGetResources(ec->drm.fd);
2231 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002232 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002233 return;
2234 }
2235
2236 /* collect new connects */
2237 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002238 int connector_id = resources->connectors[i];
2239
2240 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002241 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002242 continue;
2243
David Herrmann7551cff2011-12-08 17:05:43 +01002244 if (connector->connection != DRM_MODE_CONNECTED) {
2245 drmModeFreeConnector(connector);
2246 continue;
2247 }
2248
Benjamin Franzke117483d2011-08-30 11:38:26 +02002249 connected |= (1 << connector_id);
2250
2251 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002252 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002253 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002254 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002255
2256 /* XXX: not yet needed, we die with 0 outputs */
2257 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002258 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002259 else
2260 x = 0;
2261 y = 0;
2262 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002263 connector, x, y,
2264 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002265 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002266
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002267 }
2268 drmModeFreeConnector(connector);
2269 }
2270 drmModeFreeResources(resources);
2271
2272 disconnects = ec->connector_allocator & ~connected;
2273 if (disconnects) {
2274 wl_list_for_each_safe(output, next, &ec->base.output_list,
2275 base.link) {
2276 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002277 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002278 output->base.x - x_offset,
2279 output->base.y - y_offset);
2280 }
2281
2282 if (disconnects & (1 << output->connector_id)) {
2283 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002284 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002285 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002286 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002287 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002288 }
2289 }
2290 }
2291
2292 /* FIXME: handle zero outputs, without terminating */
2293 if (ec->connector_allocator == 0)
2294 wl_display_terminate(ec->base.wl_display);
2295}
2296
2297static int
David Herrmannd7488c22012-03-11 20:05:21 +01002298udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002299{
David Herrmannd7488c22012-03-11 20:05:21 +01002300 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002301 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002302
2303 sysnum = udev_device_get_sysnum(device);
2304 if (!sysnum || atoi(sysnum) != ec->drm.id)
2305 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002306
David Herrmann6ac52db2012-03-11 20:05:22 +01002307 val = udev_device_get_property_value(device, "HOTPLUG");
2308 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002309 return 0;
2310
David Herrmann6ac52db2012-03-11 20:05:22 +01002311 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002312}
2313
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002314static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002315udev_drm_event(int fd, uint32_t mask, void *data)
2316{
2317 struct drm_compositor *ec = data;
2318 struct udev_device *event;
2319
2320 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002321
David Herrmannd7488c22012-03-11 20:05:21 +01002322 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002323 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002324
2325 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002326
2327 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002328}
2329
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002330static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002331drm_restore(struct weston_compositor *ec)
2332{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002333 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002334}
2335
2336static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002337drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002338{
2339 struct drm_compositor *d = (struct drm_compositor *) ec;
2340
Rob Bradfordd355b802013-05-31 18:09:55 +01002341 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002342
2343 wl_event_source_remove(d->udev_drm_source);
2344 wl_event_source_remove(d->drm_source);
2345
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002346 destroy_sprites(d);
2347
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002348 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002349
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002350 weston_compositor_shutdown(ec);
2351
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002352 if (d->gbm)
2353 gbm_device_destroy(d->gbm);
2354
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002355 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002356
Rob Bradford45c15b82013-07-26 16:29:35 +01002357 close(d->drm.fd);
2358
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002359 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002360}
2361
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002362static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002363drm_compositor_set_modes(struct drm_compositor *compositor)
2364{
2365 struct drm_output *output;
2366 struct drm_mode *drm_mode;
2367 int ret;
2368
2369 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002370 if (!output->current) {
2371 /* If something that would cause the output to
2372 * switch mode happened while in another vt, we
2373 * might not have a current drm_fb. In that case,
2374 * schedule a repaint and let drm_output_repaint
2375 * handle setting the mode. */
2376 weston_output_schedule_repaint(&output->base);
2377 continue;
2378 }
2379
Hardeningff39efa2013-09-18 23:56:35 +02002380 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002381 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002382 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002383 &output->connector_id, 1,
2384 &drm_mode->mode_info);
2385 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002386 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002387 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002388 drm_mode->base.width, drm_mode->base.height,
2389 output->base.x, output->base.y);
2390 }
2391 }
2392}
2393
2394static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002395session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002396{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002397 struct weston_compositor *compositor = data;
2398 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002399 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002400 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002401
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002402 if (ec->base.session_active) {
2403 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002404 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002405 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002406 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002407 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002408 } else {
2409 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002410 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002411
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002412 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002413 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002414
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002415 /* If we have a repaint scheduled (either from a
2416 * pending pageflip or the idle handler), make sure we
2417 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002418 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002419 * further attemps at repainting. When we switch
2420 * back, we schedule a repaint, which will process
2421 * pending frame callbacks. */
2422
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002423 wl_list_for_each(output, &ec->base.output_list, base.link) {
2424 output->base.repaint_needed = 0;
2425 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002426 }
2427
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002428 output = container_of(ec->base.output_list.next,
2429 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002430
2431 wl_list_for_each(sprite, &ec->sprite_list, link)
2432 drmModeSetPlane(ec->drm.fd,
2433 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002434 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002435 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002436 };
2437}
2438
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002439static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002440switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002441{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002442 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002443
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002444 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002445}
2446
David Herrmann0af066f2012-10-29 19:21:16 +01002447/*
2448 * Find primary GPU
2449 * Some systems may have multiple DRM devices attached to a single seat. This
2450 * function loops over all devices and tries to find a PCI device with the
2451 * boot_vga sysfs attribute set to 1.
2452 * If no such device is found, the first DRM device reported by udev is used.
2453 */
2454static struct udev_device*
2455find_primary_gpu(struct drm_compositor *ec, const char *seat)
2456{
2457 struct udev_enumerate *e;
2458 struct udev_list_entry *entry;
2459 const char *path, *device_seat, *id;
2460 struct udev_device *device, *drm_device, *pci;
2461
2462 e = udev_enumerate_new(ec->udev);
2463 udev_enumerate_add_match_subsystem(e, "drm");
2464 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2465
2466 udev_enumerate_scan_devices(e);
2467 drm_device = NULL;
2468 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2469 path = udev_list_entry_get_name(entry);
2470 device = udev_device_new_from_syspath(ec->udev, path);
2471 if (!device)
2472 continue;
2473 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2474 if (!device_seat)
2475 device_seat = default_seat;
2476 if (strcmp(device_seat, seat)) {
2477 udev_device_unref(device);
2478 continue;
2479 }
2480
2481 pci = udev_device_get_parent_with_subsystem_devtype(device,
2482 "pci", NULL);
2483 if (pci) {
2484 id = udev_device_get_sysattr_value(pci, "boot_vga");
2485 if (id && !strcmp(id, "1")) {
2486 if (drm_device)
2487 udev_device_unref(drm_device);
2488 drm_device = device;
2489 break;
2490 }
2491 }
2492
2493 if (!drm_device)
2494 drm_device = device;
2495 else
2496 udev_device_unref(device);
2497 }
2498
2499 udev_enumerate_unref(e);
2500 return drm_device;
2501}
2502
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002503static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002504planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002505{
2506 struct drm_compositor *c = data;
2507
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002508 switch (key) {
2509 case KEY_C:
2510 c->cursors_are_broken ^= 1;
2511 break;
2512 case KEY_V:
2513 c->sprites_are_broken ^= 1;
2514 break;
2515 case KEY_O:
2516 c->sprites_hidden ^= 1;
2517 break;
2518 default:
2519 break;
2520 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002521}
2522
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002523#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002524static void
2525recorder_frame_notify(struct wl_listener *listener, void *data)
2526{
2527 struct drm_output *output;
2528 struct drm_compositor *c;
2529 int fd, ret;
2530
2531 output = container_of(listener, struct drm_output,
2532 recorder_frame_listener);
2533 c = (struct drm_compositor *) output->base.compositor;
2534
2535 if (!output->recorder)
2536 return;
2537
2538 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2539 DRM_CLOEXEC, &fd);
2540 if (ret) {
2541 weston_log("[libva recorder] "
2542 "failed to create prime fd for front buffer\n");
2543 return;
2544 }
2545
2546 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002547}
2548
2549static void *
2550create_recorder(struct drm_compositor *c, int width, int height,
2551 const char *filename)
2552{
2553 int fd;
2554 drm_magic_t magic;
2555
2556 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2557 if (fd < 0)
2558 return NULL;
2559
2560 drmGetMagic(fd, &magic);
2561 drmAuthMagic(c->drm.fd, magic);
2562
2563 return vaapi_recorder_create(fd, width, height, filename);
2564}
2565
2566static void
2567recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2568 void *data)
2569{
2570 struct drm_compositor *c = data;
2571 struct drm_output *output;
2572 int width, height;
2573
2574 output = container_of(c->base.output_list.next,
2575 struct drm_output, base.link);
2576
2577 if (!output->recorder) {
Hardeningff39efa2013-09-18 23:56:35 +02002578 width = output->base.current_mode->width;
2579 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002580
2581 output->recorder =
2582 create_recorder(c, width, height, "capture.h264");
2583 if (!output->recorder) {
2584 weston_log("failed to create vaapi recorder\n");
2585 return;
2586 }
2587
2588 output->base.disable_planes++;
2589
2590 output->recorder_frame_listener.notify = recorder_frame_notify;
2591 wl_signal_add(&output->base.frame_signal,
2592 &output->recorder_frame_listener);
2593
2594 weston_output_schedule_repaint(&output->base);
2595
2596 weston_log("[libva recorder] initialized\n");
2597 } else {
2598 vaapi_recorder_destroy(output->recorder);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002599 output->recorder = NULL;
2600
2601 output->base.disable_planes--;
2602
2603 wl_list_remove(&output->recorder_frame_listener.link);
2604 weston_log("[libva recorder] done\n");
2605 }
2606}
2607#else
2608static void
2609recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2610 void *data)
2611{
2612 weston_log("Compiled without libva support\n");
2613}
2614#endif
2615
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002616static void
2617switch_to_gl_renderer(struct drm_compositor *c)
2618{
2619 struct drm_output *output;
2620
2621 if (!c->use_pixman)
2622 return;
2623
2624 weston_log("Switching to GL renderer\n");
2625
2626 c->gbm = create_gbm_device(c->drm.fd);
2627 if (!c->gbm) {
2628 weston_log("Failed to create gbm device. "
2629 "Aborting renderer switch\n");
2630 return;
2631 }
2632
2633 wl_list_for_each(output, &c->base.output_list, base.link)
2634 pixman_renderer_output_destroy(&output->base);
2635
2636 c->base.renderer->destroy(&c->base);
2637
2638 if (drm_compositor_create_gl_renderer(c) < 0) {
2639 gbm_device_destroy(c->gbm);
2640 weston_log("Failed to create GL renderer. Quitting.\n");
2641 /* FIXME: we need a function to shutdown cleanly */
2642 assert(0);
2643 }
2644
2645 wl_list_for_each(output, &c->base.output_list, base.link)
2646 drm_output_init_egl(output, c);
2647
2648 c->use_pixman = 0;
2649}
2650
2651static void
2652renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2653 void *data)
2654{
2655 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2656
2657 switch_to_gl_renderer(c);
2658}
2659
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002660static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002661drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002662 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002663 int *argc, char *argv[],
2664 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002665{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002666 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002667 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002668 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002669 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002670 const char *path;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002671 char *s;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002672 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002673
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002674 weston_log("initializing drm backend\n");
2675
Peter Huttererf3d62272013-08-08 11:57:05 +10002676 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002677 if (ec == NULL)
2678 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002679
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002680 /* KMS support for sprites is not complete yet, so disable the
2681 * functionality for now. */
2682 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002683
2684 section = weston_config_get_section(config, "core", NULL, NULL);
2685 weston_config_section_get_string(section,
2686 "gbm-format", &s, "xrgb8888");
2687 if (strcmp(s, "xrgb8888") == 0)
2688 ec->format = GBM_FORMAT_XRGB8888;
2689 else if (strcmp(s, "rgb565") == 0)
2690 ec->format = GBM_FORMAT_RGB565;
2691 else if (strcmp(s, "xrgb2101010") == 0)
2692 ec->format = GBM_FORMAT_XRGB2101010;
2693 else {
2694 weston_log("fatal: unrecognized pixel format: %s\n", s);
2695 free(s);
2696 goto err_base;
2697 }
2698 free(s);
2699
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002700 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002701
Daniel Stone725c2c32012-06-22 14:04:36 +01002702 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002703 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002704 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002705 goto err_base;
2706 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002707
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002708 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002709 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
2710 param->seat_id);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002711 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002712 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002713 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002714 goto err_compositor;
2715 }
2716
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002717 ec->udev = udev_new();
2718 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002719 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002720 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002721 }
2722
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002723 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002724 ec->session_listener.notify = session_notify;
2725 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002726
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002727 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002728 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002729 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002730 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002731 }
David Herrmann0af066f2012-10-29 19:21:16 +01002732 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002733
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002734 if (init_drm(ec, drm_device) < 0) {
2735 weston_log("failed to initialize kms\n");
2736 goto err_udev_dev;
2737 }
2738
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002739 if (ec->use_pixman) {
2740 if (init_pixman(ec) < 0) {
2741 weston_log("failed to initialize pixman renderer\n");
2742 goto err_udev_dev;
2743 }
2744 } else {
2745 if (init_egl(ec) < 0) {
2746 weston_log("failed to initialize egl\n");
2747 goto err_udev_dev;
2748 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002749 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002750
2751 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002752 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002753
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002754 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002755
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002756 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002757 weston_compositor_add_key_binding(&ec->base, key,
2758 MODIFIER_CTRL | MODIFIER_ALT,
2759 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002760
Jesse Barnes58ef3792012-02-23 09:45:49 -05002761 wl_list_init(&ec->sprite_list);
2762 create_sprites(ec);
2763
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002764 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002765 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002766 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002767 }
2768
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002769 path = NULL;
2770
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002771 if (udev_input_init(&ec->input,
2772 &ec->base, ec->udev, param->seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002773 weston_log("failed to create input devices\n");
2774 goto err_sprite;
2775 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002776
2777 loop = wl_display_get_event_loop(ec->base.wl_display);
2778 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002779 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002780 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002781
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002782 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2783 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002784 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002785 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002786 }
2787 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2788 "drm", NULL);
2789 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002790 wl_event_loop_add_fd(loop,
2791 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002792 WL_EVENT_READABLE, udev_drm_event, ec);
2793
2794 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002795 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002796 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002797 }
2798
Daniel Stonea96b93c2012-06-22 14:04:37 +01002799 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002800
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002801 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002802 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002803 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002804 planes_binding, ec);
2805 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2806 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002807 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2808 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002809 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2810 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002811
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002812 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002813
2814err_udev_monitor:
2815 wl_event_source_remove(ec->udev_drm_source);
2816 udev_monitor_unref(ec->udev_monitor);
2817err_drm_source:
2818 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002819 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002820err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002821 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002822 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002823 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002824err_udev_dev:
2825 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002826err_launcher:
2827 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002828err_udev:
2829 udev_unref(ec->udev);
2830err_compositor:
2831 weston_compositor_shutdown(&ec->base);
2832err_base:
2833 free(ec);
2834 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002835}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002836
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002837WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002838backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002839 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002840{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002841 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002842
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002843 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002844 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2845 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2846 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002847 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002848 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002849 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002850
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002851 param.seat_id = default_seat;
2852
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002853 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002854
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002855 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002856}