blob: 9c83b1a738e88fd239963a3ebe1cba445d1440d7 [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Daniel Stonec228e232013-05-22 18:03:19 +030024#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040025
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010028#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040029#include <string.h>
30#include <fcntl.h>
31#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040032#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070033#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030034#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020035#include <sys/mman.h>
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030036#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030037#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040038
Benjamin Franzkec649a922011-03-02 11:56:04 +010039#include <xf86drm.h>
40#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050041#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010042
Benjamin Franzke060cf802011-04-30 09:32:11 +020043#include <gbm.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040044#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020045
Kristian Høgsberg36d5fac2014-01-27 23:02:35 -080046#include "libbacklight.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040047#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010048#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020049#include "pixman-renderer.h"
Jonas Ådahle0de3c22014-03-12 22:08:42 +010050#include "udev-input.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010051#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030052#include "vaapi-recorder.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040053
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030054#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
55#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
56#endif
57
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030058#ifndef DRM_CAP_CURSOR_WIDTH
59#define DRM_CAP_CURSOR_WIDTH 0x8
60#endif
61
62#ifndef DRM_CAP_CURSOR_HEIGHT
63#define DRM_CAP_CURSOR_HEIGHT 0x9
64#endif
65
66#ifndef GBM_BO_USE_CURSOR
67#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
68#endif
69
Kristian Høgsberg061c4252012-06-28 11:28:15 -040070static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060071
72enum output_config {
73 OUTPUT_CONFIG_INVALID = 0,
74 OUTPUT_CONFIG_OFF,
75 OUTPUT_CONFIG_PREFERRED,
76 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060077 OUTPUT_CONFIG_MODE,
78 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060079};
80
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040081struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050082 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040083
84 struct udev *udev;
85 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040086
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010087 struct udev_monitor *udev_monitor;
88 struct wl_event_source *udev_drm_source;
89
Benjamin Franzke2af7f102011-03-02 11:14:59 +010090 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010091 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010092 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030093 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010094 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020095 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050096 uint32_t *crtcs;
97 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050098 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010099 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700100 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700101 uint32_t format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200102
Rob Clark4339add2012-08-09 14:18:28 -0500103 /* we need these parameters in order to not fail drmModeAddFB2()
104 * due to out of bounds dimensions, and then mistakenly set
105 * sprites_are_broken:
106 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200107 uint32_t min_width, max_width;
108 uint32_t min_height, max_height;
109 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500110
Jesse Barnes58ef3792012-02-23 09:45:49 -0500111 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500112 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200113 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500114
Rob Clarkab5b1e32012-08-09 13:24:45 -0500115 int cursors_are_broken;
116
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200117 int use_pixman;
118
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200119 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300120
121 clockid_t clock;
Rob Bradfordd355b802013-05-31 18:09:55 +0100122 struct udev_input input;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -0300123
124 uint32_t cursor_width;
125 uint32_t cursor_height;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400126};
127
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400128struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500129 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400130 drmModeModeInfo mode_info;
131};
132
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300133struct drm_output;
134
135struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300136 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200137 uint32_t fb_id, stride, handle, size;
138 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300139 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200140 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200141
142 /* Used by gbm fbs */
143 struct gbm_bo *bo;
144
145 /* Used by dumb fbs */
146 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300147};
148
Richard Hughes2b2092a2013-04-24 14:58:02 +0100149struct drm_edid {
150 char eisa_id[13];
151 char monitor_name[13];
152 char pnp_id[5];
153 char serial_number[13];
154};
155
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400156struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500157 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400158
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400159 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500160 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400161 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700162 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100163 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300164 drmModePropertyPtr dpms_prop;
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000165 uint32_t format;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200166
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300167 int vblank_pending;
168 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800169 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300170
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400171 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400172 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400173 struct weston_plane cursor_plane;
174 struct weston_plane fb_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500175 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400176 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300177 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200178 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200179
180 struct drm_fb *dumb[2];
181 pixman_image_t *image[2];
182 int current_image;
183 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300184
185 struct vaapi_recorder *recorder;
186 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400187};
188
Jesse Barnes58ef3792012-02-23 09:45:49 -0500189/*
190 * An output has a primary display plane plus zero or more sprites for
191 * blending display contents.
192 */
193struct drm_sprite {
194 struct wl_list link;
195
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400196 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500197
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200198 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300199 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500200 struct drm_compositor *compositor;
201
Jesse Barnes58ef3792012-02-23 09:45:49 -0500202 uint32_t possible_crtcs;
203 uint32_t plane_id;
204 uint32_t count_formats;
205
206 int32_t src_x, src_y;
207 uint32_t src_w, src_h;
208 uint32_t dest_x, dest_y;
209 uint32_t dest_w, dest_h;
210
211 uint32_t formats[];
212};
213
Kristian Høgsbergd8e98332013-10-16 16:15:11 -0700214struct drm_parameters {
215 int connector;
216 int tty;
217 int use_pixman;
218 const char *seat_id;
219};
220
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300221static struct gl_renderer_interface *gl_renderer;
222
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500223static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400224
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400225static void
226drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400227
Jesse Barnes58ef3792012-02-23 09:45:49 -0500228static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500229drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
230{
231 struct weston_compositor *ec = output_base->compositor;
232 struct drm_compositor *c =(struct drm_compositor *) ec;
233 struct drm_output *output = (struct drm_output *) output_base;
234 int crtc;
235
236 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
237 if (c->crtcs[crtc] != output->crtc_id)
238 continue;
239
240 if (supported & (1 << crtc))
241 return -1;
242 }
243
244 return 0;
245}
246
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300247static void
248drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
249{
250 struct drm_fb *fb = data;
251 struct gbm_device *gbm = gbm_bo_get_device(bo);
252
253 if (fb->fb_id)
254 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
255
Pekka Paalanende685b82012-12-04 15:58:12 +0200256 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300257
258 free(data);
259}
260
261static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200262drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
263{
264 struct drm_fb *fb;
265 int ret;
266
267 struct drm_mode_create_dumb create_arg;
268 struct drm_mode_destroy_dumb destroy_arg;
269 struct drm_mode_map_dumb map_arg;
270
Peter Huttererf3d62272013-08-08 11:57:05 +1000271 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200272 if (!fb)
273 return NULL;
274
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700275 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200276 create_arg.bpp = 32;
277 create_arg.width = width;
278 create_arg.height = height;
279
280 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
281 if (ret)
282 goto err_fb;
283
284 fb->handle = create_arg.handle;
285 fb->stride = create_arg.pitch;
286 fb->size = create_arg.size;
287 fb->fd = ec->drm.fd;
288
289 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
290 fb->stride, fb->handle, &fb->fb_id);
291 if (ret)
292 goto err_bo;
293
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700294 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200295 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400296 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200297 if (ret)
298 goto err_add_fb;
299
300 fb->map = mmap(0, fb->size, PROT_WRITE,
301 MAP_SHARED, ec->drm.fd, map_arg.offset);
302 if (fb->map == MAP_FAILED)
303 goto err_add_fb;
304
305 return fb;
306
307err_add_fb:
308 drmModeRmFB(ec->drm.fd, fb->fb_id);
309err_bo:
310 memset(&destroy_arg, 0, sizeof(destroy_arg));
311 destroy_arg.handle = create_arg.handle;
312 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
313err_fb:
314 free(fb);
315 return NULL;
316}
317
318static void
319drm_fb_destroy_dumb(struct drm_fb *fb)
320{
321 struct drm_mode_destroy_dumb destroy_arg;
322
323 if (!fb->map)
324 return;
325
326 if (fb->fb_id)
327 drmModeRmFB(fb->fd, fb->fb_id);
328
329 weston_buffer_reference(&fb->buffer_ref, NULL);
330
331 munmap(fb->map, fb->size);
332
333 memset(&destroy_arg, 0, sizeof(destroy_arg));
334 destroy_arg.handle = fb->handle;
335 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
336
337 free(fb);
338}
339
340static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500341drm_fb_get_from_bo(struct gbm_bo *bo,
342 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300343{
344 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200345 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200346 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300347 int ret;
348
349 if (fb)
350 return fb;
351
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200352 fb = calloc(1, sizeof *fb);
353 if (!fb)
354 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300355
356 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300357
358 width = gbm_bo_get_width(bo);
359 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200360 fb->stride = gbm_bo_get_stride(bo);
361 fb->handle = gbm_bo_get_handle(bo).u32;
362 fb->size = fb->stride * height;
363 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300364
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200365 if (compositor->min_width > width || width > compositor->max_width ||
366 compositor->min_height > height ||
367 height > compositor->max_height) {
368 weston_log("bo geometry out of bounds\n");
369 goto err_free;
370 }
371
372 ret = -1;
373
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200374 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200375 handles[0] = fb->handle;
376 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200377 offsets[0] = 0;
378
379 ret = drmModeAddFB2(compositor->drm.fd, width, height,
380 format, handles, pitches, offsets,
381 &fb->fb_id, 0);
382 if (ret) {
383 weston_log("addfb2 failed: %m\n");
384 compositor->no_addfb2 = 1;
385 compositor->sprites_are_broken = 1;
386 }
387 }
388
389 if (ret)
390 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200391 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200392
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300393 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200394 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200395 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300396 }
397
398 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
399
400 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200401
402err_free:
403 free(fb);
404 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300405}
406
407static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500408drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200409{
Pekka Paalanende685b82012-12-04 15:58:12 +0200410 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200411
412 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200413
Pekka Paalanende685b82012-12-04 15:58:12 +0200414 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200415}
416
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200417static void
418drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
419{
420 if (!fb)
421 return;
422
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200423 if (fb->map &&
424 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200425 drm_fb_destroy_dumb(fb);
426 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200427 if (fb->is_client_buffer)
428 gbm_bo_destroy(fb->bo);
429 else
430 gbm_surface_release_buffer(output->surface,
Jason Ekstrand3ec57f52013-11-14 20:52:35 -0600431 fb->bo);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200432 }
433}
434
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500435static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200436drm_output_check_scanout_format(struct drm_output *output,
437 struct weston_surface *es, struct gbm_bo *bo)
438{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200439 uint32_t format;
440 pixman_region32_t r;
441
442 format = gbm_bo_get_format(bo);
443
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700444 if (format == GBM_FORMAT_ARGB8888) {
445 /* We can scanout an ARGB buffer if the surface's
446 * opaque region covers the whole output, but we have
447 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -0800448 pixman_region32_init_rect(&r, 0, 0,
449 output->base.width,
450 output->base.height);
451 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200452
453 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500454 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200455
456 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500457 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700458
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000459 if (output->format == format)
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700460 return format;
461
462 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200463}
464
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400465static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500466drm_output_prepare_scanout_view(struct weston_output *_output,
467 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500468{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400469 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500470 struct drm_compositor *c =
471 (struct drm_compositor *) output->base.compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500472 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200473 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300474 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500475 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500476
Jason Ekstranda7af7042013-10-12 22:38:11 -0500477 if (ev->geometry.x != output->base.x ||
478 ev->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200479 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200480 buffer->width != output->base.current_mode->width ||
481 buffer->height != output->base.current_mode->height ||
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200482 output->base.transform != viewport->buffer.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500483 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400484 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500485
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400486 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700487 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500488
Rob Bradford9b101872012-09-14 23:25:41 +0100489 /* Unable to use the buffer for scanout */
490 if (!bo)
491 return NULL;
492
Jason Ekstranda7af7042013-10-12 22:38:11 -0500493 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500494 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300495 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400496 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300497 }
498
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500499 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300500 if (!output->next) {
501 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400502 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300503 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500504
Pekka Paalanende685b82012-12-04 15:58:12 +0200505 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500506
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400507 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500508}
509
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500510static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200511drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400512{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200513 struct drm_compositor *c =
514 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300515 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400516
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200517 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400518
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300519 bo = gbm_surface_lock_front_buffer(output->surface);
520 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200521 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400522 return;
523 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300524
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000525 output->next = drm_fb_get_from_bo(bo, c, output->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300526 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200527 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300528 gbm_surface_release_buffer(output->surface, bo);
529 return;
530 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400531}
532
533static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200534drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
535{
536 struct weston_compositor *ec = output->base.compositor;
537 pixman_region32_t total_damage, previous_damage;
538
539 pixman_region32_init(&total_damage);
540 pixman_region32_init(&previous_damage);
541
542 pixman_region32_copy(&previous_damage, damage);
543
544 pixman_region32_union(&total_damage, damage, &output->previous_damage);
545 pixman_region32_copy(&output->previous_damage, &previous_damage);
546
547 output->current_image ^= 1;
548
549 output->next = output->dumb[output->current_image];
550 pixman_renderer_output_set_buffer(&output->base,
551 output->image[output->current_image]);
552
553 ec->renderer->repaint_output(&output->base, &total_damage);
554
555 pixman_region32_fini(&total_damage);
556 pixman_region32_fini(&previous_damage);
557}
558
559static void
560drm_output_render(struct drm_output *output, pixman_region32_t *damage)
561{
562 struct drm_compositor *c =
563 (struct drm_compositor *) output->base.compositor;
564
565 if (c->use_pixman)
566 drm_output_render_pixman(output, damage);
567 else
568 drm_output_render_gl(output, damage);
569
570 pixman_region32_subtract(&c->base.primary_plane.damage,
571 &c->base.primary_plane.damage, damage);
572}
573
574static void
Richard Hughese7299962013-05-01 21:52:12 +0100575drm_output_set_gamma(struct weston_output *output_base,
576 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
577{
578 int rc;
579 struct drm_output *output = (struct drm_output *) output_base;
580 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
581
582 /* check */
583 if (output_base->gamma_size != size)
584 return;
585 if (!output->original_crtc)
586 return;
587
588 rc = drmModeCrtcSetGamma(compositor->drm.fd,
589 output->crtc_id,
590 size, r, g, b);
591 if (rc)
592 weston_log("set gamma failed: %m\n");
593}
594
David Herrmann1edf44c2013-10-22 17:11:26 +0200595static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500596drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400597 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100598{
599 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500600 struct drm_compositor *compositor =
601 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500602 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400603 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500604 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100605
Xiong Zhangabd5d472013-10-11 14:43:07 +0800606 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200607 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800608
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300609 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400610 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300611 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200612 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100613
Hardeningff39efa2013-09-18 23:56:35 +0200614 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200615 if (!output->current ||
616 output->current->stride != output->next->stride) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400617 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300618 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400619 &output->connector_id, 1,
620 &mode->mode_info);
621 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200622 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200623 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400624 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300625 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200626 }
627
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500628 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300629 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500630 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200631 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200632 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500633 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100634
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300635 output->page_flip_pending = 1;
636
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400637 drm_output_set_cursor(output);
638
Jesse Barnes58ef3792012-02-23 09:45:49 -0500639 /*
640 * Now, update all the sprite surfaces
641 */
642 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200643 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500644 drmVBlank vbl = {
645 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
646 .request.sequence = 1,
647 };
648
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200649 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200650 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500651 continue;
652
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200653 if (s->next && !compositor->sprites_hidden)
654 fb_id = s->next->fb_id;
655
Jesse Barnes58ef3792012-02-23 09:45:49 -0500656 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200657 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500658 s->dest_x, s->dest_y,
659 s->dest_w, s->dest_h,
660 s->src_x, s->src_y,
661 s->src_w, s->src_h);
662 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200663 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500664 ret, strerror(errno));
665
Rob Clark5ca1a472012-08-08 20:27:37 -0500666 if (output->pipe > 0)
667 vbl.request.type |= DRM_VBLANK_SECONDARY;
668
Jesse Barnes58ef3792012-02-23 09:45:49 -0500669 /*
670 * Queue a vblank signal so we know when the surface
671 * becomes active on the display or has been replaced.
672 */
673 vbl.request.signal = (unsigned long)s;
674 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
675 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200676 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500677 ret, strerror(errno));
678 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300679
680 s->output = output;
681 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500682 }
683
David Herrmann1edf44c2013-10-22 17:11:26 +0200684 return 0;
685
686err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800687 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200688 if (output->next) {
689 drm_output_release_fb(output, output->next);
690 output->next = NULL;
691 }
692
693 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400694}
695
696static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200697drm_output_start_repaint_loop(struct weston_output *output_base)
698{
699 struct drm_output *output = (struct drm_output *) output_base;
700 struct drm_compositor *compositor = (struct drm_compositor *)
701 output_base->compositor;
702 uint32_t fb_id;
David Herrmann3c688c52013-10-22 17:11:25 +0200703 uint32_t msec;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300704 struct timespec ts;
705
Xiong Zhangabd5d472013-10-11 14:43:07 +0800706 if (output->destroy_pending)
707 return;
708
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300709 if (!output->current) {
710 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200711 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300712 }
713
714 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200715
716 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
717 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
718 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200719 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200720 }
David Herrmann3c688c52013-10-22 17:11:25 +0200721
722 return;
723
724finish_frame:
725 /* if we cannot page-flip, immediately finish frame */
726 clock_gettime(compositor->clock, &ts);
727 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
728 weston_output_finish_frame(output_base, msec);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200729}
730
731static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500732vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
733 void *data)
734{
735 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300736 struct drm_output *output = s->output;
737 uint32_t msecs;
738
739 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500740
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200741 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200742 s->current = s->next;
743 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300744
745 if (!output->page_flip_pending) {
746 msecs = sec * 1000 + usec / 1000;
747 weston_output_finish_frame(&output->base, msecs);
748 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500749}
750
751static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800752drm_output_destroy(struct weston_output *output_base);
753
754static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400755page_flip_handler(int fd, unsigned int frame,
756 unsigned int sec, unsigned int usec, void *data)
757{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200758 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400759 uint32_t msecs;
760
Jonas Ådahle5a12252013-04-05 23:07:11 +0200761 /* We don't set page_flip_pending on start_repaint_loop, in that case
762 * we just want to page flip to the current buffer to get an accurate
763 * timestamp */
764 if (output->page_flip_pending) {
765 drm_output_release_fb(output, output->current);
766 output->current = output->next;
767 output->next = NULL;
768 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300769
Jonas Ådahle5a12252013-04-05 23:07:11 +0200770 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400771
Xiong Zhangabd5d472013-10-11 14:43:07 +0800772 if (output->destroy_pending)
773 drm_output_destroy(&output->base);
774 else if (!output->vblank_pending) {
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300775 msecs = sec * 1000 + usec / 1000;
776 weston_output_finish_frame(&output->base, msecs);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300777
778 /* We can't call this from frame_notify, because the output's
779 * repaint needed flag is cleared just after that */
780 if (output->recorder)
781 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300782 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200783}
784
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500785static uint32_t
786drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500787 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500788{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500789 uint32_t i, format;
790
791 format = gbm_bo_get_format(bo);
792
793 if (format == GBM_FORMAT_ARGB8888) {
794 pixman_region32_t r;
795
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500796 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600797 ev->surface->width,
798 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500799 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500800
801 if (!pixman_region32_not_empty(&r))
802 format = GBM_FORMAT_XRGB8888;
803
804 pixman_region32_fini(&r);
805 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500806
807 for (i = 0; i < s->count_formats; i++)
808 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500809 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500810
811 return 0;
812}
813
814static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500815drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500816{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500817 return !ev->transform.enabled ||
818 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500819}
820
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400821static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500822drm_output_prepare_overlay_view(struct weston_output *output_base,
823 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500824{
825 struct weston_compositor *ec = output_base->compositor;
826 struct drm_compositor *c =(struct drm_compositor *) ec;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200827 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500828 struct drm_sprite *s;
829 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500830 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500831 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200832 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500833 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400834 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500835
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200836 if (c->gbm == NULL)
837 return NULL;
838
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200839 if (viewport->buffer.transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200840 return NULL;
841
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200842 if (viewport->buffer.scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200843 return NULL;
844
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500845 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400846 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500847
Jason Ekstranda7af7042013-10-12 22:38:11 -0500848 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400849 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300850
Jason Ekstranda7af7042013-10-12 22:38:11 -0500851 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400852 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500853
Jason Ekstranda7af7042013-10-12 22:38:11 -0500854 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200855 return NULL;
856
Jason Ekstranda7af7042013-10-12 22:38:11 -0500857 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500858 return NULL;
859
Jason Ekstranda7af7042013-10-12 22:38:11 -0500860 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400861 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500862
Jesse Barnes58ef3792012-02-23 09:45:49 -0500863 wl_list_for_each(s, &c->sprite_list, link) {
864 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
865 continue;
866
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200867 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500868 found = 1;
869 break;
870 }
871 }
872
873 /* No sprites available */
874 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400875 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500876
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400877 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500878 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700879 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400880 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400881 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400882
Jason Ekstranda7af7042013-10-12 22:38:11 -0500883 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500884 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200885 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400886 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500887 }
888
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200889 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200890 if (!s->next) {
891 gbm_bo_destroy(bo);
892 return NULL;
893 }
894
Jason Ekstranda7af7042013-10-12 22:38:11 -0500895 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500896
Jason Ekstranda7af7042013-10-12 22:38:11 -0500897 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400898 s->plane.x = box->x1;
899 s->plane.y = box->y1;
900
Jesse Barnes58ef3792012-02-23 09:45:49 -0500901 /*
902 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200903 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500904 * for us already).
905 */
906 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500907 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500908 &output_base->region);
909 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
910 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200911 tbox = weston_transformed_rect(output_base->width,
912 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200913 output_base->transform,
Hardeningff39efa2013-09-18 23:56:35 +0200914 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200915 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200916 s->dest_x = tbox.x1;
917 s->dest_y = tbox.y1;
918 s->dest_w = tbox.x2 - tbox.x1;
919 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500920 pixman_region32_fini(&dest_rect);
921
922 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500923 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500924 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500925 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400926
Jason Ekstranda7af7042013-10-12 22:38:11 -0500927 weston_view_from_global_fixed(ev,
928 wl_fixed_from_int(box->x1),
929 wl_fixed_from_int(box->y1),
930 &sx1, &sy1);
931 weston_view_from_global_fixed(ev,
932 wl_fixed_from_int(box->x2),
933 wl_fixed_from_int(box->y2),
934 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400935
936 if (sx1 < 0)
937 sx1 = 0;
938 if (sy1 < 0)
939 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600940 if (sx2 > wl_fixed_from_int(ev->surface->width))
941 sx2 = wl_fixed_from_int(ev->surface->width);
942 if (sy2 > wl_fixed_from_int(ev->surface->height))
943 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400944
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200945 tbox.x1 = sx1;
946 tbox.y1 = sy1;
947 tbox.x2 = sx2;
948 tbox.y2 = sy2;
949
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600950 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
951 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200952 viewport->buffer.transform,
953 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100954 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200955
956 s->src_x = tbox.x1 << 8;
957 s->src_y = tbox.y1 << 8;
958 s->src_w = (tbox.x2 - tbox.x1) << 8;
959 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500960 pixman_region32_fini(&src_rect);
961
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400962 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500963}
964
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400965static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500966drm_output_prepare_cursor_view(struct weston_output *output_base,
967 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500968{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400969 struct drm_compositor *c =
970 (struct drm_compositor *) output_base->compositor;
Neil Robertsf37f82c2014-05-01 18:00:41 +0100971 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400972 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400973
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200974 if (c->gbm == NULL)
975 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200976 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
977 return NULL;
Neil Robertsf37f82c2014-05-01 18:00:41 +0100978 if (viewport->buffer.scale != output_base->current_scale)
979 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500980 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400981 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500982 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400983 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500984 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400985 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500986 if (ev->surface->buffer_ref.buffer == NULL ||
987 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600988 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400989 return NULL;
990
Jason Ekstranda7af7042013-10-12 22:38:11 -0500991 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400992
993 return &output->cursor_plane;
994}
995
996static void
997drm_output_set_cursor(struct drm_output *output)
998{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500999 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001000 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001001 struct drm_compositor *c =
1002 (struct drm_compositor *) output->base.compositor;
1003 EGLint handle, stride;
1004 struct gbm_bo *bo;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001005 uint32_t buf[c->cursor_width * c->cursor_height];
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001006 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001007 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001008
Jason Ekstranda7af7042013-10-12 22:38:11 -05001009 output->cursor_view = NULL;
1010 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001011 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
1012 return;
1013 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001014
Neil Robertse5051712013-11-13 15:44:06 +00001015 buffer = ev->surface->buffer_ref.buffer;
1016
1017 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001018 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001019 pixman_region32_fini(&output->cursor_plane.damage);
1020 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001021 output->current_cursor ^= 1;
1022 bo = output->cursor_bo[output->current_cursor];
1023 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001024 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1025 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1026 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001027 for (i = 0; i < ev->surface->height; i++)
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001028 memcpy(buf + i * c->cursor_width, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001029 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001030 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001031
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001032 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001033 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001034
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001035 handle = gbm_bo_get_handle(bo).s32;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001036 if (drmModeSetCursor(c->drm.fd, output->crtc_id, handle,
1037 c->cursor_width, c->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001038 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001039 c->cursors_are_broken = 1;
1040 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001041 }
1042
Jason Ekstranda7af7042013-10-12 22:38:11 -05001043 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1044 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001045 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001046 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001047 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001048 c->cursors_are_broken = 1;
1049 }
1050
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001051 output->cursor_plane.x = x;
1052 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001053 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001054}
1055
Jesse Barnes58ef3792012-02-23 09:45:49 -05001056static void
1057drm_assign_planes(struct weston_output *output)
1058{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001059 struct drm_compositor *c =
1060 (struct drm_compositor *) output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001061 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001062 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001063 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001064
1065 /*
1066 * Find a surface for each sprite in the output using some heuristics:
1067 * 1) size
1068 * 2) frequency of update
1069 * 3) opacity (though some hw might support alpha blending)
1070 * 4) clipping (this can be fixed with color keys)
1071 *
1072 * The idea is to save on blitting since this should save power.
1073 * If we can get a large video surface on the sprite for example,
1074 * the main display surface may not need to update at all, and
1075 * the client buffer can be used directly for the sprite surface
1076 * as we do for flipping full screen surfaces.
1077 */
1078 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001079 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001080
Jason Ekstranda7af7042013-10-12 22:38:11 -05001081 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001082 struct weston_surface *es = ev->surface;
1083
1084 /* Test whether this buffer can ever go into a plane:
1085 * non-shm, or small enough to be a cursor.
1086 *
1087 * Also, keep a reference when using the pixman renderer.
1088 * That makes it possible to do a seamless switch to the GL
1089 * renderer and since the pixman renderer keeps a reference
1090 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001091 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001092 if (c->use_pixman ||
1093 (es->buffer_ref.buffer &&
1094 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001095 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001096 es->keep_buffer = 1;
1097 else
1098 es->keep_buffer = 0;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001099
Jesse Barnes58ef3792012-02-23 09:45:49 -05001100 pixman_region32_init(&surface_overlap);
1101 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001102 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001103
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001104 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001105 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001106 next_plane = primary;
1107 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001108 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001109 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001110 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001111 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001112 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001113 if (next_plane == NULL)
1114 next_plane = primary;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001115 weston_view_move_to_plane(ev, next_plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001116 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001117 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001118 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001119
Jesse Barnes58ef3792012-02-23 09:45:49 -05001120 pixman_region32_fini(&surface_overlap);
1121 }
1122 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001123}
1124
Matt Roper361d2ad2011-08-29 13:52:23 -07001125static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001126drm_output_fini_pixman(struct drm_output *output);
1127
1128static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001129drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001130{
1131 struct drm_output *output = (struct drm_output *) output_base;
1132 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001133 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001134 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001135
Xiong Zhangabd5d472013-10-11 14:43:07 +08001136 if (output->page_flip_pending) {
1137 output->destroy_pending = 1;
1138 weston_log("destroy output while page flip pending\n");
1139 return;
1140 }
1141
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001142 if (output->backlight)
1143 backlight_destroy(output->backlight);
1144
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001145 drmModeFreeProperty(output->dpms_prop);
1146
Matt Roper361d2ad2011-08-29 13:52:23 -07001147 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001148 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001149
1150 /* Restore original CRTC state */
1151 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001152 origcrtc->x, origcrtc->y,
1153 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001154 drmModeFreeCrtc(origcrtc);
1155
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001156 c->crtc_allocator &= ~(1 << output->crtc_id);
1157 c->connector_allocator &= ~(1 << output->connector_id);
1158
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001159 if (c->use_pixman) {
1160 drm_output_fini_pixman(output);
1161 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001162 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001163 gbm_surface_destroy(output->surface);
1164 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001165
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001166 weston_plane_release(&output->fb_plane);
1167 weston_plane_release(&output->cursor_plane);
1168
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001169 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001170
Matt Roper361d2ad2011-08-29 13:52:23 -07001171 free(output);
1172}
1173
Alex Wub7b8bda2012-04-17 17:20:48 +08001174static struct drm_mode *
1175choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1176{
1177 struct drm_mode *tmp_mode = NULL, *mode;
1178
Hardeningff39efa2013-09-18 23:56:35 +02001179 if (output->base.current_mode->width == target_mode->width &&
1180 output->base.current_mode->height == target_mode->height &&
1181 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001182 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001183 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001184
1185 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1186 if (mode->mode_info.hdisplay == target_mode->width &&
1187 mode->mode_info.vdisplay == target_mode->height) {
1188 if (mode->mode_info.vrefresh == target_mode->refresh ||
1189 target_mode->refresh == 0) {
1190 return mode;
1191 } else if (!tmp_mode)
1192 tmp_mode = mode;
1193 }
1194 }
1195
1196 return tmp_mode;
1197}
1198
1199static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001200drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001201static int
1202drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001203
1204static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001205drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1206{
1207 struct drm_output *output;
1208 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001209 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001210
1211 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001212 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001213 return -1;
1214 }
1215
1216 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001217 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001218 return -1;
1219 }
1220
1221 ec = (struct drm_compositor *)output_base->compositor;
1222 output = (struct drm_output *)output_base;
1223 drm_mode = choose_mode (output, mode);
1224
1225 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001226 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001227 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001228 }
1229
Hardeningff39efa2013-09-18 23:56:35 +02001230 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001231 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001232
Hardeningff39efa2013-09-18 23:56:35 +02001233 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001234
Hardeningff39efa2013-09-18 23:56:35 +02001235 output->base.current_mode = &drm_mode->base;
1236 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001237 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1238
Alex Wub7b8bda2012-04-17 17:20:48 +08001239 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001240 drm_output_release_fb(output, output->current);
1241 drm_output_release_fb(output, output->next);
1242 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001243
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001244 if (ec->use_pixman) {
1245 drm_output_fini_pixman(output);
1246 if (drm_output_init_pixman(output, ec) < 0) {
1247 weston_log("failed to init output pixman state with "
1248 "new mode\n");
1249 return -1;
1250 }
1251 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001252 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001253 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001254
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001255 if (drm_output_init_egl(output, ec) < 0) {
1256 weston_log("failed to init output egl state with "
1257 "new mode");
1258 return -1;
1259 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001260 }
1261
Alex Wub7b8bda2012-04-17 17:20:48 +08001262 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001263}
1264
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001265static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001266on_drm_input(int fd, uint32_t mask, void *data)
1267{
1268 drmEventContext evctx;
1269
1270 memset(&evctx, 0, sizeof evctx);
1271 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1272 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001273 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001274 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001275
1276 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001277}
1278
1279static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001280init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001281{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001282 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001283 uint64_t cap;
1284 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001285
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001286 sysnum = udev_device_get_sysnum(device);
1287 if (sysnum)
1288 ec->drm.id = atoi(sysnum);
1289 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001290 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001291 return -1;
1292 }
1293
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001294 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001295 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001296 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001297 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001298 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001299 udev_device_get_devnode(device));
1300 return -1;
1301 }
1302
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001303 weston_log("using %s\n", filename);
1304
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001305 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001306 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001307
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001308 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1309 if (ret == 0 && cap == 1)
1310 ec->clock = CLOCK_MONOTONIC;
1311 else
1312 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001313
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001314 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1315 if (ret == 0)
1316 ec->cursor_width = cap;
1317 else
1318 ec->cursor_width = 64;
1319
1320 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1321 if (ret == 0)
1322 ec->cursor_height = cap;
1323 else
1324 ec->cursor_height = 64;
1325
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001326 return 0;
1327}
1328
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001329static struct gbm_device *
1330create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001331{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001332 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001333
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001334 gl_renderer = weston_load_module("gl-renderer.so",
1335 "gl_renderer_interface");
1336 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001337 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001338
1339 /* GBM will load a dri driver, but even though they need symbols from
1340 * libglapi, in some version of Mesa they are not linked to it. Since
1341 * only the gl-renderer module links to it, the call above won't make
1342 * these symbols globally available, and loading the DRI driver fails.
1343 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1344 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1345
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001346 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001347
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001348 return gbm;
1349}
1350
1351static int
1352drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1353{
1354 EGLint format;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001355
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001356 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001357 if (gl_renderer->create(&ec->base, ec->gbm,
1358 gl_renderer->opaque_attribs, &format) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001359 return -1;
1360 }
1361
1362 return 0;
1363}
1364
1365static int
1366init_egl(struct drm_compositor *ec)
1367{
1368 ec->gbm = create_gbm_device(ec->drm.fd);
1369
1370 if (!ec->gbm)
1371 return -1;
1372
1373 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001374 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001375 return -1;
1376 }
1377
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001378 return 0;
1379}
1380
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001381static int
1382init_pixman(struct drm_compositor *ec)
1383{
1384 return pixman_renderer_init(&ec->base);
1385}
1386
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001387static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001388drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001389{
1390 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001391 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001392
1393 mode = malloc(sizeof *mode);
1394 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001395 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001396
1397 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001398 mode->base.width = info->hdisplay;
1399 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001400
1401 /* Calculate higher precision (mHz) refresh rate */
1402 refresh = (info->clock * 1000000LL / info->htotal +
1403 info->vtotal / 2) / info->vtotal;
1404
1405 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1406 refresh *= 2;
1407 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1408 refresh /= 2;
1409 if (info->vscan > 1)
1410 refresh /= info->vscan;
1411
1412 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001413 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001414
1415 if (info->type & DRM_MODE_TYPE_PREFERRED)
1416 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1417
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001418 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1419
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001420 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001421}
1422
1423static int
1424drm_subpixel_to_wayland(int drm_value)
1425{
1426 switch (drm_value) {
1427 default:
1428 case DRM_MODE_SUBPIXEL_UNKNOWN:
1429 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1430 case DRM_MODE_SUBPIXEL_NONE:
1431 return WL_OUTPUT_SUBPIXEL_NONE;
1432 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1433 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1434 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1435 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1436 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1437 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1438 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1439 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1440 }
1441}
1442
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001443/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001444static uint32_t
1445drm_get_backlight(struct drm_output *output)
1446{
1447 long brightness, max_brightness, norm;
1448
1449 brightness = backlight_get_brightness(output->backlight);
1450 max_brightness = backlight_get_max_brightness(output->backlight);
1451
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001452 /* convert it on a scale of 0 to 255 */
1453 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001454
1455 return (uint32_t) norm;
1456}
1457
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001458/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001459static void
1460drm_set_backlight(struct weston_output *output_base, uint32_t value)
1461{
1462 struct drm_output *output = (struct drm_output *) output_base;
1463 long max_brightness, new_brightness;
1464
1465 if (!output->backlight)
1466 return;
1467
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001468 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001469 return;
1470
1471 max_brightness = backlight_get_max_brightness(output->backlight);
1472
1473 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001474 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001475
1476 backlight_set_brightness(output->backlight, new_brightness);
1477}
1478
1479static drmModePropertyPtr
1480drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1481{
1482 drmModePropertyPtr props;
1483 int i;
1484
1485 for (i = 0; i < connector->count_props; i++) {
1486 props = drmModeGetProperty(fd, connector->props[i]);
1487 if (!props)
1488 continue;
1489
1490 if (!strcmp(props->name, name))
1491 return props;
1492
1493 drmModeFreeProperty(props);
1494 }
1495
1496 return NULL;
1497}
1498
1499static void
1500drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1501{
1502 struct drm_output *output = (struct drm_output *) output_base;
1503 struct weston_compositor *ec = output_base->compositor;
1504 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001505
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001506 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001507 return;
1508
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001509 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1510 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001511}
1512
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001513static const char *connector_type_names[] = {
1514 "None",
1515 "VGA",
1516 "DVI",
1517 "DVI",
1518 "DVI",
1519 "Composite",
1520 "TV",
1521 "LVDS",
1522 "CTV",
1523 "DIN",
1524 "DP",
1525 "HDMI",
1526 "HDMI",
1527 "TV",
1528 "eDP",
1529};
1530
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001531static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001532find_crtc_for_connector(struct drm_compositor *ec,
1533 drmModeRes *resources, drmModeConnector *connector)
1534{
1535 drmModeEncoder *encoder;
1536 uint32_t possible_crtcs;
1537 int i, j;
1538
1539 for (j = 0; j < connector->count_encoders; j++) {
1540 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1541 if (encoder == NULL) {
1542 weston_log("Failed to get encoder.\n");
1543 return -1;
1544 }
1545 possible_crtcs = encoder->possible_crtcs;
1546 drmModeFreeEncoder(encoder);
1547
1548 for (i = 0; i < resources->count_crtcs; i++) {
1549 if (possible_crtcs & (1 << i) &&
1550 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1551 return i;
1552 }
1553 }
1554
1555 return -1;
1556}
1557
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001558/* Init output state that depends on gl or gbm */
1559static int
1560drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1561{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001562 EGLint format = output->format;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001563 int i, flags;
1564
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001565 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001566 output->base.current_mode->width,
1567 output->base.current_mode->height,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001568 format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001569 GBM_BO_USE_SCANOUT |
1570 GBM_BO_USE_RENDERING);
1571 if (!output->surface) {
1572 weston_log("failed to create gbm surface\n");
1573 return -1;
1574 }
1575
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001576 if (gl_renderer->output_create(&output->base, output->surface,
1577 gl_renderer->opaque_attribs,
1578 &format) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001579 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001580 gbm_surface_destroy(output->surface);
1581 return -1;
1582 }
1583
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001584 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001585
1586 for (i = 0; i < 2; i++) {
1587 if (output->cursor_bo[i])
1588 continue;
1589
1590 output->cursor_bo[i] =
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001591 gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
1592 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001593 }
1594
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001595 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1596 weston_log("cursor buffers unavailable, using gl cursors\n");
1597 ec->cursors_are_broken = 1;
1598 }
1599
1600 return 0;
1601}
1602
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001603static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001604drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1605{
Hardeningff39efa2013-09-18 23:56:35 +02001606 int w = output->base.current_mode->width;
1607 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001608 unsigned int i;
1609
1610 /* FIXME error checking */
1611
1612 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001613 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001614 if (!output->dumb[i])
1615 goto err;
1616
1617 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001618 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001619 output->dumb[i]->map,
1620 output->dumb[i]->stride);
1621 if (!output->image[i])
1622 goto err;
1623 }
1624
1625 if (pixman_renderer_output_create(&output->base) < 0)
1626 goto err;
1627
1628 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001629 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001630
1631 return 0;
1632
1633err:
1634 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1635 if (output->dumb[i])
1636 drm_fb_destroy_dumb(output->dumb[i]);
1637 if (output->image[i])
1638 pixman_image_unref(output->image[i]);
1639
1640 output->dumb[i] = NULL;
1641 output->image[i] = NULL;
1642 }
1643
1644 return -1;
1645}
1646
1647static void
1648drm_output_fini_pixman(struct drm_output *output)
1649{
1650 unsigned int i;
1651
1652 pixman_renderer_output_destroy(&output->base);
1653 pixman_region32_fini(&output->previous_damage);
1654
1655 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1656 drm_fb_destroy_dumb(output->dumb[i]);
1657 pixman_image_unref(output->image[i]);
1658 output->dumb[i] = NULL;
1659 output->image[i] = NULL;
1660 }
1661}
1662
Richard Hughes2b2092a2013-04-24 14:58:02 +01001663static void
1664edid_parse_string(const uint8_t *data, char text[])
1665{
1666 int i;
1667 int replaced = 0;
1668
1669 /* this is always 12 bytes, but we can't guarantee it's null
1670 * terminated or not junk. */
1671 strncpy(text, (const char *) data, 12);
1672
1673 /* remove insane chars */
1674 for (i = 0; text[i] != '\0'; i++) {
1675 if (text[i] == '\n' ||
1676 text[i] == '\r') {
1677 text[i] = '\0';
1678 break;
1679 }
1680 }
1681
1682 /* ensure string is printable */
1683 for (i = 0; text[i] != '\0'; i++) {
1684 if (!isprint(text[i])) {
1685 text[i] = '-';
1686 replaced++;
1687 }
1688 }
1689
1690 /* if the string is random junk, ignore the string */
1691 if (replaced > 4)
1692 text[0] = '\0';
1693}
1694
1695#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1696#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1697#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1698#define EDID_OFFSET_DATA_BLOCKS 0x36
1699#define EDID_OFFSET_LAST_BLOCK 0x6c
1700#define EDID_OFFSET_PNPID 0x08
1701#define EDID_OFFSET_SERIAL 0x0c
1702
1703static int
1704edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1705{
1706 int i;
1707 uint32_t serial_number;
1708
1709 /* check header */
1710 if (length < 128)
1711 return -1;
1712 if (data[0] != 0x00 || data[1] != 0xff)
1713 return -1;
1714
1715 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1716 * /--08--\/--09--\
1717 * 7654321076543210
1718 * |\---/\---/\---/
1719 * R C1 C2 C3 */
1720 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1721 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1722 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1723 edid->pnp_id[3] = '\0';
1724
1725 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1726 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1727 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1728 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1729 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1730 if (serial_number > 0)
1731 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1732
1733 /* parse EDID data */
1734 for (i = EDID_OFFSET_DATA_BLOCKS;
1735 i <= EDID_OFFSET_LAST_BLOCK;
1736 i += 18) {
1737 /* ignore pixel clock data */
1738 if (data[i] != 0)
1739 continue;
1740 if (data[i+2] != 0)
1741 continue;
1742
1743 /* any useful blocks? */
1744 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1745 edid_parse_string(&data[i+5],
1746 edid->monitor_name);
1747 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1748 edid_parse_string(&data[i+5],
1749 edid->serial_number);
1750 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1751 edid_parse_string(&data[i+5],
1752 edid->eisa_id);
1753 }
1754 }
1755 return 0;
1756}
1757
1758static void
1759find_and_parse_output_edid(struct drm_compositor *ec,
1760 struct drm_output *output,
1761 drmModeConnector *connector)
1762{
1763 drmModePropertyBlobPtr edid_blob = NULL;
1764 drmModePropertyPtr property;
1765 int i;
1766 int rc;
1767
1768 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1769 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1770 if (!property)
1771 continue;
1772 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1773 !strcmp(property->name, "EDID")) {
1774 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1775 connector->prop_values[i]);
1776 }
1777 drmModeFreeProperty(property);
1778 }
1779 if (!edid_blob)
1780 return;
1781
1782 rc = edid_parse(&output->edid,
1783 edid_blob->data,
1784 edid_blob->length);
1785 if (!rc) {
1786 weston_log("EDID data '%s', '%s', '%s'\n",
1787 output->edid.pnp_id,
1788 output->edid.monitor_name,
1789 output->edid.serial_number);
1790 if (output->edid.pnp_id[0] != '\0')
1791 output->base.make = output->edid.pnp_id;
1792 if (output->edid.monitor_name[0] != '\0')
1793 output->base.model = output->edid.monitor_name;
1794 if (output->edid.serial_number[0] != '\0')
1795 output->base.serial_number = output->edid.serial_number;
1796 }
1797 drmModeFreePropertyBlob(edid_blob);
1798}
1799
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001800
1801
1802static int
1803parse_modeline(const char *s, drmModeModeInfo *mode)
1804{
1805 char hsync[16];
1806 char vsync[16];
1807 float fclock;
1808
1809 mode->type = DRM_MODE_TYPE_USERDEF;
1810 mode->hskew = 0;
1811 mode->vscan = 0;
1812 mode->vrefresh = 0;
1813 mode->flags = 0;
1814
Rob Bradford307e09e2013-07-26 16:29:40 +01001815 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001816 &fclock,
1817 &mode->hdisplay,
1818 &mode->hsync_start,
1819 &mode->hsync_end,
1820 &mode->htotal,
1821 &mode->vdisplay,
1822 &mode->vsync_start,
1823 &mode->vsync_end,
1824 &mode->vtotal, hsync, vsync) != 11)
1825 return -1;
1826
1827 mode->clock = fclock * 1000;
1828 if (strcmp(hsync, "+hsync") == 0)
1829 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1830 else if (strcmp(hsync, "-hsync") == 0)
1831 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1832 else
1833 return -1;
1834
1835 if (strcmp(vsync, "+vsync") == 0)
1836 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1837 else if (strcmp(vsync, "-vsync") == 0)
1838 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1839 else
1840 return -1;
1841
1842 return 0;
1843}
1844
1845static uint32_t
1846parse_transform(const char *transform, const char *output_name)
1847{
1848 static const struct { const char *name; uint32_t token; } names[] = {
1849 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1850 { "90", WL_OUTPUT_TRANSFORM_90 },
1851 { "180", WL_OUTPUT_TRANSFORM_180 },
1852 { "270", WL_OUTPUT_TRANSFORM_270 },
1853 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1854 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1855 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1856 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1857 };
1858 unsigned int i;
1859
1860 for (i = 0; i < ARRAY_LENGTH(names); i++)
1861 if (strcmp(names[i].name, transform) == 0)
1862 return names[i].token;
1863
1864 weston_log("Invalid transform \"%s\" for output %s\n",
1865 transform, output_name);
1866
1867 return WL_OUTPUT_TRANSFORM_NORMAL;
1868}
1869
Rob Bradford66bd9f52013-06-25 18:56:42 +01001870static void
1871setup_output_seat_constraint(struct drm_compositor *ec,
1872 struct weston_output *output,
1873 const char *s)
1874{
1875 if (strcmp(s, "") != 0) {
1876 struct udev_seat *seat;
1877
Jonas Ådahl58e15862014-03-12 22:08:40 +01001878 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001879 if (seat)
1880 seat->base.output = output;
1881
1882 if (seat && seat->base.pointer)
1883 weston_pointer_clamp(seat->base.pointer,
1884 &seat->base.pointer->x,
1885 &seat->base.pointer->y);
1886 }
1887}
1888
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001889static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001890get_gbm_format_from_section(struct weston_config_section *section,
1891 uint32_t default_value,
1892 uint32_t *format)
1893{
1894 char *s;
1895 int ret = 0;
1896
1897 weston_config_section_get_string(section,
1898 "gbm-format", &s, NULL);
1899
1900 if (s == NULL)
1901 *format = default_value;
1902 else if (strcmp(s, "xrgb8888") == 0)
1903 *format = GBM_FORMAT_XRGB8888;
1904 else if (strcmp(s, "rgb565") == 0)
1905 *format = GBM_FORMAT_RGB565;
1906 else if (strcmp(s, "xrgb2101010") == 0)
1907 *format = GBM_FORMAT_XRGB2101010;
1908 else {
1909 weston_log("fatal: unrecognized pixel format: %s\n", s);
1910 ret = -1;
1911 }
1912
1913 free(s);
1914
1915 return ret;
1916}
1917
1918static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001919create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001920 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001921 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001922 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001923{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001924 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001925 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001926 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001927 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001928 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001929 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001930 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001931 int i, width, height, scale;
1932 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001933 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001934 enum output_config config;
1935 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001936
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001937 i = find_crtc_for_connector(ec, resources, connector);
1938 if (i < 0) {
1939 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001940 return -1;
1941 }
1942
Peter Huttererf3d62272013-08-08 11:57:05 +10001943 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001944 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001945 return -1;
1946
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001947 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1948 output->base.make = "unknown";
1949 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001950 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001951 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001952
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001953 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1954 type_name = connector_type_names[connector->connector_type];
1955 else
1956 type_name = "UNKNOWN";
1957 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001958 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001959
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001960 section = weston_config_get_section(ec->base.config, "output", "name",
1961 output->base.name);
1962 weston_config_section_get_string(section, "mode", &s, "preferred");
1963 if (strcmp(s, "off") == 0)
1964 config = OUTPUT_CONFIG_OFF;
1965 else if (strcmp(s, "preferred") == 0)
1966 config = OUTPUT_CONFIG_PREFERRED;
1967 else if (strcmp(s, "current") == 0)
1968 config = OUTPUT_CONFIG_CURRENT;
1969 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1970 config = OUTPUT_CONFIG_MODE;
1971 else if (parse_modeline(s, &modeline) == 0)
1972 config = OUTPUT_CONFIG_MODELINE;
1973 else {
1974 weston_log("Invalid mode \"%s\" for output %s\n",
1975 s, output->base.name);
1976 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001977 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001978 free(s);
1979
1980 weston_config_section_get_int(section, "scale", &scale, 1);
1981 weston_config_section_get_string(section, "transform", &s, "normal");
1982 transform = parse_transform(s, output->base.name);
1983 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001984
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001985 if (get_gbm_format_from_section(section,
1986 ec->format,
1987 &output->format) == -1)
1988 output->format = ec->format;
1989
Rob Bradford66bd9f52013-06-25 18:56:42 +01001990 weston_config_section_get_string(section, "seat", &s, "");
1991 setup_output_seat_constraint(ec, &output->base, s);
1992 free(s);
1993
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001994 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001995 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001996 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001997 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001998 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001999
Matt Roper361d2ad2011-08-29 13:52:23 -07002000 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03002001 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002002
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002003 /* Get the current mode on the crtc that's currently driving
2004 * this connector. */
2005 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002006 memset(&crtc_mode, 0, sizeof crtc_mode);
2007 if (encoder != NULL) {
2008 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
2009 drmModeFreeEncoder(encoder);
2010 if (crtc == NULL)
2011 goto err_free;
2012 if (crtc->mode_valid)
2013 crtc_mode = crtc->mode;
2014 drmModeFreeCrtc(crtc);
2015 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002016
David Herrmann0f0d54e2011-12-08 17:05:45 +01002017 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002018 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002019 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002020 goto err_free;
2021 }
2022
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002023 if (config == OUTPUT_CONFIG_OFF) {
2024 weston_log("Disabling output %s\n", output->base.name);
2025 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
2026 0, 0, 0, 0, 0, NULL);
2027 goto err_free;
2028 }
2029
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002030 preferred = NULL;
2031 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002032 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002033 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002034
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002035 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002036 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002037 width == drm_mode->base.width &&
2038 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002039 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002040 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002041 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002042 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002043 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002044 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002045 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002046
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002047 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002048 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002049 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002050 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002051 }
2052
Wang Quanxianacb805a2012-07-30 18:09:46 -04002053 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002054 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002055 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002056 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002057 }
2058
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002059 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002060 configured = current;
2061
Wang Quanxianacb805a2012-07-30 18:09:46 -04002062 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002063 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002064 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002065 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002066 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002067 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002068 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002069 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002070 else if (best)
2071 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002072
Hardeningff39efa2013-09-18 23:56:35 +02002073 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002074 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002075 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002076 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002077
Hardeningff39efa2013-09-18 23:56:35 +02002078 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002079
John Kåre Alsaker94659272012-11-13 19:10:18 +01002080 weston_output_init(&output->base, &ec->base, x, y,
2081 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002082 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002083
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002084 if (ec->use_pixman) {
2085 if (drm_output_init_pixman(output, ec) < 0) {
2086 weston_log("Failed to init output pixman state\n");
2087 goto err_output;
2088 }
2089 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002090 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002091 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002092 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002093
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002094 output->backlight = backlight_init(drm_device,
2095 connector->connector_type);
2096 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002097 weston_log("Initialized backlight, device %s\n",
2098 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002099 output->base.set_backlight = drm_set_backlight;
2100 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002101 } else {
2102 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002103 }
2104
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002105 wl_list_insert(ec->base.output_list.prev, &output->base.link);
2106
Richard Hughes2b2092a2013-04-24 14:58:02 +01002107 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002108 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2109 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002110
Jonas Ådahle5a12252013-04-05 23:07:11 +02002111 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002112 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002113 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002114 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002115 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002116 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002117
Richard Hughese7299962013-05-01 21:52:12 +01002118 output->base.gamma_size = output->original_crtc->gamma_size;
2119 output->base.set_gamma = drm_output_set_gamma;
2120
Xiong Zhang97116532013-10-23 13:58:31 +08002121 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2122 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002123
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002124 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2125 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2126 &ec->base.primary_plane);
2127
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002128 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002129 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002130 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002131 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002132 m->width, m->height, m->refresh / 1000.0,
2133 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2134 ", preferred" : "",
2135 m->flags & WL_OUTPUT_MODE_CURRENT ?
2136 ", current" : "",
2137 connector->count_modes == 0 ?
2138 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002139
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002140 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002141
John Kåre Alsaker94659272012-11-13 19:10:18 +01002142err_output:
2143 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002144err_free:
2145 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2146 base.link) {
2147 wl_list_remove(&drm_mode->base.link);
2148 free(drm_mode);
2149 }
2150
2151 drmModeFreeCrtc(output->original_crtc);
2152 ec->crtc_allocator &= ~(1 << output->crtc_id);
2153 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002154 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002155
David Herrmann0f0d54e2011-12-08 17:05:45 +01002156 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002157}
2158
Jesse Barnes58ef3792012-02-23 09:45:49 -05002159static void
2160create_sprites(struct drm_compositor *ec)
2161{
2162 struct drm_sprite *sprite;
2163 drmModePlaneRes *plane_res;
2164 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002165 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002166
2167 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2168 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002169 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002170 strerror(errno));
2171 return;
2172 }
2173
2174 for (i = 0; i < plane_res->count_planes; i++) {
2175 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2176 if (!plane)
2177 continue;
2178
Peter Huttererf3d62272013-08-08 11:57:05 +10002179 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002180 plane->count_formats));
2181 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002182 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002183 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002184 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002185 continue;
2186 }
2187
Jesse Barnes58ef3792012-02-23 09:45:49 -05002188 sprite->possible_crtcs = plane->possible_crtcs;
2189 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002190 sprite->current = NULL;
2191 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002192 sprite->compositor = ec;
2193 sprite->count_formats = plane->count_formats;
2194 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002195 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002196 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002197 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002198 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2199 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002200
2201 wl_list_insert(&ec->sprite_list, &sprite->link);
2202 }
2203
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002204 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002205}
2206
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002207static void
2208destroy_sprites(struct drm_compositor *compositor)
2209{
2210 struct drm_sprite *sprite, *next;
2211 struct drm_output *output;
2212
2213 output = container_of(compositor->base.output_list.next,
2214 struct drm_output, base.link);
2215
2216 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2217 drmModeSetPlane(compositor->drm.fd,
2218 sprite->plane_id,
2219 output->crtc_id, 0, 0,
2220 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002221 drm_output_release_fb(output, sprite->current);
2222 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002223 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002224 free(sprite);
2225 }
2226}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002227
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002228static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002229create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002230 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002231{
2232 drmModeConnector *connector;
2233 drmModeRes *resources;
2234 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002235 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002236
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002237 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002238 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002239 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002240 return -1;
2241 }
2242
Jesse Barnes58ef3792012-02-23 09:45:49 -05002243 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002244 if (!ec->crtcs) {
2245 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002246 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002247 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002248
Rob Clark4339add2012-08-09 14:18:28 -05002249 ec->min_width = resources->min_width;
2250 ec->max_width = resources->max_width;
2251 ec->min_height = resources->min_height;
2252 ec->max_height = resources->max_height;
2253
Jesse Barnes58ef3792012-02-23 09:45:49 -05002254 ec->num_crtcs = resources->count_crtcs;
2255 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2256
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002257 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002258 connector = drmModeGetConnector(ec->drm.fd,
2259 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002260 if (connector == NULL)
2261 continue;
2262
2263 if (connector->connection == DRM_MODE_CONNECTED &&
2264 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002265 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002266 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002267 connector, x, y,
2268 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002269 drmModeFreeConnector(connector);
2270 continue;
2271 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002272
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002273 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002274 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002275 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002276 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002277
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002278 drmModeFreeConnector(connector);
2279 }
2280
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002281 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002282 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002283 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002284 return -1;
2285 }
2286
2287 drmModeFreeResources(resources);
2288
2289 return 0;
2290}
2291
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002292static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002293update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002294{
2295 drmModeConnector *connector;
2296 drmModeRes *resources;
2297 struct drm_output *output, *next;
2298 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002299 uint32_t connected = 0, disconnects = 0;
2300 int i;
2301
2302 resources = drmModeGetResources(ec->drm.fd);
2303 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002304 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002305 return;
2306 }
2307
2308 /* collect new connects */
2309 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002310 int connector_id = resources->connectors[i];
2311
2312 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002313 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002314 continue;
2315
David Herrmann7551cff2011-12-08 17:05:43 +01002316 if (connector->connection != DRM_MODE_CONNECTED) {
2317 drmModeFreeConnector(connector);
2318 continue;
2319 }
2320
Benjamin Franzke117483d2011-08-30 11:38:26 +02002321 connected |= (1 << connector_id);
2322
2323 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002324 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002325 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002326 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002327
2328 /* XXX: not yet needed, we die with 0 outputs */
2329 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002330 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002331 else
2332 x = 0;
2333 y = 0;
2334 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002335 connector, x, y,
2336 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002337 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002338
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002339 }
2340 drmModeFreeConnector(connector);
2341 }
2342 drmModeFreeResources(resources);
2343
2344 disconnects = ec->connector_allocator & ~connected;
2345 if (disconnects) {
2346 wl_list_for_each_safe(output, next, &ec->base.output_list,
2347 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002348 if (disconnects & (1 << output->connector_id)) {
2349 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002350 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002351 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002352 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002353 }
2354 }
2355 }
2356
2357 /* FIXME: handle zero outputs, without terminating */
2358 if (ec->connector_allocator == 0)
2359 wl_display_terminate(ec->base.wl_display);
2360}
2361
2362static int
David Herrmannd7488c22012-03-11 20:05:21 +01002363udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002364{
David Herrmannd7488c22012-03-11 20:05:21 +01002365 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002366 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002367
2368 sysnum = udev_device_get_sysnum(device);
2369 if (!sysnum || atoi(sysnum) != ec->drm.id)
2370 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002371
David Herrmann6ac52db2012-03-11 20:05:22 +01002372 val = udev_device_get_property_value(device, "HOTPLUG");
2373 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002374 return 0;
2375
David Herrmann6ac52db2012-03-11 20:05:22 +01002376 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002377}
2378
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002379static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002380udev_drm_event(int fd, uint32_t mask, void *data)
2381{
2382 struct drm_compositor *ec = data;
2383 struct udev_device *event;
2384
2385 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002386
David Herrmannd7488c22012-03-11 20:05:21 +01002387 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002388 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002389
2390 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002391
2392 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002393}
2394
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002395static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002396drm_restore(struct weston_compositor *ec)
2397{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002398 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002399}
2400
2401static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002402drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002403{
2404 struct drm_compositor *d = (struct drm_compositor *) ec;
2405
Rob Bradfordd355b802013-05-31 18:09:55 +01002406 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002407
2408 wl_event_source_remove(d->udev_drm_source);
2409 wl_event_source_remove(d->drm_source);
2410
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002411 destroy_sprites(d);
2412
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002413 weston_compositor_shutdown(ec);
2414
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002415 if (d->gbm)
2416 gbm_device_destroy(d->gbm);
2417
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002418 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002419
Rob Bradford45c15b82013-07-26 16:29:35 +01002420 close(d->drm.fd);
2421
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002422 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002423}
2424
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002425static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002426drm_compositor_set_modes(struct drm_compositor *compositor)
2427{
2428 struct drm_output *output;
2429 struct drm_mode *drm_mode;
2430 int ret;
2431
2432 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002433 if (!output->current) {
2434 /* If something that would cause the output to
2435 * switch mode happened while in another vt, we
2436 * might not have a current drm_fb. In that case,
2437 * schedule a repaint and let drm_output_repaint
2438 * handle setting the mode. */
2439 weston_output_schedule_repaint(&output->base);
2440 continue;
2441 }
2442
Hardeningff39efa2013-09-18 23:56:35 +02002443 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002444 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002445 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002446 &output->connector_id, 1,
2447 &drm_mode->mode_info);
2448 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002449 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002450 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002451 drm_mode->base.width, drm_mode->base.height,
2452 output->base.x, output->base.y);
2453 }
2454 }
2455}
2456
2457static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002458session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002459{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002460 struct weston_compositor *compositor = data;
2461 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002462 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002463 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002464
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002465 if (ec->base.session_active) {
2466 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002467 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002468 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002469 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002470 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002471 } else {
2472 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002473 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002474
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002475 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002476 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002477
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002478 /* If we have a repaint scheduled (either from a
2479 * pending pageflip or the idle handler), make sure we
2480 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002481 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002482 * further attemps at repainting. When we switch
2483 * back, we schedule a repaint, which will process
2484 * pending frame callbacks. */
2485
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002486 wl_list_for_each(output, &ec->base.output_list, base.link) {
2487 output->base.repaint_needed = 0;
2488 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002489 }
2490
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002491 output = container_of(ec->base.output_list.next,
2492 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002493
2494 wl_list_for_each(sprite, &ec->sprite_list, link)
2495 drmModeSetPlane(ec->drm.fd,
2496 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002497 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002498 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002499 };
2500}
2501
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002502static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002503switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002504{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002505 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002506
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002507 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002508}
2509
David Herrmann0af066f2012-10-29 19:21:16 +01002510/*
2511 * Find primary GPU
2512 * Some systems may have multiple DRM devices attached to a single seat. This
2513 * function loops over all devices and tries to find a PCI device with the
2514 * boot_vga sysfs attribute set to 1.
2515 * If no such device is found, the first DRM device reported by udev is used.
2516 */
2517static struct udev_device*
2518find_primary_gpu(struct drm_compositor *ec, const char *seat)
2519{
2520 struct udev_enumerate *e;
2521 struct udev_list_entry *entry;
2522 const char *path, *device_seat, *id;
2523 struct udev_device *device, *drm_device, *pci;
2524
2525 e = udev_enumerate_new(ec->udev);
2526 udev_enumerate_add_match_subsystem(e, "drm");
2527 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2528
2529 udev_enumerate_scan_devices(e);
2530 drm_device = NULL;
2531 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2532 path = udev_list_entry_get_name(entry);
2533 device = udev_device_new_from_syspath(ec->udev, path);
2534 if (!device)
2535 continue;
2536 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2537 if (!device_seat)
2538 device_seat = default_seat;
2539 if (strcmp(device_seat, seat)) {
2540 udev_device_unref(device);
2541 continue;
2542 }
2543
2544 pci = udev_device_get_parent_with_subsystem_devtype(device,
2545 "pci", NULL);
2546 if (pci) {
2547 id = udev_device_get_sysattr_value(pci, "boot_vga");
2548 if (id && !strcmp(id, "1")) {
2549 if (drm_device)
2550 udev_device_unref(drm_device);
2551 drm_device = device;
2552 break;
2553 }
2554 }
2555
2556 if (!drm_device)
2557 drm_device = device;
2558 else
2559 udev_device_unref(device);
2560 }
2561
2562 udev_enumerate_unref(e);
2563 return drm_device;
2564}
2565
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002566static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002567planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002568{
2569 struct drm_compositor *c = data;
2570
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002571 switch (key) {
2572 case KEY_C:
2573 c->cursors_are_broken ^= 1;
2574 break;
2575 case KEY_V:
2576 c->sprites_are_broken ^= 1;
2577 break;
2578 case KEY_O:
2579 c->sprites_hidden ^= 1;
2580 break;
2581 default:
2582 break;
2583 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002584}
2585
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002586#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002587static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002588recorder_destroy(struct drm_output *output)
2589{
2590 vaapi_recorder_destroy(output->recorder);
2591 output->recorder = NULL;
2592
2593 output->base.disable_planes--;
2594
2595 wl_list_remove(&output->recorder_frame_listener.link);
2596 weston_log("[libva recorder] done\n");
2597}
2598
2599static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002600recorder_frame_notify(struct wl_listener *listener, void *data)
2601{
2602 struct drm_output *output;
2603 struct drm_compositor *c;
2604 int fd, ret;
2605
2606 output = container_of(listener, struct drm_output,
2607 recorder_frame_listener);
2608 c = (struct drm_compositor *) output->base.compositor;
2609
2610 if (!output->recorder)
2611 return;
2612
2613 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2614 DRM_CLOEXEC, &fd);
2615 if (ret) {
2616 weston_log("[libva recorder] "
2617 "failed to create prime fd for front buffer\n");
2618 return;
2619 }
2620
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002621 ret = vaapi_recorder_frame(output->recorder, fd,
2622 output->current->stride);
2623 if (ret < 0) {
2624 weston_log("[libva recorder] aborted: %m\n");
2625 recorder_destroy(output);
2626 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002627}
2628
2629static void *
2630create_recorder(struct drm_compositor *c, int width, int height,
2631 const char *filename)
2632{
2633 int fd;
2634 drm_magic_t magic;
2635
2636 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2637 if (fd < 0)
2638 return NULL;
2639
2640 drmGetMagic(fd, &magic);
2641 drmAuthMagic(c->drm.fd, magic);
2642
2643 return vaapi_recorder_create(fd, width, height, filename);
2644}
2645
2646static void
2647recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2648 void *data)
2649{
2650 struct drm_compositor *c = data;
2651 struct drm_output *output;
2652 int width, height;
2653
2654 output = container_of(c->base.output_list.next,
2655 struct drm_output, base.link);
2656
2657 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002658 if (output->format != GBM_FORMAT_XRGB8888) {
2659 weston_log("failed to start vaapi recorder: "
2660 "output format not supported\n");
2661 return;
2662 }
2663
Hardeningff39efa2013-09-18 23:56:35 +02002664 width = output->base.current_mode->width;
2665 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002666
2667 output->recorder =
2668 create_recorder(c, width, height, "capture.h264");
2669 if (!output->recorder) {
2670 weston_log("failed to create vaapi recorder\n");
2671 return;
2672 }
2673
2674 output->base.disable_planes++;
2675
2676 output->recorder_frame_listener.notify = recorder_frame_notify;
2677 wl_signal_add(&output->base.frame_signal,
2678 &output->recorder_frame_listener);
2679
2680 weston_output_schedule_repaint(&output->base);
2681
2682 weston_log("[libva recorder] initialized\n");
2683 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002684 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002685 }
2686}
2687#else
2688static void
2689recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2690 void *data)
2691{
2692 weston_log("Compiled without libva support\n");
2693}
2694#endif
2695
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002696static void
2697switch_to_gl_renderer(struct drm_compositor *c)
2698{
2699 struct drm_output *output;
2700
2701 if (!c->use_pixman)
2702 return;
2703
2704 weston_log("Switching to GL renderer\n");
2705
2706 c->gbm = create_gbm_device(c->drm.fd);
2707 if (!c->gbm) {
2708 weston_log("Failed to create gbm device. "
2709 "Aborting renderer switch\n");
2710 return;
2711 }
2712
2713 wl_list_for_each(output, &c->base.output_list, base.link)
2714 pixman_renderer_output_destroy(&output->base);
2715
2716 c->base.renderer->destroy(&c->base);
2717
2718 if (drm_compositor_create_gl_renderer(c) < 0) {
2719 gbm_device_destroy(c->gbm);
2720 weston_log("Failed to create GL renderer. Quitting.\n");
2721 /* FIXME: we need a function to shutdown cleanly */
2722 assert(0);
2723 }
2724
2725 wl_list_for_each(output, &c->base.output_list, base.link)
2726 drm_output_init_egl(output, c);
2727
2728 c->use_pixman = 0;
2729}
2730
2731static void
2732renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2733 void *data)
2734{
2735 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2736
2737 switch_to_gl_renderer(c);
2738}
2739
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002740static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002741drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002742 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002743 int *argc, char *argv[],
2744 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002745{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002746 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002747 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002748 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002749 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002750 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002751 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002752
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002753 weston_log("initializing drm backend\n");
2754
Peter Huttererf3d62272013-08-08 11:57:05 +10002755 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002756 if (ec == NULL)
2757 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002758
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002759 /* KMS support for sprites is not complete yet, so disable the
2760 * functionality for now. */
2761 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002762
2763 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002764 if (get_gbm_format_from_section(section,
2765 GBM_FORMAT_XRGB8888,
2766 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002767 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002768
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002769 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002770
Daniel Stone725c2c32012-06-22 14:04:36 +01002771 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002772 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002773 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002774 goto err_base;
2775 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002776
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002777 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002778 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
2779 param->seat_id);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002780 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002781 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002782 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002783 goto err_compositor;
2784 }
2785
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002786 ec->udev = udev_new();
2787 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002788 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002789 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002790 }
2791
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002792 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002793 ec->session_listener.notify = session_notify;
2794 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002795
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002796 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002797 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002798 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002799 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002800 }
David Herrmann0af066f2012-10-29 19:21:16 +01002801 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002802
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002803 if (init_drm(ec, drm_device) < 0) {
2804 weston_log("failed to initialize kms\n");
2805 goto err_udev_dev;
2806 }
2807
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002808 if (ec->use_pixman) {
2809 if (init_pixman(ec) < 0) {
2810 weston_log("failed to initialize pixman renderer\n");
2811 goto err_udev_dev;
2812 }
2813 } else {
2814 if (init_egl(ec) < 0) {
2815 weston_log("failed to initialize egl\n");
2816 goto err_udev_dev;
2817 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002818 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002819
2820 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002821 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002822
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002823 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002824
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002825 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002826 weston_compositor_add_key_binding(&ec->base, key,
2827 MODIFIER_CTRL | MODIFIER_ALT,
2828 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002829
Jesse Barnes58ef3792012-02-23 09:45:49 -05002830 wl_list_init(&ec->sprite_list);
2831 create_sprites(ec);
2832
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002833 if (udev_input_init(&ec->input,
2834 &ec->base, ec->udev, param->seat_id) < 0) {
2835 weston_log("failed to create input devices\n");
2836 goto err_sprite;
2837 }
2838
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002839 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002840 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002841 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002842 }
2843
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002844 /* A this point we have some idea of whether or not we have a working
2845 * cursor plane. */
2846 if (!ec->cursors_are_broken)
2847 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2848
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002849 path = NULL;
2850
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002851 loop = wl_display_get_event_loop(ec->base.wl_display);
2852 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002853 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002854 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002855
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002856 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2857 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002858 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002859 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002860 }
2861 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2862 "drm", NULL);
2863 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002864 wl_event_loop_add_fd(loop,
2865 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002866 WL_EVENT_READABLE, udev_drm_event, ec);
2867
2868 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002869 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002870 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002871 }
2872
Daniel Stonea96b93c2012-06-22 14:04:37 +01002873 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002874
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002875 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002876 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002877 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002878 planes_binding, ec);
2879 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2880 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002881 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2882 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002883 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2884 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002885
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002886 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002887
2888err_udev_monitor:
2889 wl_event_source_remove(ec->udev_drm_source);
2890 udev_monitor_unref(ec->udev_monitor);
2891err_drm_source:
2892 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002893err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002894 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002895err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002896 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002897 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002898 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002899err_udev_dev:
2900 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002901err_launcher:
2902 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002903err_udev:
2904 udev_unref(ec->udev);
2905err_compositor:
2906 weston_compositor_shutdown(&ec->base);
2907err_base:
2908 free(ec);
2909 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002910}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002911
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002912WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002913backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002914 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002915{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002916 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002917
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002918 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002919 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2920 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2921 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002922 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002923 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002924 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002925
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002926 param.seat_id = default_seat;
2927
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002928 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002929
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002930 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002931}