blob: 86adfee1205c9a1682d73d20232b462e0579b137 [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"
Peter Hutterer823ad332014-11-26 07:06:31 +100050#include "libinput-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010051#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030052#include "vaapi-recorder.h"
Pekka Paalanen363aa7b2014-12-17 16:20:40 +020053#include "presentation_timing-server-protocol.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040054
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030055#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
56#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
57#endif
58
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030059#ifndef DRM_CAP_CURSOR_WIDTH
60#define DRM_CAP_CURSOR_WIDTH 0x8
61#endif
62
63#ifndef DRM_CAP_CURSOR_HEIGHT
64#define DRM_CAP_CURSOR_HEIGHT 0x9
65#endif
66
67#ifndef GBM_BO_USE_CURSOR
68#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
69#endif
70
Kristian Høgsberg061c4252012-06-28 11:28:15 -040071static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060072
73enum output_config {
74 OUTPUT_CONFIG_INVALID = 0,
75 OUTPUT_CONFIG_OFF,
76 OUTPUT_CONFIG_PREFERRED,
77 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060078 OUTPUT_CONFIG_MODE,
79 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060080};
81
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040082struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050083 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040084
85 struct udev *udev;
86 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040087
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010088 struct udev_monitor *udev_monitor;
89 struct wl_event_source *udev_drm_source;
90
Benjamin Franzke2af7f102011-03-02 11:14:59 +010091 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010092 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010093 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030094 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010095 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020096 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050097 uint32_t *crtcs;
98 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050099 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100100 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700101 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700102 uint32_t format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200103
Rob Clark4339add2012-08-09 14:18:28 -0500104 /* we need these parameters in order to not fail drmModeAddFB2()
105 * due to out of bounds dimensions, and then mistakenly set
106 * sprites_are_broken:
107 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200108 uint32_t min_width, max_width;
109 uint32_t min_height, max_height;
110 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500111
Jesse Barnes58ef3792012-02-23 09:45:49 -0500112 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500113 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200114 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500115
Rob Clarkab5b1e32012-08-09 13:24:45 -0500116 int cursors_are_broken;
117
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200118 int use_pixman;
119
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200120 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300121
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
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200229drm_sprite_crtc_supported(struct drm_output *output, uint32_t supported)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500230{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200231 struct weston_compositor *ec = output->base.compositor;
232 struct drm_compositor *c = (struct drm_compositor *)ec;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500233 int crtc;
234
235 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
236 if (c->crtcs[crtc] != output->crtc_id)
237 continue;
238
239 if (supported & (1 << crtc))
240 return -1;
241 }
242
243 return 0;
244}
245
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300246static void
247drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
248{
249 struct drm_fb *fb = data;
250 struct gbm_device *gbm = gbm_bo_get_device(bo);
251
252 if (fb->fb_id)
253 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
254
Pekka Paalanende685b82012-12-04 15:58:12 +0200255 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300256
257 free(data);
258}
259
260static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200261drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
262{
263 struct drm_fb *fb;
264 int ret;
265
266 struct drm_mode_create_dumb create_arg;
267 struct drm_mode_destroy_dumb destroy_arg;
268 struct drm_mode_map_dumb map_arg;
269
Peter Huttererf3d62272013-08-08 11:57:05 +1000270 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200271 if (!fb)
272 return NULL;
273
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700274 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200275 create_arg.bpp = 32;
276 create_arg.width = width;
277 create_arg.height = height;
278
279 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
280 if (ret)
281 goto err_fb;
282
283 fb->handle = create_arg.handle;
284 fb->stride = create_arg.pitch;
285 fb->size = create_arg.size;
286 fb->fd = ec->drm.fd;
287
288 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
289 fb->stride, fb->handle, &fb->fb_id);
290 if (ret)
291 goto err_bo;
292
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700293 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200294 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400295 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200296 if (ret)
297 goto err_add_fb;
298
299 fb->map = mmap(0, fb->size, PROT_WRITE,
300 MAP_SHARED, ec->drm.fd, map_arg.offset);
301 if (fb->map == MAP_FAILED)
302 goto err_add_fb;
303
304 return fb;
305
306err_add_fb:
307 drmModeRmFB(ec->drm.fd, fb->fb_id);
308err_bo:
309 memset(&destroy_arg, 0, sizeof(destroy_arg));
310 destroy_arg.handle = create_arg.handle;
311 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
312err_fb:
313 free(fb);
314 return NULL;
315}
316
317static void
318drm_fb_destroy_dumb(struct drm_fb *fb)
319{
320 struct drm_mode_destroy_dumb destroy_arg;
321
322 if (!fb->map)
323 return;
324
325 if (fb->fb_id)
326 drmModeRmFB(fb->fd, fb->fb_id);
327
328 weston_buffer_reference(&fb->buffer_ref, NULL);
329
330 munmap(fb->map, fb->size);
331
332 memset(&destroy_arg, 0, sizeof(destroy_arg));
333 destroy_arg.handle = fb->handle;
334 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
335
336 free(fb);
337}
338
339static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500340drm_fb_get_from_bo(struct gbm_bo *bo,
341 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300342{
343 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200344 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200345 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300346 int ret;
347
348 if (fb)
349 return fb;
350
Bryce Harringtonde16d892014-11-20 22:21:57 -0800351 fb = zalloc(sizeof *fb);
352 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200353 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300354
355 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300356
357 width = gbm_bo_get_width(bo);
358 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200359 fb->stride = gbm_bo_get_stride(bo);
360 fb->handle = gbm_bo_get_handle(bo).u32;
361 fb->size = fb->stride * height;
362 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300363
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200364 if (compositor->min_width > width || width > compositor->max_width ||
365 compositor->min_height > height ||
366 height > compositor->max_height) {
367 weston_log("bo geometry out of bounds\n");
368 goto err_free;
369 }
370
371 ret = -1;
372
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200373 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200374 handles[0] = fb->handle;
375 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376 offsets[0] = 0;
377
378 ret = drmModeAddFB2(compositor->drm.fd, width, height,
379 format, handles, pitches, offsets,
380 &fb->fb_id, 0);
381 if (ret) {
382 weston_log("addfb2 failed: %m\n");
383 compositor->no_addfb2 = 1;
384 compositor->sprites_are_broken = 1;
385 }
386 }
387
388 if (ret)
389 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200390 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200391
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300392 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200393 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200394 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300395 }
396
397 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
398
399 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200400
401err_free:
402 free(fb);
403 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300404}
405
406static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500407drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200408{
Pekka Paalanende685b82012-12-04 15:58:12 +0200409 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200410
411 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200412
Pekka Paalanende685b82012-12-04 15:58:12 +0200413 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200414}
415
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200416static void
417drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
418{
419 if (!fb)
420 return;
421
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200422 if (fb->map &&
423 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200424 drm_fb_destroy_dumb(fb);
425 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200426 if (fb->is_client_buffer)
427 gbm_bo_destroy(fb->bo);
428 else
429 gbm_surface_release_buffer(output->surface,
Jason Ekstrand3ec57f52013-11-14 20:52:35 -0600430 fb->bo);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200431 }
432}
433
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500434static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200435drm_output_check_scanout_format(struct drm_output *output,
436 struct weston_surface *es, struct gbm_bo *bo)
437{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200438 uint32_t format;
439 pixman_region32_t r;
440
441 format = gbm_bo_get_format(bo);
442
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700443 if (format == GBM_FORMAT_ARGB8888) {
444 /* We can scanout an ARGB buffer if the surface's
445 * opaque region covers the whole output, but we have
446 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -0800447 pixman_region32_init_rect(&r, 0, 0,
448 output->base.width,
449 output->base.height);
450 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200451
452 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500453 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200454
455 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500456 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700457
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000458 if (output->format == format)
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700459 return format;
460
461 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200462}
463
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400464static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200465drm_output_prepare_scanout_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500466 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500467{
468 struct drm_compositor *c =
469 (struct drm_compositor *) output->base.compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500470 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200471 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300472 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500473 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500474
Jason Ekstranda7af7042013-10-12 22:38:11 -0500475 if (ev->geometry.x != output->base.x ||
476 ev->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200477 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200478 buffer->width != output->base.current_mode->width ||
479 buffer->height != output->base.current_mode->height ||
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200480 output->base.transform != viewport->buffer.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500481 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400482 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500483
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400484 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700485 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500486
Rob Bradford9b101872012-09-14 23:25:41 +0100487 /* Unable to use the buffer for scanout */
488 if (!bo)
489 return NULL;
490
Jason Ekstranda7af7042013-10-12 22:38:11 -0500491 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500492 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300493 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400494 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300495 }
496
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500497 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300498 if (!output->next) {
499 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400500 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300501 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500502
Pekka Paalanende685b82012-12-04 15:58:12 +0200503 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500504
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400505 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500506}
507
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500508static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200509drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400510{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200511 struct drm_compositor *c =
512 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300513 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400514
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200515 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400516
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300517 bo = gbm_surface_lock_front_buffer(output->surface);
518 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200519 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400520 return;
521 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300522
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000523 output->next = drm_fb_get_from_bo(bo, c, output->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300524 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200525 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300526 gbm_surface_release_buffer(output->surface, bo);
527 return;
528 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400529}
530
531static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200532drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
533{
534 struct weston_compositor *ec = output->base.compositor;
535 pixman_region32_t total_damage, previous_damage;
536
537 pixman_region32_init(&total_damage);
538 pixman_region32_init(&previous_damage);
539
540 pixman_region32_copy(&previous_damage, damage);
541
542 pixman_region32_union(&total_damage, damage, &output->previous_damage);
543 pixman_region32_copy(&output->previous_damage, &previous_damage);
544
545 output->current_image ^= 1;
546
547 output->next = output->dumb[output->current_image];
548 pixman_renderer_output_set_buffer(&output->base,
549 output->image[output->current_image]);
550
551 ec->renderer->repaint_output(&output->base, &total_damage);
552
553 pixman_region32_fini(&total_damage);
554 pixman_region32_fini(&previous_damage);
555}
556
557static void
558drm_output_render(struct drm_output *output, pixman_region32_t *damage)
559{
560 struct drm_compositor *c =
561 (struct drm_compositor *) output->base.compositor;
562
563 if (c->use_pixman)
564 drm_output_render_pixman(output, damage);
565 else
566 drm_output_render_gl(output, damage);
567
568 pixman_region32_subtract(&c->base.primary_plane.damage,
569 &c->base.primary_plane.damage, damage);
570}
571
572static void
Richard Hughese7299962013-05-01 21:52:12 +0100573drm_output_set_gamma(struct weston_output *output_base,
574 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
575{
576 int rc;
577 struct drm_output *output = (struct drm_output *) output_base;
578 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
579
580 /* check */
581 if (output_base->gamma_size != size)
582 return;
583 if (!output->original_crtc)
584 return;
585
586 rc = drmModeCrtcSetGamma(compositor->drm.fd,
587 output->crtc_id,
588 size, r, g, b);
589 if (rc)
590 weston_log("set gamma failed: %m\n");
591}
592
David Herrmann1edf44c2013-10-22 17:11:26 +0200593static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500594drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400595 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100596{
597 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500598 struct drm_compositor *compositor =
599 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500600 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400601 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500602 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100603
Xiong Zhangabd5d472013-10-11 14:43:07 +0800604 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200605 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800606
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300607 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400608 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300609 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200610 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100611
Hardeningff39efa2013-09-18 23:56:35 +0200612 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200613 if (!output->current ||
614 output->current->stride != output->next->stride) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400615 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300616 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400617 &output->connector_id, 1,
618 &mode->mode_info);
619 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200620 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200621 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400622 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300623 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200624 }
625
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500626 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300627 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500628 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200629 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200630 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500631 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100632
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300633 output->page_flip_pending = 1;
634
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400635 drm_output_set_cursor(output);
636
Jesse Barnes58ef3792012-02-23 09:45:49 -0500637 /*
638 * Now, update all the sprite surfaces
639 */
640 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200641 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500642 drmVBlank vbl = {
643 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
644 .request.sequence = 1,
645 };
646
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200647 if ((!s->current && !s->next) ||
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200648 !drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500649 continue;
650
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200651 if (s->next && !compositor->sprites_hidden)
652 fb_id = s->next->fb_id;
653
Jesse Barnes58ef3792012-02-23 09:45:49 -0500654 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200655 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500656 s->dest_x, s->dest_y,
657 s->dest_w, s->dest_h,
658 s->src_x, s->src_y,
659 s->src_w, s->src_h);
660 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200661 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500662 ret, strerror(errno));
663
Rob Clark5ca1a472012-08-08 20:27:37 -0500664 if (output->pipe > 0)
665 vbl.request.type |= DRM_VBLANK_SECONDARY;
666
Jesse Barnes58ef3792012-02-23 09:45:49 -0500667 /*
668 * Queue a vblank signal so we know when the surface
669 * becomes active on the display or has been replaced.
670 */
671 vbl.request.signal = (unsigned long)s;
672 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
673 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200674 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500675 ret, strerror(errno));
676 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300677
678 s->output = output;
679 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500680 }
681
David Herrmann1edf44c2013-10-22 17:11:26 +0200682 return 0;
683
684err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800685 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200686 if (output->next) {
687 drm_output_release_fb(output, output->next);
688 output->next = NULL;
689 }
690
691 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400692}
693
694static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200695drm_output_start_repaint_loop(struct weston_output *output_base)
696{
697 struct drm_output *output = (struct drm_output *) output_base;
698 struct drm_compositor *compositor = (struct drm_compositor *)
699 output_base->compositor;
700 uint32_t fb_id;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300701 struct timespec ts;
702
Xiong Zhangabd5d472013-10-11 14:43:07 +0800703 if (output->destroy_pending)
704 return;
705
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300706 if (!output->current) {
707 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200708 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300709 }
710
711 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200712
713 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
714 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
715 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200716 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200717 }
David Herrmann3c688c52013-10-22 17:11:25 +0200718
719 return;
720
721finish_frame:
722 /* if we cannot page-flip, immediately finish frame */
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400723 clock_gettime(compositor->base.presentation_clock, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200724 weston_output_finish_frame(output_base, &ts,
725 PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200726}
727
728static void
Pekka Paalanen641307c2014-09-23 22:08:47 -0400729drm_output_update_msc(struct drm_output *output, unsigned int seq)
730{
731 uint64_t msc_hi = output->base.msc >> 32;
732
733 if (seq < (output->base.msc & 0xffffffff))
734 msc_hi++;
735
736 output->base.msc = (msc_hi << 32) + seq;
737}
738
739static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500740vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
741 void *data)
742{
743 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300744 struct drm_output *output = s->output;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400745 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200746 uint32_t flags = PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
747 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300748
Pekka Paalanen641307c2014-09-23 22:08:47 -0400749 drm_output_update_msc(output, frame);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300750 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500751
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200752 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200753 s->current = s->next;
754 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300755
756 if (!output->page_flip_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400757 ts.tv_sec = sec;
758 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200759 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300760 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500761}
762
763static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800764drm_output_destroy(struct weston_output *output_base);
765
766static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400767page_flip_handler(int fd, unsigned int frame,
768 unsigned int sec, unsigned int usec, void *data)
769{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200770 struct drm_output *output = (struct drm_output *) data;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400771 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200772 uint32_t flags = PRESENTATION_FEEDBACK_KIND_VSYNC |
773 PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
774 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400775
Pekka Paalanen641307c2014-09-23 22:08:47 -0400776 drm_output_update_msc(output, frame);
777
Jonas Ådahle5a12252013-04-05 23:07:11 +0200778 /* We don't set page_flip_pending on start_repaint_loop, in that case
779 * we just want to page flip to the current buffer to get an accurate
780 * timestamp */
781 if (output->page_flip_pending) {
782 drm_output_release_fb(output, output->current);
783 output->current = output->next;
784 output->next = NULL;
785 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300786
Jonas Ådahle5a12252013-04-05 23:07:11 +0200787 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400788
Xiong Zhangabd5d472013-10-11 14:43:07 +0800789 if (output->destroy_pending)
790 drm_output_destroy(&output->base);
791 else if (!output->vblank_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400792 ts.tv_sec = sec;
793 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200794 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300795
796 /* We can't call this from frame_notify, because the output's
797 * repaint needed flag is cleared just after that */
798 if (output->recorder)
799 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300800 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200801}
802
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500803static uint32_t
804drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500805 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500806{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500807 uint32_t i, format;
808
809 format = gbm_bo_get_format(bo);
810
811 if (format == GBM_FORMAT_ARGB8888) {
812 pixman_region32_t r;
813
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500814 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600815 ev->surface->width,
816 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500817 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500818
819 if (!pixman_region32_not_empty(&r))
820 format = GBM_FORMAT_XRGB8888;
821
822 pixman_region32_fini(&r);
823 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500824
825 for (i = 0; i < s->count_formats; i++)
826 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500827 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500828
829 return 0;
830}
831
832static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500833drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500834{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500835 return !ev->transform.enabled ||
836 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500837}
838
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400839static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200840drm_output_prepare_overlay_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500841 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500842{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200843 struct weston_compositor *ec = output->base.compositor;
844 struct drm_compositor *c = (struct drm_compositor *)ec;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200845 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500846 struct drm_sprite *s;
847 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500848 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500849 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200850 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500851 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400852 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500853
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200854 if (c->gbm == NULL)
855 return NULL;
856
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200857 if (viewport->buffer.transform != output->base.transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200858 return NULL;
859
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200860 if (viewport->buffer.scale != output->base.current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200861 return NULL;
862
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500863 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400864 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500865
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200866 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400867 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300868
Jason Ekstranda7af7042013-10-12 22:38:11 -0500869 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400870 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500871
Jason Ekstranda7af7042013-10-12 22:38:11 -0500872 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200873 return NULL;
874
Jason Ekstranda7af7042013-10-12 22:38:11 -0500875 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500876 return NULL;
877
Jason Ekstranda7af7042013-10-12 22:38:11 -0500878 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400879 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500880
Jesse Barnes58ef3792012-02-23 09:45:49 -0500881 wl_list_for_each(s, &c->sprite_list, link) {
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200882 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500883 continue;
884
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200885 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500886 found = 1;
887 break;
888 }
889 }
890
891 /* No sprites available */
892 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400893 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500894
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400895 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500896 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700897 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400898 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400899 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400900
Jason Ekstranda7af7042013-10-12 22:38:11 -0500901 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500902 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200903 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400904 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500905 }
906
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200907 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200908 if (!s->next) {
909 gbm_bo_destroy(bo);
910 return NULL;
911 }
912
Jason Ekstranda7af7042013-10-12 22:38:11 -0500913 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500914
Jason Ekstranda7af7042013-10-12 22:38:11 -0500915 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400916 s->plane.x = box->x1;
917 s->plane.y = box->y1;
918
Jesse Barnes58ef3792012-02-23 09:45:49 -0500919 /*
920 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -0500921 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500922 * for us already).
923 */
924 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500925 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200926 &output->base.region);
927 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500928 box = pixman_region32_extents(&dest_rect);
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200929 tbox = weston_transformed_rect(output->base.width,
930 output->base.height,
931 output->base.transform,
932 output->base.current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200933 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200934 s->dest_x = tbox.x1;
935 s->dest_y = tbox.y1;
936 s->dest_w = tbox.x2 - tbox.x1;
937 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500938 pixman_region32_fini(&dest_rect);
939
940 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500941 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200942 &output->base.region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500943 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400944
Jason Ekstranda7af7042013-10-12 22:38:11 -0500945 weston_view_from_global_fixed(ev,
946 wl_fixed_from_int(box->x1),
947 wl_fixed_from_int(box->y1),
948 &sx1, &sy1);
949 weston_view_from_global_fixed(ev,
950 wl_fixed_from_int(box->x2),
951 wl_fixed_from_int(box->y2),
952 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400953
954 if (sx1 < 0)
955 sx1 = 0;
956 if (sy1 < 0)
957 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600958 if (sx2 > wl_fixed_from_int(ev->surface->width))
959 sx2 = wl_fixed_from_int(ev->surface->width);
960 if (sy2 > wl_fixed_from_int(ev->surface->height))
961 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400962
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200963 tbox.x1 = sx1;
964 tbox.y1 = sy1;
965 tbox.x2 = sx2;
966 tbox.y2 = sy2;
967
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600968 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
969 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200970 viewport->buffer.transform,
971 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100972 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200973
974 s->src_x = tbox.x1 << 8;
975 s->src_y = tbox.y1 << 8;
976 s->src_w = (tbox.x2 - tbox.x1) << 8;
977 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500978 pixman_region32_fini(&src_rect);
979
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400980 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500981}
982
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400983static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200984drm_output_prepare_cursor_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500985 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500986{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400987 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200988 (struct drm_compositor *)output->base.compositor;
Neil Robertsf37f82c2014-05-01 18:00:41 +0100989 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400990
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200991 if (c->gbm == NULL)
992 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200993 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
994 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200995 if (viewport->buffer.scale != output->base.current_scale)
Neil Robertsf37f82c2014-05-01 18:00:41 +0100996 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500997 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400998 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200999 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001000 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001001 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -04001002 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001003 if (ev->surface->buffer_ref.buffer == NULL ||
1004 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001005 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001006 return NULL;
1007
Jason Ekstranda7af7042013-10-12 22:38:11 -05001008 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001009
1010 return &output->cursor_plane;
1011}
1012
1013static void
1014drm_output_set_cursor(struct drm_output *output)
1015{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001016 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001017 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001018 struct drm_compositor *c =
1019 (struct drm_compositor *) output->base.compositor;
1020 EGLint handle, stride;
1021 struct gbm_bo *bo;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001022 uint32_t buf[c->cursor_width * c->cursor_height];
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001023 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001024 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001025
Jason Ekstranda7af7042013-10-12 22:38:11 -05001026 output->cursor_view = NULL;
1027 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001028 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
1029 return;
1030 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001031
Neil Robertse5051712013-11-13 15:44:06 +00001032 buffer = ev->surface->buffer_ref.buffer;
1033
1034 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001035 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001036 pixman_region32_fini(&output->cursor_plane.damage);
1037 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001038 output->current_cursor ^= 1;
1039 bo = output->cursor_bo[output->current_cursor];
1040 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001041 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1042 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1043 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001044 for (i = 0; i < ev->surface->height; i++)
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001045 memcpy(buf + i * c->cursor_width, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001046 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001047 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001048
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001049 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001050 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001051
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001052 handle = gbm_bo_get_handle(bo).s32;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001053 if (drmModeSetCursor(c->drm.fd, output->crtc_id, handle,
1054 c->cursor_width, c->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001055 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001056 c->cursors_are_broken = 1;
1057 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001058 }
1059
Jason Ekstranda7af7042013-10-12 22:38:11 -05001060 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1061 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001062 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001063 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001064 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001065 c->cursors_are_broken = 1;
1066 }
1067
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001068 output->cursor_plane.x = x;
1069 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001070 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001071}
1072
Jesse Barnes58ef3792012-02-23 09:45:49 -05001073static void
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001074drm_assign_planes(struct weston_output *output_base)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001075{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001076 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001077 (struct drm_compositor *)output_base->compositor;
1078 struct drm_output *output = (struct drm_output *)output_base;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001079 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001080 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001081 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001082
1083 /*
1084 * Find a surface for each sprite in the output using some heuristics:
1085 * 1) size
1086 * 2) frequency of update
1087 * 3) opacity (though some hw might support alpha blending)
1088 * 4) clipping (this can be fixed with color keys)
1089 *
1090 * The idea is to save on blitting since this should save power.
1091 * If we can get a large video surface on the sprite for example,
1092 * the main display surface may not need to update at all, and
1093 * the client buffer can be used directly for the sprite surface
1094 * as we do for flipping full screen surfaces.
1095 */
1096 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001097 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001098
Jason Ekstranda7af7042013-10-12 22:38:11 -05001099 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001100 struct weston_surface *es = ev->surface;
1101
1102 /* Test whether this buffer can ever go into a plane:
1103 * non-shm, or small enough to be a cursor.
1104 *
1105 * Also, keep a reference when using the pixman renderer.
1106 * That makes it possible to do a seamless switch to the GL
1107 * renderer and since the pixman renderer keeps a reference
1108 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001109 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001110 if (c->use_pixman ||
1111 (es->buffer_ref.buffer &&
1112 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001113 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001114 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001115 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001116 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001117
Jesse Barnes58ef3792012-02-23 09:45:49 -05001118 pixman_region32_init(&surface_overlap);
1119 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001120 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001121
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001122 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001123 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001124 next_plane = primary;
1125 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001126 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001127 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001128 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001129 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001130 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001131 if (next_plane == NULL)
1132 next_plane = primary;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001133 weston_view_move_to_plane(ev, next_plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001134 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001135 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001136 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001137
Jesse Barnes58ef3792012-02-23 09:45:49 -05001138 pixman_region32_fini(&surface_overlap);
1139 }
1140 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001141}
1142
Matt Roper361d2ad2011-08-29 13:52:23 -07001143static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001144drm_output_fini_pixman(struct drm_output *output);
1145
1146static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001147drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001148{
1149 struct drm_output *output = (struct drm_output *) output_base;
1150 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001151 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001152 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001153
Xiong Zhangabd5d472013-10-11 14:43:07 +08001154 if (output->page_flip_pending) {
1155 output->destroy_pending = 1;
1156 weston_log("destroy output while page flip pending\n");
1157 return;
1158 }
1159
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001160 if (output->backlight)
1161 backlight_destroy(output->backlight);
1162
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001163 drmModeFreeProperty(output->dpms_prop);
1164
Matt Roper361d2ad2011-08-29 13:52:23 -07001165 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001166 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001167
1168 /* Restore original CRTC state */
1169 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001170 origcrtc->x, origcrtc->y,
1171 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001172 drmModeFreeCrtc(origcrtc);
1173
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001174 c->crtc_allocator &= ~(1 << output->crtc_id);
1175 c->connector_allocator &= ~(1 << output->connector_id);
1176
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001177 if (c->use_pixman) {
1178 drm_output_fini_pixman(output);
1179 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001180 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001181 gbm_surface_destroy(output->surface);
1182 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001183
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001184 weston_plane_release(&output->fb_plane);
1185 weston_plane_release(&output->cursor_plane);
1186
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001187 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001188
Matt Roper361d2ad2011-08-29 13:52:23 -07001189 free(output);
1190}
1191
Alex Wub7b8bda2012-04-17 17:20:48 +08001192static struct drm_mode *
1193choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1194{
1195 struct drm_mode *tmp_mode = NULL, *mode;
1196
Hardeningff39efa2013-09-18 23:56:35 +02001197 if (output->base.current_mode->width == target_mode->width &&
1198 output->base.current_mode->height == target_mode->height &&
1199 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001200 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001201 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001202
1203 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1204 if (mode->mode_info.hdisplay == target_mode->width &&
1205 mode->mode_info.vdisplay == target_mode->height) {
1206 if (mode->mode_info.vrefresh == target_mode->refresh ||
1207 target_mode->refresh == 0) {
1208 return mode;
1209 } else if (!tmp_mode)
1210 tmp_mode = mode;
1211 }
1212 }
1213
1214 return tmp_mode;
1215}
1216
1217static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001218drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001219static int
1220drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001221
1222static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001223drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1224{
1225 struct drm_output *output;
1226 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001227 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001228
1229 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001230 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001231 return -1;
1232 }
1233
1234 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001235 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001236 return -1;
1237 }
1238
1239 ec = (struct drm_compositor *)output_base->compositor;
1240 output = (struct drm_output *)output_base;
1241 drm_mode = choose_mode (output, mode);
1242
1243 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001244 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001245 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001246 }
1247
Hardeningff39efa2013-09-18 23:56:35 +02001248 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001249 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001250
Hardeningff39efa2013-09-18 23:56:35 +02001251 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001252
Hardeningff39efa2013-09-18 23:56:35 +02001253 output->base.current_mode = &drm_mode->base;
1254 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001255 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1256
Alex Wub7b8bda2012-04-17 17:20:48 +08001257 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001258 drm_output_release_fb(output, output->current);
1259 drm_output_release_fb(output, output->next);
1260 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001261
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001262 if (ec->use_pixman) {
1263 drm_output_fini_pixman(output);
1264 if (drm_output_init_pixman(output, ec) < 0) {
1265 weston_log("failed to init output pixman state with "
1266 "new mode\n");
1267 return -1;
1268 }
1269 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001270 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001271 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001272
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001273 if (drm_output_init_egl(output, ec) < 0) {
1274 weston_log("failed to init output egl state with "
1275 "new mode");
1276 return -1;
1277 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001278 }
1279
Alex Wub7b8bda2012-04-17 17:20:48 +08001280 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001281}
1282
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001283static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001284on_drm_input(int fd, uint32_t mask, void *data)
1285{
1286 drmEventContext evctx;
1287
1288 memset(&evctx, 0, sizeof evctx);
1289 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1290 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001291 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001292 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001293
1294 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001295}
1296
1297static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001298init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001299{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001300 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001301 uint64_t cap;
1302 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001303 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001304
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001305 sysnum = udev_device_get_sysnum(device);
1306 if (sysnum)
1307 ec->drm.id = atoi(sysnum);
1308 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001309 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001310 return -1;
1311 }
1312
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001313 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001314 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001315 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001316 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001317 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001318 udev_device_get_devnode(device));
1319 return -1;
1320 }
1321
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001322 weston_log("using %s\n", filename);
1323
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001324 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001325 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001326
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001327 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1328 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001329 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001330 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001331 clk_id = CLOCK_REALTIME;
1332
1333 if (weston_compositor_set_presentation_clock(&ec->base, clk_id) < 0) {
1334 weston_log("Error: failed to set presentation clock %d.\n",
1335 clk_id);
1336 return -1;
1337 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001338
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001339 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1340 if (ret == 0)
1341 ec->cursor_width = cap;
1342 else
1343 ec->cursor_width = 64;
1344
1345 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1346 if (ret == 0)
1347 ec->cursor_height = cap;
1348 else
1349 ec->cursor_height = 64;
1350
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001351 return 0;
1352}
1353
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001354static struct gbm_device *
1355create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001356{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001357 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001358
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001359 gl_renderer = weston_load_module("gl-renderer.so",
1360 "gl_renderer_interface");
1361 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001362 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001363
1364 /* GBM will load a dri driver, but even though they need symbols from
1365 * libglapi, in some version of Mesa they are not linked to it. Since
1366 * only the gl-renderer module links to it, the call above won't make
1367 * these symbols globally available, and loading the DRI driver fails.
1368 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1369 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1370
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001371 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001372
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001373 return gbm;
1374}
1375
1376static int
1377drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1378{
1379 EGLint format;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001380
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001381 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001382 if (gl_renderer->create(&ec->base, ec->gbm,
1383 gl_renderer->opaque_attribs, &format) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001384 return -1;
1385 }
1386
1387 return 0;
1388}
1389
1390static int
1391init_egl(struct drm_compositor *ec)
1392{
1393 ec->gbm = create_gbm_device(ec->drm.fd);
1394
1395 if (!ec->gbm)
1396 return -1;
1397
1398 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001399 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001400 return -1;
1401 }
1402
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001403 return 0;
1404}
1405
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001406static int
1407init_pixman(struct drm_compositor *ec)
1408{
1409 return pixman_renderer_init(&ec->base);
1410}
1411
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001412static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001413drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001414{
1415 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001416 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001417
1418 mode = malloc(sizeof *mode);
1419 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001420 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001421
1422 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001423 mode->base.width = info->hdisplay;
1424 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001425
1426 /* Calculate higher precision (mHz) refresh rate */
1427 refresh = (info->clock * 1000000LL / info->htotal +
1428 info->vtotal / 2) / info->vtotal;
1429
1430 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1431 refresh *= 2;
1432 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1433 refresh /= 2;
1434 if (info->vscan > 1)
1435 refresh /= info->vscan;
1436
1437 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001438 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001439
1440 if (info->type & DRM_MODE_TYPE_PREFERRED)
1441 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1442
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001443 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1444
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001445 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001446}
1447
1448static int
1449drm_subpixel_to_wayland(int drm_value)
1450{
1451 switch (drm_value) {
1452 default:
1453 case DRM_MODE_SUBPIXEL_UNKNOWN:
1454 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1455 case DRM_MODE_SUBPIXEL_NONE:
1456 return WL_OUTPUT_SUBPIXEL_NONE;
1457 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1458 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1459 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1460 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1461 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1462 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1463 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1464 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1465 }
1466}
1467
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001468/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001469static uint32_t
1470drm_get_backlight(struct drm_output *output)
1471{
1472 long brightness, max_brightness, norm;
1473
1474 brightness = backlight_get_brightness(output->backlight);
1475 max_brightness = backlight_get_max_brightness(output->backlight);
1476
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001477 /* convert it on a scale of 0 to 255 */
1478 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001479
1480 return (uint32_t) norm;
1481}
1482
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001483/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001484static void
1485drm_set_backlight(struct weston_output *output_base, uint32_t value)
1486{
1487 struct drm_output *output = (struct drm_output *) output_base;
1488 long max_brightness, new_brightness;
1489
1490 if (!output->backlight)
1491 return;
1492
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001493 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001494 return;
1495
1496 max_brightness = backlight_get_max_brightness(output->backlight);
1497
1498 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001499 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001500
1501 backlight_set_brightness(output->backlight, new_brightness);
1502}
1503
1504static drmModePropertyPtr
1505drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1506{
1507 drmModePropertyPtr props;
1508 int i;
1509
1510 for (i = 0; i < connector->count_props; i++) {
1511 props = drmModeGetProperty(fd, connector->props[i]);
1512 if (!props)
1513 continue;
1514
1515 if (!strcmp(props->name, name))
1516 return props;
1517
1518 drmModeFreeProperty(props);
1519 }
1520
1521 return NULL;
1522}
1523
1524static void
1525drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1526{
1527 struct drm_output *output = (struct drm_output *) output_base;
1528 struct weston_compositor *ec = output_base->compositor;
1529 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001530
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001531 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001532 return;
1533
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001534 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1535 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001536}
1537
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001538static const char *connector_type_names[] = {
1539 "None",
1540 "VGA",
1541 "DVI",
1542 "DVI",
1543 "DVI",
1544 "Composite",
1545 "TV",
1546 "LVDS",
1547 "CTV",
1548 "DIN",
1549 "DP",
1550 "HDMI",
1551 "HDMI",
1552 "TV",
1553 "eDP",
1554};
1555
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001556static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001557find_crtc_for_connector(struct drm_compositor *ec,
1558 drmModeRes *resources, drmModeConnector *connector)
1559{
1560 drmModeEncoder *encoder;
1561 uint32_t possible_crtcs;
1562 int i, j;
1563
1564 for (j = 0; j < connector->count_encoders; j++) {
1565 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1566 if (encoder == NULL) {
1567 weston_log("Failed to get encoder.\n");
1568 return -1;
1569 }
1570 possible_crtcs = encoder->possible_crtcs;
1571 drmModeFreeEncoder(encoder);
1572
1573 for (i = 0; i < resources->count_crtcs; i++) {
1574 if (possible_crtcs & (1 << i) &&
1575 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1576 return i;
1577 }
1578 }
1579
1580 return -1;
1581}
1582
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001583/* Init output state that depends on gl or gbm */
1584static int
1585drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1586{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001587 EGLint format = output->format;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001588 int i, flags;
1589
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001590 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001591 output->base.current_mode->width,
1592 output->base.current_mode->height,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001593 format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001594 GBM_BO_USE_SCANOUT |
1595 GBM_BO_USE_RENDERING);
1596 if (!output->surface) {
1597 weston_log("failed to create gbm surface\n");
1598 return -1;
1599 }
1600
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001601 if (gl_renderer->output_create(&output->base, output->surface,
1602 gl_renderer->opaque_attribs,
1603 &format) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001604 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001605 gbm_surface_destroy(output->surface);
1606 return -1;
1607 }
1608
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001609 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001610
1611 for (i = 0; i < 2; i++) {
1612 if (output->cursor_bo[i])
1613 continue;
1614
1615 output->cursor_bo[i] =
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001616 gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
1617 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001618 }
1619
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001620 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1621 weston_log("cursor buffers unavailable, using gl cursors\n");
1622 ec->cursors_are_broken = 1;
1623 }
1624
1625 return 0;
1626}
1627
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001628static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001629drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1630{
Hardeningff39efa2013-09-18 23:56:35 +02001631 int w = output->base.current_mode->width;
1632 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001633 unsigned int i;
1634
1635 /* FIXME error checking */
1636
1637 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001638 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001639 if (!output->dumb[i])
1640 goto err;
1641
1642 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001643 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001644 output->dumb[i]->map,
1645 output->dumb[i]->stride);
1646 if (!output->image[i])
1647 goto err;
1648 }
1649
1650 if (pixman_renderer_output_create(&output->base) < 0)
1651 goto err;
1652
1653 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001654 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001655
1656 return 0;
1657
1658err:
1659 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1660 if (output->dumb[i])
1661 drm_fb_destroy_dumb(output->dumb[i]);
1662 if (output->image[i])
1663 pixman_image_unref(output->image[i]);
1664
1665 output->dumb[i] = NULL;
1666 output->image[i] = NULL;
1667 }
1668
1669 return -1;
1670}
1671
1672static void
1673drm_output_fini_pixman(struct drm_output *output)
1674{
1675 unsigned int i;
1676
1677 pixman_renderer_output_destroy(&output->base);
1678 pixman_region32_fini(&output->previous_damage);
1679
1680 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1681 drm_fb_destroy_dumb(output->dumb[i]);
1682 pixman_image_unref(output->image[i]);
1683 output->dumb[i] = NULL;
1684 output->image[i] = NULL;
1685 }
1686}
1687
Richard Hughes2b2092a2013-04-24 14:58:02 +01001688static void
1689edid_parse_string(const uint8_t *data, char text[])
1690{
1691 int i;
1692 int replaced = 0;
1693
1694 /* this is always 12 bytes, but we can't guarantee it's null
1695 * terminated or not junk. */
1696 strncpy(text, (const char *) data, 12);
1697
1698 /* remove insane chars */
1699 for (i = 0; text[i] != '\0'; i++) {
1700 if (text[i] == '\n' ||
1701 text[i] == '\r') {
1702 text[i] = '\0';
1703 break;
1704 }
1705 }
1706
1707 /* ensure string is printable */
1708 for (i = 0; text[i] != '\0'; i++) {
1709 if (!isprint(text[i])) {
1710 text[i] = '-';
1711 replaced++;
1712 }
1713 }
1714
1715 /* if the string is random junk, ignore the string */
1716 if (replaced > 4)
1717 text[0] = '\0';
1718}
1719
1720#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1721#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1722#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1723#define EDID_OFFSET_DATA_BLOCKS 0x36
1724#define EDID_OFFSET_LAST_BLOCK 0x6c
1725#define EDID_OFFSET_PNPID 0x08
1726#define EDID_OFFSET_SERIAL 0x0c
1727
1728static int
1729edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1730{
1731 int i;
1732 uint32_t serial_number;
1733
1734 /* check header */
1735 if (length < 128)
1736 return -1;
1737 if (data[0] != 0x00 || data[1] != 0xff)
1738 return -1;
1739
1740 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1741 * /--08--\/--09--\
1742 * 7654321076543210
1743 * |\---/\---/\---/
1744 * R C1 C2 C3 */
1745 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1746 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1747 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1748 edid->pnp_id[3] = '\0';
1749
1750 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1751 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1752 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1753 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1754 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1755 if (serial_number > 0)
1756 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1757
1758 /* parse EDID data */
1759 for (i = EDID_OFFSET_DATA_BLOCKS;
1760 i <= EDID_OFFSET_LAST_BLOCK;
1761 i += 18) {
1762 /* ignore pixel clock data */
1763 if (data[i] != 0)
1764 continue;
1765 if (data[i+2] != 0)
1766 continue;
1767
1768 /* any useful blocks? */
1769 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1770 edid_parse_string(&data[i+5],
1771 edid->monitor_name);
1772 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1773 edid_parse_string(&data[i+5],
1774 edid->serial_number);
1775 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1776 edid_parse_string(&data[i+5],
1777 edid->eisa_id);
1778 }
1779 }
1780 return 0;
1781}
1782
1783static void
1784find_and_parse_output_edid(struct drm_compositor *ec,
1785 struct drm_output *output,
1786 drmModeConnector *connector)
1787{
1788 drmModePropertyBlobPtr edid_blob = NULL;
1789 drmModePropertyPtr property;
1790 int i;
1791 int rc;
1792
1793 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1794 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1795 if (!property)
1796 continue;
1797 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1798 !strcmp(property->name, "EDID")) {
1799 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1800 connector->prop_values[i]);
1801 }
1802 drmModeFreeProperty(property);
1803 }
1804 if (!edid_blob)
1805 return;
1806
1807 rc = edid_parse(&output->edid,
1808 edid_blob->data,
1809 edid_blob->length);
1810 if (!rc) {
1811 weston_log("EDID data '%s', '%s', '%s'\n",
1812 output->edid.pnp_id,
1813 output->edid.monitor_name,
1814 output->edid.serial_number);
1815 if (output->edid.pnp_id[0] != '\0')
1816 output->base.make = output->edid.pnp_id;
1817 if (output->edid.monitor_name[0] != '\0')
1818 output->base.model = output->edid.monitor_name;
1819 if (output->edid.serial_number[0] != '\0')
1820 output->base.serial_number = output->edid.serial_number;
1821 }
1822 drmModeFreePropertyBlob(edid_blob);
1823}
1824
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001825
1826
1827static int
1828parse_modeline(const char *s, drmModeModeInfo *mode)
1829{
1830 char hsync[16];
1831 char vsync[16];
1832 float fclock;
1833
1834 mode->type = DRM_MODE_TYPE_USERDEF;
1835 mode->hskew = 0;
1836 mode->vscan = 0;
1837 mode->vrefresh = 0;
1838 mode->flags = 0;
1839
Rob Bradford307e09e2013-07-26 16:29:40 +01001840 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001841 &fclock,
1842 &mode->hdisplay,
1843 &mode->hsync_start,
1844 &mode->hsync_end,
1845 &mode->htotal,
1846 &mode->vdisplay,
1847 &mode->vsync_start,
1848 &mode->vsync_end,
1849 &mode->vtotal, hsync, vsync) != 11)
1850 return -1;
1851
1852 mode->clock = fclock * 1000;
1853 if (strcmp(hsync, "+hsync") == 0)
1854 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1855 else if (strcmp(hsync, "-hsync") == 0)
1856 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1857 else
1858 return -1;
1859
1860 if (strcmp(vsync, "+vsync") == 0)
1861 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1862 else if (strcmp(vsync, "-vsync") == 0)
1863 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1864 else
1865 return -1;
1866
1867 return 0;
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");
Derek Foreman64a3df02014-10-23 12:24:18 -05001982 if (weston_parse_transform(s, &transform) < 0)
1983 weston_log("Invalid transform \"%s\" for output %s\n",
1984 s, output->base.name);
1985
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001986 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001987
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001988 if (get_gbm_format_from_section(section,
1989 ec->format,
1990 &output->format) == -1)
1991 output->format = ec->format;
1992
Rob Bradford66bd9f52013-06-25 18:56:42 +01001993 weston_config_section_get_string(section, "seat", &s, "");
1994 setup_output_seat_constraint(ec, &output->base, s);
1995 free(s);
1996
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001997 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001998 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001999 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002000 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002001 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002002
Matt Roper361d2ad2011-08-29 13:52:23 -07002003 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03002004 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002005
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002006 /* Get the current mode on the crtc that's currently driving
2007 * this connector. */
2008 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002009 memset(&crtc_mode, 0, sizeof crtc_mode);
2010 if (encoder != NULL) {
2011 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
2012 drmModeFreeEncoder(encoder);
2013 if (crtc == NULL)
2014 goto err_free;
2015 if (crtc->mode_valid)
2016 crtc_mode = crtc->mode;
2017 drmModeFreeCrtc(crtc);
2018 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002019
David Herrmann0f0d54e2011-12-08 17:05:45 +01002020 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002021 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002022 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002023 goto err_free;
2024 }
2025
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002026 if (config == OUTPUT_CONFIG_OFF) {
2027 weston_log("Disabling output %s\n", output->base.name);
2028 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
2029 0, 0, 0, 0, 0, NULL);
2030 goto err_free;
2031 }
2032
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002033 preferred = NULL;
2034 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002035 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002036 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002037
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002038 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002039 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002040 width == drm_mode->base.width &&
2041 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002042 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002043 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002044 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002045 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002046 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002047 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002048 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002049
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002050 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002051 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002052 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002053 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002054 }
2055
Wang Quanxianacb805a2012-07-30 18:09:46 -04002056 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002057 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002058 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002059 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002060 }
2061
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002062 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002063 configured = current;
2064
Wang Quanxianacb805a2012-07-30 18:09:46 -04002065 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002066 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002067 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002068 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002069 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002070 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002071 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002072 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002073 else if (best)
2074 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002075
Hardeningff39efa2013-09-18 23:56:35 +02002076 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002077 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002078 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002079 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002080
Hardeningff39efa2013-09-18 23:56:35 +02002081 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002082
John Kåre Alsaker94659272012-11-13 19:10:18 +01002083 weston_output_init(&output->base, &ec->base, x, y,
2084 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002085 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002086
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002087 if (ec->use_pixman) {
2088 if (drm_output_init_pixman(output, ec) < 0) {
2089 weston_log("Failed to init output pixman state\n");
2090 goto err_output;
2091 }
2092 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002093 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002094 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002095 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002096
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002097 output->backlight = backlight_init(drm_device,
2098 connector->connector_type);
2099 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002100 weston_log("Initialized backlight, device %s\n",
2101 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002102 output->base.set_backlight = drm_set_backlight;
2103 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002104 } else {
2105 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002106 }
2107
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002108 wl_list_insert(ec->base.output_list.prev, &output->base.link);
2109
Richard Hughes2b2092a2013-04-24 14:58:02 +01002110 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002111 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2112 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002113
Jonas Ådahle5a12252013-04-05 23:07:11 +02002114 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002115 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002116 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002117 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002118 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002119 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002120
Richard Hughese7299962013-05-01 21:52:12 +01002121 output->base.gamma_size = output->original_crtc->gamma_size;
2122 output->base.set_gamma = drm_output_set_gamma;
2123
Xiong Zhang97116532013-10-23 13:58:31 +08002124 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2125 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002126
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002127 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2128 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2129 &ec->base.primary_plane);
2130
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002131 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002132 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002133 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002134 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002135 m->width, m->height, m->refresh / 1000.0,
2136 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2137 ", preferred" : "",
2138 m->flags & WL_OUTPUT_MODE_CURRENT ?
2139 ", current" : "",
2140 connector->count_modes == 0 ?
2141 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002142
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002143 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002144
John Kåre Alsaker94659272012-11-13 19:10:18 +01002145err_output:
2146 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002147err_free:
2148 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2149 base.link) {
2150 wl_list_remove(&drm_mode->base.link);
2151 free(drm_mode);
2152 }
2153
2154 drmModeFreeCrtc(output->original_crtc);
2155 ec->crtc_allocator &= ~(1 << output->crtc_id);
2156 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002157 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002158
David Herrmann0f0d54e2011-12-08 17:05:45 +01002159 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002160}
2161
Jesse Barnes58ef3792012-02-23 09:45:49 -05002162static void
2163create_sprites(struct drm_compositor *ec)
2164{
2165 struct drm_sprite *sprite;
2166 drmModePlaneRes *plane_res;
2167 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002168 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002169
2170 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2171 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002172 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002173 strerror(errno));
2174 return;
2175 }
2176
2177 for (i = 0; i < plane_res->count_planes; i++) {
2178 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2179 if (!plane)
2180 continue;
2181
Peter Huttererf3d62272013-08-08 11:57:05 +10002182 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002183 plane->count_formats));
2184 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002185 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002186 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002187 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002188 continue;
2189 }
2190
Jesse Barnes58ef3792012-02-23 09:45:49 -05002191 sprite->possible_crtcs = plane->possible_crtcs;
2192 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002193 sprite->current = NULL;
2194 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002195 sprite->compositor = ec;
2196 sprite->count_formats = plane->count_formats;
2197 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002198 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002199 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002200 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002201 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2202 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002203
2204 wl_list_insert(&ec->sprite_list, &sprite->link);
2205 }
2206
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002207 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002208}
2209
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002210static void
2211destroy_sprites(struct drm_compositor *compositor)
2212{
2213 struct drm_sprite *sprite, *next;
2214 struct drm_output *output;
2215
2216 output = container_of(compositor->base.output_list.next,
2217 struct drm_output, base.link);
2218
2219 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2220 drmModeSetPlane(compositor->drm.fd,
2221 sprite->plane_id,
2222 output->crtc_id, 0, 0,
2223 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002224 drm_output_release_fb(output, sprite->current);
2225 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002226 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002227 free(sprite);
2228 }
2229}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002230
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002231static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002232create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002233 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002234{
2235 drmModeConnector *connector;
2236 drmModeRes *resources;
2237 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002238 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002239
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002240 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002241 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002242 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002243 return -1;
2244 }
2245
Jesse Barnes58ef3792012-02-23 09:45:49 -05002246 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002247 if (!ec->crtcs) {
2248 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002249 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002250 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002251
Rob Clark4339add2012-08-09 14:18:28 -05002252 ec->min_width = resources->min_width;
2253 ec->max_width = resources->max_width;
2254 ec->min_height = resources->min_height;
2255 ec->max_height = resources->max_height;
2256
Jesse Barnes58ef3792012-02-23 09:45:49 -05002257 ec->num_crtcs = resources->count_crtcs;
2258 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2259
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002260 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002261 connector = drmModeGetConnector(ec->drm.fd,
2262 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002263 if (connector == NULL)
2264 continue;
2265
2266 if (connector->connection == DRM_MODE_CONNECTED &&
2267 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002268 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002269 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002270 connector, x, y,
2271 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002272 drmModeFreeConnector(connector);
2273 continue;
2274 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002275
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002276 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002277 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002278 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002279 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002280
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002281 drmModeFreeConnector(connector);
2282 }
2283
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002284 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002285 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002286 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002287 return -1;
2288 }
2289
2290 drmModeFreeResources(resources);
2291
2292 return 0;
2293}
2294
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002295static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002296update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002297{
2298 drmModeConnector *connector;
2299 drmModeRes *resources;
2300 struct drm_output *output, *next;
2301 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002302 uint32_t connected = 0, disconnects = 0;
2303 int i;
2304
2305 resources = drmModeGetResources(ec->drm.fd);
2306 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002307 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002308 return;
2309 }
2310
2311 /* collect new connects */
2312 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002313 int connector_id = resources->connectors[i];
2314
2315 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002316 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002317 continue;
2318
David Herrmann7551cff2011-12-08 17:05:43 +01002319 if (connector->connection != DRM_MODE_CONNECTED) {
2320 drmModeFreeConnector(connector);
2321 continue;
2322 }
2323
Benjamin Franzke117483d2011-08-30 11:38:26 +02002324 connected |= (1 << connector_id);
2325
2326 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002327 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002328 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002329 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002330
2331 /* XXX: not yet needed, we die with 0 outputs */
2332 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002333 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002334 else
2335 x = 0;
2336 y = 0;
2337 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002338 connector, x, y,
2339 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002340 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002341
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002342 }
2343 drmModeFreeConnector(connector);
2344 }
2345 drmModeFreeResources(resources);
2346
2347 disconnects = ec->connector_allocator & ~connected;
2348 if (disconnects) {
2349 wl_list_for_each_safe(output, next, &ec->base.output_list,
2350 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002351 if (disconnects & (1 << output->connector_id)) {
2352 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002353 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002354 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002355 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002356 }
2357 }
2358 }
2359
2360 /* FIXME: handle zero outputs, without terminating */
2361 if (ec->connector_allocator == 0)
2362 wl_display_terminate(ec->base.wl_display);
2363}
2364
2365static int
David Herrmannd7488c22012-03-11 20:05:21 +01002366udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002367{
David Herrmannd7488c22012-03-11 20:05:21 +01002368 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002369 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002370
2371 sysnum = udev_device_get_sysnum(device);
2372 if (!sysnum || atoi(sysnum) != ec->drm.id)
2373 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002374
David Herrmann6ac52db2012-03-11 20:05:22 +01002375 val = udev_device_get_property_value(device, "HOTPLUG");
2376 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002377 return 0;
2378
David Herrmann6ac52db2012-03-11 20:05:22 +01002379 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002380}
2381
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002382static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002383udev_drm_event(int fd, uint32_t mask, void *data)
2384{
2385 struct drm_compositor *ec = data;
2386 struct udev_device *event;
2387
2388 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002389
David Herrmannd7488c22012-03-11 20:05:21 +01002390 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002391 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002392
2393 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002394
2395 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002396}
2397
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002398static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002399drm_restore(struct weston_compositor *ec)
2400{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002401 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002402}
2403
2404static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002405drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002406{
2407 struct drm_compositor *d = (struct drm_compositor *) ec;
2408
Rob Bradfordd355b802013-05-31 18:09:55 +01002409 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002410
2411 wl_event_source_remove(d->udev_drm_source);
2412 wl_event_source_remove(d->drm_source);
2413
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002414 destroy_sprites(d);
2415
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002416 weston_compositor_shutdown(ec);
2417
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002418 if (d->gbm)
2419 gbm_device_destroy(d->gbm);
2420
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002421 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002422
Rob Bradford45c15b82013-07-26 16:29:35 +01002423 close(d->drm.fd);
2424
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002425 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002426}
2427
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002428static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002429drm_compositor_set_modes(struct drm_compositor *compositor)
2430{
2431 struct drm_output *output;
2432 struct drm_mode *drm_mode;
2433 int ret;
2434
2435 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002436 if (!output->current) {
2437 /* If something that would cause the output to
2438 * switch mode happened while in another vt, we
2439 * might not have a current drm_fb. In that case,
2440 * schedule a repaint and let drm_output_repaint
2441 * handle setting the mode. */
2442 weston_output_schedule_repaint(&output->base);
2443 continue;
2444 }
2445
Hardeningff39efa2013-09-18 23:56:35 +02002446 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002447 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002448 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002449 &output->connector_id, 1,
2450 &drm_mode->mode_info);
2451 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002452 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002453 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002454 drm_mode->base.width, drm_mode->base.height,
2455 output->base.x, output->base.y);
2456 }
2457 }
2458}
2459
2460static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002461session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002462{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002463 struct weston_compositor *compositor = data;
2464 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002465 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002466 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002467
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002468 if (ec->base.session_active) {
2469 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002470 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002471 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002472 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002473 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002474 } else {
2475 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002476 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002477
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002478 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002479 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002480
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002481 /* If we have a repaint scheduled (either from a
2482 * pending pageflip or the idle handler), make sure we
2483 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002484 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002485 * further attemps at repainting. When we switch
2486 * back, we schedule a repaint, which will process
2487 * pending frame callbacks. */
2488
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002489 wl_list_for_each(output, &ec->base.output_list, base.link) {
2490 output->base.repaint_needed = 0;
2491 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002492 }
2493
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002494 output = container_of(ec->base.output_list.next,
2495 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002496
2497 wl_list_for_each(sprite, &ec->sprite_list, link)
2498 drmModeSetPlane(ec->drm.fd,
2499 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002500 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002501 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002502 };
2503}
2504
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002505static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002506switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002507{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002508 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002509
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002510 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002511}
2512
David Herrmann0af066f2012-10-29 19:21:16 +01002513/*
2514 * Find primary GPU
2515 * Some systems may have multiple DRM devices attached to a single seat. This
2516 * function loops over all devices and tries to find a PCI device with the
2517 * boot_vga sysfs attribute set to 1.
2518 * If no such device is found, the first DRM device reported by udev is used.
2519 */
2520static struct udev_device*
2521find_primary_gpu(struct drm_compositor *ec, const char *seat)
2522{
2523 struct udev_enumerate *e;
2524 struct udev_list_entry *entry;
2525 const char *path, *device_seat, *id;
2526 struct udev_device *device, *drm_device, *pci;
2527
2528 e = udev_enumerate_new(ec->udev);
2529 udev_enumerate_add_match_subsystem(e, "drm");
2530 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2531
2532 udev_enumerate_scan_devices(e);
2533 drm_device = NULL;
2534 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2535 path = udev_list_entry_get_name(entry);
2536 device = udev_device_new_from_syspath(ec->udev, path);
2537 if (!device)
2538 continue;
2539 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2540 if (!device_seat)
2541 device_seat = default_seat;
2542 if (strcmp(device_seat, seat)) {
2543 udev_device_unref(device);
2544 continue;
2545 }
2546
2547 pci = udev_device_get_parent_with_subsystem_devtype(device,
2548 "pci", NULL);
2549 if (pci) {
2550 id = udev_device_get_sysattr_value(pci, "boot_vga");
2551 if (id && !strcmp(id, "1")) {
2552 if (drm_device)
2553 udev_device_unref(drm_device);
2554 drm_device = device;
2555 break;
2556 }
2557 }
2558
2559 if (!drm_device)
2560 drm_device = device;
2561 else
2562 udev_device_unref(device);
2563 }
2564
2565 udev_enumerate_unref(e);
2566 return drm_device;
2567}
2568
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002569static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002570planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002571{
2572 struct drm_compositor *c = data;
2573
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002574 switch (key) {
2575 case KEY_C:
2576 c->cursors_are_broken ^= 1;
2577 break;
2578 case KEY_V:
2579 c->sprites_are_broken ^= 1;
2580 break;
2581 case KEY_O:
2582 c->sprites_hidden ^= 1;
2583 break;
2584 default:
2585 break;
2586 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002587}
2588
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002589#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002590static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002591recorder_destroy(struct drm_output *output)
2592{
2593 vaapi_recorder_destroy(output->recorder);
2594 output->recorder = NULL;
2595
2596 output->base.disable_planes--;
2597
2598 wl_list_remove(&output->recorder_frame_listener.link);
2599 weston_log("[libva recorder] done\n");
2600}
2601
2602static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002603recorder_frame_notify(struct wl_listener *listener, void *data)
2604{
2605 struct drm_output *output;
2606 struct drm_compositor *c;
2607 int fd, ret;
2608
2609 output = container_of(listener, struct drm_output,
2610 recorder_frame_listener);
2611 c = (struct drm_compositor *) output->base.compositor;
2612
2613 if (!output->recorder)
2614 return;
2615
2616 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2617 DRM_CLOEXEC, &fd);
2618 if (ret) {
2619 weston_log("[libva recorder] "
2620 "failed to create prime fd for front buffer\n");
2621 return;
2622 }
2623
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002624 ret = vaapi_recorder_frame(output->recorder, fd,
2625 output->current->stride);
2626 if (ret < 0) {
2627 weston_log("[libva recorder] aborted: %m\n");
2628 recorder_destroy(output);
2629 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002630}
2631
2632static void *
2633create_recorder(struct drm_compositor *c, int width, int height,
2634 const char *filename)
2635{
2636 int fd;
2637 drm_magic_t magic;
2638
2639 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2640 if (fd < 0)
2641 return NULL;
2642
2643 drmGetMagic(fd, &magic);
2644 drmAuthMagic(c->drm.fd, magic);
2645
2646 return vaapi_recorder_create(fd, width, height, filename);
2647}
2648
2649static void
2650recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2651 void *data)
2652{
2653 struct drm_compositor *c = data;
2654 struct drm_output *output;
2655 int width, height;
2656
2657 output = container_of(c->base.output_list.next,
2658 struct drm_output, base.link);
2659
2660 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002661 if (output->format != GBM_FORMAT_XRGB8888) {
2662 weston_log("failed to start vaapi recorder: "
2663 "output format not supported\n");
2664 return;
2665 }
2666
Hardeningff39efa2013-09-18 23:56:35 +02002667 width = output->base.current_mode->width;
2668 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002669
2670 output->recorder =
2671 create_recorder(c, width, height, "capture.h264");
2672 if (!output->recorder) {
2673 weston_log("failed to create vaapi recorder\n");
2674 return;
2675 }
2676
2677 output->base.disable_planes++;
2678
2679 output->recorder_frame_listener.notify = recorder_frame_notify;
2680 wl_signal_add(&output->base.frame_signal,
2681 &output->recorder_frame_listener);
2682
2683 weston_output_schedule_repaint(&output->base);
2684
2685 weston_log("[libva recorder] initialized\n");
2686 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002687 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002688 }
2689}
2690#else
2691static void
2692recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2693 void *data)
2694{
2695 weston_log("Compiled without libva support\n");
2696}
2697#endif
2698
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002699static void
2700switch_to_gl_renderer(struct drm_compositor *c)
2701{
2702 struct drm_output *output;
2703
2704 if (!c->use_pixman)
2705 return;
2706
2707 weston_log("Switching to GL renderer\n");
2708
2709 c->gbm = create_gbm_device(c->drm.fd);
2710 if (!c->gbm) {
2711 weston_log("Failed to create gbm device. "
2712 "Aborting renderer switch\n");
2713 return;
2714 }
2715
2716 wl_list_for_each(output, &c->base.output_list, base.link)
2717 pixman_renderer_output_destroy(&output->base);
2718
2719 c->base.renderer->destroy(&c->base);
2720
2721 if (drm_compositor_create_gl_renderer(c) < 0) {
2722 gbm_device_destroy(c->gbm);
2723 weston_log("Failed to create GL renderer. Quitting.\n");
2724 /* FIXME: we need a function to shutdown cleanly */
2725 assert(0);
2726 }
2727
2728 wl_list_for_each(output, &c->base.output_list, base.link)
2729 drm_output_init_egl(output, c);
2730
2731 c->use_pixman = 0;
2732}
2733
2734static void
2735renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2736 void *data)
2737{
2738 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2739
2740 switch_to_gl_renderer(c);
2741}
2742
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002743static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002744drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002745 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002746 int *argc, char *argv[],
2747 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002748{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002749 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002750 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002751 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002752 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002753 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002754 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002755
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002756 weston_log("initializing drm backend\n");
2757
Peter Huttererf3d62272013-08-08 11:57:05 +10002758 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002759 if (ec == NULL)
2760 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002761
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002762 /* KMS support for sprites is not complete yet, so disable the
2763 * functionality for now. */
2764 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002765
2766 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002767 if (get_gbm_format_from_section(section,
2768 GBM_FORMAT_XRGB8888,
2769 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002770 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002771
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002772 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002773
Daniel Stone725c2c32012-06-22 14:04:36 +01002774 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002775 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002776 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002777 goto err_base;
2778 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002779
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002780 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002781 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
David Herrmann2ecb84a2014-12-30 14:33:22 +01002782 param->seat_id, true);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002783 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002784 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002785 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002786 goto err_compositor;
2787 }
2788
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002789 ec->udev = udev_new();
2790 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002791 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002792 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002793 }
2794
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002795 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002796 ec->session_listener.notify = session_notify;
2797 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002798
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002799 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002800 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002801 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002802 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002803 }
David Herrmann0af066f2012-10-29 19:21:16 +01002804 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002805
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002806 if (init_drm(ec, drm_device) < 0) {
2807 weston_log("failed to initialize kms\n");
2808 goto err_udev_dev;
2809 }
2810
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002811 if (ec->use_pixman) {
2812 if (init_pixman(ec) < 0) {
2813 weston_log("failed to initialize pixman renderer\n");
2814 goto err_udev_dev;
2815 }
2816 } else {
2817 if (init_egl(ec) < 0) {
2818 weston_log("failed to initialize egl\n");
2819 goto err_udev_dev;
2820 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002821 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002822
2823 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002824 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002825
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002826 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002827
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002828 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002829 weston_compositor_add_key_binding(&ec->base, key,
2830 MODIFIER_CTRL | MODIFIER_ALT,
2831 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002832
Jesse Barnes58ef3792012-02-23 09:45:49 -05002833 wl_list_init(&ec->sprite_list);
2834 create_sprites(ec);
2835
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002836 if (udev_input_init(&ec->input,
2837 &ec->base, ec->udev, param->seat_id) < 0) {
2838 weston_log("failed to create input devices\n");
2839 goto err_sprite;
2840 }
2841
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002842 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002843 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002844 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002845 }
2846
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002847 /* A this point we have some idea of whether or not we have a working
2848 * cursor plane. */
2849 if (!ec->cursors_are_broken)
2850 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2851
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002852 path = NULL;
2853
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002854 loop = wl_display_get_event_loop(ec->base.wl_display);
2855 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002856 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002857 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002858
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002859 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2860 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002861 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002862 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002863 }
2864 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2865 "drm", NULL);
2866 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002867 wl_event_loop_add_fd(loop,
2868 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002869 WL_EVENT_READABLE, udev_drm_event, ec);
2870
2871 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002872 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002873 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002874 }
2875
Daniel Stonea96b93c2012-06-22 14:04:37 +01002876 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002877
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002878 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002879 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002880 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002881 planes_binding, ec);
2882 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2883 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002884 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2885 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002886 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2887 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002888
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002889 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002890
2891err_udev_monitor:
2892 wl_event_source_remove(ec->udev_drm_source);
2893 udev_monitor_unref(ec->udev_monitor);
2894err_drm_source:
2895 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002896err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002897 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002898err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002899 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002900 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002901 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002902err_udev_dev:
2903 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002904err_launcher:
2905 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002906err_udev:
2907 udev_unref(ec->udev);
2908err_compositor:
2909 weston_compositor_shutdown(&ec->base);
2910err_base:
2911 free(ec);
2912 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002913}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002914
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002915WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002916backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002917 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002918{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002919 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002920
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002921 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002922 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2923 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2924 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002925 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002926 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002927 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002928
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002929 param.seat_id = default_seat;
2930
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002931 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002932
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002933 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002934}