blob: 313860bd89bfbc07de610fbc067d37dc3af6919b [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
Derek Foremanc4cfe852015-05-15 12:12:40 -05001394/* When initializing EGL, if the preferred buffer format isn't availble
1395 * we may be able to susbstitute an ARGB format for an XRGB one.
1396 *
1397 * This returns 0 if substitution isn't possible, but 0 might be a
1398 * legitimate format for other EGL platforms, so the caller is
1399 * responsible for checking for 0 before calling gl_renderer->create().
1400 *
1401 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
1402 * but it's entirely possible we'll see this again on other implementations.
1403 */
1404static int
1405fallback_format_for(uint32_t format)
1406{
1407 switch (format) {
1408 case GBM_FORMAT_XRGB8888:
1409 return GBM_FORMAT_ARGB8888;
1410 case GBM_FORMAT_XRGB2101010:
1411 return GBM_FORMAT_ARGB2101010;
1412 default:
1413 return 0;
1414 }
1415}
1416
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001417static int
1418drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1419{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001420 EGLint format[2] = {
1421 ec->format,
1422 fallback_format_for(ec->format),
1423 };
1424 int n_formats = 1;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001425
Derek Foremanc4cfe852015-05-15 12:12:40 -05001426 if (format[1])
1427 n_formats = 2;
1428 if (gl_renderer->create(&ec->base,
1429 EGL_PLATFORM_GBM_KHR,
1430 (void *)ec->gbm,
1431 gl_renderer->opaque_attribs,
1432 format,
1433 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001434 return -1;
1435 }
1436
1437 return 0;
1438}
1439
1440static int
1441init_egl(struct drm_compositor *ec)
1442{
1443 ec->gbm = create_gbm_device(ec->drm.fd);
1444
1445 if (!ec->gbm)
1446 return -1;
1447
1448 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001449 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001450 return -1;
1451 }
1452
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001453 return 0;
1454}
1455
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001456static int
1457init_pixman(struct drm_compositor *ec)
1458{
1459 return pixman_renderer_init(&ec->base);
1460}
1461
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001462static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001463drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001464{
1465 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001466 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001467
1468 mode = malloc(sizeof *mode);
1469 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001470 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001471
1472 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001473 mode->base.width = info->hdisplay;
1474 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001475
1476 /* Calculate higher precision (mHz) refresh rate */
1477 refresh = (info->clock * 1000000LL / info->htotal +
1478 info->vtotal / 2) / info->vtotal;
1479
1480 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1481 refresh *= 2;
1482 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1483 refresh /= 2;
1484 if (info->vscan > 1)
1485 refresh /= info->vscan;
1486
1487 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001488 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001489
1490 if (info->type & DRM_MODE_TYPE_PREFERRED)
1491 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1492
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001493 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1494
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001495 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001496}
1497
1498static int
1499drm_subpixel_to_wayland(int drm_value)
1500{
1501 switch (drm_value) {
1502 default:
1503 case DRM_MODE_SUBPIXEL_UNKNOWN:
1504 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1505 case DRM_MODE_SUBPIXEL_NONE:
1506 return WL_OUTPUT_SUBPIXEL_NONE;
1507 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1508 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1509 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1510 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1511 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1512 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1513 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1514 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1515 }
1516}
1517
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001518/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001519static uint32_t
1520drm_get_backlight(struct drm_output *output)
1521{
1522 long brightness, max_brightness, norm;
1523
1524 brightness = backlight_get_brightness(output->backlight);
1525 max_brightness = backlight_get_max_brightness(output->backlight);
1526
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001527 /* convert it on a scale of 0 to 255 */
1528 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001529
1530 return (uint32_t) norm;
1531}
1532
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001533/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001534static void
1535drm_set_backlight(struct weston_output *output_base, uint32_t value)
1536{
1537 struct drm_output *output = (struct drm_output *) output_base;
1538 long max_brightness, new_brightness;
1539
1540 if (!output->backlight)
1541 return;
1542
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001543 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001544 return;
1545
1546 max_brightness = backlight_get_max_brightness(output->backlight);
1547
1548 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001549 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001550
1551 backlight_set_brightness(output->backlight, new_brightness);
1552}
1553
1554static drmModePropertyPtr
1555drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1556{
1557 drmModePropertyPtr props;
1558 int i;
1559
1560 for (i = 0; i < connector->count_props; i++) {
1561 props = drmModeGetProperty(fd, connector->props[i]);
1562 if (!props)
1563 continue;
1564
1565 if (!strcmp(props->name, name))
1566 return props;
1567
1568 drmModeFreeProperty(props);
1569 }
1570
1571 return NULL;
1572}
1573
1574static void
1575drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1576{
1577 struct drm_output *output = (struct drm_output *) output_base;
1578 struct weston_compositor *ec = output_base->compositor;
1579 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001580
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001581 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001582 return;
1583
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001584 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1585 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001586}
1587
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001588static const char *connector_type_names[] = {
1589 "None",
1590 "VGA",
1591 "DVI",
1592 "DVI",
1593 "DVI",
1594 "Composite",
1595 "TV",
1596 "LVDS",
1597 "CTV",
1598 "DIN",
1599 "DP",
1600 "HDMI",
1601 "HDMI",
1602 "TV",
1603 "eDP",
1604};
1605
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001606static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001607find_crtc_for_connector(struct drm_compositor *ec,
1608 drmModeRes *resources, drmModeConnector *connector)
1609{
1610 drmModeEncoder *encoder;
1611 uint32_t possible_crtcs;
1612 int i, j;
1613
1614 for (j = 0; j < connector->count_encoders; j++) {
1615 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1616 if (encoder == NULL) {
1617 weston_log("Failed to get encoder.\n");
1618 return -1;
1619 }
1620 possible_crtcs = encoder->possible_crtcs;
1621 drmModeFreeEncoder(encoder);
1622
1623 for (i = 0; i < resources->count_crtcs; i++) {
1624 if (possible_crtcs & (1 << i) &&
1625 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1626 return i;
1627 }
1628 }
1629
1630 return -1;
1631}
1632
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001633/* Init output state that depends on gl or gbm */
1634static int
1635drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1636{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001637 EGLint format[2] = {
1638 output->format,
1639 fallback_format_for(output->format),
1640 };
1641 int i, flags, n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001642
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001643 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001644 output->base.current_mode->width,
1645 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001646 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001647 GBM_BO_USE_SCANOUT |
1648 GBM_BO_USE_RENDERING);
1649 if (!output->surface) {
1650 weston_log("failed to create gbm surface\n");
1651 return -1;
1652 }
1653
Derek Foremanc4cfe852015-05-15 12:12:40 -05001654 if (format[1])
1655 n_formats = 2;
Jonny Lamb671148f2015-03-20 15:26:52 +01001656 if (gl_renderer->output_create(&output->base,
Jonny Lamb445fb692015-03-24 13:12:01 +01001657 (EGLNativeDisplayType)output->surface,
1658 output->surface,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001659 gl_renderer->opaque_attribs,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001660 format,
1661 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001662 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001663 gbm_surface_destroy(output->surface);
1664 return -1;
1665 }
1666
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001667 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001668
1669 for (i = 0; i < 2; i++) {
1670 if (output->cursor_bo[i])
1671 continue;
1672
1673 output->cursor_bo[i] =
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001674 gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
1675 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001676 }
1677
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001678 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1679 weston_log("cursor buffers unavailable, using gl cursors\n");
1680 ec->cursors_are_broken = 1;
1681 }
1682
1683 return 0;
1684}
1685
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001686static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001687drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1688{
Hardeningff39efa2013-09-18 23:56:35 +02001689 int w = output->base.current_mode->width;
1690 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001691 unsigned int i;
1692
1693 /* FIXME error checking */
1694
1695 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001696 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001697 if (!output->dumb[i])
1698 goto err;
1699
1700 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001701 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001702 output->dumb[i]->map,
1703 output->dumb[i]->stride);
1704 if (!output->image[i])
1705 goto err;
1706 }
1707
1708 if (pixman_renderer_output_create(&output->base) < 0)
1709 goto err;
1710
1711 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001712 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001713
1714 return 0;
1715
1716err:
1717 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1718 if (output->dumb[i])
1719 drm_fb_destroy_dumb(output->dumb[i]);
1720 if (output->image[i])
1721 pixman_image_unref(output->image[i]);
1722
1723 output->dumb[i] = NULL;
1724 output->image[i] = NULL;
1725 }
1726
1727 return -1;
1728}
1729
1730static void
1731drm_output_fini_pixman(struct drm_output *output)
1732{
1733 unsigned int i;
1734
1735 pixman_renderer_output_destroy(&output->base);
1736 pixman_region32_fini(&output->previous_damage);
1737
1738 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1739 drm_fb_destroy_dumb(output->dumb[i]);
1740 pixman_image_unref(output->image[i]);
1741 output->dumb[i] = NULL;
1742 output->image[i] = NULL;
1743 }
1744}
1745
Richard Hughes2b2092a2013-04-24 14:58:02 +01001746static void
1747edid_parse_string(const uint8_t *data, char text[])
1748{
1749 int i;
1750 int replaced = 0;
1751
1752 /* this is always 12 bytes, but we can't guarantee it's null
1753 * terminated or not junk. */
1754 strncpy(text, (const char *) data, 12);
1755
1756 /* remove insane chars */
1757 for (i = 0; text[i] != '\0'; i++) {
1758 if (text[i] == '\n' ||
1759 text[i] == '\r') {
1760 text[i] = '\0';
1761 break;
1762 }
1763 }
1764
1765 /* ensure string is printable */
1766 for (i = 0; text[i] != '\0'; i++) {
1767 if (!isprint(text[i])) {
1768 text[i] = '-';
1769 replaced++;
1770 }
1771 }
1772
1773 /* if the string is random junk, ignore the string */
1774 if (replaced > 4)
1775 text[0] = '\0';
1776}
1777
1778#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1779#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1780#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1781#define EDID_OFFSET_DATA_BLOCKS 0x36
1782#define EDID_OFFSET_LAST_BLOCK 0x6c
1783#define EDID_OFFSET_PNPID 0x08
1784#define EDID_OFFSET_SERIAL 0x0c
1785
1786static int
1787edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1788{
1789 int i;
1790 uint32_t serial_number;
1791
1792 /* check header */
1793 if (length < 128)
1794 return -1;
1795 if (data[0] != 0x00 || data[1] != 0xff)
1796 return -1;
1797
1798 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1799 * /--08--\/--09--\
1800 * 7654321076543210
1801 * |\---/\---/\---/
1802 * R C1 C2 C3 */
1803 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1804 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1805 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1806 edid->pnp_id[3] = '\0';
1807
1808 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1809 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1810 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1811 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1812 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1813 if (serial_number > 0)
1814 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1815
1816 /* parse EDID data */
1817 for (i = EDID_OFFSET_DATA_BLOCKS;
1818 i <= EDID_OFFSET_LAST_BLOCK;
1819 i += 18) {
1820 /* ignore pixel clock data */
1821 if (data[i] != 0)
1822 continue;
1823 if (data[i+2] != 0)
1824 continue;
1825
1826 /* any useful blocks? */
1827 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1828 edid_parse_string(&data[i+5],
1829 edid->monitor_name);
1830 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1831 edid_parse_string(&data[i+5],
1832 edid->serial_number);
1833 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1834 edid_parse_string(&data[i+5],
1835 edid->eisa_id);
1836 }
1837 }
1838 return 0;
1839}
1840
1841static void
1842find_and_parse_output_edid(struct drm_compositor *ec,
1843 struct drm_output *output,
1844 drmModeConnector *connector)
1845{
1846 drmModePropertyBlobPtr edid_blob = NULL;
1847 drmModePropertyPtr property;
1848 int i;
1849 int rc;
1850
1851 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1852 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1853 if (!property)
1854 continue;
1855 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1856 !strcmp(property->name, "EDID")) {
1857 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1858 connector->prop_values[i]);
1859 }
1860 drmModeFreeProperty(property);
1861 }
1862 if (!edid_blob)
1863 return;
1864
1865 rc = edid_parse(&output->edid,
1866 edid_blob->data,
1867 edid_blob->length);
1868 if (!rc) {
1869 weston_log("EDID data '%s', '%s', '%s'\n",
1870 output->edid.pnp_id,
1871 output->edid.monitor_name,
1872 output->edid.serial_number);
1873 if (output->edid.pnp_id[0] != '\0')
1874 output->base.make = output->edid.pnp_id;
1875 if (output->edid.monitor_name[0] != '\0')
1876 output->base.model = output->edid.monitor_name;
1877 if (output->edid.serial_number[0] != '\0')
1878 output->base.serial_number = output->edid.serial_number;
1879 }
1880 drmModeFreePropertyBlob(edid_blob);
1881}
1882
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001883
1884
1885static int
1886parse_modeline(const char *s, drmModeModeInfo *mode)
1887{
1888 char hsync[16];
1889 char vsync[16];
1890 float fclock;
1891
1892 mode->type = DRM_MODE_TYPE_USERDEF;
1893 mode->hskew = 0;
1894 mode->vscan = 0;
1895 mode->vrefresh = 0;
1896 mode->flags = 0;
1897
Rob Bradford307e09e2013-07-26 16:29:40 +01001898 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001899 &fclock,
1900 &mode->hdisplay,
1901 &mode->hsync_start,
1902 &mode->hsync_end,
1903 &mode->htotal,
1904 &mode->vdisplay,
1905 &mode->vsync_start,
1906 &mode->vsync_end,
1907 &mode->vtotal, hsync, vsync) != 11)
1908 return -1;
1909
1910 mode->clock = fclock * 1000;
1911 if (strcmp(hsync, "+hsync") == 0)
1912 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1913 else if (strcmp(hsync, "-hsync") == 0)
1914 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1915 else
1916 return -1;
1917
1918 if (strcmp(vsync, "+vsync") == 0)
1919 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1920 else if (strcmp(vsync, "-vsync") == 0)
1921 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1922 else
1923 return -1;
1924
1925 return 0;
1926}
1927
Rob Bradford66bd9f52013-06-25 18:56:42 +01001928static void
1929setup_output_seat_constraint(struct drm_compositor *ec,
1930 struct weston_output *output,
1931 const char *s)
1932{
1933 if (strcmp(s, "") != 0) {
1934 struct udev_seat *seat;
1935
Jonas Ådahl58e15862014-03-12 22:08:40 +01001936 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001937 if (seat)
1938 seat->base.output = output;
1939
1940 if (seat && seat->base.pointer)
1941 weston_pointer_clamp(seat->base.pointer,
1942 &seat->base.pointer->x,
1943 &seat->base.pointer->y);
1944 }
1945}
1946
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001947static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001948get_gbm_format_from_section(struct weston_config_section *section,
1949 uint32_t default_value,
1950 uint32_t *format)
1951{
1952 char *s;
1953 int ret = 0;
1954
1955 weston_config_section_get_string(section,
1956 "gbm-format", &s, NULL);
1957
1958 if (s == NULL)
1959 *format = default_value;
1960 else if (strcmp(s, "xrgb8888") == 0)
1961 *format = GBM_FORMAT_XRGB8888;
1962 else if (strcmp(s, "rgb565") == 0)
1963 *format = GBM_FORMAT_RGB565;
1964 else if (strcmp(s, "xrgb2101010") == 0)
1965 *format = GBM_FORMAT_XRGB2101010;
1966 else {
1967 weston_log("fatal: unrecognized pixel format: %s\n", s);
1968 ret = -1;
1969 }
1970
1971 free(s);
1972
1973 return ret;
1974}
1975
1976static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001977create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001978 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001979 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001980 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001981{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001982 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001983 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001984 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001985 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001986 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001987 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001988 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001989 int i, width, height, scale;
1990 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001991 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001992 enum output_config config;
1993 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001994
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001995 i = find_crtc_for_connector(ec, resources, connector);
1996 if (i < 0) {
1997 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001998 return -1;
1999 }
2000
Peter Huttererf3d62272013-08-08 11:57:05 +10002001 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002002 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002003 return -1;
2004
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002005 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
2006 output->base.make = "unknown";
2007 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01002008 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002009 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002010
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002011 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
2012 type_name = connector_type_names[connector->connector_type];
2013 else
2014 type_name = "UNKNOWN";
2015 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01002016 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002017
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002018 section = weston_config_get_section(ec->base.config, "output", "name",
2019 output->base.name);
2020 weston_config_section_get_string(section, "mode", &s, "preferred");
2021 if (strcmp(s, "off") == 0)
2022 config = OUTPUT_CONFIG_OFF;
2023 else if (strcmp(s, "preferred") == 0)
2024 config = OUTPUT_CONFIG_PREFERRED;
2025 else if (strcmp(s, "current") == 0)
2026 config = OUTPUT_CONFIG_CURRENT;
2027 else if (sscanf(s, "%dx%d", &width, &height) == 2)
2028 config = OUTPUT_CONFIG_MODE;
2029 else if (parse_modeline(s, &modeline) == 0)
2030 config = OUTPUT_CONFIG_MODELINE;
2031 else {
2032 weston_log("Invalid mode \"%s\" for output %s\n",
2033 s, output->base.name);
2034 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002035 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002036 free(s);
2037
2038 weston_config_section_get_int(section, "scale", &scale, 1);
2039 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05002040 if (weston_parse_transform(s, &transform) < 0)
2041 weston_log("Invalid transform \"%s\" for output %s\n",
2042 s, output->base.name);
2043
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002044 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002045
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002046 if (get_gbm_format_from_section(section,
2047 ec->format,
2048 &output->format) == -1)
2049 output->format = ec->format;
2050
Rob Bradford66bd9f52013-06-25 18:56:42 +01002051 weston_config_section_get_string(section, "seat", &s, "");
2052 setup_output_seat_constraint(ec, &output->base, s);
2053 free(s);
2054
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002055 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002056 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002057 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002058 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002059 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002060
Matt Roper361d2ad2011-08-29 13:52:23 -07002061 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03002062 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002063
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002064 /* Get the current mode on the crtc that's currently driving
2065 * this connector. */
2066 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002067 memset(&crtc_mode, 0, sizeof crtc_mode);
2068 if (encoder != NULL) {
2069 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
2070 drmModeFreeEncoder(encoder);
2071 if (crtc == NULL)
2072 goto err_free;
2073 if (crtc->mode_valid)
2074 crtc_mode = crtc->mode;
2075 drmModeFreeCrtc(crtc);
2076 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002077
David Herrmann0f0d54e2011-12-08 17:05:45 +01002078 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002079 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002080 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002081 goto err_free;
2082 }
2083
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002084 if (config == OUTPUT_CONFIG_OFF) {
2085 weston_log("Disabling output %s\n", output->base.name);
2086 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
2087 0, 0, 0, 0, 0, NULL);
2088 goto err_free;
2089 }
2090
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002091 preferred = NULL;
2092 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002093 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002094 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002095
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002096 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002097 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002098 width == drm_mode->base.width &&
2099 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002100 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002101 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002102 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002103 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002104 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002105 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002106 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002107
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002108 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002109 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002110 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002111 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002112 }
2113
Wang Quanxianacb805a2012-07-30 18:09:46 -04002114 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002115 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002116 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002117 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002118 }
2119
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002120 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002121 configured = current;
2122
Wang Quanxianacb805a2012-07-30 18:09:46 -04002123 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002124 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002125 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002126 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002127 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002128 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002129 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002130 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002131 else if (best)
2132 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002133
Hardeningff39efa2013-09-18 23:56:35 +02002134 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002135 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002136 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002137 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002138
Hardeningff39efa2013-09-18 23:56:35 +02002139 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002140
John Kåre Alsaker94659272012-11-13 19:10:18 +01002141 weston_output_init(&output->base, &ec->base, x, y,
2142 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002143 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002144
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002145 if (ec->use_pixman) {
2146 if (drm_output_init_pixman(output, ec) < 0) {
2147 weston_log("Failed to init output pixman state\n");
2148 goto err_output;
2149 }
2150 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002151 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002152 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002153 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002154
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002155 output->backlight = backlight_init(drm_device,
2156 connector->connector_type);
2157 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002158 weston_log("Initialized backlight, device %s\n",
2159 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002160 output->base.set_backlight = drm_set_backlight;
2161 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002162 } else {
2163 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002164 }
2165
Giulio Camuffob1147152015-05-06 21:41:57 +03002166 weston_compositor_add_output(&ec->base, &output->base);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002167
Richard Hughes2b2092a2013-04-24 14:58:02 +01002168 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002169 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2170 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002171
Jonas Ådahle5a12252013-04-05 23:07:11 +02002172 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002173 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002174 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002175 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002176 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002177 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002178
Richard Hughese7299962013-05-01 21:52:12 +01002179 output->base.gamma_size = output->original_crtc->gamma_size;
2180 output->base.set_gamma = drm_output_set_gamma;
2181
Xiong Zhang97116532013-10-23 13:58:31 +08002182 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2183 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002184
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002185 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2186 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2187 &ec->base.primary_plane);
2188
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002189 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002190 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002191 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002192 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002193 m->width, m->height, m->refresh / 1000.0,
2194 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2195 ", preferred" : "",
2196 m->flags & WL_OUTPUT_MODE_CURRENT ?
2197 ", current" : "",
2198 connector->count_modes == 0 ?
2199 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002200
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002201 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002202
John Kåre Alsaker94659272012-11-13 19:10:18 +01002203err_output:
2204 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002205err_free:
2206 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2207 base.link) {
2208 wl_list_remove(&drm_mode->base.link);
2209 free(drm_mode);
2210 }
2211
2212 drmModeFreeCrtc(output->original_crtc);
2213 ec->crtc_allocator &= ~(1 << output->crtc_id);
2214 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002215 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002216
David Herrmann0f0d54e2011-12-08 17:05:45 +01002217 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002218}
2219
Jesse Barnes58ef3792012-02-23 09:45:49 -05002220static void
2221create_sprites(struct drm_compositor *ec)
2222{
2223 struct drm_sprite *sprite;
2224 drmModePlaneRes *plane_res;
2225 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002226 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002227
2228 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2229 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002230 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002231 strerror(errno));
2232 return;
2233 }
2234
2235 for (i = 0; i < plane_res->count_planes; i++) {
2236 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2237 if (!plane)
2238 continue;
2239
Peter Huttererf3d62272013-08-08 11:57:05 +10002240 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002241 plane->count_formats));
2242 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002243 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002244 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002245 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002246 continue;
2247 }
2248
Jesse Barnes58ef3792012-02-23 09:45:49 -05002249 sprite->possible_crtcs = plane->possible_crtcs;
2250 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002251 sprite->current = NULL;
2252 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002253 sprite->compositor = ec;
2254 sprite->count_formats = plane->count_formats;
2255 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002256 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002257 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002258 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002259 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2260 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002261
2262 wl_list_insert(&ec->sprite_list, &sprite->link);
2263 }
2264
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002265 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002266}
2267
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002268static void
2269destroy_sprites(struct drm_compositor *compositor)
2270{
2271 struct drm_sprite *sprite, *next;
2272 struct drm_output *output;
2273
2274 output = container_of(compositor->base.output_list.next,
2275 struct drm_output, base.link);
2276
2277 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2278 drmModeSetPlane(compositor->drm.fd,
2279 sprite->plane_id,
2280 output->crtc_id, 0, 0,
2281 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002282 drm_output_release_fb(output, sprite->current);
2283 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002284 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002285 free(sprite);
2286 }
2287}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002288
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002289static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002290create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002291 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002292{
2293 drmModeConnector *connector;
2294 drmModeRes *resources;
2295 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002296 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002297
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002298 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002299 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002300 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002301 return -1;
2302 }
2303
Jesse Barnes58ef3792012-02-23 09:45:49 -05002304 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002305 if (!ec->crtcs) {
2306 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002307 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002308 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002309
Rob Clark4339add2012-08-09 14:18:28 -05002310 ec->min_width = resources->min_width;
2311 ec->max_width = resources->max_width;
2312 ec->min_height = resources->min_height;
2313 ec->max_height = resources->max_height;
2314
Jesse Barnes58ef3792012-02-23 09:45:49 -05002315 ec->num_crtcs = resources->count_crtcs;
2316 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2317
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002318 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002319 connector = drmModeGetConnector(ec->drm.fd,
2320 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002321 if (connector == NULL)
2322 continue;
2323
2324 if (connector->connection == DRM_MODE_CONNECTED &&
2325 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002326 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002327 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002328 connector, x, y,
2329 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002330 drmModeFreeConnector(connector);
2331 continue;
2332 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002333
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002334 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002335 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002336 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002337 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002338
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002339 drmModeFreeConnector(connector);
2340 }
2341
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002342 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002343 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002344 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002345 return -1;
2346 }
2347
2348 drmModeFreeResources(resources);
2349
2350 return 0;
2351}
2352
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002353static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002354update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002355{
2356 drmModeConnector *connector;
2357 drmModeRes *resources;
2358 struct drm_output *output, *next;
2359 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002360 uint32_t connected = 0, disconnects = 0;
2361 int i;
2362
2363 resources = drmModeGetResources(ec->drm.fd);
2364 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002365 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002366 return;
2367 }
2368
2369 /* collect new connects */
2370 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002371 int connector_id = resources->connectors[i];
2372
2373 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002374 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002375 continue;
2376
David Herrmann7551cff2011-12-08 17:05:43 +01002377 if (connector->connection != DRM_MODE_CONNECTED) {
2378 drmModeFreeConnector(connector);
2379 continue;
2380 }
2381
Benjamin Franzke117483d2011-08-30 11:38:26 +02002382 connected |= (1 << connector_id);
2383
2384 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002385 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002386 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002387 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002388
2389 /* XXX: not yet needed, we die with 0 outputs */
2390 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002391 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002392 else
2393 x = 0;
2394 y = 0;
2395 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002396 connector, x, y,
2397 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002398 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002399
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002400 }
2401 drmModeFreeConnector(connector);
2402 }
2403 drmModeFreeResources(resources);
2404
2405 disconnects = ec->connector_allocator & ~connected;
2406 if (disconnects) {
2407 wl_list_for_each_safe(output, next, &ec->base.output_list,
2408 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002409 if (disconnects & (1 << output->connector_id)) {
2410 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002411 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002412 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002413 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002414 }
2415 }
2416 }
2417
2418 /* FIXME: handle zero outputs, without terminating */
2419 if (ec->connector_allocator == 0)
2420 wl_display_terminate(ec->base.wl_display);
2421}
2422
2423static int
David Herrmannd7488c22012-03-11 20:05:21 +01002424udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002425{
David Herrmannd7488c22012-03-11 20:05:21 +01002426 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002427 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002428
2429 sysnum = udev_device_get_sysnum(device);
2430 if (!sysnum || atoi(sysnum) != ec->drm.id)
2431 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002432
David Herrmann6ac52db2012-03-11 20:05:22 +01002433 val = udev_device_get_property_value(device, "HOTPLUG");
2434 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002435 return 0;
2436
David Herrmann6ac52db2012-03-11 20:05:22 +01002437 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002438}
2439
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002440static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002441udev_drm_event(int fd, uint32_t mask, void *data)
2442{
2443 struct drm_compositor *ec = data;
2444 struct udev_device *event;
2445
2446 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002447
David Herrmannd7488c22012-03-11 20:05:21 +01002448 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002449 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002450
2451 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002452
2453 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002454}
2455
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002456static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002457drm_restore(struct weston_compositor *ec)
2458{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002459 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002460}
2461
2462static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002463drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002464{
2465 struct drm_compositor *d = (struct drm_compositor *) ec;
2466
Rob Bradfordd355b802013-05-31 18:09:55 +01002467 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002468
2469 wl_event_source_remove(d->udev_drm_source);
2470 wl_event_source_remove(d->drm_source);
2471
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002472 destroy_sprites(d);
2473
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002474 weston_compositor_shutdown(ec);
2475
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002476 if (d->gbm)
2477 gbm_device_destroy(d->gbm);
2478
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002479 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002480
Rob Bradford45c15b82013-07-26 16:29:35 +01002481 close(d->drm.fd);
2482
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002483 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002484}
2485
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002486static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002487drm_compositor_set_modes(struct drm_compositor *compositor)
2488{
2489 struct drm_output *output;
2490 struct drm_mode *drm_mode;
2491 int ret;
2492
2493 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002494 if (!output->current) {
2495 /* If something that would cause the output to
2496 * switch mode happened while in another vt, we
2497 * might not have a current drm_fb. In that case,
2498 * schedule a repaint and let drm_output_repaint
2499 * handle setting the mode. */
2500 weston_output_schedule_repaint(&output->base);
2501 continue;
2502 }
2503
Hardeningff39efa2013-09-18 23:56:35 +02002504 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002505 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002506 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002507 &output->connector_id, 1,
2508 &drm_mode->mode_info);
2509 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002510 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002511 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002512 drm_mode->base.width, drm_mode->base.height,
2513 output->base.x, output->base.y);
2514 }
2515 }
2516}
2517
2518static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002519session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002520{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002521 struct weston_compositor *compositor = data;
2522 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002523 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002524 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002525
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002526 if (ec->base.session_active) {
2527 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002528 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002529 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002530 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002531 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002532 } else {
2533 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002534 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002535
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002536 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002537 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002538
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002539 /* If we have a repaint scheduled (either from a
2540 * pending pageflip or the idle handler), make sure we
2541 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002542 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002543 * further attemps at repainting. When we switch
2544 * back, we schedule a repaint, which will process
2545 * pending frame callbacks. */
2546
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002547 wl_list_for_each(output, &ec->base.output_list, base.link) {
2548 output->base.repaint_needed = 0;
2549 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002550 }
2551
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002552 output = container_of(ec->base.output_list.next,
2553 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002554
2555 wl_list_for_each(sprite, &ec->sprite_list, link)
2556 drmModeSetPlane(ec->drm.fd,
2557 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002558 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002559 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002560 };
2561}
2562
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002563static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002564switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002565{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002566 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002567
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002568 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002569}
2570
David Herrmann0af066f2012-10-29 19:21:16 +01002571/*
2572 * Find primary GPU
2573 * Some systems may have multiple DRM devices attached to a single seat. This
2574 * function loops over all devices and tries to find a PCI device with the
2575 * boot_vga sysfs attribute set to 1.
2576 * If no such device is found, the first DRM device reported by udev is used.
2577 */
2578static struct udev_device*
2579find_primary_gpu(struct drm_compositor *ec, const char *seat)
2580{
2581 struct udev_enumerate *e;
2582 struct udev_list_entry *entry;
2583 const char *path, *device_seat, *id;
2584 struct udev_device *device, *drm_device, *pci;
2585
2586 e = udev_enumerate_new(ec->udev);
2587 udev_enumerate_add_match_subsystem(e, "drm");
2588 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2589
2590 udev_enumerate_scan_devices(e);
2591 drm_device = NULL;
2592 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2593 path = udev_list_entry_get_name(entry);
2594 device = udev_device_new_from_syspath(ec->udev, path);
2595 if (!device)
2596 continue;
2597 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2598 if (!device_seat)
2599 device_seat = default_seat;
2600 if (strcmp(device_seat, seat)) {
2601 udev_device_unref(device);
2602 continue;
2603 }
2604
2605 pci = udev_device_get_parent_with_subsystem_devtype(device,
2606 "pci", NULL);
2607 if (pci) {
2608 id = udev_device_get_sysattr_value(pci, "boot_vga");
2609 if (id && !strcmp(id, "1")) {
2610 if (drm_device)
2611 udev_device_unref(drm_device);
2612 drm_device = device;
2613 break;
2614 }
2615 }
2616
2617 if (!drm_device)
2618 drm_device = device;
2619 else
2620 udev_device_unref(device);
2621 }
2622
2623 udev_enumerate_unref(e);
2624 return drm_device;
2625}
2626
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002627static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002628planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002629{
2630 struct drm_compositor *c = data;
2631
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002632 switch (key) {
2633 case KEY_C:
2634 c->cursors_are_broken ^= 1;
2635 break;
2636 case KEY_V:
2637 c->sprites_are_broken ^= 1;
2638 break;
2639 case KEY_O:
2640 c->sprites_hidden ^= 1;
2641 break;
2642 default:
2643 break;
2644 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002645}
2646
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002647#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002648static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002649recorder_destroy(struct drm_output *output)
2650{
2651 vaapi_recorder_destroy(output->recorder);
2652 output->recorder = NULL;
2653
2654 output->base.disable_planes--;
2655
2656 wl_list_remove(&output->recorder_frame_listener.link);
2657 weston_log("[libva recorder] done\n");
2658}
2659
2660static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002661recorder_frame_notify(struct wl_listener *listener, void *data)
2662{
2663 struct drm_output *output;
2664 struct drm_compositor *c;
2665 int fd, ret;
2666
2667 output = container_of(listener, struct drm_output,
2668 recorder_frame_listener);
2669 c = (struct drm_compositor *) output->base.compositor;
2670
2671 if (!output->recorder)
2672 return;
2673
2674 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2675 DRM_CLOEXEC, &fd);
2676 if (ret) {
2677 weston_log("[libva recorder] "
2678 "failed to create prime fd for front buffer\n");
2679 return;
2680 }
2681
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002682 ret = vaapi_recorder_frame(output->recorder, fd,
2683 output->current->stride);
2684 if (ret < 0) {
2685 weston_log("[libva recorder] aborted: %m\n");
2686 recorder_destroy(output);
2687 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002688}
2689
2690static void *
2691create_recorder(struct drm_compositor *c, int width, int height,
2692 const char *filename)
2693{
2694 int fd;
2695 drm_magic_t magic;
2696
2697 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2698 if (fd < 0)
2699 return NULL;
2700
2701 drmGetMagic(fd, &magic);
2702 drmAuthMagic(c->drm.fd, magic);
2703
2704 return vaapi_recorder_create(fd, width, height, filename);
2705}
2706
2707static void
2708recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2709 void *data)
2710{
2711 struct drm_compositor *c = data;
2712 struct drm_output *output;
2713 int width, height;
2714
2715 output = container_of(c->base.output_list.next,
2716 struct drm_output, base.link);
2717
2718 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002719 if (output->format != GBM_FORMAT_XRGB8888) {
2720 weston_log("failed to start vaapi recorder: "
2721 "output format not supported\n");
2722 return;
2723 }
2724
Hardeningff39efa2013-09-18 23:56:35 +02002725 width = output->base.current_mode->width;
2726 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002727
2728 output->recorder =
2729 create_recorder(c, width, height, "capture.h264");
2730 if (!output->recorder) {
2731 weston_log("failed to create vaapi recorder\n");
2732 return;
2733 }
2734
2735 output->base.disable_planes++;
2736
2737 output->recorder_frame_listener.notify = recorder_frame_notify;
2738 wl_signal_add(&output->base.frame_signal,
2739 &output->recorder_frame_listener);
2740
2741 weston_output_schedule_repaint(&output->base);
2742
2743 weston_log("[libva recorder] initialized\n");
2744 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002745 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002746 }
2747}
2748#else
2749static void
2750recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2751 void *data)
2752{
2753 weston_log("Compiled without libva support\n");
2754}
2755#endif
2756
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002757static void
2758switch_to_gl_renderer(struct drm_compositor *c)
2759{
2760 struct drm_output *output;
2761
2762 if (!c->use_pixman)
2763 return;
2764
2765 weston_log("Switching to GL renderer\n");
2766
2767 c->gbm = create_gbm_device(c->drm.fd);
2768 if (!c->gbm) {
2769 weston_log("Failed to create gbm device. "
2770 "Aborting renderer switch\n");
2771 return;
2772 }
2773
2774 wl_list_for_each(output, &c->base.output_list, base.link)
2775 pixman_renderer_output_destroy(&output->base);
2776
2777 c->base.renderer->destroy(&c->base);
2778
2779 if (drm_compositor_create_gl_renderer(c) < 0) {
2780 gbm_device_destroy(c->gbm);
2781 weston_log("Failed to create GL renderer. Quitting.\n");
2782 /* FIXME: we need a function to shutdown cleanly */
2783 assert(0);
2784 }
2785
2786 wl_list_for_each(output, &c->base.output_list, base.link)
2787 drm_output_init_egl(output, c);
2788
2789 c->use_pixman = 0;
2790}
2791
2792static void
2793renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2794 void *data)
2795{
2796 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2797
2798 switch_to_gl_renderer(c);
2799}
2800
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002801static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002802drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002803 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002804 int *argc, char *argv[],
2805 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002806{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002807 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002808 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002809 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002810 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002811 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002812 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002813
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002814 weston_log("initializing drm backend\n");
2815
Peter Huttererf3d62272013-08-08 11:57:05 +10002816 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002817 if (ec == NULL)
2818 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002819
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002820 /* KMS support for sprites is not complete yet, so disable the
2821 * functionality for now. */
2822 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002823
2824 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002825 if (get_gbm_format_from_section(section,
2826 GBM_FORMAT_XRGB8888,
2827 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002828 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002829
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002830 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002831
Daniel Stone725c2c32012-06-22 14:04:36 +01002832 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002833 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002834 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002835 goto err_base;
2836 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002837
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002838 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002839 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
David Herrmann2ecb84a2014-12-30 14:33:22 +01002840 param->seat_id, true);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002841 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002842 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002843 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002844 goto err_compositor;
2845 }
2846
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002847 ec->udev = udev_new();
2848 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002849 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002850 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002851 }
2852
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002853 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002854 ec->session_listener.notify = session_notify;
2855 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002856
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002857 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002858 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002859 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002860 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002861 }
David Herrmann0af066f2012-10-29 19:21:16 +01002862 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002863
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002864 if (init_drm(ec, drm_device) < 0) {
2865 weston_log("failed to initialize kms\n");
2866 goto err_udev_dev;
2867 }
2868
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002869 if (ec->use_pixman) {
2870 if (init_pixman(ec) < 0) {
2871 weston_log("failed to initialize pixman renderer\n");
2872 goto err_udev_dev;
2873 }
2874 } else {
2875 if (init_egl(ec) < 0) {
2876 weston_log("failed to initialize egl\n");
2877 goto err_udev_dev;
2878 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002879 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002880
2881 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002882 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002883
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002884 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002885
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002886 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002887 weston_compositor_add_key_binding(&ec->base, key,
2888 MODIFIER_CTRL | MODIFIER_ALT,
2889 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002890
Jesse Barnes58ef3792012-02-23 09:45:49 -05002891 wl_list_init(&ec->sprite_list);
2892 create_sprites(ec);
2893
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002894 if (udev_input_init(&ec->input,
2895 &ec->base, ec->udev, param->seat_id) < 0) {
2896 weston_log("failed to create input devices\n");
2897 goto err_sprite;
2898 }
2899
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002900 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002901 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002902 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002903 }
2904
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002905 /* A this point we have some idea of whether or not we have a working
2906 * cursor plane. */
2907 if (!ec->cursors_are_broken)
2908 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2909
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002910 path = NULL;
2911
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002912 loop = wl_display_get_event_loop(ec->base.wl_display);
2913 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002914 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002915 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002916
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002917 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2918 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002919 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002920 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002921 }
2922 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2923 "drm", NULL);
2924 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002925 wl_event_loop_add_fd(loop,
2926 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002927 WL_EVENT_READABLE, udev_drm_event, ec);
2928
2929 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002930 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002931 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002932 }
2933
Daniel Stonea96b93c2012-06-22 14:04:37 +01002934 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002935
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002936 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002937 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002938 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002939 planes_binding, ec);
2940 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2941 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002942 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2943 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002944 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2945 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002946
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002947 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002948
2949err_udev_monitor:
2950 wl_event_source_remove(ec->udev_drm_source);
2951 udev_monitor_unref(ec->udev_monitor);
2952err_drm_source:
2953 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002954err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002955 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002956err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002957 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002958 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002959 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002960err_udev_dev:
2961 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002962err_launcher:
2963 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002964err_udev:
2965 udev_unref(ec->udev);
2966err_compositor:
2967 weston_compositor_shutdown(&ec->base);
2968err_base:
2969 free(ec);
2970 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002971}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002972
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002973WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002974backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002975 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002976{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002977 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002978
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002979 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002980 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2981 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2982 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002983 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002984 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002985 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002986
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002987 param.seat_id = default_seat;
2988
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002989 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002990
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002991 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002992}