blob: eb3ec612f5cd7e561d9881cb66443877a5471b51 [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,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700459 buffer->resource, 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,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700825 es->buffer_ref.buffer->resource,
826 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400827 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400828 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400829
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500830 format = drm_output_check_sprite_format(s, es, bo);
831 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200832 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400833 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500834 }
835
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200836 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200837 if (!s->next) {
838 gbm_bo_destroy(bo);
839 return NULL;
840 }
841
Pekka Paalanende685b82012-12-04 15:58:12 +0200842 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500843
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400844 box = pixman_region32_extents(&es->transform.boundingbox);
845 s->plane.x = box->x1;
846 s->plane.y = box->y1;
847
Jesse Barnes58ef3792012-02-23 09:45:49 -0500848 /*
849 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200850 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500851 * for us already).
852 */
853 pixman_region32_init(&dest_rect);
854 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
855 &output_base->region);
856 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
857 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200858 tbox = weston_transformed_rect(output_base->width,
859 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200860 output_base->transform,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200861 output_base->scale,
862 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200863 s->dest_x = tbox.x1;
864 s->dest_y = tbox.y1;
865 s->dest_w = tbox.x2 - tbox.x1;
866 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500867 pixman_region32_fini(&dest_rect);
868
869 pixman_region32_init(&src_rect);
870 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
871 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500872 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400873
874 weston_surface_from_global_fixed(es,
875 wl_fixed_from_int(box->x1),
876 wl_fixed_from_int(box->y1),
877 &sx1, &sy1);
878 weston_surface_from_global_fixed(es,
879 wl_fixed_from_int(box->x2),
880 wl_fixed_from_int(box->y2),
881 &sx2, &sy2);
882
883 if (sx1 < 0)
884 sx1 = 0;
885 if (sy1 < 0)
886 sy1 = 0;
887 if (sx2 > wl_fixed_from_int(es->geometry.width))
888 sx2 = wl_fixed_from_int(es->geometry.width);
889 if (sy2 > wl_fixed_from_int(es->geometry.height))
890 sy2 = wl_fixed_from_int(es->geometry.height);
891
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200892 tbox.x1 = sx1;
893 tbox.y1 = sy1;
894 tbox.x2 = sx2;
895 tbox.y2 = sy2;
896
897 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
898 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200899 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200900
901 s->src_x = tbox.x1 << 8;
902 s->src_y = tbox.y1 << 8;
903 s->src_w = (tbox.x2 - tbox.x1) << 8;
904 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500905 pixman_region32_fini(&src_rect);
906
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400907 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500908}
909
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400910static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400911drm_output_prepare_cursor_surface(struct weston_output *output_base,
912 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500913{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400914 struct drm_compositor *c =
915 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400916 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400917
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200918 if (c->gbm == NULL)
919 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200920 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
921 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400922 if (output->cursor_surface)
923 return NULL;
924 if (es->output_mask != (1u << output_base->id))
925 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500926 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400927 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200928 if (es->buffer_ref.buffer == NULL ||
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500929 !wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400930 es->geometry.width > 64 || es->geometry.height > 64)
931 return NULL;
932
933 output->cursor_surface = es;
934
935 return &output->cursor_plane;
936}
937
938static void
939drm_output_set_cursor(struct drm_output *output)
940{
941 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400942 struct drm_compositor *c =
943 (struct drm_compositor *) output->base.compositor;
944 EGLint handle, stride;
945 struct gbm_bo *bo;
946 uint32_t buf[64 * 64];
947 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400948 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500949
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400950 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400951 if (es == NULL) {
952 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
953 return;
954 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500955
Pekka Paalanende685b82012-12-04 15:58:12 +0200956 if (es->buffer_ref.buffer &&
957 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400958 pixman_region32_fini(&output->cursor_plane.damage);
959 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400960 output->current_cursor ^= 1;
961 bo = output->cursor_bo[output->current_cursor];
962 memset(buf, 0, sizeof buf);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500963 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
964 s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400965 for (i = 0; i < es->geometry.height; i++)
966 memcpy(buf + i * 64, s + i * stride,
967 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500968
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400969 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300970 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400971
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400972 handle = gbm_bo_get_handle(bo).s32;
973 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500974 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300975 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500976 c->cursors_are_broken = 1;
977 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400978 }
979
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200980 x = (es->geometry.x - output->base.x) * output->base.scale;
981 y = (es->geometry.y - output->base.y) * output->base.scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400982 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500983 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400984 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500985 c->cursors_are_broken = 1;
986 }
987
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400988 output->cursor_plane.x = x;
989 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400990 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500991}
992
Jesse Barnes58ef3792012-02-23 09:45:49 -0500993static void
994drm_assign_planes(struct weston_output *output)
995{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400996 struct drm_compositor *c =
997 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400998 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500999 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001000 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001001
1002 /*
1003 * Find a surface for each sprite in the output using some heuristics:
1004 * 1) size
1005 * 2) frequency of update
1006 * 3) opacity (though some hw might support alpha blending)
1007 * 4) clipping (this can be fixed with color keys)
1008 *
1009 * The idea is to save on blitting since this should save power.
1010 * If we can get a large video surface on the sprite for example,
1011 * the main display surface may not need to update at all, and
1012 * the client buffer can be used directly for the sprite surface
1013 * as we do for flipping full screen surfaces.
1014 */
1015 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001016 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001017 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001018 /* test whether this buffer can ever go into a plane:
1019 * non-shm, or small enough to be a cursor
1020 */
1021 if ((es->buffer_ref.buffer &&
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001022 !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) ||
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001023 (es->geometry.width <= 64 && es->geometry.height <= 64))
1024 es->keep_buffer = 1;
1025 else
1026 es->keep_buffer = 0;
1027
Jesse Barnes58ef3792012-02-23 09:45:49 -05001028 pixman_region32_init(&surface_overlap);
1029 pixman_region32_intersect(&surface_overlap, &overlap,
1030 &es->transform.boundingbox);
1031
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001032 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001033 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001034 next_plane = primary;
1035 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001036 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001037 if (next_plane == NULL)
1038 next_plane = drm_output_prepare_scanout_surface(output, es);
1039 if (next_plane == NULL)
1040 next_plane = drm_output_prepare_overlay_surface(output, es);
1041 if (next_plane == NULL)
1042 next_plane = primary;
1043 weston_surface_move_to_plane(es, next_plane);
1044 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001045 pixman_region32_union(&overlap, &overlap,
1046 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001047
Jesse Barnes58ef3792012-02-23 09:45:49 -05001048 pixman_region32_fini(&surface_overlap);
1049 }
1050 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001051}
1052
Matt Roper361d2ad2011-08-29 13:52:23 -07001053static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001054drm_output_fini_pixman(struct drm_output *output);
1055
1056static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001057drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001058{
1059 struct drm_output *output = (struct drm_output *) output_base;
1060 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001061 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001062 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001063
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001064 if (output->backlight)
1065 backlight_destroy(output->backlight);
1066
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001067 drmModeFreeProperty(output->dpms_prop);
1068
Matt Roper361d2ad2011-08-29 13:52:23 -07001069 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001070 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001071
1072 /* Restore original CRTC state */
1073 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001074 origcrtc->x, origcrtc->y,
1075 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001076 drmModeFreeCrtc(origcrtc);
1077
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001078 c->crtc_allocator &= ~(1 << output->crtc_id);
1079 c->connector_allocator &= ~(1 << output->connector_id);
1080
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001081 if (c->use_pixman) {
1082 drm_output_fini_pixman(output);
1083 } else {
1084 gl_renderer_output_destroy(output_base);
1085 gbm_surface_destroy(output->surface);
1086 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001087
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001088 weston_plane_release(&output->fb_plane);
1089 weston_plane_release(&output->cursor_plane);
1090
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001091 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001092 wl_list_remove(&output->base.link);
1093
Matt Roper361d2ad2011-08-29 13:52:23 -07001094 free(output);
1095}
1096
Alex Wub7b8bda2012-04-17 17:20:48 +08001097static struct drm_mode *
1098choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1099{
1100 struct drm_mode *tmp_mode = NULL, *mode;
1101
1102 if (output->base.current->width == target_mode->width &&
1103 output->base.current->height == target_mode->height &&
1104 (output->base.current->refresh == target_mode->refresh ||
1105 target_mode->refresh == 0))
1106 return (struct drm_mode *)output->base.current;
1107
1108 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1109 if (mode->mode_info.hdisplay == target_mode->width &&
1110 mode->mode_info.vdisplay == target_mode->height) {
1111 if (mode->mode_info.vrefresh == target_mode->refresh ||
1112 target_mode->refresh == 0) {
1113 return mode;
1114 } else if (!tmp_mode)
1115 tmp_mode = mode;
1116 }
1117 }
1118
1119 return tmp_mode;
1120}
1121
1122static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001123drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001124static int
1125drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001126
1127static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001128drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1129{
1130 struct drm_output *output;
1131 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001132 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001133
1134 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001135 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001136 return -1;
1137 }
1138
1139 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001140 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001141 return -1;
1142 }
1143
1144 ec = (struct drm_compositor *)output_base->compositor;
1145 output = (struct drm_output *)output_base;
1146 drm_mode = choose_mode (output, mode);
1147
1148 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001149 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001150 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001151 }
1152
1153 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001154 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001155
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001156 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001157
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001158 output->base.current = &drm_mode->base;
1159 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001160 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1161
Alex Wub7b8bda2012-04-17 17:20:48 +08001162 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001163 drm_output_release_fb(output, output->current);
1164 drm_output_release_fb(output, output->next);
1165 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001166
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001167 if (ec->use_pixman) {
1168 drm_output_fini_pixman(output);
1169 if (drm_output_init_pixman(output, ec) < 0) {
1170 weston_log("failed to init output pixman state with "
1171 "new mode\n");
1172 return -1;
1173 }
1174 } else {
1175 gl_renderer_output_destroy(&output->base);
1176 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001177
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001178 if (drm_output_init_egl(output, ec) < 0) {
1179 weston_log("failed to init output egl state with "
1180 "new mode");
1181 return -1;
1182 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001183 }
1184
Alex Wub7b8bda2012-04-17 17:20:48 +08001185 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001186}
1187
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001188static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001189on_drm_input(int fd, uint32_t mask, void *data)
1190{
1191 drmEventContext evctx;
1192
1193 memset(&evctx, 0, sizeof evctx);
1194 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1195 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001196 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001197 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001198
1199 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001200}
1201
1202static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001203init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001204{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001205 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001206 uint64_t cap;
1207 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001208
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001209 sysnum = udev_device_get_sysnum(device);
1210 if (sysnum)
1211 ec->drm.id = atoi(sysnum);
1212 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001213 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001214 return -1;
1215 }
1216
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001217 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001218 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001219 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001220 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001221 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001222 udev_device_get_devnode(device));
1223 return -1;
1224 }
1225
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001226 weston_log("using %s\n", filename);
1227
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001228 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001229 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001230
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001231 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1232 if (ret == 0 && cap == 1)
1233 ec->clock = CLOCK_MONOTONIC;
1234 else
1235 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001236
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001237 return 0;
1238}
1239
1240static int
1241init_egl(struct drm_compositor *ec)
1242{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001243 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001244
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001245 if (!ec->gbm)
1246 return -1;
1247
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001248 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001249 NULL) < 0) {
1250 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001251 return -1;
1252 }
1253
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001254 return 0;
1255}
1256
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001257static int
1258init_pixman(struct drm_compositor *ec)
1259{
1260 return pixman_renderer_init(&ec->base);
1261}
1262
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001263static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001264drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001265{
1266 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001267 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001268
1269 mode = malloc(sizeof *mode);
1270 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001271 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001272
1273 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001274 mode->base.width = info->hdisplay;
1275 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001276
1277 /* Calculate higher precision (mHz) refresh rate */
1278 refresh = (info->clock * 1000000LL / info->htotal +
1279 info->vtotal / 2) / info->vtotal;
1280
1281 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1282 refresh *= 2;
1283 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1284 refresh /= 2;
1285 if (info->vscan > 1)
1286 refresh /= info->vscan;
1287
1288 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001289 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001290
1291 if (info->type & DRM_MODE_TYPE_PREFERRED)
1292 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1293
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001294 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1295
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001296 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001297}
1298
1299static int
1300drm_subpixel_to_wayland(int drm_value)
1301{
1302 switch (drm_value) {
1303 default:
1304 case DRM_MODE_SUBPIXEL_UNKNOWN:
1305 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1306 case DRM_MODE_SUBPIXEL_NONE:
1307 return WL_OUTPUT_SUBPIXEL_NONE;
1308 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1309 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1310 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1311 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1312 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1313 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1314 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1315 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1316 }
1317}
1318
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001319/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001320static uint32_t
1321drm_get_backlight(struct drm_output *output)
1322{
1323 long brightness, max_brightness, norm;
1324
1325 brightness = backlight_get_brightness(output->backlight);
1326 max_brightness = backlight_get_max_brightness(output->backlight);
1327
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001328 /* convert it on a scale of 0 to 255 */
1329 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001330
1331 return (uint32_t) norm;
1332}
1333
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001334/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001335static void
1336drm_set_backlight(struct weston_output *output_base, uint32_t value)
1337{
1338 struct drm_output *output = (struct drm_output *) output_base;
1339 long max_brightness, new_brightness;
1340
1341 if (!output->backlight)
1342 return;
1343
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001344 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001345 return;
1346
1347 max_brightness = backlight_get_max_brightness(output->backlight);
1348
1349 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001350 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001351
1352 backlight_set_brightness(output->backlight, new_brightness);
1353}
1354
1355static drmModePropertyPtr
1356drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1357{
1358 drmModePropertyPtr props;
1359 int i;
1360
1361 for (i = 0; i < connector->count_props; i++) {
1362 props = drmModeGetProperty(fd, connector->props[i]);
1363 if (!props)
1364 continue;
1365
1366 if (!strcmp(props->name, name))
1367 return props;
1368
1369 drmModeFreeProperty(props);
1370 }
1371
1372 return NULL;
1373}
1374
1375static void
1376drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1377{
1378 struct drm_output *output = (struct drm_output *) output_base;
1379 struct weston_compositor *ec = output_base->compositor;
1380 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001381
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001382 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001383 return;
1384
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001385 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1386 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001387}
1388
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001389static const char *connector_type_names[] = {
1390 "None",
1391 "VGA",
1392 "DVI",
1393 "DVI",
1394 "DVI",
1395 "Composite",
1396 "TV",
1397 "LVDS",
1398 "CTV",
1399 "DIN",
1400 "DP",
1401 "HDMI",
1402 "HDMI",
1403 "TV",
1404 "eDP",
1405};
1406
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001407static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001408find_crtc_for_connector(struct drm_compositor *ec,
1409 drmModeRes *resources, drmModeConnector *connector)
1410{
1411 drmModeEncoder *encoder;
1412 uint32_t possible_crtcs;
1413 int i, j;
1414
1415 for (j = 0; j < connector->count_encoders; j++) {
1416 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1417 if (encoder == NULL) {
1418 weston_log("Failed to get encoder.\n");
1419 return -1;
1420 }
1421 possible_crtcs = encoder->possible_crtcs;
1422 drmModeFreeEncoder(encoder);
1423
1424 for (i = 0; i < resources->count_crtcs; i++) {
1425 if (possible_crtcs & (1 << i) &&
1426 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1427 return i;
1428 }
1429 }
1430
1431 return -1;
1432}
1433
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001434/* Init output state that depends on gl or gbm */
1435static int
1436drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1437{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001438 int i, flags;
1439
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001440 output->surface = gbm_surface_create(ec->gbm,
Alexander Larsson0b135062013-05-28 16:23:36 +02001441 output->base.current->width,
1442 output->base.current->height,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001443 GBM_FORMAT_XRGB8888,
1444 GBM_BO_USE_SCANOUT |
1445 GBM_BO_USE_RENDERING);
1446 if (!output->surface) {
1447 weston_log("failed to create gbm surface\n");
1448 return -1;
1449 }
1450
1451 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001452 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001453 gbm_surface_destroy(output->surface);
1454 return -1;
1455 }
1456
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001457 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1458
1459 for (i = 0; i < 2; i++) {
1460 if (output->cursor_bo[i])
1461 continue;
1462
1463 output->cursor_bo[i] =
1464 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1465 flags);
1466 }
1467
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001468 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1469 weston_log("cursor buffers unavailable, using gl cursors\n");
1470 ec->cursors_are_broken = 1;
1471 }
1472
1473 return 0;
1474}
1475
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001476static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001477drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1478{
1479 int w = output->base.current->width;
1480 int h = output->base.current->height;
1481 unsigned int i;
1482
1483 /* FIXME error checking */
1484
1485 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001486 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001487 if (!output->dumb[i])
1488 goto err;
1489
1490 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001491 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001492 output->dumb[i]->map,
1493 output->dumb[i]->stride);
1494 if (!output->image[i])
1495 goto err;
1496 }
1497
1498 if (pixman_renderer_output_create(&output->base) < 0)
1499 goto err;
1500
1501 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001502 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001503
1504 return 0;
1505
1506err:
1507 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1508 if (output->dumb[i])
1509 drm_fb_destroy_dumb(output->dumb[i]);
1510 if (output->image[i])
1511 pixman_image_unref(output->image[i]);
1512
1513 output->dumb[i] = NULL;
1514 output->image[i] = NULL;
1515 }
1516
1517 return -1;
1518}
1519
1520static void
1521drm_output_fini_pixman(struct drm_output *output)
1522{
1523 unsigned int i;
1524
1525 pixman_renderer_output_destroy(&output->base);
1526 pixman_region32_fini(&output->previous_damage);
1527
1528 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1529 drm_fb_destroy_dumb(output->dumb[i]);
1530 pixman_image_unref(output->image[i]);
1531 output->dumb[i] = NULL;
1532 output->image[i] = NULL;
1533 }
1534}
1535
Richard Hughes2b2092a2013-04-24 14:58:02 +01001536static void
1537edid_parse_string(const uint8_t *data, char text[])
1538{
1539 int i;
1540 int replaced = 0;
1541
1542 /* this is always 12 bytes, but we can't guarantee it's null
1543 * terminated or not junk. */
1544 strncpy(text, (const char *) data, 12);
1545
1546 /* remove insane chars */
1547 for (i = 0; text[i] != '\0'; i++) {
1548 if (text[i] == '\n' ||
1549 text[i] == '\r') {
1550 text[i] = '\0';
1551 break;
1552 }
1553 }
1554
1555 /* ensure string is printable */
1556 for (i = 0; text[i] != '\0'; i++) {
1557 if (!isprint(text[i])) {
1558 text[i] = '-';
1559 replaced++;
1560 }
1561 }
1562
1563 /* if the string is random junk, ignore the string */
1564 if (replaced > 4)
1565 text[0] = '\0';
1566}
1567
1568#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1569#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1570#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1571#define EDID_OFFSET_DATA_BLOCKS 0x36
1572#define EDID_OFFSET_LAST_BLOCK 0x6c
1573#define EDID_OFFSET_PNPID 0x08
1574#define EDID_OFFSET_SERIAL 0x0c
1575
1576static int
1577edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1578{
1579 int i;
1580 uint32_t serial_number;
1581
1582 /* check header */
1583 if (length < 128)
1584 return -1;
1585 if (data[0] != 0x00 || data[1] != 0xff)
1586 return -1;
1587
1588 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1589 * /--08--\/--09--\
1590 * 7654321076543210
1591 * |\---/\---/\---/
1592 * R C1 C2 C3 */
1593 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1594 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1595 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1596 edid->pnp_id[3] = '\0';
1597
1598 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1599 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1600 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1601 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1602 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1603 if (serial_number > 0)
1604 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1605
1606 /* parse EDID data */
1607 for (i = EDID_OFFSET_DATA_BLOCKS;
1608 i <= EDID_OFFSET_LAST_BLOCK;
1609 i += 18) {
1610 /* ignore pixel clock data */
1611 if (data[i] != 0)
1612 continue;
1613 if (data[i+2] != 0)
1614 continue;
1615
1616 /* any useful blocks? */
1617 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1618 edid_parse_string(&data[i+5],
1619 edid->monitor_name);
1620 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1621 edid_parse_string(&data[i+5],
1622 edid->serial_number);
1623 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1624 edid_parse_string(&data[i+5],
1625 edid->eisa_id);
1626 }
1627 }
1628 return 0;
1629}
1630
1631static void
1632find_and_parse_output_edid(struct drm_compositor *ec,
1633 struct drm_output *output,
1634 drmModeConnector *connector)
1635{
1636 drmModePropertyBlobPtr edid_blob = NULL;
1637 drmModePropertyPtr property;
1638 int i;
1639 int rc;
1640
1641 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1642 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1643 if (!property)
1644 continue;
1645 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1646 !strcmp(property->name, "EDID")) {
1647 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1648 connector->prop_values[i]);
1649 }
1650 drmModeFreeProperty(property);
1651 }
1652 if (!edid_blob)
1653 return;
1654
1655 rc = edid_parse(&output->edid,
1656 edid_blob->data,
1657 edid_blob->length);
1658 if (!rc) {
1659 weston_log("EDID data '%s', '%s', '%s'\n",
1660 output->edid.pnp_id,
1661 output->edid.monitor_name,
1662 output->edid.serial_number);
1663 if (output->edid.pnp_id[0] != '\0')
1664 output->base.make = output->edid.pnp_id;
1665 if (output->edid.monitor_name[0] != '\0')
1666 output->base.model = output->edid.monitor_name;
1667 if (output->edid.serial_number[0] != '\0')
1668 output->base.serial_number = output->edid.serial_number;
1669 }
1670 drmModeFreePropertyBlob(edid_blob);
1671}
1672
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001673
1674
1675static int
1676parse_modeline(const char *s, drmModeModeInfo *mode)
1677{
1678 char hsync[16];
1679 char vsync[16];
1680 float fclock;
1681
1682 mode->type = DRM_MODE_TYPE_USERDEF;
1683 mode->hskew = 0;
1684 mode->vscan = 0;
1685 mode->vrefresh = 0;
1686 mode->flags = 0;
1687
Rob Bradford307e09e2013-07-26 16:29:40 +01001688 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001689 &fclock,
1690 &mode->hdisplay,
1691 &mode->hsync_start,
1692 &mode->hsync_end,
1693 &mode->htotal,
1694 &mode->vdisplay,
1695 &mode->vsync_start,
1696 &mode->vsync_end,
1697 &mode->vtotal, hsync, vsync) != 11)
1698 return -1;
1699
1700 mode->clock = fclock * 1000;
1701 if (strcmp(hsync, "+hsync") == 0)
1702 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1703 else if (strcmp(hsync, "-hsync") == 0)
1704 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1705 else
1706 return -1;
1707
1708 if (strcmp(vsync, "+vsync") == 0)
1709 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1710 else if (strcmp(vsync, "-vsync") == 0)
1711 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1712 else
1713 return -1;
1714
1715 return 0;
1716}
1717
1718static uint32_t
1719parse_transform(const char *transform, const char *output_name)
1720{
1721 static const struct { const char *name; uint32_t token; } names[] = {
1722 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1723 { "90", WL_OUTPUT_TRANSFORM_90 },
1724 { "180", WL_OUTPUT_TRANSFORM_180 },
1725 { "270", WL_OUTPUT_TRANSFORM_270 },
1726 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1727 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1728 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1729 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1730 };
1731 unsigned int i;
1732
1733 for (i = 0; i < ARRAY_LENGTH(names); i++)
1734 if (strcmp(names[i].name, transform) == 0)
1735 return names[i].token;
1736
1737 weston_log("Invalid transform \"%s\" for output %s\n",
1738 transform, output_name);
1739
1740 return WL_OUTPUT_TRANSFORM_NORMAL;
1741}
1742
Rob Bradford66bd9f52013-06-25 18:56:42 +01001743static void
1744setup_output_seat_constraint(struct drm_compositor *ec,
1745 struct weston_output *output,
1746 const char *s)
1747{
1748 if (strcmp(s, "") != 0) {
1749 struct udev_seat *seat;
1750
1751 seat = udev_seat_get_named(&ec->base, s);
1752 if (seat)
1753 seat->base.output = output;
1754
1755 if (seat && seat->base.pointer)
1756 weston_pointer_clamp(seat->base.pointer,
1757 &seat->base.pointer->x,
1758 &seat->base.pointer->y);
1759 }
1760}
1761
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001762static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001763create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001764 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001765 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001766 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001767{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001768 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001769 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1770 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001771 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001772 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001773 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001774 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001775 int i, width, height, scale;
1776 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001777 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001778 enum output_config config;
1779 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001780
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001781 i = find_crtc_for_connector(ec, resources, connector);
1782 if (i < 0) {
1783 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001784 return -1;
1785 }
1786
Peter Huttererf3d62272013-08-08 11:57:05 +10001787 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001788 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001789 return -1;
1790
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001791 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1792 output->base.make = "unknown";
1793 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001794 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001795 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001796
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001797 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1798 type_name = connector_type_names[connector->connector_type];
1799 else
1800 type_name = "UNKNOWN";
1801 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001802 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001803
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001804 section = weston_config_get_section(ec->base.config, "output", "name",
1805 output->base.name);
1806 weston_config_section_get_string(section, "mode", &s, "preferred");
1807 if (strcmp(s, "off") == 0)
1808 config = OUTPUT_CONFIG_OFF;
1809 else if (strcmp(s, "preferred") == 0)
1810 config = OUTPUT_CONFIG_PREFERRED;
1811 else if (strcmp(s, "current") == 0)
1812 config = OUTPUT_CONFIG_CURRENT;
1813 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1814 config = OUTPUT_CONFIG_MODE;
1815 else if (parse_modeline(s, &modeline) == 0)
1816 config = OUTPUT_CONFIG_MODELINE;
1817 else {
1818 weston_log("Invalid mode \"%s\" for output %s\n",
1819 s, output->base.name);
1820 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001821 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001822 free(s);
1823
1824 weston_config_section_get_int(section, "scale", &scale, 1);
1825 weston_config_section_get_string(section, "transform", &s, "normal");
1826 transform = parse_transform(s, output->base.name);
1827 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001828
Rob Bradford66bd9f52013-06-25 18:56:42 +01001829 weston_config_section_get_string(section, "seat", &s, "");
1830 setup_output_seat_constraint(ec, &output->base, s);
1831 free(s);
1832
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001833 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001834 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001835 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001836 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001837 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001838
Matt Roper361d2ad2011-08-29 13:52:23 -07001839 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001840 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001841
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001842 /* Get the current mode on the crtc that's currently driving
1843 * this connector. */
1844 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001845 memset(&crtc_mode, 0, sizeof crtc_mode);
1846 if (encoder != NULL) {
1847 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1848 drmModeFreeEncoder(encoder);
1849 if (crtc == NULL)
1850 goto err_free;
1851 if (crtc->mode_valid)
1852 crtc_mode = crtc->mode;
1853 drmModeFreeCrtc(crtc);
1854 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001855
David Herrmann0f0d54e2011-12-08 17:05:45 +01001856 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001857 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001858 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001859 goto err_free;
1860 }
1861
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001862 if (config == OUTPUT_CONFIG_OFF) {
1863 weston_log("Disabling output %s\n", output->base.name);
1864 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1865 0, 0, 0, 0, 0, NULL);
1866 goto err_free;
1867 }
1868
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001869 preferred = NULL;
1870 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001871 configured = NULL;
1872
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001873 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001874 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001875 width == drm_mode->base.width &&
1876 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001877 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001878 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001879 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001880 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001881 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001882 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001883
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001884 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001885 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001886 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001887 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001888 }
1889
Wang Quanxianacb805a2012-07-30 18:09:46 -04001890 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001891 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001892 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001893 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001894 }
1895
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001896 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001897 configured = current;
1898
Wang Quanxianacb805a2012-07-30 18:09:46 -04001899 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001900 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001901 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001902 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001903 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001904 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001905 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001906 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001907
1908 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001909 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001910 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001911 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001912
Wang Quanxianacb805a2012-07-30 18:09:46 -04001913 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1914
John Kåre Alsaker94659272012-11-13 19:10:18 +01001915 weston_output_init(&output->base, &ec->base, x, y,
1916 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001917 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001918
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001919 if (ec->use_pixman) {
1920 if (drm_output_init_pixman(output, ec) < 0) {
1921 weston_log("Failed to init output pixman state\n");
1922 goto err_output;
1923 }
1924 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001925 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001926 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001927 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001928
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001929 output->backlight = backlight_init(drm_device,
1930 connector->connector_type);
1931 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001932 weston_log("Initialized backlight, device %s\n",
1933 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001934 output->base.set_backlight = drm_set_backlight;
1935 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001936 } else {
1937 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001938 }
1939
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001940 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1941
Richard Hughes2b2092a2013-04-24 14:58:02 +01001942 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001943 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1944 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001945
Alex Wubd3354b2012-04-17 17:20:49 +08001946 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001947 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001948 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001949 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001950 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001951 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001952 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001953
Richard Hughese7299962013-05-01 21:52:12 +01001954 output->base.gamma_size = output->original_crtc->gamma_size;
1955 output->base.set_gamma = drm_output_set_gamma;
1956
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001957 weston_plane_init(&output->cursor_plane, 0, 0);
1958 weston_plane_init(&output->fb_plane, 0, 0);
1959
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001960 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1961 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1962 &ec->base.primary_plane);
1963
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001964 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001965 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001966 wl_list_for_each(m, &output->base.mode_list, link)
1967 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1968 m->width, m->height, m->refresh / 1000.0,
1969 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1970 ", preferred" : "",
1971 m->flags & WL_OUTPUT_MODE_CURRENT ?
1972 ", current" : "",
1973 connector->count_modes == 0 ?
1974 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001975
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001976 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001977
John Kåre Alsaker94659272012-11-13 19:10:18 +01001978err_output:
1979 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001980err_free:
1981 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1982 base.link) {
1983 wl_list_remove(&drm_mode->base.link);
1984 free(drm_mode);
1985 }
1986
1987 drmModeFreeCrtc(output->original_crtc);
1988 ec->crtc_allocator &= ~(1 << output->crtc_id);
1989 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001990 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001991
David Herrmann0f0d54e2011-12-08 17:05:45 +01001992 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001993}
1994
Jesse Barnes58ef3792012-02-23 09:45:49 -05001995static void
1996create_sprites(struct drm_compositor *ec)
1997{
1998 struct drm_sprite *sprite;
1999 drmModePlaneRes *plane_res;
2000 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002001 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002002
2003 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2004 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002005 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002006 strerror(errno));
2007 return;
2008 }
2009
2010 for (i = 0; i < plane_res->count_planes; i++) {
2011 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2012 if (!plane)
2013 continue;
2014
Peter Huttererf3d62272013-08-08 11:57:05 +10002015 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002016 plane->count_formats));
2017 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002018 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002019 __func__);
2020 free(plane);
2021 continue;
2022 }
2023
Jesse Barnes58ef3792012-02-23 09:45:49 -05002024 sprite->possible_crtcs = plane->possible_crtcs;
2025 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002026 sprite->current = NULL;
2027 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002028 sprite->compositor = ec;
2029 sprite->count_formats = plane->count_formats;
2030 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002031 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002032 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002033 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002034 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2035 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002036
2037 wl_list_insert(&ec->sprite_list, &sprite->link);
2038 }
2039
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002040 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002041}
2042
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002043static void
2044destroy_sprites(struct drm_compositor *compositor)
2045{
2046 struct drm_sprite *sprite, *next;
2047 struct drm_output *output;
2048
2049 output = container_of(compositor->base.output_list.next,
2050 struct drm_output, base.link);
2051
2052 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2053 drmModeSetPlane(compositor->drm.fd,
2054 sprite->plane_id,
2055 output->crtc_id, 0, 0,
2056 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002057 drm_output_release_fb(output, sprite->current);
2058 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002059 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002060 free(sprite);
2061 }
2062}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002063
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002064static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002065create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002066 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002067{
2068 drmModeConnector *connector;
2069 drmModeRes *resources;
2070 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002071 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002072
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002073 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002074 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002075 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002076 return -1;
2077 }
2078
Jesse Barnes58ef3792012-02-23 09:45:49 -05002079 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002080 if (!ec->crtcs) {
2081 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002082 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002083 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002084
Rob Clark4339add2012-08-09 14:18:28 -05002085 ec->min_width = resources->min_width;
2086 ec->max_width = resources->max_width;
2087 ec->min_height = resources->min_height;
2088 ec->max_height = resources->max_height;
2089
Jesse Barnes58ef3792012-02-23 09:45:49 -05002090 ec->num_crtcs = resources->count_crtcs;
2091 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2092
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002093 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002094 connector = drmModeGetConnector(ec->drm.fd,
2095 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002096 if (connector == NULL)
2097 continue;
2098
2099 if (connector->connection == DRM_MODE_CONNECTED &&
2100 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002101 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002102 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002103 connector, x, y,
2104 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002105 drmModeFreeConnector(connector);
2106 continue;
2107 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002108
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002109 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002110 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002111 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002112 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002113
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002114 drmModeFreeConnector(connector);
2115 }
2116
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002117 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002118 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002119 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002120 return -1;
2121 }
2122
2123 drmModeFreeResources(resources);
2124
2125 return 0;
2126}
2127
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002128static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002129update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002130{
2131 drmModeConnector *connector;
2132 drmModeRes *resources;
2133 struct drm_output *output, *next;
2134 int x = 0, y = 0;
2135 int x_offset = 0, y_offset = 0;
2136 uint32_t connected = 0, disconnects = 0;
2137 int i;
2138
2139 resources = drmModeGetResources(ec->drm.fd);
2140 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002141 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002142 return;
2143 }
2144
2145 /* collect new connects */
2146 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002147 int connector_id = resources->connectors[i];
2148
2149 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002150 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002151 continue;
2152
David Herrmann7551cff2011-12-08 17:05:43 +01002153 if (connector->connection != DRM_MODE_CONNECTED) {
2154 drmModeFreeConnector(connector);
2155 continue;
2156 }
2157
Benjamin Franzke117483d2011-08-30 11:38:26 +02002158 connected |= (1 << connector_id);
2159
2160 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002161 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002162 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002163 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002164
2165 /* XXX: not yet needed, we die with 0 outputs */
2166 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002167 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002168 else
2169 x = 0;
2170 y = 0;
2171 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002172 connector, x, y,
2173 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002174 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002175
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002176 }
2177 drmModeFreeConnector(connector);
2178 }
2179 drmModeFreeResources(resources);
2180
2181 disconnects = ec->connector_allocator & ~connected;
2182 if (disconnects) {
2183 wl_list_for_each_safe(output, next, &ec->base.output_list,
2184 base.link) {
2185 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002186 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002187 output->base.x - x_offset,
2188 output->base.y - y_offset);
2189 }
2190
2191 if (disconnects & (1 << output->connector_id)) {
2192 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002193 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002194 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002195 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002196 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002197 }
2198 }
2199 }
2200
2201 /* FIXME: handle zero outputs, without terminating */
2202 if (ec->connector_allocator == 0)
2203 wl_display_terminate(ec->base.wl_display);
2204}
2205
2206static int
David Herrmannd7488c22012-03-11 20:05:21 +01002207udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002208{
David Herrmannd7488c22012-03-11 20:05:21 +01002209 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002210 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002211
2212 sysnum = udev_device_get_sysnum(device);
2213 if (!sysnum || atoi(sysnum) != ec->drm.id)
2214 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002215
David Herrmann6ac52db2012-03-11 20:05:22 +01002216 val = udev_device_get_property_value(device, "HOTPLUG");
2217 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002218 return 0;
2219
David Herrmann6ac52db2012-03-11 20:05:22 +01002220 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002221}
2222
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002223static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002224udev_drm_event(int fd, uint32_t mask, void *data)
2225{
2226 struct drm_compositor *ec = data;
2227 struct udev_device *event;
2228
2229 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002230
David Herrmannd7488c22012-03-11 20:05:21 +01002231 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002232 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002233
2234 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002235
2236 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002237}
2238
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002239static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002240drm_restore(struct weston_compositor *ec)
2241{
2242 struct drm_compositor *d = (struct drm_compositor *) ec;
2243
2244 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2245 weston_log("failed to drop master: %m\n");
2246 tty_reset(d->tty);
2247}
2248
2249static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002250drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002251{
2252 struct drm_compositor *d = (struct drm_compositor *) ec;
2253
Rob Bradfordd355b802013-05-31 18:09:55 +01002254 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002255
2256 wl_event_source_remove(d->udev_drm_source);
2257 wl_event_source_remove(d->drm_source);
2258
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002259 destroy_sprites(d);
2260
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002261 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002262
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002263 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002264
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002265 if (d->gbm)
2266 gbm_device_destroy(d->gbm);
2267
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002268 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002269 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002270 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002271
Rob Bradford45c15b82013-07-26 16:29:35 +01002272 close(d->drm.fd);
2273
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002274 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002275}
2276
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002277static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002278drm_compositor_set_modes(struct drm_compositor *compositor)
2279{
2280 struct drm_output *output;
2281 struct drm_mode *drm_mode;
2282 int ret;
2283
2284 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002285 if (!output->current) {
2286 /* If something that would cause the output to
2287 * switch mode happened while in another vt, we
2288 * might not have a current drm_fb. In that case,
2289 * schedule a repaint and let drm_output_repaint
2290 * handle setting the mode. */
2291 weston_output_schedule_repaint(&output->base);
2292 continue;
2293 }
2294
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002295 drm_mode = (struct drm_mode *) output->base.current;
2296 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002297 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002298 &output->connector_id, 1,
2299 &drm_mode->mode_info);
2300 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002301 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002302 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002303 drm_mode->base.width, drm_mode->base.height,
2304 output->base.x, output->base.y);
2305 }
2306 }
2307}
2308
2309static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002310vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002311{
2312 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002313 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002314 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002315
2316 switch (event) {
2317 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002318 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002319 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002320 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002321 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002322 wl_display_terminate(compositor->wl_display);
2323 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002324 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002325 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002326 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002327 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002328 break;
2329 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002330 weston_log("leaving VT\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002331 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002332
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002333 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002334 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002335 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002336
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002337 /* If we have a repaint scheduled (either from a
2338 * pending pageflip or the idle handler), make sure we
2339 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002340 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002341 * further attemps at repainting. When we switch
2342 * back, we schedule a repaint, which will process
2343 * pending frame callbacks. */
2344
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002345 wl_list_for_each(output, &ec->base.output_list, base.link) {
2346 output->base.repaint_needed = 0;
2347 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002348 }
2349
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002350 output = container_of(ec->base.output_list.next,
2351 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002352
2353 wl_list_for_each(sprite, &ec->sprite_list, link)
2354 drmModeSetPlane(ec->drm.fd,
2355 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002356 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002357 0, 0, 0, 0, 0, 0, 0, 0);
2358
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002359 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002360 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002361
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002362 break;
2363 };
2364}
2365
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002366static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002367switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002368{
2369 struct drm_compositor *ec = data;
2370
Daniel Stone325fc2d2012-05-30 16:31:58 +01002371 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002372}
2373
David Herrmann0af066f2012-10-29 19:21:16 +01002374/*
2375 * Find primary GPU
2376 * Some systems may have multiple DRM devices attached to a single seat. This
2377 * function loops over all devices and tries to find a PCI device with the
2378 * boot_vga sysfs attribute set to 1.
2379 * If no such device is found, the first DRM device reported by udev is used.
2380 */
2381static struct udev_device*
2382find_primary_gpu(struct drm_compositor *ec, const char *seat)
2383{
2384 struct udev_enumerate *e;
2385 struct udev_list_entry *entry;
2386 const char *path, *device_seat, *id;
2387 struct udev_device *device, *drm_device, *pci;
2388
2389 e = udev_enumerate_new(ec->udev);
2390 udev_enumerate_add_match_subsystem(e, "drm");
2391 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2392
2393 udev_enumerate_scan_devices(e);
2394 drm_device = NULL;
2395 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2396 path = udev_list_entry_get_name(entry);
2397 device = udev_device_new_from_syspath(ec->udev, path);
2398 if (!device)
2399 continue;
2400 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2401 if (!device_seat)
2402 device_seat = default_seat;
2403 if (strcmp(device_seat, seat)) {
2404 udev_device_unref(device);
2405 continue;
2406 }
2407
2408 pci = udev_device_get_parent_with_subsystem_devtype(device,
2409 "pci", NULL);
2410 if (pci) {
2411 id = udev_device_get_sysattr_value(pci, "boot_vga");
2412 if (id && !strcmp(id, "1")) {
2413 if (drm_device)
2414 udev_device_unref(drm_device);
2415 drm_device = device;
2416 break;
2417 }
2418 }
2419
2420 if (!drm_device)
2421 drm_device = device;
2422 else
2423 udev_device_unref(device);
2424 }
2425
2426 udev_enumerate_unref(e);
2427 return drm_device;
2428}
2429
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002430static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002431planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002432{
2433 struct drm_compositor *c = data;
2434
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002435 switch (key) {
2436 case KEY_C:
2437 c->cursors_are_broken ^= 1;
2438 break;
2439 case KEY_V:
2440 c->sprites_are_broken ^= 1;
2441 break;
2442 case KEY_O:
2443 c->sprites_hidden ^= 1;
2444 break;
2445 default:
2446 break;
2447 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002448}
2449
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002450#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002451static void
2452recorder_frame_notify(struct wl_listener *listener, void *data)
2453{
2454 struct drm_output *output;
2455 struct drm_compositor *c;
2456 int fd, ret;
2457
2458 output = container_of(listener, struct drm_output,
2459 recorder_frame_listener);
2460 c = (struct drm_compositor *) output->base.compositor;
2461
2462 if (!output->recorder)
2463 return;
2464
2465 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2466 DRM_CLOEXEC, &fd);
2467 if (ret) {
2468 weston_log("[libva recorder] "
2469 "failed to create prime fd for front buffer\n");
2470 return;
2471 }
2472
2473 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
2474
2475 close(fd);
2476}
2477
2478static void *
2479create_recorder(struct drm_compositor *c, int width, int height,
2480 const char *filename)
2481{
2482 int fd;
2483 drm_magic_t magic;
2484
2485 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2486 if (fd < 0)
2487 return NULL;
2488
2489 drmGetMagic(fd, &magic);
2490 drmAuthMagic(c->drm.fd, magic);
2491
2492 return vaapi_recorder_create(fd, width, height, filename);
2493}
2494
2495static void
2496recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2497 void *data)
2498{
2499 struct drm_compositor *c = data;
2500 struct drm_output *output;
2501 int width, height;
2502
2503 output = container_of(c->base.output_list.next,
2504 struct drm_output, base.link);
2505
2506 if (!output->recorder) {
2507 width = output->base.current->width;
2508 height = output->base.current->height;
2509
2510 output->recorder =
2511 create_recorder(c, width, height, "capture.h264");
2512 if (!output->recorder) {
2513 weston_log("failed to create vaapi recorder\n");
2514 return;
2515 }
2516
2517 output->base.disable_planes++;
2518
2519 output->recorder_frame_listener.notify = recorder_frame_notify;
2520 wl_signal_add(&output->base.frame_signal,
2521 &output->recorder_frame_listener);
2522
2523 weston_output_schedule_repaint(&output->base);
2524
2525 weston_log("[libva recorder] initialized\n");
2526 } else {
2527 vaapi_recorder_destroy(output->recorder);
2528 /* FIXME: close drm fd passed to recorder */
2529 output->recorder = NULL;
2530
2531 output->base.disable_planes--;
2532
2533 wl_list_remove(&output->recorder_frame_listener.link);
2534 weston_log("[libva recorder] done\n");
2535 }
2536}
2537#else
2538static void
2539recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2540 void *data)
2541{
2542 weston_log("Compiled without libva support\n");
2543}
2544#endif
2545
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002546static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002547drm_compositor_create(struct wl_display *display,
Rob Bradford643641d2013-05-31 18:09:53 +01002548 int connector, const char *seat_id, int tty, int pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002549 int *argc, char *argv[],
2550 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002551{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002552 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002553 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002554 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002555 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002556 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002557
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002558 weston_log("initializing drm backend\n");
2559
Peter Huttererf3d62272013-08-08 11:57:05 +10002560 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002561 if (ec == NULL)
2562 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002563
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002564 /* KMS support for sprites is not complete yet, so disable the
2565 * functionality for now. */
2566 ec->sprites_are_broken = 1;
2567
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002568 ec->use_pixman = pixman;
2569
Daniel Stone725c2c32012-06-22 14:04:36 +01002570 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002571 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002572 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002573 goto err_base;
2574 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002575
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002576 /* Check if we run drm-backend using weston-launch */
Kristian Høgsberg3c95e702013-07-23 12:24:00 -07002577 ec->base.launcher_sock =
2578 weston_environment_get_fd("WESTON_LAUNCHER_SOCK");
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002579 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002580 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002581 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002582 goto err_compositor;
2583 }
2584
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002585 ec->udev = udev_new();
2586 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002587 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002588 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002589 }
2590
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002591 ec->base.wl_display = display;
2592 ec->tty = tty_create(&ec->base, vt_func, tty);
2593 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002594 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002595 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002596 }
2597
Rob Bradford643641d2013-05-31 18:09:53 +01002598 drm_device = find_primary_gpu(ec, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002599 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002600 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002601 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002602 }
David Herrmann0af066f2012-10-29 19:21:16 +01002603 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002604
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002605 if (init_drm(ec, drm_device) < 0) {
2606 weston_log("failed to initialize kms\n");
2607 goto err_udev_dev;
2608 }
2609
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002610 if (ec->use_pixman) {
2611 if (init_pixman(ec) < 0) {
2612 weston_log("failed to initialize pixman renderer\n");
2613 goto err_udev_dev;
2614 }
2615 } else {
2616 if (init_egl(ec) < 0) {
2617 weston_log("failed to initialize egl\n");
2618 goto err_udev_dev;
2619 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002620 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002621
2622 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002623 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002624
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002625 ec->base.focus = 1;
2626
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002627 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002628
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002629 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002630 weston_compositor_add_key_binding(&ec->base, key,
2631 MODIFIER_CTRL | MODIFIER_ALT,
2632 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002633
Jesse Barnes58ef3792012-02-23 09:45:49 -05002634 wl_list_init(&ec->sprite_list);
2635 create_sprites(ec);
2636
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002637 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002638 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002639 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002640 }
2641
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002642 path = NULL;
2643
Rob Bradfordd355b802013-05-31 18:09:55 +01002644 if (udev_input_init(&ec->input, &ec->base, ec->udev, seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002645 weston_log("failed to create input devices\n");
2646 goto err_sprite;
2647 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002648
2649 loop = wl_display_get_event_loop(ec->base.wl_display);
2650 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002651 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002652 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002653
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002654 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2655 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002656 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002657 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002658 }
2659 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2660 "drm", NULL);
2661 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002662 wl_event_loop_add_fd(loop,
2663 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002664 WL_EVENT_READABLE, udev_drm_event, ec);
2665
2666 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002667 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002668 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002669 }
2670
Daniel Stonea96b93c2012-06-22 14:04:37 +01002671 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002672
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002673 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002674 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002675 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002676 planes_binding, ec);
2677 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2678 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002679 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2680 recorder_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002681
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002682 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002683
2684err_udev_monitor:
2685 wl_event_source_remove(ec->udev_drm_source);
2686 udev_monitor_unref(ec->udev_monitor);
2687err_drm_source:
2688 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002689 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002690err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002691 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002692 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002693 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002694err_udev_dev:
2695 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002696err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002697 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2698 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002699 tty_destroy(ec->tty);
2700err_udev:
2701 udev_unref(ec->udev);
2702err_compositor:
2703 weston_compositor_shutdown(&ec->base);
2704err_base:
2705 free(ec);
2706 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002707}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002708
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002709WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002710backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002711 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002712{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002713 int connector = 0, tty = 0, use_pixman = 0;
Rob Bradford643641d2013-05-31 18:09:53 +01002714 const char *seat_id = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002715
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002716 const struct weston_option drm_options[] = {
2717 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
Rob Bradford643641d2013-05-31 18:09:53 +01002718 { WESTON_OPTION_STRING, "seat", 0, &seat_id },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002719 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002720 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002721 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002722 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002723
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002724 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002725
Rob Bradford643641d2013-05-31 18:09:53 +01002726 return drm_compositor_create(display, connector, seat_id, tty, use_pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002727 argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002728}