blob: 69bdcfdd256bfeedc140b4fc0b139a86e36964d3 [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
Pekka Paalanen5580f222015-02-17 16:33:18 +0200484 if (ev->geometry.scissor_enabled)
485 return NULL;
486
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400487 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700488 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500489
Rob Bradford9b101872012-09-14 23:25:41 +0100490 /* Unable to use the buffer for scanout */
491 if (!bo)
492 return NULL;
493
Jason Ekstranda7af7042013-10-12 22:38:11 -0500494 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500495 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300496 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400497 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300498 }
499
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500500 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300501 if (!output->next) {
502 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400503 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300504 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500505
Pekka Paalanende685b82012-12-04 15:58:12 +0200506 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500507
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400508 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500509}
510
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500511static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200512drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400513{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200514 struct drm_compositor *c =
515 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300516 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400517
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200518 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400519
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300520 bo = gbm_surface_lock_front_buffer(output->surface);
521 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200522 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400523 return;
524 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300525
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000526 output->next = drm_fb_get_from_bo(bo, c, output->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300527 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200528 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300529 gbm_surface_release_buffer(output->surface, bo);
530 return;
531 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400532}
533
534static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200535drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
536{
537 struct weston_compositor *ec = output->base.compositor;
538 pixman_region32_t total_damage, previous_damage;
539
540 pixman_region32_init(&total_damage);
541 pixman_region32_init(&previous_damage);
542
543 pixman_region32_copy(&previous_damage, damage);
544
545 pixman_region32_union(&total_damage, damage, &output->previous_damage);
546 pixman_region32_copy(&output->previous_damage, &previous_damage);
547
548 output->current_image ^= 1;
549
550 output->next = output->dumb[output->current_image];
551 pixman_renderer_output_set_buffer(&output->base,
552 output->image[output->current_image]);
553
554 ec->renderer->repaint_output(&output->base, &total_damage);
555
556 pixman_region32_fini(&total_damage);
557 pixman_region32_fini(&previous_damage);
558}
559
560static void
561drm_output_render(struct drm_output *output, pixman_region32_t *damage)
562{
563 struct drm_compositor *c =
564 (struct drm_compositor *) output->base.compositor;
565
566 if (c->use_pixman)
567 drm_output_render_pixman(output, damage);
568 else
569 drm_output_render_gl(output, damage);
570
571 pixman_region32_subtract(&c->base.primary_plane.damage,
572 &c->base.primary_plane.damage, damage);
573}
574
575static void
Richard Hughese7299962013-05-01 21:52:12 +0100576drm_output_set_gamma(struct weston_output *output_base,
577 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
578{
579 int rc;
580 struct drm_output *output = (struct drm_output *) output_base;
581 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
582
583 /* check */
584 if (output_base->gamma_size != size)
585 return;
586 if (!output->original_crtc)
587 return;
588
589 rc = drmModeCrtcSetGamma(compositor->drm.fd,
590 output->crtc_id,
591 size, r, g, b);
592 if (rc)
593 weston_log("set gamma failed: %m\n");
594}
595
David Herrmann1edf44c2013-10-22 17:11:26 +0200596static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500597drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400598 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100599{
600 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500601 struct drm_compositor *compositor =
602 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500603 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400604 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500605 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100606
Xiong Zhangabd5d472013-10-11 14:43:07 +0800607 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200608 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800609
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300610 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400611 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300612 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200613 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100614
Hardeningff39efa2013-09-18 23:56:35 +0200615 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200616 if (!output->current ||
617 output->current->stride != output->next->stride) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400618 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300619 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400620 &output->connector_id, 1,
621 &mode->mode_info);
622 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200623 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200624 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400625 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300626 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200627 }
628
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500629 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300630 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500631 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200632 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200633 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500634 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100635
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300636 output->page_flip_pending = 1;
637
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400638 drm_output_set_cursor(output);
639
Jesse Barnes58ef3792012-02-23 09:45:49 -0500640 /*
641 * Now, update all the sprite surfaces
642 */
643 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200644 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500645 drmVBlank vbl = {
646 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
647 .request.sequence = 1,
648 };
649
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200650 if ((!s->current && !s->next) ||
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200651 !drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500652 continue;
653
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200654 if (s->next && !compositor->sprites_hidden)
655 fb_id = s->next->fb_id;
656
Jesse Barnes58ef3792012-02-23 09:45:49 -0500657 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200658 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500659 s->dest_x, s->dest_y,
660 s->dest_w, s->dest_h,
661 s->src_x, s->src_y,
662 s->src_w, s->src_h);
663 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200664 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500665 ret, strerror(errno));
666
Rob Clark5ca1a472012-08-08 20:27:37 -0500667 if (output->pipe > 0)
668 vbl.request.type |= DRM_VBLANK_SECONDARY;
669
Jesse Barnes58ef3792012-02-23 09:45:49 -0500670 /*
671 * Queue a vblank signal so we know when the surface
672 * becomes active on the display or has been replaced.
673 */
674 vbl.request.signal = (unsigned long)s;
675 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
676 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200677 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500678 ret, strerror(errno));
679 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300680
681 s->output = output;
682 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500683 }
684
David Herrmann1edf44c2013-10-22 17:11:26 +0200685 return 0;
686
687err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800688 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200689 if (output->next) {
690 drm_output_release_fb(output, output->next);
691 output->next = NULL;
692 }
693
694 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400695}
696
697static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200698drm_output_start_repaint_loop(struct weston_output *output_base)
699{
700 struct drm_output *output = (struct drm_output *) output_base;
701 struct drm_compositor *compositor = (struct drm_compositor *)
702 output_base->compositor;
703 uint32_t fb_id;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300704 struct timespec ts;
705
Xiong Zhangabd5d472013-10-11 14:43:07 +0800706 if (output->destroy_pending)
707 return;
708
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300709 if (!output->current) {
710 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200711 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300712 }
713
714 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200715
716 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
717 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
718 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200719 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200720 }
David Herrmann3c688c52013-10-22 17:11:25 +0200721
722 return;
723
724finish_frame:
725 /* if we cannot page-flip, immediately finish frame */
Pekka Paalanen662f3842015-03-18 12:17:26 +0200726 weston_compositor_read_presentation_clock(&compositor->base, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200727 weston_output_finish_frame(output_base, &ts,
728 PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200729}
730
731static void
Pekka Paalanen641307c2014-09-23 22:08:47 -0400732drm_output_update_msc(struct drm_output *output, unsigned int seq)
733{
734 uint64_t msc_hi = output->base.msc >> 32;
735
736 if (seq < (output->base.msc & 0xffffffff))
737 msc_hi++;
738
739 output->base.msc = (msc_hi << 32) + seq;
740}
741
742static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500743vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
744 void *data)
745{
746 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300747 struct drm_output *output = s->output;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400748 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200749 uint32_t flags = PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
750 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300751
Pekka Paalanen641307c2014-09-23 22:08:47 -0400752 drm_output_update_msc(output, frame);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300753 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500754
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200755 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200756 s->current = s->next;
757 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300758
759 if (!output->page_flip_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400760 ts.tv_sec = sec;
761 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200762 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300763 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500764}
765
766static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800767drm_output_destroy(struct weston_output *output_base);
768
769static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400770page_flip_handler(int fd, unsigned int frame,
771 unsigned int sec, unsigned int usec, void *data)
772{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200773 struct drm_output *output = (struct drm_output *) data;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400774 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200775 uint32_t flags = PRESENTATION_FEEDBACK_KIND_VSYNC |
776 PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
777 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400778
Pekka Paalanen641307c2014-09-23 22:08:47 -0400779 drm_output_update_msc(output, frame);
780
Jonas Ådahle5a12252013-04-05 23:07:11 +0200781 /* We don't set page_flip_pending on start_repaint_loop, in that case
782 * we just want to page flip to the current buffer to get an accurate
783 * timestamp */
784 if (output->page_flip_pending) {
785 drm_output_release_fb(output, output->current);
786 output->current = output->next;
787 output->next = NULL;
788 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300789
Jonas Ådahle5a12252013-04-05 23:07:11 +0200790 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400791
Xiong Zhangabd5d472013-10-11 14:43:07 +0800792 if (output->destroy_pending)
793 drm_output_destroy(&output->base);
794 else if (!output->vblank_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400795 ts.tv_sec = sec;
796 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200797 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300798
799 /* We can't call this from frame_notify, because the output's
800 * repaint needed flag is cleared just after that */
801 if (output->recorder)
802 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300803 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200804}
805
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500806static uint32_t
807drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500808 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500809{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500810 uint32_t i, format;
811
812 format = gbm_bo_get_format(bo);
813
814 if (format == GBM_FORMAT_ARGB8888) {
815 pixman_region32_t r;
816
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500817 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600818 ev->surface->width,
819 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500820 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500821
822 if (!pixman_region32_not_empty(&r))
823 format = GBM_FORMAT_XRGB8888;
824
825 pixman_region32_fini(&r);
826 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500827
828 for (i = 0; i < s->count_formats; i++)
829 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500830 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500831
832 return 0;
833}
834
835static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500836drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500837{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500838 return !ev->transform.enabled ||
839 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500840}
841
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400842static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200843drm_output_prepare_overlay_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500844 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500845{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200846 struct weston_compositor *ec = output->base.compositor;
847 struct drm_compositor *c = (struct drm_compositor *)ec;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200848 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500849 struct drm_sprite *s;
850 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500851 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500852 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200853 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500854 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400855 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500856
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200857 if (c->gbm == NULL)
858 return NULL;
859
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200860 if (viewport->buffer.transform != output->base.transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200861 return NULL;
862
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200863 if (viewport->buffer.scale != output->base.current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200864 return NULL;
865
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500866 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400867 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500868
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200869 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400870 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300871
Jason Ekstranda7af7042013-10-12 22:38:11 -0500872 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400873 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500874
Jason Ekstranda7af7042013-10-12 22:38:11 -0500875 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200876 return NULL;
877
Jason Ekstranda7af7042013-10-12 22:38:11 -0500878 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500879 return NULL;
880
Jason Ekstranda7af7042013-10-12 22:38:11 -0500881 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400882 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500883
Jesse Barnes58ef3792012-02-23 09:45:49 -0500884 wl_list_for_each(s, &c->sprite_list, link) {
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200885 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500886 continue;
887
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200888 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500889 found = 1;
890 break;
891 }
892 }
893
894 /* No sprites available */
895 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400896 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500897
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400898 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500899 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700900 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400901 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400902 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400903
Jason Ekstranda7af7042013-10-12 22:38:11 -0500904 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500905 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200906 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400907 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500908 }
909
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200910 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200911 if (!s->next) {
912 gbm_bo_destroy(bo);
913 return NULL;
914 }
915
Jason Ekstranda7af7042013-10-12 22:38:11 -0500916 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500917
Jason Ekstranda7af7042013-10-12 22:38:11 -0500918 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400919 s->plane.x = box->x1;
920 s->plane.y = box->y1;
921
Jesse Barnes58ef3792012-02-23 09:45:49 -0500922 /*
923 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -0500924 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500925 * for us already).
926 */
927 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500928 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200929 &output->base.region);
930 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500931 box = pixman_region32_extents(&dest_rect);
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200932 tbox = weston_transformed_rect(output->base.width,
933 output->base.height,
934 output->base.transform,
935 output->base.current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200936 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200937 s->dest_x = tbox.x1;
938 s->dest_y = tbox.y1;
939 s->dest_w = tbox.x2 - tbox.x1;
940 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500941 pixman_region32_fini(&dest_rect);
942
943 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500944 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200945 &output->base.region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500946 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400947
Jason Ekstranda7af7042013-10-12 22:38:11 -0500948 weston_view_from_global_fixed(ev,
949 wl_fixed_from_int(box->x1),
950 wl_fixed_from_int(box->y1),
951 &sx1, &sy1);
952 weston_view_from_global_fixed(ev,
953 wl_fixed_from_int(box->x2),
954 wl_fixed_from_int(box->y2),
955 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400956
957 if (sx1 < 0)
958 sx1 = 0;
959 if (sy1 < 0)
960 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600961 if (sx2 > wl_fixed_from_int(ev->surface->width))
962 sx2 = wl_fixed_from_int(ev->surface->width);
963 if (sy2 > wl_fixed_from_int(ev->surface->height))
964 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400965
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200966 tbox.x1 = sx1;
967 tbox.y1 = sy1;
968 tbox.x2 = sx2;
969 tbox.y2 = sy2;
970
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600971 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
972 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200973 viewport->buffer.transform,
974 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100975 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200976
977 s->src_x = tbox.x1 << 8;
978 s->src_y = tbox.y1 << 8;
979 s->src_w = (tbox.x2 - tbox.x1) << 8;
980 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500981 pixman_region32_fini(&src_rect);
982
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400983 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500984}
985
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400986static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200987drm_output_prepare_cursor_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500988 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500989{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400990 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200991 (struct drm_compositor *)output->base.compositor;
Neil Robertsf37f82c2014-05-01 18:00:41 +0100992 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400993
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200994 if (c->gbm == NULL)
995 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200996 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
997 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200998 if (viewport->buffer.scale != output->base.current_scale)
Neil Robertsf37f82c2014-05-01 18:00:41 +0100999 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001000 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001001 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001002 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001003 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001004 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -04001005 return NULL;
Pekka Paalanen5580f222015-02-17 16:33:18 +02001006 if (ev->geometry.scissor_enabled)
1007 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001008 if (ev->surface->buffer_ref.buffer == NULL ||
1009 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001010 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001011 return NULL;
1012
Jason Ekstranda7af7042013-10-12 22:38:11 -05001013 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001014
1015 return &output->cursor_plane;
1016}
1017
1018static void
1019drm_output_set_cursor(struct drm_output *output)
1020{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001021 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001022 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001023 struct drm_compositor *c =
1024 (struct drm_compositor *) output->base.compositor;
1025 EGLint handle, stride;
1026 struct gbm_bo *bo;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001027 uint32_t buf[c->cursor_width * c->cursor_height];
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001028 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001029 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001030
Jason Ekstranda7af7042013-10-12 22:38:11 -05001031 output->cursor_view = NULL;
1032 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001033 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
1034 return;
1035 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001036
Neil Robertse5051712013-11-13 15:44:06 +00001037 buffer = ev->surface->buffer_ref.buffer;
1038
1039 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001040 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001041 pixman_region32_fini(&output->cursor_plane.damage);
1042 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001043 output->current_cursor ^= 1;
1044 bo = output->cursor_bo[output->current_cursor];
1045 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001046 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1047 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1048 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001049 for (i = 0; i < ev->surface->height; i++)
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001050 memcpy(buf + i * c->cursor_width, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001051 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001052 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001053
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001054 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001055 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001056
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001057 handle = gbm_bo_get_handle(bo).s32;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001058 if (drmModeSetCursor(c->drm.fd, output->crtc_id, handle,
1059 c->cursor_width, c->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001060 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001061 c->cursors_are_broken = 1;
1062 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001063 }
1064
Jason Ekstranda7af7042013-10-12 22:38:11 -05001065 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1066 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001067 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001068 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001069 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001070 c->cursors_are_broken = 1;
1071 }
1072
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001073 output->cursor_plane.x = x;
1074 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001075 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001076}
1077
Jesse Barnes58ef3792012-02-23 09:45:49 -05001078static void
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001079drm_assign_planes(struct weston_output *output_base)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001080{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001081 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001082 (struct drm_compositor *)output_base->compositor;
1083 struct drm_output *output = (struct drm_output *)output_base;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001084 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001085 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001086 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001087
1088 /*
1089 * Find a surface for each sprite in the output using some heuristics:
1090 * 1) size
1091 * 2) frequency of update
1092 * 3) opacity (though some hw might support alpha blending)
1093 * 4) clipping (this can be fixed with color keys)
1094 *
1095 * The idea is to save on blitting since this should save power.
1096 * If we can get a large video surface on the sprite for example,
1097 * the main display surface may not need to update at all, and
1098 * the client buffer can be used directly for the sprite surface
1099 * as we do for flipping full screen surfaces.
1100 */
1101 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001102 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001103
Jason Ekstranda7af7042013-10-12 22:38:11 -05001104 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001105 struct weston_surface *es = ev->surface;
1106
1107 /* Test whether this buffer can ever go into a plane:
1108 * non-shm, or small enough to be a cursor.
1109 *
1110 * Also, keep a reference when using the pixman renderer.
1111 * That makes it possible to do a seamless switch to the GL
1112 * renderer and since the pixman renderer keeps a reference
1113 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001114 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001115 if (c->use_pixman ||
1116 (es->buffer_ref.buffer &&
1117 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001118 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001119 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001120 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001121 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001122
Jesse Barnes58ef3792012-02-23 09:45:49 -05001123 pixman_region32_init(&surface_overlap);
1124 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001125 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001126
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001127 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001128 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001129 next_plane = primary;
1130 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001131 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001132 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001133 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001134 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001135 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001136 if (next_plane == NULL)
1137 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001138
Jason Ekstranda7af7042013-10-12 22:38:11 -05001139 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001140
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001141 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001142 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001143 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001144
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001145 if (next_plane == primary ||
1146 next_plane == &output->cursor_plane) {
1147 /* cursor plane involves a copy */
1148 ev->psf_flags = 0;
1149 } else {
1150 /* All other planes are a direct scanout of a
1151 * single client buffer.
1152 */
1153 ev->psf_flags = PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
1154 }
1155
Jesse Barnes58ef3792012-02-23 09:45:49 -05001156 pixman_region32_fini(&surface_overlap);
1157 }
1158 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001159}
1160
Matt Roper361d2ad2011-08-29 13:52:23 -07001161static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001162drm_output_fini_pixman(struct drm_output *output);
1163
1164static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001165drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001166{
1167 struct drm_output *output = (struct drm_output *) output_base;
1168 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001169 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001170 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001171
Xiong Zhangabd5d472013-10-11 14:43:07 +08001172 if (output->page_flip_pending) {
1173 output->destroy_pending = 1;
1174 weston_log("destroy output while page flip pending\n");
1175 return;
1176 }
1177
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001178 if (output->backlight)
1179 backlight_destroy(output->backlight);
1180
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001181 drmModeFreeProperty(output->dpms_prop);
1182
Matt Roper361d2ad2011-08-29 13:52:23 -07001183 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001184 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001185
1186 /* Restore original CRTC state */
1187 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001188 origcrtc->x, origcrtc->y,
1189 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001190 drmModeFreeCrtc(origcrtc);
1191
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001192 c->crtc_allocator &= ~(1 << output->crtc_id);
1193 c->connector_allocator &= ~(1 << output->connector_id);
1194
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001195 if (c->use_pixman) {
1196 drm_output_fini_pixman(output);
1197 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001198 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001199 gbm_surface_destroy(output->surface);
1200 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001201
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001202 weston_plane_release(&output->fb_plane);
1203 weston_plane_release(&output->cursor_plane);
1204
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001205 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001206
Matt Roper361d2ad2011-08-29 13:52:23 -07001207 free(output);
1208}
1209
Alex Wub7b8bda2012-04-17 17:20:48 +08001210static struct drm_mode *
1211choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1212{
1213 struct drm_mode *tmp_mode = NULL, *mode;
1214
Hardeningff39efa2013-09-18 23:56:35 +02001215 if (output->base.current_mode->width == target_mode->width &&
1216 output->base.current_mode->height == target_mode->height &&
1217 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001218 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001219 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001220
1221 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1222 if (mode->mode_info.hdisplay == target_mode->width &&
1223 mode->mode_info.vdisplay == target_mode->height) {
1224 if (mode->mode_info.vrefresh == target_mode->refresh ||
1225 target_mode->refresh == 0) {
1226 return mode;
1227 } else if (!tmp_mode)
1228 tmp_mode = mode;
1229 }
1230 }
1231
1232 return tmp_mode;
1233}
1234
1235static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001236drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001237static int
1238drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001239
1240static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001241drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1242{
1243 struct drm_output *output;
1244 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001245 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001246
1247 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001248 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001249 return -1;
1250 }
1251
1252 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001253 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001254 return -1;
1255 }
1256
1257 ec = (struct drm_compositor *)output_base->compositor;
1258 output = (struct drm_output *)output_base;
1259 drm_mode = choose_mode (output, mode);
1260
1261 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001262 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001263 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001264 }
1265
Hardeningff39efa2013-09-18 23:56:35 +02001266 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001267 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001268
Hardeningff39efa2013-09-18 23:56:35 +02001269 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001270
Hardeningff39efa2013-09-18 23:56:35 +02001271 output->base.current_mode = &drm_mode->base;
1272 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001273 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1274
Alex Wub7b8bda2012-04-17 17:20:48 +08001275 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001276 drm_output_release_fb(output, output->current);
1277 drm_output_release_fb(output, output->next);
1278 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001279
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001280 if (ec->use_pixman) {
1281 drm_output_fini_pixman(output);
1282 if (drm_output_init_pixman(output, ec) < 0) {
1283 weston_log("failed to init output pixman state with "
1284 "new mode\n");
1285 return -1;
1286 }
1287 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001288 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001289 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001290
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001291 if (drm_output_init_egl(output, ec) < 0) {
1292 weston_log("failed to init output egl state with "
1293 "new mode");
1294 return -1;
1295 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001296 }
1297
Alex Wub7b8bda2012-04-17 17:20:48 +08001298 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001299}
1300
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001301static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001302on_drm_input(int fd, uint32_t mask, void *data)
1303{
1304 drmEventContext evctx;
1305
1306 memset(&evctx, 0, sizeof evctx);
1307 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1308 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001309 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001310 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001311
1312 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001313}
1314
1315static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001316init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001317{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001318 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001319 uint64_t cap;
1320 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001321 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001322
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001323 sysnum = udev_device_get_sysnum(device);
1324 if (sysnum)
1325 ec->drm.id = atoi(sysnum);
1326 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001327 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001328 return -1;
1329 }
1330
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001331 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001332 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001333 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001334 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001335 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001336 udev_device_get_devnode(device));
1337 return -1;
1338 }
1339
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001340 weston_log("using %s\n", filename);
1341
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001342 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001343 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001344
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001345 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1346 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001347 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001348 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001349 clk_id = CLOCK_REALTIME;
1350
1351 if (weston_compositor_set_presentation_clock(&ec->base, clk_id) < 0) {
1352 weston_log("Error: failed to set presentation clock %d.\n",
1353 clk_id);
1354 return -1;
1355 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001356
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001357 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1358 if (ret == 0)
1359 ec->cursor_width = cap;
1360 else
1361 ec->cursor_width = 64;
1362
1363 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1364 if (ret == 0)
1365 ec->cursor_height = cap;
1366 else
1367 ec->cursor_height = 64;
1368
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001369 return 0;
1370}
1371
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001372static struct gbm_device *
1373create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001374{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001375 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001376
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001377 gl_renderer = weston_load_module("gl-renderer.so",
1378 "gl_renderer_interface");
1379 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001380 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001381
1382 /* GBM will load a dri driver, but even though they need symbols from
1383 * libglapi, in some version of Mesa they are not linked to it. Since
1384 * only the gl-renderer module links to it, the call above won't make
1385 * these symbols globally available, and loading the DRI driver fails.
1386 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1387 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1388
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001389 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001390
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001391 return gbm;
1392}
1393
1394static int
1395drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1396{
1397 EGLint format;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001398
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001399 format = ec->format;
Jonny Lamb70eba3f2015-03-20 15:26:50 +01001400 if (gl_renderer->create(&ec->base, EGL_PLATFORM_GBM_KHR, (void *) ec->gbm,
Derek Foremane76f1852015-05-15 12:12:39 -05001401 gl_renderer->opaque_attribs, &format, 1) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001402 return -1;
1403 }
1404
1405 return 0;
1406}
1407
1408static int
1409init_egl(struct drm_compositor *ec)
1410{
1411 ec->gbm = create_gbm_device(ec->drm.fd);
1412
1413 if (!ec->gbm)
1414 return -1;
1415
1416 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001417 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001418 return -1;
1419 }
1420
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001421 return 0;
1422}
1423
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001424static int
1425init_pixman(struct drm_compositor *ec)
1426{
1427 return pixman_renderer_init(&ec->base);
1428}
1429
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001430static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001431drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001432{
1433 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001434 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001435
1436 mode = malloc(sizeof *mode);
1437 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001438 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001439
1440 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001441 mode->base.width = info->hdisplay;
1442 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001443
1444 /* Calculate higher precision (mHz) refresh rate */
1445 refresh = (info->clock * 1000000LL / info->htotal +
1446 info->vtotal / 2) / info->vtotal;
1447
1448 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1449 refresh *= 2;
1450 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1451 refresh /= 2;
1452 if (info->vscan > 1)
1453 refresh /= info->vscan;
1454
1455 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001456 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001457
1458 if (info->type & DRM_MODE_TYPE_PREFERRED)
1459 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1460
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001461 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1462
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001463 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001464}
1465
1466static int
1467drm_subpixel_to_wayland(int drm_value)
1468{
1469 switch (drm_value) {
1470 default:
1471 case DRM_MODE_SUBPIXEL_UNKNOWN:
1472 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1473 case DRM_MODE_SUBPIXEL_NONE:
1474 return WL_OUTPUT_SUBPIXEL_NONE;
1475 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1476 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1477 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1478 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1479 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1480 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1481 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1482 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1483 }
1484}
1485
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001486/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001487static uint32_t
1488drm_get_backlight(struct drm_output *output)
1489{
1490 long brightness, max_brightness, norm;
1491
1492 brightness = backlight_get_brightness(output->backlight);
1493 max_brightness = backlight_get_max_brightness(output->backlight);
1494
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001495 /* convert it on a scale of 0 to 255 */
1496 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001497
1498 return (uint32_t) norm;
1499}
1500
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001501/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001502static void
1503drm_set_backlight(struct weston_output *output_base, uint32_t value)
1504{
1505 struct drm_output *output = (struct drm_output *) output_base;
1506 long max_brightness, new_brightness;
1507
1508 if (!output->backlight)
1509 return;
1510
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001511 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001512 return;
1513
1514 max_brightness = backlight_get_max_brightness(output->backlight);
1515
1516 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001517 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001518
1519 backlight_set_brightness(output->backlight, new_brightness);
1520}
1521
1522static drmModePropertyPtr
1523drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1524{
1525 drmModePropertyPtr props;
1526 int i;
1527
1528 for (i = 0; i < connector->count_props; i++) {
1529 props = drmModeGetProperty(fd, connector->props[i]);
1530 if (!props)
1531 continue;
1532
1533 if (!strcmp(props->name, name))
1534 return props;
1535
1536 drmModeFreeProperty(props);
1537 }
1538
1539 return NULL;
1540}
1541
1542static void
1543drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1544{
1545 struct drm_output *output = (struct drm_output *) output_base;
1546 struct weston_compositor *ec = output_base->compositor;
1547 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001548
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001549 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001550 return;
1551
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001552 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1553 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001554}
1555
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001556static const char *connector_type_names[] = {
1557 "None",
1558 "VGA",
1559 "DVI",
1560 "DVI",
1561 "DVI",
1562 "Composite",
1563 "TV",
1564 "LVDS",
1565 "CTV",
1566 "DIN",
1567 "DP",
1568 "HDMI",
1569 "HDMI",
1570 "TV",
1571 "eDP",
1572};
1573
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001574static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001575find_crtc_for_connector(struct drm_compositor *ec,
1576 drmModeRes *resources, drmModeConnector *connector)
1577{
1578 drmModeEncoder *encoder;
1579 uint32_t possible_crtcs;
1580 int i, j;
1581
1582 for (j = 0; j < connector->count_encoders; j++) {
1583 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1584 if (encoder == NULL) {
1585 weston_log("Failed to get encoder.\n");
1586 return -1;
1587 }
1588 possible_crtcs = encoder->possible_crtcs;
1589 drmModeFreeEncoder(encoder);
1590
1591 for (i = 0; i < resources->count_crtcs; i++) {
1592 if (possible_crtcs & (1 << i) &&
1593 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1594 return i;
1595 }
1596 }
1597
1598 return -1;
1599}
1600
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001601/* Init output state that depends on gl or gbm */
1602static int
1603drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1604{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001605 EGLint format = output->format;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001606 int i, flags;
1607
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001608 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001609 output->base.current_mode->width,
1610 output->base.current_mode->height,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001611 format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001612 GBM_BO_USE_SCANOUT |
1613 GBM_BO_USE_RENDERING);
1614 if (!output->surface) {
1615 weston_log("failed to create gbm surface\n");
1616 return -1;
1617 }
1618
Jonny Lamb671148f2015-03-20 15:26:52 +01001619 if (gl_renderer->output_create(&output->base,
Jonny Lamb445fb692015-03-24 13:12:01 +01001620 (EGLNativeDisplayType)output->surface,
1621 output->surface,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001622 gl_renderer->opaque_attribs,
Derek Foremane76f1852015-05-15 12:12:39 -05001623 &format,
1624 1) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001625 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001626 gbm_surface_destroy(output->surface);
1627 return -1;
1628 }
1629
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001630 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001631
1632 for (i = 0; i < 2; i++) {
1633 if (output->cursor_bo[i])
1634 continue;
1635
1636 output->cursor_bo[i] =
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001637 gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
1638 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001639 }
1640
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001641 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1642 weston_log("cursor buffers unavailable, using gl cursors\n");
1643 ec->cursors_are_broken = 1;
1644 }
1645
1646 return 0;
1647}
1648
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001649static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001650drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1651{
Hardeningff39efa2013-09-18 23:56:35 +02001652 int w = output->base.current_mode->width;
1653 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001654 unsigned int i;
1655
1656 /* FIXME error checking */
1657
1658 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001659 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001660 if (!output->dumb[i])
1661 goto err;
1662
1663 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001664 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001665 output->dumb[i]->map,
1666 output->dumb[i]->stride);
1667 if (!output->image[i])
1668 goto err;
1669 }
1670
1671 if (pixman_renderer_output_create(&output->base) < 0)
1672 goto err;
1673
1674 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001675 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001676
1677 return 0;
1678
1679err:
1680 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1681 if (output->dumb[i])
1682 drm_fb_destroy_dumb(output->dumb[i]);
1683 if (output->image[i])
1684 pixman_image_unref(output->image[i]);
1685
1686 output->dumb[i] = NULL;
1687 output->image[i] = NULL;
1688 }
1689
1690 return -1;
1691}
1692
1693static void
1694drm_output_fini_pixman(struct drm_output *output)
1695{
1696 unsigned int i;
1697
1698 pixman_renderer_output_destroy(&output->base);
1699 pixman_region32_fini(&output->previous_damage);
1700
1701 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1702 drm_fb_destroy_dumb(output->dumb[i]);
1703 pixman_image_unref(output->image[i]);
1704 output->dumb[i] = NULL;
1705 output->image[i] = NULL;
1706 }
1707}
1708
Richard Hughes2b2092a2013-04-24 14:58:02 +01001709static void
1710edid_parse_string(const uint8_t *data, char text[])
1711{
1712 int i;
1713 int replaced = 0;
1714
1715 /* this is always 12 bytes, but we can't guarantee it's null
1716 * terminated or not junk. */
1717 strncpy(text, (const char *) data, 12);
1718
1719 /* remove insane chars */
1720 for (i = 0; text[i] != '\0'; i++) {
1721 if (text[i] == '\n' ||
1722 text[i] == '\r') {
1723 text[i] = '\0';
1724 break;
1725 }
1726 }
1727
1728 /* ensure string is printable */
1729 for (i = 0; text[i] != '\0'; i++) {
1730 if (!isprint(text[i])) {
1731 text[i] = '-';
1732 replaced++;
1733 }
1734 }
1735
1736 /* if the string is random junk, ignore the string */
1737 if (replaced > 4)
1738 text[0] = '\0';
1739}
1740
1741#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1742#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1743#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1744#define EDID_OFFSET_DATA_BLOCKS 0x36
1745#define EDID_OFFSET_LAST_BLOCK 0x6c
1746#define EDID_OFFSET_PNPID 0x08
1747#define EDID_OFFSET_SERIAL 0x0c
1748
1749static int
1750edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1751{
1752 int i;
1753 uint32_t serial_number;
1754
1755 /* check header */
1756 if (length < 128)
1757 return -1;
1758 if (data[0] != 0x00 || data[1] != 0xff)
1759 return -1;
1760
1761 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1762 * /--08--\/--09--\
1763 * 7654321076543210
1764 * |\---/\---/\---/
1765 * R C1 C2 C3 */
1766 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1767 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1768 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1769 edid->pnp_id[3] = '\0';
1770
1771 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1772 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1773 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1774 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1775 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1776 if (serial_number > 0)
1777 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1778
1779 /* parse EDID data */
1780 for (i = EDID_OFFSET_DATA_BLOCKS;
1781 i <= EDID_OFFSET_LAST_BLOCK;
1782 i += 18) {
1783 /* ignore pixel clock data */
1784 if (data[i] != 0)
1785 continue;
1786 if (data[i+2] != 0)
1787 continue;
1788
1789 /* any useful blocks? */
1790 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1791 edid_parse_string(&data[i+5],
1792 edid->monitor_name);
1793 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1794 edid_parse_string(&data[i+5],
1795 edid->serial_number);
1796 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1797 edid_parse_string(&data[i+5],
1798 edid->eisa_id);
1799 }
1800 }
1801 return 0;
1802}
1803
1804static void
1805find_and_parse_output_edid(struct drm_compositor *ec,
1806 struct drm_output *output,
1807 drmModeConnector *connector)
1808{
1809 drmModePropertyBlobPtr edid_blob = NULL;
1810 drmModePropertyPtr property;
1811 int i;
1812 int rc;
1813
1814 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1815 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1816 if (!property)
1817 continue;
1818 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1819 !strcmp(property->name, "EDID")) {
1820 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1821 connector->prop_values[i]);
1822 }
1823 drmModeFreeProperty(property);
1824 }
1825 if (!edid_blob)
1826 return;
1827
1828 rc = edid_parse(&output->edid,
1829 edid_blob->data,
1830 edid_blob->length);
1831 if (!rc) {
1832 weston_log("EDID data '%s', '%s', '%s'\n",
1833 output->edid.pnp_id,
1834 output->edid.monitor_name,
1835 output->edid.serial_number);
1836 if (output->edid.pnp_id[0] != '\0')
1837 output->base.make = output->edid.pnp_id;
1838 if (output->edid.monitor_name[0] != '\0')
1839 output->base.model = output->edid.monitor_name;
1840 if (output->edid.serial_number[0] != '\0')
1841 output->base.serial_number = output->edid.serial_number;
1842 }
1843 drmModeFreePropertyBlob(edid_blob);
1844}
1845
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001846
1847
1848static int
1849parse_modeline(const char *s, drmModeModeInfo *mode)
1850{
1851 char hsync[16];
1852 char vsync[16];
1853 float fclock;
1854
1855 mode->type = DRM_MODE_TYPE_USERDEF;
1856 mode->hskew = 0;
1857 mode->vscan = 0;
1858 mode->vrefresh = 0;
1859 mode->flags = 0;
1860
Rob Bradford307e09e2013-07-26 16:29:40 +01001861 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001862 &fclock,
1863 &mode->hdisplay,
1864 &mode->hsync_start,
1865 &mode->hsync_end,
1866 &mode->htotal,
1867 &mode->vdisplay,
1868 &mode->vsync_start,
1869 &mode->vsync_end,
1870 &mode->vtotal, hsync, vsync) != 11)
1871 return -1;
1872
1873 mode->clock = fclock * 1000;
1874 if (strcmp(hsync, "+hsync") == 0)
1875 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1876 else if (strcmp(hsync, "-hsync") == 0)
1877 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1878 else
1879 return -1;
1880
1881 if (strcmp(vsync, "+vsync") == 0)
1882 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1883 else if (strcmp(vsync, "-vsync") == 0)
1884 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1885 else
1886 return -1;
1887
1888 return 0;
1889}
1890
Rob Bradford66bd9f52013-06-25 18:56:42 +01001891static void
1892setup_output_seat_constraint(struct drm_compositor *ec,
1893 struct weston_output *output,
1894 const char *s)
1895{
1896 if (strcmp(s, "") != 0) {
1897 struct udev_seat *seat;
1898
Jonas Ådahl58e15862014-03-12 22:08:40 +01001899 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001900 if (seat)
1901 seat->base.output = output;
1902
1903 if (seat && seat->base.pointer)
1904 weston_pointer_clamp(seat->base.pointer,
1905 &seat->base.pointer->x,
1906 &seat->base.pointer->y);
1907 }
1908}
1909
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001910static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001911get_gbm_format_from_section(struct weston_config_section *section,
1912 uint32_t default_value,
1913 uint32_t *format)
1914{
1915 char *s;
1916 int ret = 0;
1917
1918 weston_config_section_get_string(section,
1919 "gbm-format", &s, NULL);
1920
1921 if (s == NULL)
1922 *format = default_value;
1923 else if (strcmp(s, "xrgb8888") == 0)
1924 *format = GBM_FORMAT_XRGB8888;
1925 else if (strcmp(s, "rgb565") == 0)
1926 *format = GBM_FORMAT_RGB565;
1927 else if (strcmp(s, "xrgb2101010") == 0)
1928 *format = GBM_FORMAT_XRGB2101010;
1929 else {
1930 weston_log("fatal: unrecognized pixel format: %s\n", s);
1931 ret = -1;
1932 }
1933
1934 free(s);
1935
1936 return ret;
1937}
1938
1939static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001940create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001941 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001942 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001943 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001944{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001945 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001946 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001947 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001948 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001949 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001950 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001951 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001952 int i, width, height, scale;
1953 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001954 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001955 enum output_config config;
1956 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001957
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001958 i = find_crtc_for_connector(ec, resources, connector);
1959 if (i < 0) {
1960 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001961 return -1;
1962 }
1963
Peter Huttererf3d62272013-08-08 11:57:05 +10001964 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001965 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001966 return -1;
1967
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001968 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1969 output->base.make = "unknown";
1970 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001971 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001972 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001973
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001974 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1975 type_name = connector_type_names[connector->connector_type];
1976 else
1977 type_name = "UNKNOWN";
1978 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001979 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001980
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001981 section = weston_config_get_section(ec->base.config, "output", "name",
1982 output->base.name);
1983 weston_config_section_get_string(section, "mode", &s, "preferred");
1984 if (strcmp(s, "off") == 0)
1985 config = OUTPUT_CONFIG_OFF;
1986 else if (strcmp(s, "preferred") == 0)
1987 config = OUTPUT_CONFIG_PREFERRED;
1988 else if (strcmp(s, "current") == 0)
1989 config = OUTPUT_CONFIG_CURRENT;
1990 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1991 config = OUTPUT_CONFIG_MODE;
1992 else if (parse_modeline(s, &modeline) == 0)
1993 config = OUTPUT_CONFIG_MODELINE;
1994 else {
1995 weston_log("Invalid mode \"%s\" for output %s\n",
1996 s, output->base.name);
1997 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001998 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001999 free(s);
2000
2001 weston_config_section_get_int(section, "scale", &scale, 1);
2002 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05002003 if (weston_parse_transform(s, &transform) < 0)
2004 weston_log("Invalid transform \"%s\" for output %s\n",
2005 s, output->base.name);
2006
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002007 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002008
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002009 if (get_gbm_format_from_section(section,
2010 ec->format,
2011 &output->format) == -1)
2012 output->format = ec->format;
2013
Rob Bradford66bd9f52013-06-25 18:56:42 +01002014 weston_config_section_get_string(section, "seat", &s, "");
2015 setup_output_seat_constraint(ec, &output->base, s);
2016 free(s);
2017
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002018 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002019 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002020 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002021 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002022 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002023
Matt Roper361d2ad2011-08-29 13:52:23 -07002024 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03002025 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002026
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002027 /* Get the current mode on the crtc that's currently driving
2028 * this connector. */
2029 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002030 memset(&crtc_mode, 0, sizeof crtc_mode);
2031 if (encoder != NULL) {
2032 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
2033 drmModeFreeEncoder(encoder);
2034 if (crtc == NULL)
2035 goto err_free;
2036 if (crtc->mode_valid)
2037 crtc_mode = crtc->mode;
2038 drmModeFreeCrtc(crtc);
2039 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002040
David Herrmann0f0d54e2011-12-08 17:05:45 +01002041 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002042 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002043 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002044 goto err_free;
2045 }
2046
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002047 if (config == OUTPUT_CONFIG_OFF) {
2048 weston_log("Disabling output %s\n", output->base.name);
2049 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
2050 0, 0, 0, 0, 0, NULL);
2051 goto err_free;
2052 }
2053
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002054 preferred = NULL;
2055 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002056 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002057 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002058
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002059 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002060 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002061 width == drm_mode->base.width &&
2062 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002063 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002064 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002065 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002066 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002067 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002068 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002069 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002070
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002071 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002072 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002073 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002074 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002075 }
2076
Wang Quanxianacb805a2012-07-30 18:09:46 -04002077 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002078 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002079 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002080 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002081 }
2082
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002083 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002084 configured = current;
2085
Wang Quanxianacb805a2012-07-30 18:09:46 -04002086 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002087 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002088 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002089 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002090 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002091 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002092 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002093 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002094 else if (best)
2095 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002096
Hardeningff39efa2013-09-18 23:56:35 +02002097 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002098 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002099 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002100 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002101
Hardeningff39efa2013-09-18 23:56:35 +02002102 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002103
John Kåre Alsaker94659272012-11-13 19:10:18 +01002104 weston_output_init(&output->base, &ec->base, x, y,
2105 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002106 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002107
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002108 if (ec->use_pixman) {
2109 if (drm_output_init_pixman(output, ec) < 0) {
2110 weston_log("Failed to init output pixman state\n");
2111 goto err_output;
2112 }
2113 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002114 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002115 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002116 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002117
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002118 output->backlight = backlight_init(drm_device,
2119 connector->connector_type);
2120 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002121 weston_log("Initialized backlight, device %s\n",
2122 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002123 output->base.set_backlight = drm_set_backlight;
2124 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002125 } else {
2126 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002127 }
2128
Giulio Camuffob1147152015-05-06 21:41:57 +03002129 weston_compositor_add_output(&ec->base, &output->base);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002130
Richard Hughes2b2092a2013-04-24 14:58:02 +01002131 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002132 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2133 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002134
Jonas Ådahle5a12252013-04-05 23:07:11 +02002135 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002136 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002137 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002138 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002139 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002140 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002141
Richard Hughese7299962013-05-01 21:52:12 +01002142 output->base.gamma_size = output->original_crtc->gamma_size;
2143 output->base.set_gamma = drm_output_set_gamma;
2144
Xiong Zhang97116532013-10-23 13:58:31 +08002145 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2146 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002147
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002148 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2149 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2150 &ec->base.primary_plane);
2151
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002152 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002153 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002154 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002155 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002156 m->width, m->height, m->refresh / 1000.0,
2157 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2158 ", preferred" : "",
2159 m->flags & WL_OUTPUT_MODE_CURRENT ?
2160 ", current" : "",
2161 connector->count_modes == 0 ?
2162 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002163
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002164 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002165
John Kåre Alsaker94659272012-11-13 19:10:18 +01002166err_output:
2167 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002168err_free:
2169 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2170 base.link) {
2171 wl_list_remove(&drm_mode->base.link);
2172 free(drm_mode);
2173 }
2174
2175 drmModeFreeCrtc(output->original_crtc);
2176 ec->crtc_allocator &= ~(1 << output->crtc_id);
2177 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002178 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002179
David Herrmann0f0d54e2011-12-08 17:05:45 +01002180 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002181}
2182
Jesse Barnes58ef3792012-02-23 09:45:49 -05002183static void
2184create_sprites(struct drm_compositor *ec)
2185{
2186 struct drm_sprite *sprite;
2187 drmModePlaneRes *plane_res;
2188 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002189 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002190
2191 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2192 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002193 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002194 strerror(errno));
2195 return;
2196 }
2197
2198 for (i = 0; i < plane_res->count_planes; i++) {
2199 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2200 if (!plane)
2201 continue;
2202
Peter Huttererf3d62272013-08-08 11:57:05 +10002203 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002204 plane->count_formats));
2205 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002206 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002207 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002208 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002209 continue;
2210 }
2211
Jesse Barnes58ef3792012-02-23 09:45:49 -05002212 sprite->possible_crtcs = plane->possible_crtcs;
2213 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002214 sprite->current = NULL;
2215 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002216 sprite->compositor = ec;
2217 sprite->count_formats = plane->count_formats;
2218 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002219 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002220 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002221 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002222 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2223 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002224
2225 wl_list_insert(&ec->sprite_list, &sprite->link);
2226 }
2227
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002228 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002229}
2230
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002231static void
2232destroy_sprites(struct drm_compositor *compositor)
2233{
2234 struct drm_sprite *sprite, *next;
2235 struct drm_output *output;
2236
2237 output = container_of(compositor->base.output_list.next,
2238 struct drm_output, base.link);
2239
2240 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2241 drmModeSetPlane(compositor->drm.fd,
2242 sprite->plane_id,
2243 output->crtc_id, 0, 0,
2244 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002245 drm_output_release_fb(output, sprite->current);
2246 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002247 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002248 free(sprite);
2249 }
2250}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002251
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002252static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002253create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002254 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002255{
2256 drmModeConnector *connector;
2257 drmModeRes *resources;
2258 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002259 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002260
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002261 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002262 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002263 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002264 return -1;
2265 }
2266
Jesse Barnes58ef3792012-02-23 09:45:49 -05002267 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002268 if (!ec->crtcs) {
2269 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002270 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002271 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002272
Rob Clark4339add2012-08-09 14:18:28 -05002273 ec->min_width = resources->min_width;
2274 ec->max_width = resources->max_width;
2275 ec->min_height = resources->min_height;
2276 ec->max_height = resources->max_height;
2277
Jesse Barnes58ef3792012-02-23 09:45:49 -05002278 ec->num_crtcs = resources->count_crtcs;
2279 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2280
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002281 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002282 connector = drmModeGetConnector(ec->drm.fd,
2283 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002284 if (connector == NULL)
2285 continue;
2286
2287 if (connector->connection == DRM_MODE_CONNECTED &&
2288 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002289 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002290 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002291 connector, x, y,
2292 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002293 drmModeFreeConnector(connector);
2294 continue;
2295 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002296
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002297 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002298 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002299 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002300 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002301
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002302 drmModeFreeConnector(connector);
2303 }
2304
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002305 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002306 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002307 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002308 return -1;
2309 }
2310
2311 drmModeFreeResources(resources);
2312
2313 return 0;
2314}
2315
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002316static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002317update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002318{
2319 drmModeConnector *connector;
2320 drmModeRes *resources;
2321 struct drm_output *output, *next;
2322 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002323 uint32_t connected = 0, disconnects = 0;
2324 int i;
2325
2326 resources = drmModeGetResources(ec->drm.fd);
2327 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002328 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002329 return;
2330 }
2331
2332 /* collect new connects */
2333 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002334 int connector_id = resources->connectors[i];
2335
2336 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002337 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002338 continue;
2339
David Herrmann7551cff2011-12-08 17:05:43 +01002340 if (connector->connection != DRM_MODE_CONNECTED) {
2341 drmModeFreeConnector(connector);
2342 continue;
2343 }
2344
Benjamin Franzke117483d2011-08-30 11:38:26 +02002345 connected |= (1 << connector_id);
2346
2347 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002348 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002349 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002350 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002351
2352 /* XXX: not yet needed, we die with 0 outputs */
2353 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002354 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002355 else
2356 x = 0;
2357 y = 0;
2358 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002359 connector, x, y,
2360 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002361 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002362
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002363 }
2364 drmModeFreeConnector(connector);
2365 }
2366 drmModeFreeResources(resources);
2367
2368 disconnects = ec->connector_allocator & ~connected;
2369 if (disconnects) {
2370 wl_list_for_each_safe(output, next, &ec->base.output_list,
2371 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002372 if (disconnects & (1 << output->connector_id)) {
2373 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002374 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002375 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002376 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002377 }
2378 }
2379 }
2380
2381 /* FIXME: handle zero outputs, without terminating */
2382 if (ec->connector_allocator == 0)
2383 wl_display_terminate(ec->base.wl_display);
2384}
2385
2386static int
David Herrmannd7488c22012-03-11 20:05:21 +01002387udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002388{
David Herrmannd7488c22012-03-11 20:05:21 +01002389 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002390 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002391
2392 sysnum = udev_device_get_sysnum(device);
2393 if (!sysnum || atoi(sysnum) != ec->drm.id)
2394 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002395
David Herrmann6ac52db2012-03-11 20:05:22 +01002396 val = udev_device_get_property_value(device, "HOTPLUG");
2397 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002398 return 0;
2399
David Herrmann6ac52db2012-03-11 20:05:22 +01002400 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002401}
2402
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002403static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002404udev_drm_event(int fd, uint32_t mask, void *data)
2405{
2406 struct drm_compositor *ec = data;
2407 struct udev_device *event;
2408
2409 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002410
David Herrmannd7488c22012-03-11 20:05:21 +01002411 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002412 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002413
2414 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002415
2416 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002417}
2418
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002419static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002420drm_restore(struct weston_compositor *ec)
2421{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002422 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002423}
2424
2425static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002426drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002427{
2428 struct drm_compositor *d = (struct drm_compositor *) ec;
2429
Rob Bradfordd355b802013-05-31 18:09:55 +01002430 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002431
2432 wl_event_source_remove(d->udev_drm_source);
2433 wl_event_source_remove(d->drm_source);
2434
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002435 destroy_sprites(d);
2436
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002437 weston_compositor_shutdown(ec);
2438
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002439 if (d->gbm)
2440 gbm_device_destroy(d->gbm);
2441
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002442 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002443
Rob Bradford45c15b82013-07-26 16:29:35 +01002444 close(d->drm.fd);
2445
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002446 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002447}
2448
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002449static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002450drm_compositor_set_modes(struct drm_compositor *compositor)
2451{
2452 struct drm_output *output;
2453 struct drm_mode *drm_mode;
2454 int ret;
2455
2456 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002457 if (!output->current) {
2458 /* If something that would cause the output to
2459 * switch mode happened while in another vt, we
2460 * might not have a current drm_fb. In that case,
2461 * schedule a repaint and let drm_output_repaint
2462 * handle setting the mode. */
2463 weston_output_schedule_repaint(&output->base);
2464 continue;
2465 }
2466
Hardeningff39efa2013-09-18 23:56:35 +02002467 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002468 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002469 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002470 &output->connector_id, 1,
2471 &drm_mode->mode_info);
2472 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002473 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002474 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002475 drm_mode->base.width, drm_mode->base.height,
2476 output->base.x, output->base.y);
2477 }
2478 }
2479}
2480
2481static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002482session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002483{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002484 struct weston_compositor *compositor = data;
2485 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002486 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002487 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002488
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002489 if (ec->base.session_active) {
2490 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002491 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002492 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002493 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002494 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002495 } else {
2496 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002497 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002498
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002499 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002500 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002501
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002502 /* If we have a repaint scheduled (either from a
2503 * pending pageflip or the idle handler), make sure we
2504 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002505 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002506 * further attemps at repainting. When we switch
2507 * back, we schedule a repaint, which will process
2508 * pending frame callbacks. */
2509
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002510 wl_list_for_each(output, &ec->base.output_list, base.link) {
2511 output->base.repaint_needed = 0;
2512 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002513 }
2514
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002515 output = container_of(ec->base.output_list.next,
2516 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002517
2518 wl_list_for_each(sprite, &ec->sprite_list, link)
2519 drmModeSetPlane(ec->drm.fd,
2520 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002521 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002522 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002523 };
2524}
2525
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002526static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002527switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002528{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002529 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002530
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002531 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002532}
2533
David Herrmann0af066f2012-10-29 19:21:16 +01002534/*
2535 * Find primary GPU
2536 * Some systems may have multiple DRM devices attached to a single seat. This
2537 * function loops over all devices and tries to find a PCI device with the
2538 * boot_vga sysfs attribute set to 1.
2539 * If no such device is found, the first DRM device reported by udev is used.
2540 */
2541static struct udev_device*
2542find_primary_gpu(struct drm_compositor *ec, const char *seat)
2543{
2544 struct udev_enumerate *e;
2545 struct udev_list_entry *entry;
2546 const char *path, *device_seat, *id;
2547 struct udev_device *device, *drm_device, *pci;
2548
2549 e = udev_enumerate_new(ec->udev);
2550 udev_enumerate_add_match_subsystem(e, "drm");
2551 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2552
2553 udev_enumerate_scan_devices(e);
2554 drm_device = NULL;
2555 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2556 path = udev_list_entry_get_name(entry);
2557 device = udev_device_new_from_syspath(ec->udev, path);
2558 if (!device)
2559 continue;
2560 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2561 if (!device_seat)
2562 device_seat = default_seat;
2563 if (strcmp(device_seat, seat)) {
2564 udev_device_unref(device);
2565 continue;
2566 }
2567
2568 pci = udev_device_get_parent_with_subsystem_devtype(device,
2569 "pci", NULL);
2570 if (pci) {
2571 id = udev_device_get_sysattr_value(pci, "boot_vga");
2572 if (id && !strcmp(id, "1")) {
2573 if (drm_device)
2574 udev_device_unref(drm_device);
2575 drm_device = device;
2576 break;
2577 }
2578 }
2579
2580 if (!drm_device)
2581 drm_device = device;
2582 else
2583 udev_device_unref(device);
2584 }
2585
2586 udev_enumerate_unref(e);
2587 return drm_device;
2588}
2589
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002590static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002591planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002592{
2593 struct drm_compositor *c = data;
2594
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002595 switch (key) {
2596 case KEY_C:
2597 c->cursors_are_broken ^= 1;
2598 break;
2599 case KEY_V:
2600 c->sprites_are_broken ^= 1;
2601 break;
2602 case KEY_O:
2603 c->sprites_hidden ^= 1;
2604 break;
2605 default:
2606 break;
2607 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002608}
2609
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002610#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002611static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002612recorder_destroy(struct drm_output *output)
2613{
2614 vaapi_recorder_destroy(output->recorder);
2615 output->recorder = NULL;
2616
2617 output->base.disable_planes--;
2618
2619 wl_list_remove(&output->recorder_frame_listener.link);
2620 weston_log("[libva recorder] done\n");
2621}
2622
2623static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002624recorder_frame_notify(struct wl_listener *listener, void *data)
2625{
2626 struct drm_output *output;
2627 struct drm_compositor *c;
2628 int fd, ret;
2629
2630 output = container_of(listener, struct drm_output,
2631 recorder_frame_listener);
2632 c = (struct drm_compositor *) output->base.compositor;
2633
2634 if (!output->recorder)
2635 return;
2636
2637 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2638 DRM_CLOEXEC, &fd);
2639 if (ret) {
2640 weston_log("[libva recorder] "
2641 "failed to create prime fd for front buffer\n");
2642 return;
2643 }
2644
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002645 ret = vaapi_recorder_frame(output->recorder, fd,
2646 output->current->stride);
2647 if (ret < 0) {
2648 weston_log("[libva recorder] aborted: %m\n");
2649 recorder_destroy(output);
2650 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002651}
2652
2653static void *
2654create_recorder(struct drm_compositor *c, int width, int height,
2655 const char *filename)
2656{
2657 int fd;
2658 drm_magic_t magic;
2659
2660 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2661 if (fd < 0)
2662 return NULL;
2663
2664 drmGetMagic(fd, &magic);
2665 drmAuthMagic(c->drm.fd, magic);
2666
2667 return vaapi_recorder_create(fd, width, height, filename);
2668}
2669
2670static void
2671recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2672 void *data)
2673{
2674 struct drm_compositor *c = data;
2675 struct drm_output *output;
2676 int width, height;
2677
2678 output = container_of(c->base.output_list.next,
2679 struct drm_output, base.link);
2680
2681 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002682 if (output->format != GBM_FORMAT_XRGB8888) {
2683 weston_log("failed to start vaapi recorder: "
2684 "output format not supported\n");
2685 return;
2686 }
2687
Hardeningff39efa2013-09-18 23:56:35 +02002688 width = output->base.current_mode->width;
2689 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002690
2691 output->recorder =
2692 create_recorder(c, width, height, "capture.h264");
2693 if (!output->recorder) {
2694 weston_log("failed to create vaapi recorder\n");
2695 return;
2696 }
2697
2698 output->base.disable_planes++;
2699
2700 output->recorder_frame_listener.notify = recorder_frame_notify;
2701 wl_signal_add(&output->base.frame_signal,
2702 &output->recorder_frame_listener);
2703
2704 weston_output_schedule_repaint(&output->base);
2705
2706 weston_log("[libva recorder] initialized\n");
2707 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002708 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002709 }
2710}
2711#else
2712static void
2713recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2714 void *data)
2715{
2716 weston_log("Compiled without libva support\n");
2717}
2718#endif
2719
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002720static void
2721switch_to_gl_renderer(struct drm_compositor *c)
2722{
2723 struct drm_output *output;
2724
2725 if (!c->use_pixman)
2726 return;
2727
2728 weston_log("Switching to GL renderer\n");
2729
2730 c->gbm = create_gbm_device(c->drm.fd);
2731 if (!c->gbm) {
2732 weston_log("Failed to create gbm device. "
2733 "Aborting renderer switch\n");
2734 return;
2735 }
2736
2737 wl_list_for_each(output, &c->base.output_list, base.link)
2738 pixman_renderer_output_destroy(&output->base);
2739
2740 c->base.renderer->destroy(&c->base);
2741
2742 if (drm_compositor_create_gl_renderer(c) < 0) {
2743 gbm_device_destroy(c->gbm);
2744 weston_log("Failed to create GL renderer. Quitting.\n");
2745 /* FIXME: we need a function to shutdown cleanly */
2746 assert(0);
2747 }
2748
2749 wl_list_for_each(output, &c->base.output_list, base.link)
2750 drm_output_init_egl(output, c);
2751
2752 c->use_pixman = 0;
2753}
2754
2755static void
2756renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2757 void *data)
2758{
2759 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2760
2761 switch_to_gl_renderer(c);
2762}
2763
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002764static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002765drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002766 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002767 int *argc, char *argv[],
2768 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002769{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002770 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002771 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002772 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002773 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002774 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002775 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002776
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002777 weston_log("initializing drm backend\n");
2778
Peter Huttererf3d62272013-08-08 11:57:05 +10002779 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002780 if (ec == NULL)
2781 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002782
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002783 /* KMS support for sprites is not complete yet, so disable the
2784 * functionality for now. */
2785 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002786
2787 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002788 if (get_gbm_format_from_section(section,
2789 GBM_FORMAT_XRGB8888,
2790 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002791 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002792
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002793 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002794
Daniel Stone725c2c32012-06-22 14:04:36 +01002795 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002796 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002797 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002798 goto err_base;
2799 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002800
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002801 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002802 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
David Herrmann2ecb84a2014-12-30 14:33:22 +01002803 param->seat_id, true);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002804 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002805 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002806 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002807 goto err_compositor;
2808 }
2809
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002810 ec->udev = udev_new();
2811 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002812 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002813 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002814 }
2815
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002816 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002817 ec->session_listener.notify = session_notify;
2818 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002819
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002820 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002821 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002822 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002823 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002824 }
David Herrmann0af066f2012-10-29 19:21:16 +01002825 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002826
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002827 if (init_drm(ec, drm_device) < 0) {
2828 weston_log("failed to initialize kms\n");
2829 goto err_udev_dev;
2830 }
2831
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002832 if (ec->use_pixman) {
2833 if (init_pixman(ec) < 0) {
2834 weston_log("failed to initialize pixman renderer\n");
2835 goto err_udev_dev;
2836 }
2837 } else {
2838 if (init_egl(ec) < 0) {
2839 weston_log("failed to initialize egl\n");
2840 goto err_udev_dev;
2841 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002842 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002843
2844 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002845 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002846
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002847 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002848
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002849 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002850 weston_compositor_add_key_binding(&ec->base, key,
2851 MODIFIER_CTRL | MODIFIER_ALT,
2852 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002853
Jesse Barnes58ef3792012-02-23 09:45:49 -05002854 wl_list_init(&ec->sprite_list);
2855 create_sprites(ec);
2856
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002857 if (udev_input_init(&ec->input,
2858 &ec->base, ec->udev, param->seat_id) < 0) {
2859 weston_log("failed to create input devices\n");
2860 goto err_sprite;
2861 }
2862
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002863 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002864 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002865 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002866 }
2867
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002868 /* A this point we have some idea of whether or not we have a working
2869 * cursor plane. */
2870 if (!ec->cursors_are_broken)
2871 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2872
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002873 path = NULL;
2874
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002875 loop = wl_display_get_event_loop(ec->base.wl_display);
2876 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002877 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002878 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002879
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002880 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2881 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002882 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002883 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002884 }
2885 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2886 "drm", NULL);
2887 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002888 wl_event_loop_add_fd(loop,
2889 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002890 WL_EVENT_READABLE, udev_drm_event, ec);
2891
2892 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002893 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002894 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002895 }
2896
Daniel Stonea96b93c2012-06-22 14:04:37 +01002897 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002898
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002899 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002900 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002901 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002902 planes_binding, ec);
2903 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2904 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002905 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2906 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002907 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2908 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002909
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002910 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002911
2912err_udev_monitor:
2913 wl_event_source_remove(ec->udev_drm_source);
2914 udev_monitor_unref(ec->udev_monitor);
2915err_drm_source:
2916 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002917err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002918 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002919err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002920 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002921 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002922 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002923err_udev_dev:
2924 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002925err_launcher:
2926 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002927err_udev:
2928 udev_unref(ec->udev);
2929err_compositor:
2930 weston_compositor_shutdown(&ec->base);
2931err_base:
2932 free(ec);
2933 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002934}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002935
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002936WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002937backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002938 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002939{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002940 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002941
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002942 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002943 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2944 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2945 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002946 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002947 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002948 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002949
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002950 param.seat_id = default_seat;
2951
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002952 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002953
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002954 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002955}