blob: 23d6f0fcc7c6ea934e472d25459c80f70aadef37 [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>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030033#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020034#include <sys/mman.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030035#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040036
Benjamin Franzkec649a922011-03-02 11:56:04 +010037#include <xf86drm.h>
38#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050039#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010040
Benjamin Franzke060cf802011-04-30 09:32:11 +020041#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020042#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040043#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020044
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040045#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010046#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020047#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050048#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010049#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030050#include "vaapi-recorder.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040051
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030052#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
53#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
54#endif
55
Kristian Høgsberg061c4252012-06-28 11:28:15 -040056static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060057
58enum output_config {
59 OUTPUT_CONFIG_INVALID = 0,
60 OUTPUT_CONFIG_OFF,
61 OUTPUT_CONFIG_PREFERRED,
62 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060063 OUTPUT_CONFIG_MODE,
64 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060065};
66
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040067struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050068 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040069
70 struct udev *udev;
71 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040072
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010073 struct udev_monitor *udev_monitor;
74 struct wl_event_source *udev_drm_source;
75
Benjamin Franzke2af7f102011-03-02 11:14:59 +010076 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010077 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010078 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030079 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010080 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020081 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050082 uint32_t *crtcs;
83 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050084 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010085 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050086 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020087
Rob Clark4339add2012-08-09 14:18:28 -050088 /* we need these parameters in order to not fail drmModeAddFB2()
89 * due to out of bounds dimensions, and then mistakenly set
90 * sprites_are_broken:
91 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020092 uint32_t min_width, max_width;
93 uint32_t min_height, max_height;
94 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050095
Jesse Barnes58ef3792012-02-23 09:45:49 -050096 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -050097 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +020098 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -050099
Rob Clarkab5b1e32012-08-09 13:24:45 -0500100 int cursors_are_broken;
101
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200102 int use_pixman;
103
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200104 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300105
106 clockid_t clock;
Rob Bradfordd355b802013-05-31 18:09:55 +0100107 struct udev_input input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400108};
109
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400110struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500111 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400112 drmModeModeInfo mode_info;
113};
114
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300115struct drm_output;
116
117struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300118 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200119 uint32_t fb_id, stride, handle, size;
120 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300121 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200122 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200123
124 /* Used by gbm fbs */
125 struct gbm_bo *bo;
126
127 /* Used by dumb fbs */
128 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300129};
130
Richard Hughes2b2092a2013-04-24 14:58:02 +0100131struct drm_edid {
132 char eisa_id[13];
133 char monitor_name[13];
134 char pnp_id[5];
135 char serial_number[13];
136};
137
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400138struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500139 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400140
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400141 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500142 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400143 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700144 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100145 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300146 drmModePropertyPtr dpms_prop;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200147
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300148 int vblank_pending;
149 int page_flip_pending;
150
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400151 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400152 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400153 struct weston_plane cursor_plane;
154 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400155 struct weston_surface *cursor_surface;
156 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300157 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200158 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200159
160 struct drm_fb *dumb[2];
161 pixman_image_t *image[2];
162 int current_image;
163 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300164
165 struct vaapi_recorder *recorder;
166 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400167};
168
Jesse Barnes58ef3792012-02-23 09:45:49 -0500169/*
170 * An output has a primary display plane plus zero or more sprites for
171 * blending display contents.
172 */
173struct drm_sprite {
174 struct wl_list link;
175
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400176 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500177
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200178 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300179 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500180 struct drm_compositor *compositor;
181
Jesse Barnes58ef3792012-02-23 09:45:49 -0500182 uint32_t possible_crtcs;
183 uint32_t plane_id;
184 uint32_t count_formats;
185
186 int32_t src_x, src_y;
187 uint32_t src_w, src_h;
188 uint32_t dest_x, dest_y;
189 uint32_t dest_w, dest_h;
190
191 uint32_t formats[];
192};
193
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500194static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400195
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400196static void
197drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400198
Jesse Barnes58ef3792012-02-23 09:45:49 -0500199static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500200drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
201{
202 struct weston_compositor *ec = output_base->compositor;
203 struct drm_compositor *c =(struct drm_compositor *) ec;
204 struct drm_output *output = (struct drm_output *) output_base;
205 int crtc;
206
207 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
208 if (c->crtcs[crtc] != output->crtc_id)
209 continue;
210
211 if (supported & (1 << crtc))
212 return -1;
213 }
214
215 return 0;
216}
217
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300218static void
219drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
220{
221 struct drm_fb *fb = data;
222 struct gbm_device *gbm = gbm_bo_get_device(bo);
223
224 if (fb->fb_id)
225 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
226
Pekka Paalanende685b82012-12-04 15:58:12 +0200227 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300228
229 free(data);
230}
231
232static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200233drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
234{
235 struct drm_fb *fb;
236 int ret;
237
238 struct drm_mode_create_dumb create_arg;
239 struct drm_mode_destroy_dumb destroy_arg;
240 struct drm_mode_map_dumb map_arg;
241
Peter Huttererf3d62272013-08-08 11:57:05 +1000242 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200243 if (!fb)
244 return NULL;
245
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700246 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200247 create_arg.bpp = 32;
248 create_arg.width = width;
249 create_arg.height = height;
250
251 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
252 if (ret)
253 goto err_fb;
254
255 fb->handle = create_arg.handle;
256 fb->stride = create_arg.pitch;
257 fb->size = create_arg.size;
258 fb->fd = ec->drm.fd;
259
260 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
261 fb->stride, fb->handle, &fb->fb_id);
262 if (ret)
263 goto err_bo;
264
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700265 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200266 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400267 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200268 if (ret)
269 goto err_add_fb;
270
271 fb->map = mmap(0, fb->size, PROT_WRITE,
272 MAP_SHARED, ec->drm.fd, map_arg.offset);
273 if (fb->map == MAP_FAILED)
274 goto err_add_fb;
275
276 return fb;
277
278err_add_fb:
279 drmModeRmFB(ec->drm.fd, fb->fb_id);
280err_bo:
281 memset(&destroy_arg, 0, sizeof(destroy_arg));
282 destroy_arg.handle = create_arg.handle;
283 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
284err_fb:
285 free(fb);
286 return NULL;
287}
288
289static void
290drm_fb_destroy_dumb(struct drm_fb *fb)
291{
292 struct drm_mode_destroy_dumb destroy_arg;
293
294 if (!fb->map)
295 return;
296
297 if (fb->fb_id)
298 drmModeRmFB(fb->fd, fb->fb_id);
299
300 weston_buffer_reference(&fb->buffer_ref, NULL);
301
302 munmap(fb->map, fb->size);
303
304 memset(&destroy_arg, 0, sizeof(destroy_arg));
305 destroy_arg.handle = fb->handle;
306 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
307
308 free(fb);
309}
310
311static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500312drm_fb_get_from_bo(struct gbm_bo *bo,
313 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300314{
315 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200316 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200317 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300318 int ret;
319
320 if (fb)
321 return fb;
322
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200323 fb = calloc(1, sizeof *fb);
324 if (!fb)
325 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300326
327 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300328
329 width = gbm_bo_get_width(bo);
330 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200331 fb->stride = gbm_bo_get_stride(bo);
332 fb->handle = gbm_bo_get_handle(bo).u32;
333 fb->size = fb->stride * height;
334 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300335
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200336 if (compositor->min_width > width || width > compositor->max_width ||
337 compositor->min_height > height ||
338 height > compositor->max_height) {
339 weston_log("bo geometry out of bounds\n");
340 goto err_free;
341 }
342
343 ret = -1;
344
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200345 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200346 handles[0] = fb->handle;
347 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200348 offsets[0] = 0;
349
350 ret = drmModeAddFB2(compositor->drm.fd, width, height,
351 format, handles, pitches, offsets,
352 &fb->fb_id, 0);
353 if (ret) {
354 weston_log("addfb2 failed: %m\n");
355 compositor->no_addfb2 = 1;
356 compositor->sprites_are_broken = 1;
357 }
358 }
359
360 if (ret)
361 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200362 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200363
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300364 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200365 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200366 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300367 }
368
369 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
370
371 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200372
373err_free:
374 free(fb);
375 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300376}
377
378static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500379drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200380{
Pekka Paalanende685b82012-12-04 15:58:12 +0200381 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200382
383 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200384
Pekka Paalanende685b82012-12-04 15:58:12 +0200385 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200386}
387
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200388static void
389drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
390{
391 if (!fb)
392 return;
393
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200394 if (fb->map &&
395 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200396 drm_fb_destroy_dumb(fb);
397 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200398 if (fb->is_client_buffer)
399 gbm_bo_destroy(fb->bo);
400 else
401 gbm_surface_release_buffer(output->surface,
402 output->current->bo);
403 }
404}
405
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500406static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200407drm_output_check_scanout_format(struct drm_output *output,
408 struct weston_surface *es, struct gbm_bo *bo)
409{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200410 uint32_t format;
411 pixman_region32_t r;
412
413 format = gbm_bo_get_format(bo);
414
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500415 switch (format) {
416 case GBM_FORMAT_XRGB8888:
417 return format;
418 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200419 /* We can only scanout an ARGB buffer if the surface's
420 * opaque region covers the whole output */
421 pixman_region32_init(&r);
422 pixman_region32_subtract(&r, &output->base.region,
423 &es->opaque);
424
425 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500426 format = GBM_FORMAT_XRGB8888;
427 else
428 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200429
430 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200431
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500432 return format;
433 default:
434 return 0;
435 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200436}
437
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400438static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400439drm_output_prepare_scanout_surface(struct weston_output *_output,
440 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500441{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400442 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500443 struct drm_compositor *c =
444 (struct drm_compositor *) output->base.compositor;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500445 struct weston_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300446 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500447 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500448
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500449 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200450 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200451 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200452 buffer->width != output->base.current->width ||
453 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200454 output->base.transform != es->buffer_transform ||
455 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400456 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500457
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400458 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200459 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500460
Rob Bradford9b101872012-09-14 23:25:41 +0100461 /* Unable to use the buffer for scanout */
462 if (!bo)
463 return NULL;
464
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500465 format = drm_output_check_scanout_format(output, es, bo);
466 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300467 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400468 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300469 }
470
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500471 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300472 if (!output->next) {
473 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400474 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300475 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500476
Pekka Paalanende685b82012-12-04 15:58:12 +0200477 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500478
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400479 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500480}
481
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500482static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200483drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400484{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200485 struct drm_compositor *c =
486 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300487 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400488
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200489 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400490
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300491 bo = gbm_surface_lock_front_buffer(output->surface);
492 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200493 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400494 return;
495 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300496
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500497 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300498 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200499 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300500 gbm_surface_release_buffer(output->surface, bo);
501 return;
502 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400503}
504
505static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200506drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
507{
508 struct weston_compositor *ec = output->base.compositor;
509 pixman_region32_t total_damage, previous_damage;
510
511 pixman_region32_init(&total_damage);
512 pixman_region32_init(&previous_damage);
513
514 pixman_region32_copy(&previous_damage, damage);
515
516 pixman_region32_union(&total_damage, damage, &output->previous_damage);
517 pixman_region32_copy(&output->previous_damage, &previous_damage);
518
519 output->current_image ^= 1;
520
521 output->next = output->dumb[output->current_image];
522 pixman_renderer_output_set_buffer(&output->base,
523 output->image[output->current_image]);
524
525 ec->renderer->repaint_output(&output->base, &total_damage);
526
527 pixman_region32_fini(&total_damage);
528 pixman_region32_fini(&previous_damage);
529}
530
531static void
532drm_output_render(struct drm_output *output, pixman_region32_t *damage)
533{
534 struct drm_compositor *c =
535 (struct drm_compositor *) output->base.compositor;
536
537 if (c->use_pixman)
538 drm_output_render_pixman(output, damage);
539 else
540 drm_output_render_gl(output, damage);
541
542 pixman_region32_subtract(&c->base.primary_plane.damage,
543 &c->base.primary_plane.damage, damage);
544}
545
546static void
Richard Hughese7299962013-05-01 21:52:12 +0100547drm_output_set_gamma(struct weston_output *output_base,
548 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
549{
550 int rc;
551 struct drm_output *output = (struct drm_output *) output_base;
552 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
553
554 /* check */
555 if (output_base->gamma_size != size)
556 return;
557 if (!output->original_crtc)
558 return;
559
560 rc = drmModeCrtcSetGamma(compositor->drm.fd,
561 output->crtc_id,
562 size, r, g, b);
563 if (rc)
564 weston_log("set gamma failed: %m\n");
565}
566
567static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500568drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400569 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100570{
571 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500572 struct drm_compositor *compositor =
573 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500574 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400575 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500576 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100577
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300578 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400579 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300580 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400581 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100582
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400583 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300584 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400585 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300586 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400587 &output->connector_id, 1,
588 &mode->mode_info);
589 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200590 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400591 return;
592 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300593 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200594 }
595
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500596 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300597 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500598 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200599 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500600 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500601 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100602
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300603 output->page_flip_pending = 1;
604
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400605 drm_output_set_cursor(output);
606
Jesse Barnes58ef3792012-02-23 09:45:49 -0500607 /*
608 * Now, update all the sprite surfaces
609 */
610 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200611 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500612 drmVBlank vbl = {
613 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
614 .request.sequence = 1,
615 };
616
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200617 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200618 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500619 continue;
620
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200621 if (s->next && !compositor->sprites_hidden)
622 fb_id = s->next->fb_id;
623
Jesse Barnes58ef3792012-02-23 09:45:49 -0500624 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200625 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500626 s->dest_x, s->dest_y,
627 s->dest_w, s->dest_h,
628 s->src_x, s->src_y,
629 s->src_w, s->src_h);
630 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200631 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500632 ret, strerror(errno));
633
Rob Clark5ca1a472012-08-08 20:27:37 -0500634 if (output->pipe > 0)
635 vbl.request.type |= DRM_VBLANK_SECONDARY;
636
Jesse Barnes58ef3792012-02-23 09:45:49 -0500637 /*
638 * Queue a vblank signal so we know when the surface
639 * becomes active on the display or has been replaced.
640 */
641 vbl.request.signal = (unsigned long)s;
642 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
643 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200644 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500645 ret, strerror(errno));
646 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300647
648 s->output = output;
649 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500650 }
651
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500652 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400653}
654
655static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200656drm_output_start_repaint_loop(struct weston_output *output_base)
657{
658 struct drm_output *output = (struct drm_output *) output_base;
659 struct drm_compositor *compositor = (struct drm_compositor *)
660 output_base->compositor;
661 uint32_t fb_id;
662
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300663 struct timespec ts;
664
665 if (!output->current) {
666 /* We can't page flip if there's no mode set */
667 uint32_t msec;
668
669 clock_gettime(compositor->clock, &ts);
670 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
671 weston_output_finish_frame(output_base, msec);
672 return;
673 }
674
675 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200676
677 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
678 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
679 weston_log("queueing pageflip failed: %m\n");
680 return;
681 }
682}
683
684static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500685vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
686 void *data)
687{
688 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300689 struct drm_output *output = s->output;
690 uint32_t msecs;
691
692 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500693
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200694 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200695 s->current = s->next;
696 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300697
698 if (!output->page_flip_pending) {
699 msecs = sec * 1000 + usec / 1000;
700 weston_output_finish_frame(&output->base, msecs);
701 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500702}
703
704static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400705page_flip_handler(int fd, unsigned int frame,
706 unsigned int sec, unsigned int usec, void *data)
707{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200708 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400709 uint32_t msecs;
710
Jonas Ådahle5a12252013-04-05 23:07:11 +0200711 /* We don't set page_flip_pending on start_repaint_loop, in that case
712 * we just want to page flip to the current buffer to get an accurate
713 * timestamp */
714 if (output->page_flip_pending) {
715 drm_output_release_fb(output, output->current);
716 output->current = output->next;
717 output->next = NULL;
718 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300719
Jonas Ådahle5a12252013-04-05 23:07:11 +0200720 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400721
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300722 if (!output->vblank_pending) {
723 msecs = sec * 1000 + usec / 1000;
724 weston_output_finish_frame(&output->base, msecs);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300725
726 /* We can't call this from frame_notify, because the output's
727 * repaint needed flag is cleared just after that */
728 if (output->recorder)
729 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300730 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200731}
732
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500733static uint32_t
734drm_output_check_sprite_format(struct drm_sprite *s,
735 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500736{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500737 uint32_t i, format;
738
739 format = gbm_bo_get_format(bo);
740
741 if (format == GBM_FORMAT_ARGB8888) {
742 pixman_region32_t r;
743
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500744 pixman_region32_init_rect(&r, 0, 0,
745 es->geometry.width,
746 es->geometry.height);
747 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500748
749 if (!pixman_region32_not_empty(&r))
750 format = GBM_FORMAT_XRGB8888;
751
752 pixman_region32_fini(&r);
753 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500754
755 for (i = 0; i < s->count_formats; i++)
756 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500757 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500758
759 return 0;
760}
761
762static int
763drm_surface_transform_supported(struct weston_surface *es)
764{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500765 return !es->transform.enabled ||
766 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500767}
768
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400769static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500770drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400771 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500772{
773 struct weston_compositor *ec = output_base->compositor;
774 struct drm_compositor *c =(struct drm_compositor *) ec;
775 struct drm_sprite *s;
776 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500777 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500778 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200779 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500780 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400781 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500782
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200783 if (c->gbm == NULL)
784 return NULL;
785
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200786 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200787 return NULL;
788
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200789 if (es->buffer_scale != output_base->scale)
790 return NULL;
791
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500792 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400793 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500794
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300795 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400796 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300797
Pekka Paalanende685b82012-12-04 15:58:12 +0200798 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400799 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500800
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200801 if (es->alpha != 1.0f)
802 return NULL;
803
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500804 if (wl_shm_buffer_get(es->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500805 return NULL;
806
Jesse Barnes58ef3792012-02-23 09:45:49 -0500807 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400808 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500809
Jesse Barnes58ef3792012-02-23 09:45:49 -0500810 wl_list_for_each(s, &c->sprite_list, link) {
811 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
812 continue;
813
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200814 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500815 found = 1;
816 break;
817 }
818 }
819
820 /* No sprites available */
821 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400822 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500823
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400824 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200825 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400826 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400827 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400828
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500829 format = drm_output_check_sprite_format(s, es, bo);
830 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200831 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400832 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500833 }
834
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200835 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200836 if (!s->next) {
837 gbm_bo_destroy(bo);
838 return NULL;
839 }
840
Pekka Paalanende685b82012-12-04 15:58:12 +0200841 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500842
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400843 box = pixman_region32_extents(&es->transform.boundingbox);
844 s->plane.x = box->x1;
845 s->plane.y = box->y1;
846
Jesse Barnes58ef3792012-02-23 09:45:49 -0500847 /*
848 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200849 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500850 * for us already).
851 */
852 pixman_region32_init(&dest_rect);
853 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
854 &output_base->region);
855 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
856 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200857 tbox = weston_transformed_rect(output_base->width,
858 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200859 output_base->transform,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200860 output_base->scale,
861 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200862 s->dest_x = tbox.x1;
863 s->dest_y = tbox.y1;
864 s->dest_w = tbox.x2 - tbox.x1;
865 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500866 pixman_region32_fini(&dest_rect);
867
868 pixman_region32_init(&src_rect);
869 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
870 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500871 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400872
873 weston_surface_from_global_fixed(es,
874 wl_fixed_from_int(box->x1),
875 wl_fixed_from_int(box->y1),
876 &sx1, &sy1);
877 weston_surface_from_global_fixed(es,
878 wl_fixed_from_int(box->x2),
879 wl_fixed_from_int(box->y2),
880 &sx2, &sy2);
881
882 if (sx1 < 0)
883 sx1 = 0;
884 if (sy1 < 0)
885 sy1 = 0;
886 if (sx2 > wl_fixed_from_int(es->geometry.width))
887 sx2 = wl_fixed_from_int(es->geometry.width);
888 if (sy2 > wl_fixed_from_int(es->geometry.height))
889 sy2 = wl_fixed_from_int(es->geometry.height);
890
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200891 tbox.x1 = sx1;
892 tbox.y1 = sy1;
893 tbox.x2 = sx2;
894 tbox.y2 = sy2;
895
896 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
897 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200898 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200899
900 s->src_x = tbox.x1 << 8;
901 s->src_y = tbox.y1 << 8;
902 s->src_w = (tbox.x2 - tbox.x1) << 8;
903 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500904 pixman_region32_fini(&src_rect);
905
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400906 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500907}
908
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400909static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400910drm_output_prepare_cursor_surface(struct weston_output *output_base,
911 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500912{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400913 struct drm_compositor *c =
914 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400915 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400916
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200917 if (c->gbm == NULL)
918 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200919 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
920 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400921 if (output->cursor_surface)
922 return NULL;
923 if (es->output_mask != (1u << output_base->id))
924 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500925 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400926 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200927 if (es->buffer_ref.buffer == NULL ||
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500928 !wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400929 es->geometry.width > 64 || es->geometry.height > 64)
930 return NULL;
931
932 output->cursor_surface = es;
933
934 return &output->cursor_plane;
935}
936
937static void
938drm_output_set_cursor(struct drm_output *output)
939{
940 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400941 struct drm_compositor *c =
942 (struct drm_compositor *) output->base.compositor;
943 EGLint handle, stride;
944 struct gbm_bo *bo;
945 uint32_t buf[64 * 64];
946 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400947 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500948
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400949 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400950 if (es == NULL) {
951 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
952 return;
953 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500954
Pekka Paalanende685b82012-12-04 15:58:12 +0200955 if (es->buffer_ref.buffer &&
956 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400957 pixman_region32_fini(&output->cursor_plane.damage);
958 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400959 output->current_cursor ^= 1;
960 bo = output->cursor_bo[output->current_cursor];
961 memset(buf, 0, sizeof buf);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500962 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
963 s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400964 for (i = 0; i < es->geometry.height; i++)
965 memcpy(buf + i * 64, s + i * stride,
966 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500967
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400968 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300969 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400970
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400971 handle = gbm_bo_get_handle(bo).s32;
972 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500973 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300974 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500975 c->cursors_are_broken = 1;
976 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400977 }
978
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200979 x = (es->geometry.x - output->base.x) * output->base.scale;
980 y = (es->geometry.y - output->base.y) * output->base.scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400981 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500982 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400983 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500984 c->cursors_are_broken = 1;
985 }
986
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400987 output->cursor_plane.x = x;
988 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400989 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500990}
991
Jesse Barnes58ef3792012-02-23 09:45:49 -0500992static void
993drm_assign_planes(struct weston_output *output)
994{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400995 struct drm_compositor *c =
996 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400997 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500998 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400999 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001000
1001 /*
1002 * Find a surface for each sprite in the output using some heuristics:
1003 * 1) size
1004 * 2) frequency of update
1005 * 3) opacity (though some hw might support alpha blending)
1006 * 4) clipping (this can be fixed with color keys)
1007 *
1008 * The idea is to save on blitting since this should save power.
1009 * If we can get a large video surface on the sprite for example,
1010 * the main display surface may not need to update at all, and
1011 * the client buffer can be used directly for the sprite surface
1012 * as we do for flipping full screen surfaces.
1013 */
1014 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001015 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001016 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001017 /* test whether this buffer can ever go into a plane:
1018 * non-shm, or small enough to be a cursor
1019 */
1020 if ((es->buffer_ref.buffer &&
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001021 !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) ||
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001022 (es->geometry.width <= 64 && es->geometry.height <= 64))
1023 es->keep_buffer = 1;
1024 else
1025 es->keep_buffer = 0;
1026
Jesse Barnes58ef3792012-02-23 09:45:49 -05001027 pixman_region32_init(&surface_overlap);
1028 pixman_region32_intersect(&surface_overlap, &overlap,
1029 &es->transform.boundingbox);
1030
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001031 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001032 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001033 next_plane = primary;
1034 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001035 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001036 if (next_plane == NULL)
1037 next_plane = drm_output_prepare_scanout_surface(output, es);
1038 if (next_plane == NULL)
1039 next_plane = drm_output_prepare_overlay_surface(output, es);
1040 if (next_plane == NULL)
1041 next_plane = primary;
1042 weston_surface_move_to_plane(es, next_plane);
1043 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001044 pixman_region32_union(&overlap, &overlap,
1045 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001046
Jesse Barnes58ef3792012-02-23 09:45:49 -05001047 pixman_region32_fini(&surface_overlap);
1048 }
1049 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001050}
1051
Matt Roper361d2ad2011-08-29 13:52:23 -07001052static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001053drm_output_fini_pixman(struct drm_output *output);
1054
1055static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001056drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001057{
1058 struct drm_output *output = (struct drm_output *) output_base;
1059 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001060 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001061 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001062
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001063 if (output->backlight)
1064 backlight_destroy(output->backlight);
1065
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001066 drmModeFreeProperty(output->dpms_prop);
1067
Matt Roper361d2ad2011-08-29 13:52:23 -07001068 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001069 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001070
1071 /* Restore original CRTC state */
1072 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001073 origcrtc->x, origcrtc->y,
1074 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001075 drmModeFreeCrtc(origcrtc);
1076
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001077 c->crtc_allocator &= ~(1 << output->crtc_id);
1078 c->connector_allocator &= ~(1 << output->connector_id);
1079
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001080 if (c->use_pixman) {
1081 drm_output_fini_pixman(output);
1082 } else {
1083 gl_renderer_output_destroy(output_base);
1084 gbm_surface_destroy(output->surface);
1085 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001086
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001087 weston_plane_release(&output->fb_plane);
1088 weston_plane_release(&output->cursor_plane);
1089
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001090 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001091 wl_list_remove(&output->base.link);
1092
Matt Roper361d2ad2011-08-29 13:52:23 -07001093 free(output);
1094}
1095
Alex Wub7b8bda2012-04-17 17:20:48 +08001096static struct drm_mode *
1097choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1098{
1099 struct drm_mode *tmp_mode = NULL, *mode;
1100
1101 if (output->base.current->width == target_mode->width &&
1102 output->base.current->height == target_mode->height &&
1103 (output->base.current->refresh == target_mode->refresh ||
1104 target_mode->refresh == 0))
1105 return (struct drm_mode *)output->base.current;
1106
1107 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1108 if (mode->mode_info.hdisplay == target_mode->width &&
1109 mode->mode_info.vdisplay == target_mode->height) {
1110 if (mode->mode_info.vrefresh == target_mode->refresh ||
1111 target_mode->refresh == 0) {
1112 return mode;
1113 } else if (!tmp_mode)
1114 tmp_mode = mode;
1115 }
1116 }
1117
1118 return tmp_mode;
1119}
1120
1121static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001122drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001123static int
1124drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001125
1126static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001127drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1128{
1129 struct drm_output *output;
1130 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001131 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001132
1133 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001134 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001135 return -1;
1136 }
1137
1138 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001139 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001140 return -1;
1141 }
1142
1143 ec = (struct drm_compositor *)output_base->compositor;
1144 output = (struct drm_output *)output_base;
1145 drm_mode = choose_mode (output, mode);
1146
1147 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001148 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001149 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001150 }
1151
1152 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001153 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001154
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001155 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001156
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001157 output->base.current = &drm_mode->base;
1158 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001159 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1160
Alex Wub7b8bda2012-04-17 17:20:48 +08001161 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001162 drm_output_release_fb(output, output->current);
1163 drm_output_release_fb(output, output->next);
1164 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001165
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001166 if (ec->use_pixman) {
1167 drm_output_fini_pixman(output);
1168 if (drm_output_init_pixman(output, ec) < 0) {
1169 weston_log("failed to init output pixman state with "
1170 "new mode\n");
1171 return -1;
1172 }
1173 } else {
1174 gl_renderer_output_destroy(&output->base);
1175 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001176
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001177 if (drm_output_init_egl(output, ec) < 0) {
1178 weston_log("failed to init output egl state with "
1179 "new mode");
1180 return -1;
1181 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001182 }
1183
Alex Wub7b8bda2012-04-17 17:20:48 +08001184 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001185}
1186
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001187static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001188on_drm_input(int fd, uint32_t mask, void *data)
1189{
1190 drmEventContext evctx;
1191
1192 memset(&evctx, 0, sizeof evctx);
1193 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1194 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001195 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001196 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001197
1198 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001199}
1200
1201static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001202init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001203{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001204 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001205 uint64_t cap;
1206 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001207
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001208 sysnum = udev_device_get_sysnum(device);
1209 if (sysnum)
1210 ec->drm.id = atoi(sysnum);
1211 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001212 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001213 return -1;
1214 }
1215
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001216 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001217 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001218 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001219 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001220 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001221 udev_device_get_devnode(device));
1222 return -1;
1223 }
1224
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001225 weston_log("using %s\n", filename);
1226
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001227 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001228 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001229
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001230 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1231 if (ret == 0 && cap == 1)
1232 ec->clock = CLOCK_MONOTONIC;
1233 else
1234 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001235
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001236 return 0;
1237}
1238
1239static int
1240init_egl(struct drm_compositor *ec)
1241{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001242 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001243
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001244 if (!ec->gbm)
1245 return -1;
1246
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001247 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001248 NULL) < 0) {
1249 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001250 return -1;
1251 }
1252
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001253 return 0;
1254}
1255
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001256static int
1257init_pixman(struct drm_compositor *ec)
1258{
1259 return pixman_renderer_init(&ec->base);
1260}
1261
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001262static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001263drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001264{
1265 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001266 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001267
1268 mode = malloc(sizeof *mode);
1269 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001270 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001271
1272 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001273 mode->base.width = info->hdisplay;
1274 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001275
1276 /* Calculate higher precision (mHz) refresh rate */
1277 refresh = (info->clock * 1000000LL / info->htotal +
1278 info->vtotal / 2) / info->vtotal;
1279
1280 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1281 refresh *= 2;
1282 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1283 refresh /= 2;
1284 if (info->vscan > 1)
1285 refresh /= info->vscan;
1286
1287 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001288 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001289
1290 if (info->type & DRM_MODE_TYPE_PREFERRED)
1291 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1292
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001293 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1294
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001295 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001296}
1297
1298static int
1299drm_subpixel_to_wayland(int drm_value)
1300{
1301 switch (drm_value) {
1302 default:
1303 case DRM_MODE_SUBPIXEL_UNKNOWN:
1304 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1305 case DRM_MODE_SUBPIXEL_NONE:
1306 return WL_OUTPUT_SUBPIXEL_NONE;
1307 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1308 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1309 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1310 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1311 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1312 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1313 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1314 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1315 }
1316}
1317
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001318/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001319static uint32_t
1320drm_get_backlight(struct drm_output *output)
1321{
1322 long brightness, max_brightness, norm;
1323
1324 brightness = backlight_get_brightness(output->backlight);
1325 max_brightness = backlight_get_max_brightness(output->backlight);
1326
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001327 /* convert it on a scale of 0 to 255 */
1328 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001329
1330 return (uint32_t) norm;
1331}
1332
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001333/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001334static void
1335drm_set_backlight(struct weston_output *output_base, uint32_t value)
1336{
1337 struct drm_output *output = (struct drm_output *) output_base;
1338 long max_brightness, new_brightness;
1339
1340 if (!output->backlight)
1341 return;
1342
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001343 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001344 return;
1345
1346 max_brightness = backlight_get_max_brightness(output->backlight);
1347
1348 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001349 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001350
1351 backlight_set_brightness(output->backlight, new_brightness);
1352}
1353
1354static drmModePropertyPtr
1355drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1356{
1357 drmModePropertyPtr props;
1358 int i;
1359
1360 for (i = 0; i < connector->count_props; i++) {
1361 props = drmModeGetProperty(fd, connector->props[i]);
1362 if (!props)
1363 continue;
1364
1365 if (!strcmp(props->name, name))
1366 return props;
1367
1368 drmModeFreeProperty(props);
1369 }
1370
1371 return NULL;
1372}
1373
1374static void
1375drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1376{
1377 struct drm_output *output = (struct drm_output *) output_base;
1378 struct weston_compositor *ec = output_base->compositor;
1379 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001380
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001381 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001382 return;
1383
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001384 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1385 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001386}
1387
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001388static const char *connector_type_names[] = {
1389 "None",
1390 "VGA",
1391 "DVI",
1392 "DVI",
1393 "DVI",
1394 "Composite",
1395 "TV",
1396 "LVDS",
1397 "CTV",
1398 "DIN",
1399 "DP",
1400 "HDMI",
1401 "HDMI",
1402 "TV",
1403 "eDP",
1404};
1405
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001406static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001407find_crtc_for_connector(struct drm_compositor *ec,
1408 drmModeRes *resources, drmModeConnector *connector)
1409{
1410 drmModeEncoder *encoder;
1411 uint32_t possible_crtcs;
1412 int i, j;
1413
1414 for (j = 0; j < connector->count_encoders; j++) {
1415 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1416 if (encoder == NULL) {
1417 weston_log("Failed to get encoder.\n");
1418 return -1;
1419 }
1420 possible_crtcs = encoder->possible_crtcs;
1421 drmModeFreeEncoder(encoder);
1422
1423 for (i = 0; i < resources->count_crtcs; i++) {
1424 if (possible_crtcs & (1 << i) &&
1425 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1426 return i;
1427 }
1428 }
1429
1430 return -1;
1431}
1432
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001433/* Init output state that depends on gl or gbm */
1434static int
1435drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1436{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001437 int i, flags;
1438
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001439 output->surface = gbm_surface_create(ec->gbm,
Alexander Larsson0b135062013-05-28 16:23:36 +02001440 output->base.current->width,
1441 output->base.current->height,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001442 GBM_FORMAT_XRGB8888,
1443 GBM_BO_USE_SCANOUT |
1444 GBM_BO_USE_RENDERING);
1445 if (!output->surface) {
1446 weston_log("failed to create gbm surface\n");
1447 return -1;
1448 }
1449
1450 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001451 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001452 gbm_surface_destroy(output->surface);
1453 return -1;
1454 }
1455
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001456 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1457
1458 for (i = 0; i < 2; i++) {
1459 if (output->cursor_bo[i])
1460 continue;
1461
1462 output->cursor_bo[i] =
1463 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1464 flags);
1465 }
1466
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001467 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1468 weston_log("cursor buffers unavailable, using gl cursors\n");
1469 ec->cursors_are_broken = 1;
1470 }
1471
1472 return 0;
1473}
1474
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001475static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001476drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1477{
1478 int w = output->base.current->width;
1479 int h = output->base.current->height;
1480 unsigned int i;
1481
1482 /* FIXME error checking */
1483
1484 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001485 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001486 if (!output->dumb[i])
1487 goto err;
1488
1489 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001490 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001491 output->dumb[i]->map,
1492 output->dumb[i]->stride);
1493 if (!output->image[i])
1494 goto err;
1495 }
1496
1497 if (pixman_renderer_output_create(&output->base) < 0)
1498 goto err;
1499
1500 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001501 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001502
1503 return 0;
1504
1505err:
1506 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1507 if (output->dumb[i])
1508 drm_fb_destroy_dumb(output->dumb[i]);
1509 if (output->image[i])
1510 pixman_image_unref(output->image[i]);
1511
1512 output->dumb[i] = NULL;
1513 output->image[i] = NULL;
1514 }
1515
1516 return -1;
1517}
1518
1519static void
1520drm_output_fini_pixman(struct drm_output *output)
1521{
1522 unsigned int i;
1523
1524 pixman_renderer_output_destroy(&output->base);
1525 pixman_region32_fini(&output->previous_damage);
1526
1527 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1528 drm_fb_destroy_dumb(output->dumb[i]);
1529 pixman_image_unref(output->image[i]);
1530 output->dumb[i] = NULL;
1531 output->image[i] = NULL;
1532 }
1533}
1534
Richard Hughes2b2092a2013-04-24 14:58:02 +01001535static void
1536edid_parse_string(const uint8_t *data, char text[])
1537{
1538 int i;
1539 int replaced = 0;
1540
1541 /* this is always 12 bytes, but we can't guarantee it's null
1542 * terminated or not junk. */
1543 strncpy(text, (const char *) data, 12);
1544
1545 /* remove insane chars */
1546 for (i = 0; text[i] != '\0'; i++) {
1547 if (text[i] == '\n' ||
1548 text[i] == '\r') {
1549 text[i] = '\0';
1550 break;
1551 }
1552 }
1553
1554 /* ensure string is printable */
1555 for (i = 0; text[i] != '\0'; i++) {
1556 if (!isprint(text[i])) {
1557 text[i] = '-';
1558 replaced++;
1559 }
1560 }
1561
1562 /* if the string is random junk, ignore the string */
1563 if (replaced > 4)
1564 text[0] = '\0';
1565}
1566
1567#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1568#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1569#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1570#define EDID_OFFSET_DATA_BLOCKS 0x36
1571#define EDID_OFFSET_LAST_BLOCK 0x6c
1572#define EDID_OFFSET_PNPID 0x08
1573#define EDID_OFFSET_SERIAL 0x0c
1574
1575static int
1576edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1577{
1578 int i;
1579 uint32_t serial_number;
1580
1581 /* check header */
1582 if (length < 128)
1583 return -1;
1584 if (data[0] != 0x00 || data[1] != 0xff)
1585 return -1;
1586
1587 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1588 * /--08--\/--09--\
1589 * 7654321076543210
1590 * |\---/\---/\---/
1591 * R C1 C2 C3 */
1592 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1593 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1594 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1595 edid->pnp_id[3] = '\0';
1596
1597 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1598 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1599 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1600 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1601 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1602 if (serial_number > 0)
1603 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1604
1605 /* parse EDID data */
1606 for (i = EDID_OFFSET_DATA_BLOCKS;
1607 i <= EDID_OFFSET_LAST_BLOCK;
1608 i += 18) {
1609 /* ignore pixel clock data */
1610 if (data[i] != 0)
1611 continue;
1612 if (data[i+2] != 0)
1613 continue;
1614
1615 /* any useful blocks? */
1616 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1617 edid_parse_string(&data[i+5],
1618 edid->monitor_name);
1619 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1620 edid_parse_string(&data[i+5],
1621 edid->serial_number);
1622 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1623 edid_parse_string(&data[i+5],
1624 edid->eisa_id);
1625 }
1626 }
1627 return 0;
1628}
1629
1630static void
1631find_and_parse_output_edid(struct drm_compositor *ec,
1632 struct drm_output *output,
1633 drmModeConnector *connector)
1634{
1635 drmModePropertyBlobPtr edid_blob = NULL;
1636 drmModePropertyPtr property;
1637 int i;
1638 int rc;
1639
1640 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1641 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1642 if (!property)
1643 continue;
1644 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1645 !strcmp(property->name, "EDID")) {
1646 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1647 connector->prop_values[i]);
1648 }
1649 drmModeFreeProperty(property);
1650 }
1651 if (!edid_blob)
1652 return;
1653
1654 rc = edid_parse(&output->edid,
1655 edid_blob->data,
1656 edid_blob->length);
1657 if (!rc) {
1658 weston_log("EDID data '%s', '%s', '%s'\n",
1659 output->edid.pnp_id,
1660 output->edid.monitor_name,
1661 output->edid.serial_number);
1662 if (output->edid.pnp_id[0] != '\0')
1663 output->base.make = output->edid.pnp_id;
1664 if (output->edid.monitor_name[0] != '\0')
1665 output->base.model = output->edid.monitor_name;
1666 if (output->edid.serial_number[0] != '\0')
1667 output->base.serial_number = output->edid.serial_number;
1668 }
1669 drmModeFreePropertyBlob(edid_blob);
1670}
1671
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001672
1673
1674static int
1675parse_modeline(const char *s, drmModeModeInfo *mode)
1676{
1677 char hsync[16];
1678 char vsync[16];
1679 float fclock;
1680
1681 mode->type = DRM_MODE_TYPE_USERDEF;
1682 mode->hskew = 0;
1683 mode->vscan = 0;
1684 mode->vrefresh = 0;
1685 mode->flags = 0;
1686
Rob Bradford307e09e2013-07-26 16:29:40 +01001687 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001688 &fclock,
1689 &mode->hdisplay,
1690 &mode->hsync_start,
1691 &mode->hsync_end,
1692 &mode->htotal,
1693 &mode->vdisplay,
1694 &mode->vsync_start,
1695 &mode->vsync_end,
1696 &mode->vtotal, hsync, vsync) != 11)
1697 return -1;
1698
1699 mode->clock = fclock * 1000;
1700 if (strcmp(hsync, "+hsync") == 0)
1701 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1702 else if (strcmp(hsync, "-hsync") == 0)
1703 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1704 else
1705 return -1;
1706
1707 if (strcmp(vsync, "+vsync") == 0)
1708 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1709 else if (strcmp(vsync, "-vsync") == 0)
1710 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1711 else
1712 return -1;
1713
1714 return 0;
1715}
1716
1717static uint32_t
1718parse_transform(const char *transform, const char *output_name)
1719{
1720 static const struct { const char *name; uint32_t token; } names[] = {
1721 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1722 { "90", WL_OUTPUT_TRANSFORM_90 },
1723 { "180", WL_OUTPUT_TRANSFORM_180 },
1724 { "270", WL_OUTPUT_TRANSFORM_270 },
1725 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1726 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1727 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1728 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1729 };
1730 unsigned int i;
1731
1732 for (i = 0; i < ARRAY_LENGTH(names); i++)
1733 if (strcmp(names[i].name, transform) == 0)
1734 return names[i].token;
1735
1736 weston_log("Invalid transform \"%s\" for output %s\n",
1737 transform, output_name);
1738
1739 return WL_OUTPUT_TRANSFORM_NORMAL;
1740}
1741
Rob Bradford66bd9f52013-06-25 18:56:42 +01001742static void
1743setup_output_seat_constraint(struct drm_compositor *ec,
1744 struct weston_output *output,
1745 const char *s)
1746{
1747 if (strcmp(s, "") != 0) {
1748 struct udev_seat *seat;
1749
1750 seat = udev_seat_get_named(&ec->base, s);
1751 if (seat)
1752 seat->base.output = output;
1753
1754 if (seat && seat->base.pointer)
1755 weston_pointer_clamp(seat->base.pointer,
1756 &seat->base.pointer->x,
1757 &seat->base.pointer->y);
1758 }
1759}
1760
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001761static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001762create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001763 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001764 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001765 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001766{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001767 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001768 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1769 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001770 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001771 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001772 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001773 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001774 int i, width, height, scale;
1775 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001776 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001777 enum output_config config;
1778 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001779
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001780 i = find_crtc_for_connector(ec, resources, connector);
1781 if (i < 0) {
1782 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001783 return -1;
1784 }
1785
Peter Huttererf3d62272013-08-08 11:57:05 +10001786 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001787 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001788 return -1;
1789
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001790 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1791 output->base.make = "unknown";
1792 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001793 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001794 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001795
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001796 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1797 type_name = connector_type_names[connector->connector_type];
1798 else
1799 type_name = "UNKNOWN";
1800 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001801 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001802
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001803 section = weston_config_get_section(ec->base.config, "output", "name",
1804 output->base.name);
1805 weston_config_section_get_string(section, "mode", &s, "preferred");
1806 if (strcmp(s, "off") == 0)
1807 config = OUTPUT_CONFIG_OFF;
1808 else if (strcmp(s, "preferred") == 0)
1809 config = OUTPUT_CONFIG_PREFERRED;
1810 else if (strcmp(s, "current") == 0)
1811 config = OUTPUT_CONFIG_CURRENT;
1812 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1813 config = OUTPUT_CONFIG_MODE;
1814 else if (parse_modeline(s, &modeline) == 0)
1815 config = OUTPUT_CONFIG_MODELINE;
1816 else {
1817 weston_log("Invalid mode \"%s\" for output %s\n",
1818 s, output->base.name);
1819 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001820 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001821 free(s);
1822
1823 weston_config_section_get_int(section, "scale", &scale, 1);
1824 weston_config_section_get_string(section, "transform", &s, "normal");
1825 transform = parse_transform(s, output->base.name);
1826 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001827
Rob Bradford66bd9f52013-06-25 18:56:42 +01001828 weston_config_section_get_string(section, "seat", &s, "");
1829 setup_output_seat_constraint(ec, &output->base, s);
1830 free(s);
1831
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001832 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001833 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001834 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001835 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001836 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001837
Matt Roper361d2ad2011-08-29 13:52:23 -07001838 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001839 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001840
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001841 /* Get the current mode on the crtc that's currently driving
1842 * this connector. */
1843 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001844 memset(&crtc_mode, 0, sizeof crtc_mode);
1845 if (encoder != NULL) {
1846 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1847 drmModeFreeEncoder(encoder);
1848 if (crtc == NULL)
1849 goto err_free;
1850 if (crtc->mode_valid)
1851 crtc_mode = crtc->mode;
1852 drmModeFreeCrtc(crtc);
1853 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001854
David Herrmann0f0d54e2011-12-08 17:05:45 +01001855 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001856 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001857 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001858 goto err_free;
1859 }
1860
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001861 if (config == OUTPUT_CONFIG_OFF) {
1862 weston_log("Disabling output %s\n", output->base.name);
1863 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1864 0, 0, 0, 0, 0, NULL);
1865 goto err_free;
1866 }
1867
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001868 preferred = NULL;
1869 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001870 configured = NULL;
1871
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001872 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001873 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001874 width == drm_mode->base.width &&
1875 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001876 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001877 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001878 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001879 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001880 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001881 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001882
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001883 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001884 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001885 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001886 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001887 }
1888
Wang Quanxianacb805a2012-07-30 18:09:46 -04001889 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001890 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001891 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001892 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001893 }
1894
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001895 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001896 configured = current;
1897
Wang Quanxianacb805a2012-07-30 18:09:46 -04001898 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001899 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001900 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001901 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001902 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001903 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001904 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001905 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001906
1907 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001908 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001909 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001910 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001911
Wang Quanxianacb805a2012-07-30 18:09:46 -04001912 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1913
John Kåre Alsaker94659272012-11-13 19:10:18 +01001914 weston_output_init(&output->base, &ec->base, x, y,
1915 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001916 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001917
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001918 if (ec->use_pixman) {
1919 if (drm_output_init_pixman(output, ec) < 0) {
1920 weston_log("Failed to init output pixman state\n");
1921 goto err_output;
1922 }
1923 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001924 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001925 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001926 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001927
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001928 output->backlight = backlight_init(drm_device,
1929 connector->connector_type);
1930 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001931 weston_log("Initialized backlight, device %s\n",
1932 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001933 output->base.set_backlight = drm_set_backlight;
1934 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001935 } else {
1936 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001937 }
1938
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001939 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1940
Richard Hughes2b2092a2013-04-24 14:58:02 +01001941 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001942 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1943 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001944
Alex Wubd3354b2012-04-17 17:20:49 +08001945 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001946 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001947 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001948 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001949 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001950 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001951 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001952
Richard Hughese7299962013-05-01 21:52:12 +01001953 output->base.gamma_size = output->original_crtc->gamma_size;
1954 output->base.set_gamma = drm_output_set_gamma;
1955
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001956 weston_plane_init(&output->cursor_plane, 0, 0);
1957 weston_plane_init(&output->fb_plane, 0, 0);
1958
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001959 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1960 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1961 &ec->base.primary_plane);
1962
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001963 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001964 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001965 wl_list_for_each(m, &output->base.mode_list, link)
1966 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1967 m->width, m->height, m->refresh / 1000.0,
1968 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1969 ", preferred" : "",
1970 m->flags & WL_OUTPUT_MODE_CURRENT ?
1971 ", current" : "",
1972 connector->count_modes == 0 ?
1973 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001974
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001975 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001976
John Kåre Alsaker94659272012-11-13 19:10:18 +01001977err_output:
1978 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001979err_free:
1980 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1981 base.link) {
1982 wl_list_remove(&drm_mode->base.link);
1983 free(drm_mode);
1984 }
1985
1986 drmModeFreeCrtc(output->original_crtc);
1987 ec->crtc_allocator &= ~(1 << output->crtc_id);
1988 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001989 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001990
David Herrmann0f0d54e2011-12-08 17:05:45 +01001991 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001992}
1993
Jesse Barnes58ef3792012-02-23 09:45:49 -05001994static void
1995create_sprites(struct drm_compositor *ec)
1996{
1997 struct drm_sprite *sprite;
1998 drmModePlaneRes *plane_res;
1999 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002000 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002001
2002 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2003 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002004 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002005 strerror(errno));
2006 return;
2007 }
2008
2009 for (i = 0; i < plane_res->count_planes; i++) {
2010 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2011 if (!plane)
2012 continue;
2013
Peter Huttererf3d62272013-08-08 11:57:05 +10002014 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002015 plane->count_formats));
2016 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002017 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002018 __func__);
2019 free(plane);
2020 continue;
2021 }
2022
Jesse Barnes58ef3792012-02-23 09:45:49 -05002023 sprite->possible_crtcs = plane->possible_crtcs;
2024 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002025 sprite->current = NULL;
2026 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002027 sprite->compositor = ec;
2028 sprite->count_formats = plane->count_formats;
2029 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002030 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002031 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002032 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002033 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2034 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002035
2036 wl_list_insert(&ec->sprite_list, &sprite->link);
2037 }
2038
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002039 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002040}
2041
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002042static void
2043destroy_sprites(struct drm_compositor *compositor)
2044{
2045 struct drm_sprite *sprite, *next;
2046 struct drm_output *output;
2047
2048 output = container_of(compositor->base.output_list.next,
2049 struct drm_output, base.link);
2050
2051 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2052 drmModeSetPlane(compositor->drm.fd,
2053 sprite->plane_id,
2054 output->crtc_id, 0, 0,
2055 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002056 drm_output_release_fb(output, sprite->current);
2057 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002058 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002059 free(sprite);
2060 }
2061}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002062
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002063static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002064create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002065 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002066{
2067 drmModeConnector *connector;
2068 drmModeRes *resources;
2069 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002070 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002071
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002072 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002073 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002074 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002075 return -1;
2076 }
2077
Jesse Barnes58ef3792012-02-23 09:45:49 -05002078 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002079 if (!ec->crtcs) {
2080 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002081 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002082 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002083
Rob Clark4339add2012-08-09 14:18:28 -05002084 ec->min_width = resources->min_width;
2085 ec->max_width = resources->max_width;
2086 ec->min_height = resources->min_height;
2087 ec->max_height = resources->max_height;
2088
Jesse Barnes58ef3792012-02-23 09:45:49 -05002089 ec->num_crtcs = resources->count_crtcs;
2090 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2091
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002092 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002093 connector = drmModeGetConnector(ec->drm.fd,
2094 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002095 if (connector == NULL)
2096 continue;
2097
2098 if (connector->connection == DRM_MODE_CONNECTED &&
2099 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002100 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002101 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002102 connector, x, y,
2103 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002104 drmModeFreeConnector(connector);
2105 continue;
2106 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002107
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002108 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002109 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002110 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002111 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002112
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002113 drmModeFreeConnector(connector);
2114 }
2115
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002116 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002117 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002118 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002119 return -1;
2120 }
2121
2122 drmModeFreeResources(resources);
2123
2124 return 0;
2125}
2126
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002127static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002128update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002129{
2130 drmModeConnector *connector;
2131 drmModeRes *resources;
2132 struct drm_output *output, *next;
2133 int x = 0, y = 0;
2134 int x_offset = 0, y_offset = 0;
2135 uint32_t connected = 0, disconnects = 0;
2136 int i;
2137
2138 resources = drmModeGetResources(ec->drm.fd);
2139 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002140 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002141 return;
2142 }
2143
2144 /* collect new connects */
2145 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002146 int connector_id = resources->connectors[i];
2147
2148 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002149 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002150 continue;
2151
David Herrmann7551cff2011-12-08 17:05:43 +01002152 if (connector->connection != DRM_MODE_CONNECTED) {
2153 drmModeFreeConnector(connector);
2154 continue;
2155 }
2156
Benjamin Franzke117483d2011-08-30 11:38:26 +02002157 connected |= (1 << connector_id);
2158
2159 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002160 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002161 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002162 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002163
2164 /* XXX: not yet needed, we die with 0 outputs */
2165 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002166 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002167 else
2168 x = 0;
2169 y = 0;
2170 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002171 connector, x, y,
2172 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002173 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002174
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002175 }
2176 drmModeFreeConnector(connector);
2177 }
2178 drmModeFreeResources(resources);
2179
2180 disconnects = ec->connector_allocator & ~connected;
2181 if (disconnects) {
2182 wl_list_for_each_safe(output, next, &ec->base.output_list,
2183 base.link) {
2184 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002185 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002186 output->base.x - x_offset,
2187 output->base.y - y_offset);
2188 }
2189
2190 if (disconnects & (1 << output->connector_id)) {
2191 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002192 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002193 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002194 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002195 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002196 }
2197 }
2198 }
2199
2200 /* FIXME: handle zero outputs, without terminating */
2201 if (ec->connector_allocator == 0)
2202 wl_display_terminate(ec->base.wl_display);
2203}
2204
2205static int
David Herrmannd7488c22012-03-11 20:05:21 +01002206udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002207{
David Herrmannd7488c22012-03-11 20:05:21 +01002208 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002209 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002210
2211 sysnum = udev_device_get_sysnum(device);
2212 if (!sysnum || atoi(sysnum) != ec->drm.id)
2213 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002214
David Herrmann6ac52db2012-03-11 20:05:22 +01002215 val = udev_device_get_property_value(device, "HOTPLUG");
2216 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002217 return 0;
2218
David Herrmann6ac52db2012-03-11 20:05:22 +01002219 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002220}
2221
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002222static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002223udev_drm_event(int fd, uint32_t mask, void *data)
2224{
2225 struct drm_compositor *ec = data;
2226 struct udev_device *event;
2227
2228 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002229
David Herrmannd7488c22012-03-11 20:05:21 +01002230 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002231 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002232
2233 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002234
2235 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002236}
2237
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002238static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002239drm_restore(struct weston_compositor *ec)
2240{
2241 struct drm_compositor *d = (struct drm_compositor *) ec;
2242
2243 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2244 weston_log("failed to drop master: %m\n");
2245 tty_reset(d->tty);
2246}
2247
2248static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002249drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002250{
2251 struct drm_compositor *d = (struct drm_compositor *) ec;
2252
Rob Bradfordd355b802013-05-31 18:09:55 +01002253 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002254
2255 wl_event_source_remove(d->udev_drm_source);
2256 wl_event_source_remove(d->drm_source);
2257
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002258 destroy_sprites(d);
2259
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002260 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002261
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002262 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002263
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002264 if (d->gbm)
2265 gbm_device_destroy(d->gbm);
2266
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002267 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002268 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002269 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002270
Rob Bradford45c15b82013-07-26 16:29:35 +01002271 close(d->drm.fd);
2272
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002273 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002274}
2275
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002276static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002277drm_compositor_set_modes(struct drm_compositor *compositor)
2278{
2279 struct drm_output *output;
2280 struct drm_mode *drm_mode;
2281 int ret;
2282
2283 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002284 if (!output->current) {
2285 /* If something that would cause the output to
2286 * switch mode happened while in another vt, we
2287 * might not have a current drm_fb. In that case,
2288 * schedule a repaint and let drm_output_repaint
2289 * handle setting the mode. */
2290 weston_output_schedule_repaint(&output->base);
2291 continue;
2292 }
2293
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002294 drm_mode = (struct drm_mode *) output->base.current;
2295 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002296 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002297 &output->connector_id, 1,
2298 &drm_mode->mode_info);
2299 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002300 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002301 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002302 drm_mode->base.width, drm_mode->base.height,
2303 output->base.x, output->base.y);
2304 }
2305 }
2306}
2307
2308static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002309vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002310{
2311 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002312 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002313 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002314
2315 switch (event) {
2316 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002317 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002318 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002319 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002320 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002321 wl_display_terminate(compositor->wl_display);
2322 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002323 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002324 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002325 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002326 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002327 break;
2328 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002329 weston_log("leaving VT\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002330 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002331
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002332 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002333 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002334 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002335
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002336 /* If we have a repaint scheduled (either from a
2337 * pending pageflip or the idle handler), make sure we
2338 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002339 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002340 * further attemps at repainting. When we switch
2341 * back, we schedule a repaint, which will process
2342 * pending frame callbacks. */
2343
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002344 wl_list_for_each(output, &ec->base.output_list, base.link) {
2345 output->base.repaint_needed = 0;
2346 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002347 }
2348
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002349 output = container_of(ec->base.output_list.next,
2350 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002351
2352 wl_list_for_each(sprite, &ec->sprite_list, link)
2353 drmModeSetPlane(ec->drm.fd,
2354 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002355 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002356 0, 0, 0, 0, 0, 0, 0, 0);
2357
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002358 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002359 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002360
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002361 break;
2362 };
2363}
2364
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002365static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002366switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002367{
2368 struct drm_compositor *ec = data;
2369
Daniel Stone325fc2d2012-05-30 16:31:58 +01002370 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002371}
2372
David Herrmann0af066f2012-10-29 19:21:16 +01002373/*
2374 * Find primary GPU
2375 * Some systems may have multiple DRM devices attached to a single seat. This
2376 * function loops over all devices and tries to find a PCI device with the
2377 * boot_vga sysfs attribute set to 1.
2378 * If no such device is found, the first DRM device reported by udev is used.
2379 */
2380static struct udev_device*
2381find_primary_gpu(struct drm_compositor *ec, const char *seat)
2382{
2383 struct udev_enumerate *e;
2384 struct udev_list_entry *entry;
2385 const char *path, *device_seat, *id;
2386 struct udev_device *device, *drm_device, *pci;
2387
2388 e = udev_enumerate_new(ec->udev);
2389 udev_enumerate_add_match_subsystem(e, "drm");
2390 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2391
2392 udev_enumerate_scan_devices(e);
2393 drm_device = NULL;
2394 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2395 path = udev_list_entry_get_name(entry);
2396 device = udev_device_new_from_syspath(ec->udev, path);
2397 if (!device)
2398 continue;
2399 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2400 if (!device_seat)
2401 device_seat = default_seat;
2402 if (strcmp(device_seat, seat)) {
2403 udev_device_unref(device);
2404 continue;
2405 }
2406
2407 pci = udev_device_get_parent_with_subsystem_devtype(device,
2408 "pci", NULL);
2409 if (pci) {
2410 id = udev_device_get_sysattr_value(pci, "boot_vga");
2411 if (id && !strcmp(id, "1")) {
2412 if (drm_device)
2413 udev_device_unref(drm_device);
2414 drm_device = device;
2415 break;
2416 }
2417 }
2418
2419 if (!drm_device)
2420 drm_device = device;
2421 else
2422 udev_device_unref(device);
2423 }
2424
2425 udev_enumerate_unref(e);
2426 return drm_device;
2427}
2428
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002429static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002430planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002431{
2432 struct drm_compositor *c = data;
2433
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002434 switch (key) {
2435 case KEY_C:
2436 c->cursors_are_broken ^= 1;
2437 break;
2438 case KEY_V:
2439 c->sprites_are_broken ^= 1;
2440 break;
2441 case KEY_O:
2442 c->sprites_hidden ^= 1;
2443 break;
2444 default:
2445 break;
2446 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002447}
2448
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002449#ifdef HAVE_LIBVA
2450static void
2451recorder_frame_notify(struct wl_listener *listener, void *data)
2452{
2453 struct drm_output *output;
2454 struct drm_compositor *c;
2455 int fd, ret;
2456
2457 output = container_of(listener, struct drm_output,
2458 recorder_frame_listener);
2459 c = (struct drm_compositor *) output->base.compositor;
2460
2461 if (!output->recorder)
2462 return;
2463
2464 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2465 DRM_CLOEXEC, &fd);
2466 if (ret) {
2467 weston_log("[libva recorder] "
2468 "failed to create prime fd for front buffer\n");
2469 return;
2470 }
2471
2472 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
2473
2474 close(fd);
2475}
2476
2477static void *
2478create_recorder(struct drm_compositor *c, int width, int height,
2479 const char *filename)
2480{
2481 int fd;
2482 drm_magic_t magic;
2483
2484 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2485 if (fd < 0)
2486 return NULL;
2487
2488 drmGetMagic(fd, &magic);
2489 drmAuthMagic(c->drm.fd, magic);
2490
2491 return vaapi_recorder_create(fd, width, height, filename);
2492}
2493
2494static void
2495recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2496 void *data)
2497{
2498 struct drm_compositor *c = data;
2499 struct drm_output *output;
2500 int width, height;
2501
2502 output = container_of(c->base.output_list.next,
2503 struct drm_output, base.link);
2504
2505 if (!output->recorder) {
2506 width = output->base.current->width;
2507 height = output->base.current->height;
2508
2509 output->recorder =
2510 create_recorder(c, width, height, "capture.h264");
2511 if (!output->recorder) {
2512 weston_log("failed to create vaapi recorder\n");
2513 return;
2514 }
2515
2516 output->base.disable_planes++;
2517
2518 output->recorder_frame_listener.notify = recorder_frame_notify;
2519 wl_signal_add(&output->base.frame_signal,
2520 &output->recorder_frame_listener);
2521
2522 weston_output_schedule_repaint(&output->base);
2523
2524 weston_log("[libva recorder] initialized\n");
2525 } else {
2526 vaapi_recorder_destroy(output->recorder);
2527 /* FIXME: close drm fd passed to recorder */
2528 output->recorder = NULL;
2529
2530 output->base.disable_planes--;
2531
2532 wl_list_remove(&output->recorder_frame_listener.link);
2533 weston_log("[libva recorder] done\n");
2534 }
2535}
2536#else
2537static void
2538recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2539 void *data)
2540{
2541 weston_log("Compiled without libva support\n");
2542}
2543#endif
2544
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002545static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002546drm_compositor_create(struct wl_display *display,
Rob Bradford643641d2013-05-31 18:09:53 +01002547 int connector, const char *seat_id, int tty, int pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002548 int *argc, char *argv[],
2549 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002550{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002551 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002552 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002553 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002554 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002555 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002556
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002557 weston_log("initializing drm backend\n");
2558
Peter Huttererf3d62272013-08-08 11:57:05 +10002559 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002560 if (ec == NULL)
2561 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002562
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002563 /* KMS support for sprites is not complete yet, so disable the
2564 * functionality for now. */
2565 ec->sprites_are_broken = 1;
2566
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002567 ec->use_pixman = pixman;
2568
Daniel Stone725c2c32012-06-22 14:04:36 +01002569 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002570 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002571 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002572 goto err_base;
2573 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002574
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002575 /* Check if we run drm-backend using weston-launch */
Kristian Høgsberg3c95e702013-07-23 12:24:00 -07002576 ec->base.launcher_sock =
2577 weston_environment_get_fd("WESTON_LAUNCHER_SOCK");
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002578 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002579 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002580 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002581 goto err_compositor;
2582 }
2583
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002584 ec->udev = udev_new();
2585 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002586 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002587 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002588 }
2589
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002590 ec->base.wl_display = display;
2591 ec->tty = tty_create(&ec->base, vt_func, tty);
2592 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002593 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002594 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002595 }
2596
Rob Bradford643641d2013-05-31 18:09:53 +01002597 drm_device = find_primary_gpu(ec, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002598 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002599 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002600 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002601 }
David Herrmann0af066f2012-10-29 19:21:16 +01002602 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002603
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002604 if (init_drm(ec, drm_device) < 0) {
2605 weston_log("failed to initialize kms\n");
2606 goto err_udev_dev;
2607 }
2608
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002609 if (ec->use_pixman) {
2610 if (init_pixman(ec) < 0) {
2611 weston_log("failed to initialize pixman renderer\n");
2612 goto err_udev_dev;
2613 }
2614 } else {
2615 if (init_egl(ec) < 0) {
2616 weston_log("failed to initialize egl\n");
2617 goto err_udev_dev;
2618 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002619 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002620
2621 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002622 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002623
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002624 ec->base.focus = 1;
2625
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002626 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002627
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002628 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002629 weston_compositor_add_key_binding(&ec->base, key,
2630 MODIFIER_CTRL | MODIFIER_ALT,
2631 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002632
Jesse Barnes58ef3792012-02-23 09:45:49 -05002633 wl_list_init(&ec->sprite_list);
2634 create_sprites(ec);
2635
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002636 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002637 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002638 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002639 }
2640
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002641 path = NULL;
2642
Rob Bradfordd355b802013-05-31 18:09:55 +01002643 if (udev_input_init(&ec->input, &ec->base, ec->udev, seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002644 weston_log("failed to create input devices\n");
2645 goto err_sprite;
2646 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002647
2648 loop = wl_display_get_event_loop(ec->base.wl_display);
2649 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002650 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002651 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002652
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002653 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2654 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002655 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002656 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002657 }
2658 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2659 "drm", NULL);
2660 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002661 wl_event_loop_add_fd(loop,
2662 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002663 WL_EVENT_READABLE, udev_drm_event, ec);
2664
2665 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002666 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002667 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002668 }
2669
Daniel Stonea96b93c2012-06-22 14:04:37 +01002670 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002671
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002672 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002673 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002674 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002675 planes_binding, ec);
2676 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2677 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002678 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2679 recorder_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002680
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002681 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002682
2683err_udev_monitor:
2684 wl_event_source_remove(ec->udev_drm_source);
2685 udev_monitor_unref(ec->udev_monitor);
2686err_drm_source:
2687 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002688 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002689err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002690 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002691 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002692 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002693err_udev_dev:
2694 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002695err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002696 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2697 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002698 tty_destroy(ec->tty);
2699err_udev:
2700 udev_unref(ec->udev);
2701err_compositor:
2702 weston_compositor_shutdown(&ec->base);
2703err_base:
2704 free(ec);
2705 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002706}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002707
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002708WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002709backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002710 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002711{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002712 int connector = 0, tty = 0, use_pixman = 0;
Rob Bradford643641d2013-05-31 18:09:53 +01002713 const char *seat_id = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002714
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002715 const struct weston_option drm_options[] = {
2716 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
Rob Bradford643641d2013-05-31 18:09:53 +01002717 { WESTON_OPTION_STRING, "seat", 0, &seat_id },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002718 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002719 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002720 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002721 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002722
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002723 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002724
Rob Bradford643641d2013-05-31 18:09:53 +01002725 return drm_compositor_create(display, connector, seat_id, tty, use_pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002726 argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002727}