blob: 209f2ae4360ee4d7b7790c74feaa6d6ffe957fdb [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;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001133
Jason Ekstranda7af7042013-10-12 22:38:11 -05001134 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001135
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001136 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001137 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001138 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001139
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001140 if (next_plane == primary ||
1141 next_plane == &output->cursor_plane) {
1142 /* cursor plane involves a copy */
1143 ev->psf_flags = 0;
1144 } else {
1145 /* All other planes are a direct scanout of a
1146 * single client buffer.
1147 */
1148 ev->psf_flags = PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
1149 }
1150
Jesse Barnes58ef3792012-02-23 09:45:49 -05001151 pixman_region32_fini(&surface_overlap);
1152 }
1153 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001154}
1155
Matt Roper361d2ad2011-08-29 13:52:23 -07001156static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001157drm_output_fini_pixman(struct drm_output *output);
1158
1159static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001160drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001161{
1162 struct drm_output *output = (struct drm_output *) output_base;
1163 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001164 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001165 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001166
Xiong Zhangabd5d472013-10-11 14:43:07 +08001167 if (output->page_flip_pending) {
1168 output->destroy_pending = 1;
1169 weston_log("destroy output while page flip pending\n");
1170 return;
1171 }
1172
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001173 if (output->backlight)
1174 backlight_destroy(output->backlight);
1175
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001176 drmModeFreeProperty(output->dpms_prop);
1177
Matt Roper361d2ad2011-08-29 13:52:23 -07001178 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001179 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001180
1181 /* Restore original CRTC state */
1182 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001183 origcrtc->x, origcrtc->y,
1184 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001185 drmModeFreeCrtc(origcrtc);
1186
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001187 c->crtc_allocator &= ~(1 << output->crtc_id);
1188 c->connector_allocator &= ~(1 << output->connector_id);
1189
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001190 if (c->use_pixman) {
1191 drm_output_fini_pixman(output);
1192 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001193 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001194 gbm_surface_destroy(output->surface);
1195 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001196
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001197 weston_plane_release(&output->fb_plane);
1198 weston_plane_release(&output->cursor_plane);
1199
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001200 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001201
Matt Roper361d2ad2011-08-29 13:52:23 -07001202 free(output);
1203}
1204
Alex Wub7b8bda2012-04-17 17:20:48 +08001205static struct drm_mode *
1206choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1207{
1208 struct drm_mode *tmp_mode = NULL, *mode;
1209
Hardeningff39efa2013-09-18 23:56:35 +02001210 if (output->base.current_mode->width == target_mode->width &&
1211 output->base.current_mode->height == target_mode->height &&
1212 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001213 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001214 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001215
1216 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1217 if (mode->mode_info.hdisplay == target_mode->width &&
1218 mode->mode_info.vdisplay == target_mode->height) {
1219 if (mode->mode_info.vrefresh == target_mode->refresh ||
1220 target_mode->refresh == 0) {
1221 return mode;
1222 } else if (!tmp_mode)
1223 tmp_mode = mode;
1224 }
1225 }
1226
1227 return tmp_mode;
1228}
1229
1230static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001231drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001232static int
1233drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001234
1235static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001236drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1237{
1238 struct drm_output *output;
1239 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001240 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001241
1242 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001243 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001244 return -1;
1245 }
1246
1247 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001248 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001249 return -1;
1250 }
1251
1252 ec = (struct drm_compositor *)output_base->compositor;
1253 output = (struct drm_output *)output_base;
1254 drm_mode = choose_mode (output, mode);
1255
1256 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001257 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001258 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001259 }
1260
Hardeningff39efa2013-09-18 23:56:35 +02001261 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001262 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001263
Hardeningff39efa2013-09-18 23:56:35 +02001264 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001265
Hardeningff39efa2013-09-18 23:56:35 +02001266 output->base.current_mode = &drm_mode->base;
1267 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001268 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1269
Alex Wub7b8bda2012-04-17 17:20:48 +08001270 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001271 drm_output_release_fb(output, output->current);
1272 drm_output_release_fb(output, output->next);
1273 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001274
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001275 if (ec->use_pixman) {
1276 drm_output_fini_pixman(output);
1277 if (drm_output_init_pixman(output, ec) < 0) {
1278 weston_log("failed to init output pixman state with "
1279 "new mode\n");
1280 return -1;
1281 }
1282 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001283 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001284 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001285
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001286 if (drm_output_init_egl(output, ec) < 0) {
1287 weston_log("failed to init output egl state with "
1288 "new mode");
1289 return -1;
1290 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001291 }
1292
Alex Wub7b8bda2012-04-17 17:20:48 +08001293 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001294}
1295
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001296static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001297on_drm_input(int fd, uint32_t mask, void *data)
1298{
1299 drmEventContext evctx;
1300
1301 memset(&evctx, 0, sizeof evctx);
1302 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1303 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001304 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001305 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001306
1307 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001308}
1309
1310static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001311init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001312{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001313 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001314 uint64_t cap;
1315 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001316 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001317
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001318 sysnum = udev_device_get_sysnum(device);
1319 if (sysnum)
1320 ec->drm.id = atoi(sysnum);
1321 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001322 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001323 return -1;
1324 }
1325
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001326 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001327 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001328 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001329 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001330 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001331 udev_device_get_devnode(device));
1332 return -1;
1333 }
1334
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001335 weston_log("using %s\n", filename);
1336
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001337 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001338 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001339
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001340 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1341 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001342 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001343 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001344 clk_id = CLOCK_REALTIME;
1345
1346 if (weston_compositor_set_presentation_clock(&ec->base, clk_id) < 0) {
1347 weston_log("Error: failed to set presentation clock %d.\n",
1348 clk_id);
1349 return -1;
1350 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001351
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001352 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1353 if (ret == 0)
1354 ec->cursor_width = cap;
1355 else
1356 ec->cursor_width = 64;
1357
1358 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1359 if (ret == 0)
1360 ec->cursor_height = cap;
1361 else
1362 ec->cursor_height = 64;
1363
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001364 return 0;
1365}
1366
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001367static struct gbm_device *
1368create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001369{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001370 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001371
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001372 gl_renderer = weston_load_module("gl-renderer.so",
1373 "gl_renderer_interface");
1374 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001375 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001376
1377 /* GBM will load a dri driver, but even though they need symbols from
1378 * libglapi, in some version of Mesa they are not linked to it. Since
1379 * only the gl-renderer module links to it, the call above won't make
1380 * these symbols globally available, and loading the DRI driver fails.
1381 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1382 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1383
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001384 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001385
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001386 return gbm;
1387}
1388
1389static int
1390drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1391{
1392 EGLint format;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001393
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001394 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001395 if (gl_renderer->create(&ec->base, ec->gbm,
1396 gl_renderer->opaque_attribs, &format) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001397 return -1;
1398 }
1399
1400 return 0;
1401}
1402
1403static int
1404init_egl(struct drm_compositor *ec)
1405{
1406 ec->gbm = create_gbm_device(ec->drm.fd);
1407
1408 if (!ec->gbm)
1409 return -1;
1410
1411 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001412 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001413 return -1;
1414 }
1415
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001416 return 0;
1417}
1418
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001419static int
1420init_pixman(struct drm_compositor *ec)
1421{
1422 return pixman_renderer_init(&ec->base);
1423}
1424
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001425static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001426drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001427{
1428 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001429 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001430
1431 mode = malloc(sizeof *mode);
1432 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001433 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001434
1435 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001436 mode->base.width = info->hdisplay;
1437 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001438
1439 /* Calculate higher precision (mHz) refresh rate */
1440 refresh = (info->clock * 1000000LL / info->htotal +
1441 info->vtotal / 2) / info->vtotal;
1442
1443 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1444 refresh *= 2;
1445 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1446 refresh /= 2;
1447 if (info->vscan > 1)
1448 refresh /= info->vscan;
1449
1450 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001451 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001452
1453 if (info->type & DRM_MODE_TYPE_PREFERRED)
1454 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1455
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001456 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1457
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001458 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001459}
1460
1461static int
1462drm_subpixel_to_wayland(int drm_value)
1463{
1464 switch (drm_value) {
1465 default:
1466 case DRM_MODE_SUBPIXEL_UNKNOWN:
1467 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1468 case DRM_MODE_SUBPIXEL_NONE:
1469 return WL_OUTPUT_SUBPIXEL_NONE;
1470 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1471 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1472 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1473 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1474 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1475 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1476 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1477 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1478 }
1479}
1480
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001481/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001482static uint32_t
1483drm_get_backlight(struct drm_output *output)
1484{
1485 long brightness, max_brightness, norm;
1486
1487 brightness = backlight_get_brightness(output->backlight);
1488 max_brightness = backlight_get_max_brightness(output->backlight);
1489
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001490 /* convert it on a scale of 0 to 255 */
1491 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001492
1493 return (uint32_t) norm;
1494}
1495
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001496/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001497static void
1498drm_set_backlight(struct weston_output *output_base, uint32_t value)
1499{
1500 struct drm_output *output = (struct drm_output *) output_base;
1501 long max_brightness, new_brightness;
1502
1503 if (!output->backlight)
1504 return;
1505
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001506 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001507 return;
1508
1509 max_brightness = backlight_get_max_brightness(output->backlight);
1510
1511 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001512 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001513
1514 backlight_set_brightness(output->backlight, new_brightness);
1515}
1516
1517static drmModePropertyPtr
1518drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1519{
1520 drmModePropertyPtr props;
1521 int i;
1522
1523 for (i = 0; i < connector->count_props; i++) {
1524 props = drmModeGetProperty(fd, connector->props[i]);
1525 if (!props)
1526 continue;
1527
1528 if (!strcmp(props->name, name))
1529 return props;
1530
1531 drmModeFreeProperty(props);
1532 }
1533
1534 return NULL;
1535}
1536
1537static void
1538drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1539{
1540 struct drm_output *output = (struct drm_output *) output_base;
1541 struct weston_compositor *ec = output_base->compositor;
1542 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001543
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001544 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001545 return;
1546
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001547 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1548 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001549}
1550
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001551static const char *connector_type_names[] = {
1552 "None",
1553 "VGA",
1554 "DVI",
1555 "DVI",
1556 "DVI",
1557 "Composite",
1558 "TV",
1559 "LVDS",
1560 "CTV",
1561 "DIN",
1562 "DP",
1563 "HDMI",
1564 "HDMI",
1565 "TV",
1566 "eDP",
1567};
1568
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001569static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001570find_crtc_for_connector(struct drm_compositor *ec,
1571 drmModeRes *resources, drmModeConnector *connector)
1572{
1573 drmModeEncoder *encoder;
1574 uint32_t possible_crtcs;
1575 int i, j;
1576
1577 for (j = 0; j < connector->count_encoders; j++) {
1578 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1579 if (encoder == NULL) {
1580 weston_log("Failed to get encoder.\n");
1581 return -1;
1582 }
1583 possible_crtcs = encoder->possible_crtcs;
1584 drmModeFreeEncoder(encoder);
1585
1586 for (i = 0; i < resources->count_crtcs; i++) {
1587 if (possible_crtcs & (1 << i) &&
1588 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1589 return i;
1590 }
1591 }
1592
1593 return -1;
1594}
1595
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001596/* Init output state that depends on gl or gbm */
1597static int
1598drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1599{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001600 EGLint format = output->format;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001601 int i, flags;
1602
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001603 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001604 output->base.current_mode->width,
1605 output->base.current_mode->height,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001606 format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001607 GBM_BO_USE_SCANOUT |
1608 GBM_BO_USE_RENDERING);
1609 if (!output->surface) {
1610 weston_log("failed to create gbm surface\n");
1611 return -1;
1612 }
1613
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001614 if (gl_renderer->output_create(&output->base, output->surface,
1615 gl_renderer->opaque_attribs,
1616 &format) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001617 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001618 gbm_surface_destroy(output->surface);
1619 return -1;
1620 }
1621
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001622 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001623
1624 for (i = 0; i < 2; i++) {
1625 if (output->cursor_bo[i])
1626 continue;
1627
1628 output->cursor_bo[i] =
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001629 gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
1630 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001631 }
1632
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001633 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1634 weston_log("cursor buffers unavailable, using gl cursors\n");
1635 ec->cursors_are_broken = 1;
1636 }
1637
1638 return 0;
1639}
1640
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001641static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001642drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1643{
Hardeningff39efa2013-09-18 23:56:35 +02001644 int w = output->base.current_mode->width;
1645 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001646 unsigned int i;
1647
1648 /* FIXME error checking */
1649
1650 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001651 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001652 if (!output->dumb[i])
1653 goto err;
1654
1655 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001656 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001657 output->dumb[i]->map,
1658 output->dumb[i]->stride);
1659 if (!output->image[i])
1660 goto err;
1661 }
1662
1663 if (pixman_renderer_output_create(&output->base) < 0)
1664 goto err;
1665
1666 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001667 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001668
1669 return 0;
1670
1671err:
1672 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1673 if (output->dumb[i])
1674 drm_fb_destroy_dumb(output->dumb[i]);
1675 if (output->image[i])
1676 pixman_image_unref(output->image[i]);
1677
1678 output->dumb[i] = NULL;
1679 output->image[i] = NULL;
1680 }
1681
1682 return -1;
1683}
1684
1685static void
1686drm_output_fini_pixman(struct drm_output *output)
1687{
1688 unsigned int i;
1689
1690 pixman_renderer_output_destroy(&output->base);
1691 pixman_region32_fini(&output->previous_damage);
1692
1693 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1694 drm_fb_destroy_dumb(output->dumb[i]);
1695 pixman_image_unref(output->image[i]);
1696 output->dumb[i] = NULL;
1697 output->image[i] = NULL;
1698 }
1699}
1700
Richard Hughes2b2092a2013-04-24 14:58:02 +01001701static void
1702edid_parse_string(const uint8_t *data, char text[])
1703{
1704 int i;
1705 int replaced = 0;
1706
1707 /* this is always 12 bytes, but we can't guarantee it's null
1708 * terminated or not junk. */
1709 strncpy(text, (const char *) data, 12);
1710
1711 /* remove insane chars */
1712 for (i = 0; text[i] != '\0'; i++) {
1713 if (text[i] == '\n' ||
1714 text[i] == '\r') {
1715 text[i] = '\0';
1716 break;
1717 }
1718 }
1719
1720 /* ensure string is printable */
1721 for (i = 0; text[i] != '\0'; i++) {
1722 if (!isprint(text[i])) {
1723 text[i] = '-';
1724 replaced++;
1725 }
1726 }
1727
1728 /* if the string is random junk, ignore the string */
1729 if (replaced > 4)
1730 text[0] = '\0';
1731}
1732
1733#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1734#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1735#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1736#define EDID_OFFSET_DATA_BLOCKS 0x36
1737#define EDID_OFFSET_LAST_BLOCK 0x6c
1738#define EDID_OFFSET_PNPID 0x08
1739#define EDID_OFFSET_SERIAL 0x0c
1740
1741static int
1742edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1743{
1744 int i;
1745 uint32_t serial_number;
1746
1747 /* check header */
1748 if (length < 128)
1749 return -1;
1750 if (data[0] != 0x00 || data[1] != 0xff)
1751 return -1;
1752
1753 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1754 * /--08--\/--09--\
1755 * 7654321076543210
1756 * |\---/\---/\---/
1757 * R C1 C2 C3 */
1758 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1759 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1760 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1761 edid->pnp_id[3] = '\0';
1762
1763 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1764 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1765 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1766 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1767 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1768 if (serial_number > 0)
1769 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1770
1771 /* parse EDID data */
1772 for (i = EDID_OFFSET_DATA_BLOCKS;
1773 i <= EDID_OFFSET_LAST_BLOCK;
1774 i += 18) {
1775 /* ignore pixel clock data */
1776 if (data[i] != 0)
1777 continue;
1778 if (data[i+2] != 0)
1779 continue;
1780
1781 /* any useful blocks? */
1782 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1783 edid_parse_string(&data[i+5],
1784 edid->monitor_name);
1785 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1786 edid_parse_string(&data[i+5],
1787 edid->serial_number);
1788 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1789 edid_parse_string(&data[i+5],
1790 edid->eisa_id);
1791 }
1792 }
1793 return 0;
1794}
1795
1796static void
1797find_and_parse_output_edid(struct drm_compositor *ec,
1798 struct drm_output *output,
1799 drmModeConnector *connector)
1800{
1801 drmModePropertyBlobPtr edid_blob = NULL;
1802 drmModePropertyPtr property;
1803 int i;
1804 int rc;
1805
1806 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1807 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1808 if (!property)
1809 continue;
1810 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1811 !strcmp(property->name, "EDID")) {
1812 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1813 connector->prop_values[i]);
1814 }
1815 drmModeFreeProperty(property);
1816 }
1817 if (!edid_blob)
1818 return;
1819
1820 rc = edid_parse(&output->edid,
1821 edid_blob->data,
1822 edid_blob->length);
1823 if (!rc) {
1824 weston_log("EDID data '%s', '%s', '%s'\n",
1825 output->edid.pnp_id,
1826 output->edid.monitor_name,
1827 output->edid.serial_number);
1828 if (output->edid.pnp_id[0] != '\0')
1829 output->base.make = output->edid.pnp_id;
1830 if (output->edid.monitor_name[0] != '\0')
1831 output->base.model = output->edid.monitor_name;
1832 if (output->edid.serial_number[0] != '\0')
1833 output->base.serial_number = output->edid.serial_number;
1834 }
1835 drmModeFreePropertyBlob(edid_blob);
1836}
1837
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001838
1839
1840static int
1841parse_modeline(const char *s, drmModeModeInfo *mode)
1842{
1843 char hsync[16];
1844 char vsync[16];
1845 float fclock;
1846
1847 mode->type = DRM_MODE_TYPE_USERDEF;
1848 mode->hskew = 0;
1849 mode->vscan = 0;
1850 mode->vrefresh = 0;
1851 mode->flags = 0;
1852
Rob Bradford307e09e2013-07-26 16:29:40 +01001853 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001854 &fclock,
1855 &mode->hdisplay,
1856 &mode->hsync_start,
1857 &mode->hsync_end,
1858 &mode->htotal,
1859 &mode->vdisplay,
1860 &mode->vsync_start,
1861 &mode->vsync_end,
1862 &mode->vtotal, hsync, vsync) != 11)
1863 return -1;
1864
1865 mode->clock = fclock * 1000;
1866 if (strcmp(hsync, "+hsync") == 0)
1867 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1868 else if (strcmp(hsync, "-hsync") == 0)
1869 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1870 else
1871 return -1;
1872
1873 if (strcmp(vsync, "+vsync") == 0)
1874 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1875 else if (strcmp(vsync, "-vsync") == 0)
1876 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1877 else
1878 return -1;
1879
1880 return 0;
1881}
1882
Rob Bradford66bd9f52013-06-25 18:56:42 +01001883static void
1884setup_output_seat_constraint(struct drm_compositor *ec,
1885 struct weston_output *output,
1886 const char *s)
1887{
1888 if (strcmp(s, "") != 0) {
1889 struct udev_seat *seat;
1890
Jonas Ådahl58e15862014-03-12 22:08:40 +01001891 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001892 if (seat)
1893 seat->base.output = output;
1894
1895 if (seat && seat->base.pointer)
1896 weston_pointer_clamp(seat->base.pointer,
1897 &seat->base.pointer->x,
1898 &seat->base.pointer->y);
1899 }
1900}
1901
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001902static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001903get_gbm_format_from_section(struct weston_config_section *section,
1904 uint32_t default_value,
1905 uint32_t *format)
1906{
1907 char *s;
1908 int ret = 0;
1909
1910 weston_config_section_get_string(section,
1911 "gbm-format", &s, NULL);
1912
1913 if (s == NULL)
1914 *format = default_value;
1915 else if (strcmp(s, "xrgb8888") == 0)
1916 *format = GBM_FORMAT_XRGB8888;
1917 else if (strcmp(s, "rgb565") == 0)
1918 *format = GBM_FORMAT_RGB565;
1919 else if (strcmp(s, "xrgb2101010") == 0)
1920 *format = GBM_FORMAT_XRGB2101010;
1921 else {
1922 weston_log("fatal: unrecognized pixel format: %s\n", s);
1923 ret = -1;
1924 }
1925
1926 free(s);
1927
1928 return ret;
1929}
1930
1931static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001932create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001933 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001934 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001935 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001936{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001937 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001938 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001939 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001940 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001941 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001942 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001943 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001944 int i, width, height, scale;
1945 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001946 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001947 enum output_config config;
1948 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001949
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001950 i = find_crtc_for_connector(ec, resources, connector);
1951 if (i < 0) {
1952 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001953 return -1;
1954 }
1955
Peter Huttererf3d62272013-08-08 11:57:05 +10001956 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001957 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001958 return -1;
1959
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001960 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1961 output->base.make = "unknown";
1962 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001963 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001964 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001965
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001966 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1967 type_name = connector_type_names[connector->connector_type];
1968 else
1969 type_name = "UNKNOWN";
1970 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001971 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001972
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001973 section = weston_config_get_section(ec->base.config, "output", "name",
1974 output->base.name);
1975 weston_config_section_get_string(section, "mode", &s, "preferred");
1976 if (strcmp(s, "off") == 0)
1977 config = OUTPUT_CONFIG_OFF;
1978 else if (strcmp(s, "preferred") == 0)
1979 config = OUTPUT_CONFIG_PREFERRED;
1980 else if (strcmp(s, "current") == 0)
1981 config = OUTPUT_CONFIG_CURRENT;
1982 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1983 config = OUTPUT_CONFIG_MODE;
1984 else if (parse_modeline(s, &modeline) == 0)
1985 config = OUTPUT_CONFIG_MODELINE;
1986 else {
1987 weston_log("Invalid mode \"%s\" for output %s\n",
1988 s, output->base.name);
1989 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001990 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001991 free(s);
1992
1993 weston_config_section_get_int(section, "scale", &scale, 1);
1994 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05001995 if (weston_parse_transform(s, &transform) < 0)
1996 weston_log("Invalid transform \"%s\" for output %s\n",
1997 s, output->base.name);
1998
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001999 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002000
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002001 if (get_gbm_format_from_section(section,
2002 ec->format,
2003 &output->format) == -1)
2004 output->format = ec->format;
2005
Rob Bradford66bd9f52013-06-25 18:56:42 +01002006 weston_config_section_get_string(section, "seat", &s, "");
2007 setup_output_seat_constraint(ec, &output->base, s);
2008 free(s);
2009
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002010 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002011 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002012 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002013 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002014 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002015
Matt Roper361d2ad2011-08-29 13:52:23 -07002016 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03002017 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002018
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002019 /* Get the current mode on the crtc that's currently driving
2020 * this connector. */
2021 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002022 memset(&crtc_mode, 0, sizeof crtc_mode);
2023 if (encoder != NULL) {
2024 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
2025 drmModeFreeEncoder(encoder);
2026 if (crtc == NULL)
2027 goto err_free;
2028 if (crtc->mode_valid)
2029 crtc_mode = crtc->mode;
2030 drmModeFreeCrtc(crtc);
2031 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002032
David Herrmann0f0d54e2011-12-08 17:05:45 +01002033 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002034 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002035 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002036 goto err_free;
2037 }
2038
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002039 if (config == OUTPUT_CONFIG_OFF) {
2040 weston_log("Disabling output %s\n", output->base.name);
2041 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
2042 0, 0, 0, 0, 0, NULL);
2043 goto err_free;
2044 }
2045
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002046 preferred = NULL;
2047 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002048 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002049 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002050
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002051 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002052 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002053 width == drm_mode->base.width &&
2054 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002055 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002056 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002057 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002058 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002059 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002060 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002061 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002062
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002063 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002064 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002065 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002066 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002067 }
2068
Wang Quanxianacb805a2012-07-30 18:09:46 -04002069 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002070 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002071 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002072 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002073 }
2074
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002075 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002076 configured = current;
2077
Wang Quanxianacb805a2012-07-30 18:09:46 -04002078 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002079 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002080 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002081 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002082 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002083 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002084 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002085 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002086 else if (best)
2087 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002088
Hardeningff39efa2013-09-18 23:56:35 +02002089 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002090 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002091 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002092 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002093
Hardeningff39efa2013-09-18 23:56:35 +02002094 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002095
John Kåre Alsaker94659272012-11-13 19:10:18 +01002096 weston_output_init(&output->base, &ec->base, x, y,
2097 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002098 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002099
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002100 if (ec->use_pixman) {
2101 if (drm_output_init_pixman(output, ec) < 0) {
2102 weston_log("Failed to init output pixman state\n");
2103 goto err_output;
2104 }
2105 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002106 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002107 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002108 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002109
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002110 output->backlight = backlight_init(drm_device,
2111 connector->connector_type);
2112 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002113 weston_log("Initialized backlight, device %s\n",
2114 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002115 output->base.set_backlight = drm_set_backlight;
2116 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002117 } else {
2118 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002119 }
2120
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002121 wl_list_insert(ec->base.output_list.prev, &output->base.link);
2122
Richard Hughes2b2092a2013-04-24 14:58:02 +01002123 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002124 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2125 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002126
Jonas Ådahle5a12252013-04-05 23:07:11 +02002127 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002128 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002129 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002130 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002131 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002132 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002133
Richard Hughese7299962013-05-01 21:52:12 +01002134 output->base.gamma_size = output->original_crtc->gamma_size;
2135 output->base.set_gamma = drm_output_set_gamma;
2136
Xiong Zhang97116532013-10-23 13:58:31 +08002137 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2138 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002139
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002140 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2141 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2142 &ec->base.primary_plane);
2143
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002144 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002145 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002146 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002147 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002148 m->width, m->height, m->refresh / 1000.0,
2149 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2150 ", preferred" : "",
2151 m->flags & WL_OUTPUT_MODE_CURRENT ?
2152 ", current" : "",
2153 connector->count_modes == 0 ?
2154 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002155
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002156 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002157
John Kåre Alsaker94659272012-11-13 19:10:18 +01002158err_output:
2159 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002160err_free:
2161 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2162 base.link) {
2163 wl_list_remove(&drm_mode->base.link);
2164 free(drm_mode);
2165 }
2166
2167 drmModeFreeCrtc(output->original_crtc);
2168 ec->crtc_allocator &= ~(1 << output->crtc_id);
2169 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002170 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002171
David Herrmann0f0d54e2011-12-08 17:05:45 +01002172 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002173}
2174
Jesse Barnes58ef3792012-02-23 09:45:49 -05002175static void
2176create_sprites(struct drm_compositor *ec)
2177{
2178 struct drm_sprite *sprite;
2179 drmModePlaneRes *plane_res;
2180 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002181 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002182
2183 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2184 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002185 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002186 strerror(errno));
2187 return;
2188 }
2189
2190 for (i = 0; i < plane_res->count_planes; i++) {
2191 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2192 if (!plane)
2193 continue;
2194
Peter Huttererf3d62272013-08-08 11:57:05 +10002195 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002196 plane->count_formats));
2197 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002198 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002199 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002200 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002201 continue;
2202 }
2203
Jesse Barnes58ef3792012-02-23 09:45:49 -05002204 sprite->possible_crtcs = plane->possible_crtcs;
2205 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002206 sprite->current = NULL;
2207 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002208 sprite->compositor = ec;
2209 sprite->count_formats = plane->count_formats;
2210 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002211 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002212 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002213 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002214 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2215 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002216
2217 wl_list_insert(&ec->sprite_list, &sprite->link);
2218 }
2219
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002220 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002221}
2222
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002223static void
2224destroy_sprites(struct drm_compositor *compositor)
2225{
2226 struct drm_sprite *sprite, *next;
2227 struct drm_output *output;
2228
2229 output = container_of(compositor->base.output_list.next,
2230 struct drm_output, base.link);
2231
2232 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2233 drmModeSetPlane(compositor->drm.fd,
2234 sprite->plane_id,
2235 output->crtc_id, 0, 0,
2236 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002237 drm_output_release_fb(output, sprite->current);
2238 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002239 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002240 free(sprite);
2241 }
2242}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002243
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002244static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002245create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002246 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002247{
2248 drmModeConnector *connector;
2249 drmModeRes *resources;
2250 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002251 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002252
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002253 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002254 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002255 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002256 return -1;
2257 }
2258
Jesse Barnes58ef3792012-02-23 09:45:49 -05002259 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002260 if (!ec->crtcs) {
2261 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002262 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002263 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002264
Rob Clark4339add2012-08-09 14:18:28 -05002265 ec->min_width = resources->min_width;
2266 ec->max_width = resources->max_width;
2267 ec->min_height = resources->min_height;
2268 ec->max_height = resources->max_height;
2269
Jesse Barnes58ef3792012-02-23 09:45:49 -05002270 ec->num_crtcs = resources->count_crtcs;
2271 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2272
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002273 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002274 connector = drmModeGetConnector(ec->drm.fd,
2275 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002276 if (connector == NULL)
2277 continue;
2278
2279 if (connector->connection == DRM_MODE_CONNECTED &&
2280 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002281 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002282 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002283 connector, x, y,
2284 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002285 drmModeFreeConnector(connector);
2286 continue;
2287 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002288
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002289 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002290 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002291 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002292 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002293
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002294 drmModeFreeConnector(connector);
2295 }
2296
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002297 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002298 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002299 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002300 return -1;
2301 }
2302
2303 drmModeFreeResources(resources);
2304
2305 return 0;
2306}
2307
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002308static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002309update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002310{
2311 drmModeConnector *connector;
2312 drmModeRes *resources;
2313 struct drm_output *output, *next;
2314 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002315 uint32_t connected = 0, disconnects = 0;
2316 int i;
2317
2318 resources = drmModeGetResources(ec->drm.fd);
2319 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002320 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002321 return;
2322 }
2323
2324 /* collect new connects */
2325 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002326 int connector_id = resources->connectors[i];
2327
2328 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002329 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002330 continue;
2331
David Herrmann7551cff2011-12-08 17:05:43 +01002332 if (connector->connection != DRM_MODE_CONNECTED) {
2333 drmModeFreeConnector(connector);
2334 continue;
2335 }
2336
Benjamin Franzke117483d2011-08-30 11:38:26 +02002337 connected |= (1 << connector_id);
2338
2339 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002340 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002341 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002342 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002343
2344 /* XXX: not yet needed, we die with 0 outputs */
2345 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002346 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002347 else
2348 x = 0;
2349 y = 0;
2350 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002351 connector, x, y,
2352 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002353 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002354
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002355 }
2356 drmModeFreeConnector(connector);
2357 }
2358 drmModeFreeResources(resources);
2359
2360 disconnects = ec->connector_allocator & ~connected;
2361 if (disconnects) {
2362 wl_list_for_each_safe(output, next, &ec->base.output_list,
2363 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002364 if (disconnects & (1 << output->connector_id)) {
2365 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002366 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002367 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002368 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002369 }
2370 }
2371 }
2372
2373 /* FIXME: handle zero outputs, without terminating */
2374 if (ec->connector_allocator == 0)
2375 wl_display_terminate(ec->base.wl_display);
2376}
2377
2378static int
David Herrmannd7488c22012-03-11 20:05:21 +01002379udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002380{
David Herrmannd7488c22012-03-11 20:05:21 +01002381 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002382 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002383
2384 sysnum = udev_device_get_sysnum(device);
2385 if (!sysnum || atoi(sysnum) != ec->drm.id)
2386 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002387
David Herrmann6ac52db2012-03-11 20:05:22 +01002388 val = udev_device_get_property_value(device, "HOTPLUG");
2389 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002390 return 0;
2391
David Herrmann6ac52db2012-03-11 20:05:22 +01002392 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002393}
2394
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002395static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002396udev_drm_event(int fd, uint32_t mask, void *data)
2397{
2398 struct drm_compositor *ec = data;
2399 struct udev_device *event;
2400
2401 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002402
David Herrmannd7488c22012-03-11 20:05:21 +01002403 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002404 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002405
2406 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002407
2408 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002409}
2410
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002411static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002412drm_restore(struct weston_compositor *ec)
2413{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002414 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002415}
2416
2417static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002418drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002419{
2420 struct drm_compositor *d = (struct drm_compositor *) ec;
2421
Rob Bradfordd355b802013-05-31 18:09:55 +01002422 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002423
2424 wl_event_source_remove(d->udev_drm_source);
2425 wl_event_source_remove(d->drm_source);
2426
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002427 destroy_sprites(d);
2428
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002429 weston_compositor_shutdown(ec);
2430
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002431 if (d->gbm)
2432 gbm_device_destroy(d->gbm);
2433
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002434 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002435
Rob Bradford45c15b82013-07-26 16:29:35 +01002436 close(d->drm.fd);
2437
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002438 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002439}
2440
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002441static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002442drm_compositor_set_modes(struct drm_compositor *compositor)
2443{
2444 struct drm_output *output;
2445 struct drm_mode *drm_mode;
2446 int ret;
2447
2448 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002449 if (!output->current) {
2450 /* If something that would cause the output to
2451 * switch mode happened while in another vt, we
2452 * might not have a current drm_fb. In that case,
2453 * schedule a repaint and let drm_output_repaint
2454 * handle setting the mode. */
2455 weston_output_schedule_repaint(&output->base);
2456 continue;
2457 }
2458
Hardeningff39efa2013-09-18 23:56:35 +02002459 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002460 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002461 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002462 &output->connector_id, 1,
2463 &drm_mode->mode_info);
2464 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002465 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002466 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002467 drm_mode->base.width, drm_mode->base.height,
2468 output->base.x, output->base.y);
2469 }
2470 }
2471}
2472
2473static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002474session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002475{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002476 struct weston_compositor *compositor = data;
2477 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002478 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002479 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002480
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002481 if (ec->base.session_active) {
2482 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002483 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002484 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002485 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002486 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002487 } else {
2488 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002489 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002490
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002491 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002492 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002493
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002494 /* If we have a repaint scheduled (either from a
2495 * pending pageflip or the idle handler), make sure we
2496 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002497 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002498 * further attemps at repainting. When we switch
2499 * back, we schedule a repaint, which will process
2500 * pending frame callbacks. */
2501
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002502 wl_list_for_each(output, &ec->base.output_list, base.link) {
2503 output->base.repaint_needed = 0;
2504 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002505 }
2506
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002507 output = container_of(ec->base.output_list.next,
2508 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002509
2510 wl_list_for_each(sprite, &ec->sprite_list, link)
2511 drmModeSetPlane(ec->drm.fd,
2512 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002513 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002514 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002515 };
2516}
2517
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002518static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002519switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002520{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002521 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002522
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002523 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002524}
2525
David Herrmann0af066f2012-10-29 19:21:16 +01002526/*
2527 * Find primary GPU
2528 * Some systems may have multiple DRM devices attached to a single seat. This
2529 * function loops over all devices and tries to find a PCI device with the
2530 * boot_vga sysfs attribute set to 1.
2531 * If no such device is found, the first DRM device reported by udev is used.
2532 */
2533static struct udev_device*
2534find_primary_gpu(struct drm_compositor *ec, const char *seat)
2535{
2536 struct udev_enumerate *e;
2537 struct udev_list_entry *entry;
2538 const char *path, *device_seat, *id;
2539 struct udev_device *device, *drm_device, *pci;
2540
2541 e = udev_enumerate_new(ec->udev);
2542 udev_enumerate_add_match_subsystem(e, "drm");
2543 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2544
2545 udev_enumerate_scan_devices(e);
2546 drm_device = NULL;
2547 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2548 path = udev_list_entry_get_name(entry);
2549 device = udev_device_new_from_syspath(ec->udev, path);
2550 if (!device)
2551 continue;
2552 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2553 if (!device_seat)
2554 device_seat = default_seat;
2555 if (strcmp(device_seat, seat)) {
2556 udev_device_unref(device);
2557 continue;
2558 }
2559
2560 pci = udev_device_get_parent_with_subsystem_devtype(device,
2561 "pci", NULL);
2562 if (pci) {
2563 id = udev_device_get_sysattr_value(pci, "boot_vga");
2564 if (id && !strcmp(id, "1")) {
2565 if (drm_device)
2566 udev_device_unref(drm_device);
2567 drm_device = device;
2568 break;
2569 }
2570 }
2571
2572 if (!drm_device)
2573 drm_device = device;
2574 else
2575 udev_device_unref(device);
2576 }
2577
2578 udev_enumerate_unref(e);
2579 return drm_device;
2580}
2581
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002582static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002583planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002584{
2585 struct drm_compositor *c = data;
2586
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002587 switch (key) {
2588 case KEY_C:
2589 c->cursors_are_broken ^= 1;
2590 break;
2591 case KEY_V:
2592 c->sprites_are_broken ^= 1;
2593 break;
2594 case KEY_O:
2595 c->sprites_hidden ^= 1;
2596 break;
2597 default:
2598 break;
2599 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002600}
2601
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002602#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002603static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002604recorder_destroy(struct drm_output *output)
2605{
2606 vaapi_recorder_destroy(output->recorder);
2607 output->recorder = NULL;
2608
2609 output->base.disable_planes--;
2610
2611 wl_list_remove(&output->recorder_frame_listener.link);
2612 weston_log("[libva recorder] done\n");
2613}
2614
2615static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002616recorder_frame_notify(struct wl_listener *listener, void *data)
2617{
2618 struct drm_output *output;
2619 struct drm_compositor *c;
2620 int fd, ret;
2621
2622 output = container_of(listener, struct drm_output,
2623 recorder_frame_listener);
2624 c = (struct drm_compositor *) output->base.compositor;
2625
2626 if (!output->recorder)
2627 return;
2628
2629 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2630 DRM_CLOEXEC, &fd);
2631 if (ret) {
2632 weston_log("[libva recorder] "
2633 "failed to create prime fd for front buffer\n");
2634 return;
2635 }
2636
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002637 ret = vaapi_recorder_frame(output->recorder, fd,
2638 output->current->stride);
2639 if (ret < 0) {
2640 weston_log("[libva recorder] aborted: %m\n");
2641 recorder_destroy(output);
2642 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002643}
2644
2645static void *
2646create_recorder(struct drm_compositor *c, int width, int height,
2647 const char *filename)
2648{
2649 int fd;
2650 drm_magic_t magic;
2651
2652 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2653 if (fd < 0)
2654 return NULL;
2655
2656 drmGetMagic(fd, &magic);
2657 drmAuthMagic(c->drm.fd, magic);
2658
2659 return vaapi_recorder_create(fd, width, height, filename);
2660}
2661
2662static void
2663recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2664 void *data)
2665{
2666 struct drm_compositor *c = data;
2667 struct drm_output *output;
2668 int width, height;
2669
2670 output = container_of(c->base.output_list.next,
2671 struct drm_output, base.link);
2672
2673 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002674 if (output->format != GBM_FORMAT_XRGB8888) {
2675 weston_log("failed to start vaapi recorder: "
2676 "output format not supported\n");
2677 return;
2678 }
2679
Hardeningff39efa2013-09-18 23:56:35 +02002680 width = output->base.current_mode->width;
2681 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002682
2683 output->recorder =
2684 create_recorder(c, width, height, "capture.h264");
2685 if (!output->recorder) {
2686 weston_log("failed to create vaapi recorder\n");
2687 return;
2688 }
2689
2690 output->base.disable_planes++;
2691
2692 output->recorder_frame_listener.notify = recorder_frame_notify;
2693 wl_signal_add(&output->base.frame_signal,
2694 &output->recorder_frame_listener);
2695
2696 weston_output_schedule_repaint(&output->base);
2697
2698 weston_log("[libva recorder] initialized\n");
2699 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002700 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002701 }
2702}
2703#else
2704static void
2705recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2706 void *data)
2707{
2708 weston_log("Compiled without libva support\n");
2709}
2710#endif
2711
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002712static void
2713switch_to_gl_renderer(struct drm_compositor *c)
2714{
2715 struct drm_output *output;
2716
2717 if (!c->use_pixman)
2718 return;
2719
2720 weston_log("Switching to GL renderer\n");
2721
2722 c->gbm = create_gbm_device(c->drm.fd);
2723 if (!c->gbm) {
2724 weston_log("Failed to create gbm device. "
2725 "Aborting renderer switch\n");
2726 return;
2727 }
2728
2729 wl_list_for_each(output, &c->base.output_list, base.link)
2730 pixman_renderer_output_destroy(&output->base);
2731
2732 c->base.renderer->destroy(&c->base);
2733
2734 if (drm_compositor_create_gl_renderer(c) < 0) {
2735 gbm_device_destroy(c->gbm);
2736 weston_log("Failed to create GL renderer. Quitting.\n");
2737 /* FIXME: we need a function to shutdown cleanly */
2738 assert(0);
2739 }
2740
2741 wl_list_for_each(output, &c->base.output_list, base.link)
2742 drm_output_init_egl(output, c);
2743
2744 c->use_pixman = 0;
2745}
2746
2747static void
2748renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2749 void *data)
2750{
2751 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2752
2753 switch_to_gl_renderer(c);
2754}
2755
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002756static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002757drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002758 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002759 int *argc, char *argv[],
2760 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002761{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002762 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002763 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002764 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002765 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002766 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002767 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002768
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002769 weston_log("initializing drm backend\n");
2770
Peter Huttererf3d62272013-08-08 11:57:05 +10002771 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002772 if (ec == NULL)
2773 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002774
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002775 /* KMS support for sprites is not complete yet, so disable the
2776 * functionality for now. */
2777 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002778
2779 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002780 if (get_gbm_format_from_section(section,
2781 GBM_FORMAT_XRGB8888,
2782 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002783 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002784
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002785 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002786
Daniel Stone725c2c32012-06-22 14:04:36 +01002787 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002788 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002789 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002790 goto err_base;
2791 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002792
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002793 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002794 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
David Herrmann2ecb84a2014-12-30 14:33:22 +01002795 param->seat_id, true);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002796 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002797 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002798 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002799 goto err_compositor;
2800 }
2801
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002802 ec->udev = udev_new();
2803 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002804 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002805 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002806 }
2807
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002808 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002809 ec->session_listener.notify = session_notify;
2810 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002811
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002812 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002813 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002814 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002815 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002816 }
David Herrmann0af066f2012-10-29 19:21:16 +01002817 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002818
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002819 if (init_drm(ec, drm_device) < 0) {
2820 weston_log("failed to initialize kms\n");
2821 goto err_udev_dev;
2822 }
2823
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002824 if (ec->use_pixman) {
2825 if (init_pixman(ec) < 0) {
2826 weston_log("failed to initialize pixman renderer\n");
2827 goto err_udev_dev;
2828 }
2829 } else {
2830 if (init_egl(ec) < 0) {
2831 weston_log("failed to initialize egl\n");
2832 goto err_udev_dev;
2833 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002834 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002835
2836 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002837 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002838
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002839 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002840
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002841 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002842 weston_compositor_add_key_binding(&ec->base, key,
2843 MODIFIER_CTRL | MODIFIER_ALT,
2844 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002845
Jesse Barnes58ef3792012-02-23 09:45:49 -05002846 wl_list_init(&ec->sprite_list);
2847 create_sprites(ec);
2848
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002849 if (udev_input_init(&ec->input,
2850 &ec->base, ec->udev, param->seat_id) < 0) {
2851 weston_log("failed to create input devices\n");
2852 goto err_sprite;
2853 }
2854
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002855 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002856 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002857 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002858 }
2859
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002860 /* A this point we have some idea of whether or not we have a working
2861 * cursor plane. */
2862 if (!ec->cursors_are_broken)
2863 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2864
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002865 path = NULL;
2866
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002867 loop = wl_display_get_event_loop(ec->base.wl_display);
2868 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002869 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002870 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002871
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002872 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2873 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002874 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002875 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002876 }
2877 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2878 "drm", NULL);
2879 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002880 wl_event_loop_add_fd(loop,
2881 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002882 WL_EVENT_READABLE, udev_drm_event, ec);
2883
2884 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002885 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002886 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002887 }
2888
Daniel Stonea96b93c2012-06-22 14:04:37 +01002889 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002890
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002891 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002892 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002893 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002894 planes_binding, ec);
2895 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2896 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002897 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2898 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002899 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2900 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002901
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002902 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002903
2904err_udev_monitor:
2905 wl_event_source_remove(ec->udev_drm_source);
2906 udev_monitor_unref(ec->udev_monitor);
2907err_drm_source:
2908 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002909err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002910 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002911err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002912 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002913 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002914 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002915err_udev_dev:
2916 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002917err_launcher:
2918 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002919err_udev:
2920 udev_unref(ec->udev);
2921err_compositor:
2922 weston_compositor_shutdown(&ec->base);
2923err_base:
2924 free(ec);
2925 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002926}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002927
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002928WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002929backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002930 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002931{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002932 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002933
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002934 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002935 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2936 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2937 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002938 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002939 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002940 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002941
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002942 param.seat_id = default_seat;
2943
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002944 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002945
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002946 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002947}