blob: 0cdb8f47a58bced016450c7c34fabf9b7248b1f8 [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Daniel Stonec228e232013-05-22 18:03:19 +030024#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040025
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010028#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040029#include <string.h>
30#include <fcntl.h>
31#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040032#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070033#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030034#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020035#include <sys/mman.h>
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030036#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030037#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040038
Benjamin Franzkec649a922011-03-02 11:56:04 +010039#include <xf86drm.h>
40#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050041#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010042
Benjamin Franzke060cf802011-04-30 09:32:11 +020043#include <gbm.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040044#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020045
Kristian Høgsberg36d5fac2014-01-27 23:02:35 -080046#include "libbacklight.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040047#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010048#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020049#include "pixman-renderer.h"
Peter Hutterer823ad332014-11-26 07:06:31 +100050#include "libinput-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010051#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030052#include "vaapi-recorder.h"
Pekka Paalanen363aa7b2014-12-17 16:20:40 +020053#include "presentation_timing-server-protocol.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040054
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030055#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
56#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
57#endif
58
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030059#ifndef DRM_CAP_CURSOR_WIDTH
60#define DRM_CAP_CURSOR_WIDTH 0x8
61#endif
62
63#ifndef DRM_CAP_CURSOR_HEIGHT
64#define DRM_CAP_CURSOR_HEIGHT 0x9
65#endif
66
67#ifndef GBM_BO_USE_CURSOR
68#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
69#endif
70
Kristian Høgsberg061c4252012-06-28 11:28:15 -040071static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060072
73enum output_config {
74 OUTPUT_CONFIG_INVALID = 0,
75 OUTPUT_CONFIG_OFF,
76 OUTPUT_CONFIG_PREFERRED,
77 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060078 OUTPUT_CONFIG_MODE,
79 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060080};
81
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040082struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050083 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040084
85 struct udev *udev;
86 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040087
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010088 struct udev_monitor *udev_monitor;
89 struct wl_event_source *udev_drm_source;
90
Benjamin Franzke2af7f102011-03-02 11:14:59 +010091 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010092 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010093 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030094 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010095 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020096 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050097 uint32_t *crtcs;
98 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050099 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100100 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700101 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700102 uint32_t format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200103
Rob Clark4339add2012-08-09 14:18:28 -0500104 /* we need these parameters in order to not fail drmModeAddFB2()
105 * due to out of bounds dimensions, and then mistakenly set
106 * sprites_are_broken:
107 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200108 uint32_t min_width, max_width;
109 uint32_t min_height, max_height;
110 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500111
Jesse Barnes58ef3792012-02-23 09:45:49 -0500112 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500113 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200114 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500115
Rob Clarkab5b1e32012-08-09 13:24:45 -0500116 int cursors_are_broken;
117
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200118 int use_pixman;
119
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200120 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300121
Rob Bradfordd355b802013-05-31 18:09:55 +0100122 struct udev_input input;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -0300123
124 uint32_t cursor_width;
125 uint32_t cursor_height;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400126};
127
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400128struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500129 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400130 drmModeModeInfo mode_info;
131};
132
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300133struct drm_output;
134
135struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300136 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200137 uint32_t fb_id, stride, handle, size;
138 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300139 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200140 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200141
142 /* Used by gbm fbs */
143 struct gbm_bo *bo;
144
145 /* Used by dumb fbs */
146 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300147};
148
Richard Hughes2b2092a2013-04-24 14:58:02 +0100149struct drm_edid {
150 char eisa_id[13];
151 char monitor_name[13];
152 char pnp_id[5];
153 char serial_number[13];
154};
155
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400156struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500157 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400158
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400159 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500160 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400161 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700162 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100163 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300164 drmModePropertyPtr dpms_prop;
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000165 uint32_t format;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200166
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300167 int vblank_pending;
168 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800169 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300170
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400171 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400172 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400173 struct weston_plane cursor_plane;
174 struct weston_plane fb_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500175 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400176 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300177 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200178 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200179
180 struct drm_fb *dumb[2];
181 pixman_image_t *image[2];
182 int current_image;
183 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300184
185 struct vaapi_recorder *recorder;
186 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400187};
188
Jesse Barnes58ef3792012-02-23 09:45:49 -0500189/*
190 * An output has a primary display plane plus zero or more sprites for
191 * blending display contents.
192 */
193struct drm_sprite {
194 struct wl_list link;
195
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400196 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500197
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200198 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300199 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500200 struct drm_compositor *compositor;
201
Jesse Barnes58ef3792012-02-23 09:45:49 -0500202 uint32_t possible_crtcs;
203 uint32_t plane_id;
204 uint32_t count_formats;
205
206 int32_t src_x, src_y;
207 uint32_t src_w, src_h;
208 uint32_t dest_x, dest_y;
209 uint32_t dest_w, dest_h;
210
211 uint32_t formats[];
212};
213
Kristian Høgsbergd8e98332013-10-16 16:15:11 -0700214struct drm_parameters {
215 int connector;
216 int tty;
217 int use_pixman;
218 const char *seat_id;
219};
220
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300221static struct gl_renderer_interface *gl_renderer;
222
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500223static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400224
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400225static void
226drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400227
Jesse Barnes58ef3792012-02-23 09:45:49 -0500228static int
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200229drm_sprite_crtc_supported(struct drm_output *output, uint32_t supported)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500230{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200231 struct weston_compositor *ec = output->base.compositor;
232 struct drm_compositor *c = (struct drm_compositor *)ec;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500233 int crtc;
234
235 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
236 if (c->crtcs[crtc] != output->crtc_id)
237 continue;
238
239 if (supported & (1 << crtc))
240 return -1;
241 }
242
243 return 0;
244}
245
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300246static void
247drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
248{
249 struct drm_fb *fb = data;
250 struct gbm_device *gbm = gbm_bo_get_device(bo);
251
252 if (fb->fb_id)
253 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
254
Pekka Paalanende685b82012-12-04 15:58:12 +0200255 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300256
257 free(data);
258}
259
260static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200261drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
262{
263 struct drm_fb *fb;
264 int ret;
265
266 struct drm_mode_create_dumb create_arg;
267 struct drm_mode_destroy_dumb destroy_arg;
268 struct drm_mode_map_dumb map_arg;
269
Peter Huttererf3d62272013-08-08 11:57:05 +1000270 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200271 if (!fb)
272 return NULL;
273
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700274 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200275 create_arg.bpp = 32;
276 create_arg.width = width;
277 create_arg.height = height;
278
279 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
280 if (ret)
281 goto err_fb;
282
283 fb->handle = create_arg.handle;
284 fb->stride = create_arg.pitch;
285 fb->size = create_arg.size;
286 fb->fd = ec->drm.fd;
287
288 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
289 fb->stride, fb->handle, &fb->fb_id);
290 if (ret)
291 goto err_bo;
292
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700293 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200294 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400295 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200296 if (ret)
297 goto err_add_fb;
298
299 fb->map = mmap(0, fb->size, PROT_WRITE,
300 MAP_SHARED, ec->drm.fd, map_arg.offset);
301 if (fb->map == MAP_FAILED)
302 goto err_add_fb;
303
304 return fb;
305
306err_add_fb:
307 drmModeRmFB(ec->drm.fd, fb->fb_id);
308err_bo:
309 memset(&destroy_arg, 0, sizeof(destroy_arg));
310 destroy_arg.handle = create_arg.handle;
311 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
312err_fb:
313 free(fb);
314 return NULL;
315}
316
317static void
318drm_fb_destroy_dumb(struct drm_fb *fb)
319{
320 struct drm_mode_destroy_dumb destroy_arg;
321
322 if (!fb->map)
323 return;
324
325 if (fb->fb_id)
326 drmModeRmFB(fb->fd, fb->fb_id);
327
328 weston_buffer_reference(&fb->buffer_ref, NULL);
329
330 munmap(fb->map, fb->size);
331
332 memset(&destroy_arg, 0, sizeof(destroy_arg));
333 destroy_arg.handle = fb->handle;
334 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
335
336 free(fb);
337}
338
339static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500340drm_fb_get_from_bo(struct gbm_bo *bo,
341 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300342{
343 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200344 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200345 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300346 int ret;
347
348 if (fb)
349 return fb;
350
Bryce Harringtonde16d892014-11-20 22:21:57 -0800351 fb = zalloc(sizeof *fb);
352 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200353 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300354
355 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300356
357 width = gbm_bo_get_width(bo);
358 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200359 fb->stride = gbm_bo_get_stride(bo);
360 fb->handle = gbm_bo_get_handle(bo).u32;
361 fb->size = fb->stride * height;
362 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300363
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200364 if (compositor->min_width > width || width > compositor->max_width ||
365 compositor->min_height > height ||
366 height > compositor->max_height) {
367 weston_log("bo geometry out of bounds\n");
368 goto err_free;
369 }
370
371 ret = -1;
372
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200373 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200374 handles[0] = fb->handle;
375 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376 offsets[0] = 0;
377
378 ret = drmModeAddFB2(compositor->drm.fd, width, height,
379 format, handles, pitches, offsets,
380 &fb->fb_id, 0);
381 if (ret) {
382 weston_log("addfb2 failed: %m\n");
383 compositor->no_addfb2 = 1;
384 compositor->sprites_are_broken = 1;
385 }
386 }
387
388 if (ret)
389 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200390 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200391
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300392 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200393 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200394 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300395 }
396
397 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
398
399 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200400
401err_free:
402 free(fb);
403 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300404}
405
406static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500407drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200408{
Pekka Paalanende685b82012-12-04 15:58:12 +0200409 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200410
411 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200412
Pekka Paalanende685b82012-12-04 15:58:12 +0200413 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200414}
415
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200416static void
417drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
418{
419 if (!fb)
420 return;
421
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200422 if (fb->map &&
423 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200424 drm_fb_destroy_dumb(fb);
425 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200426 if (fb->is_client_buffer)
427 gbm_bo_destroy(fb->bo);
428 else
429 gbm_surface_release_buffer(output->surface,
Jason Ekstrand3ec57f52013-11-14 20:52:35 -0600430 fb->bo);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200431 }
432}
433
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500434static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200435drm_output_check_scanout_format(struct drm_output *output,
436 struct weston_surface *es, struct gbm_bo *bo)
437{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200438 uint32_t format;
439 pixman_region32_t r;
440
441 format = gbm_bo_get_format(bo);
442
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700443 if (format == GBM_FORMAT_ARGB8888) {
444 /* We can scanout an ARGB buffer if the surface's
445 * opaque region covers the whole output, but we have
446 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -0800447 pixman_region32_init_rect(&r, 0, 0,
448 output->base.width,
449 output->base.height);
450 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200451
452 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500453 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200454
455 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500456 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700457
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000458 if (output->format == format)
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700459 return format;
460
461 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200462}
463
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400464static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200465drm_output_prepare_scanout_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500466 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500467{
468 struct drm_compositor *c =
469 (struct drm_compositor *) output->base.compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500470 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200471 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300472 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500473 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500474
Jason Ekstranda7af7042013-10-12 22:38:11 -0500475 if (ev->geometry.x != output->base.x ||
476 ev->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200477 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200478 buffer->width != output->base.current_mode->width ||
479 buffer->height != output->base.current_mode->height ||
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200480 output->base.transform != viewport->buffer.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500481 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400482 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500483
Pekka Paalanen5580f222015-02-17 16:33:18 +0200484 if (ev->geometry.scissor_enabled)
485 return NULL;
486
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400487 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700488 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500489
Rob Bradford9b101872012-09-14 23:25:41 +0100490 /* Unable to use the buffer for scanout */
491 if (!bo)
492 return NULL;
493
Jason Ekstranda7af7042013-10-12 22:38:11 -0500494 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500495 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300496 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400497 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300498 }
499
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500500 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300501 if (!output->next) {
502 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400503 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300504 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500505
Pekka Paalanende685b82012-12-04 15:58:12 +0200506 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500507
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400508 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500509}
510
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500511static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200512drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400513{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200514 struct drm_compositor *c =
515 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300516 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400517
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200518 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400519
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300520 bo = gbm_surface_lock_front_buffer(output->surface);
521 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200522 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400523 return;
524 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300525
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000526 output->next = drm_fb_get_from_bo(bo, c, output->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300527 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200528 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300529 gbm_surface_release_buffer(output->surface, bo);
530 return;
531 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400532}
533
534static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200535drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
536{
537 struct weston_compositor *ec = output->base.compositor;
538 pixman_region32_t total_damage, previous_damage;
539
540 pixman_region32_init(&total_damage);
541 pixman_region32_init(&previous_damage);
542
543 pixman_region32_copy(&previous_damage, damage);
544
545 pixman_region32_union(&total_damage, damage, &output->previous_damage);
546 pixman_region32_copy(&output->previous_damage, &previous_damage);
547
548 output->current_image ^= 1;
549
550 output->next = output->dumb[output->current_image];
551 pixman_renderer_output_set_buffer(&output->base,
552 output->image[output->current_image]);
553
554 ec->renderer->repaint_output(&output->base, &total_damage);
555
556 pixman_region32_fini(&total_damage);
557 pixman_region32_fini(&previous_damage);
558}
559
560static void
561drm_output_render(struct drm_output *output, pixman_region32_t *damage)
562{
563 struct drm_compositor *c =
564 (struct drm_compositor *) output->base.compositor;
565
566 if (c->use_pixman)
567 drm_output_render_pixman(output, damage);
568 else
569 drm_output_render_gl(output, damage);
570
571 pixman_region32_subtract(&c->base.primary_plane.damage,
572 &c->base.primary_plane.damage, damage);
573}
574
575static void
Richard Hughese7299962013-05-01 21:52:12 +0100576drm_output_set_gamma(struct weston_output *output_base,
577 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
578{
579 int rc;
580 struct drm_output *output = (struct drm_output *) output_base;
581 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
582
583 /* check */
584 if (output_base->gamma_size != size)
585 return;
586 if (!output->original_crtc)
587 return;
588
589 rc = drmModeCrtcSetGamma(compositor->drm.fd,
590 output->crtc_id,
591 size, r, g, b);
592 if (rc)
593 weston_log("set gamma failed: %m\n");
594}
595
David Herrmann1edf44c2013-10-22 17:11:26 +0200596static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500597drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400598 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100599{
600 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500601 struct drm_compositor *compositor =
602 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500603 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400604 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500605 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100606
Xiong Zhangabd5d472013-10-11 14:43:07 +0800607 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200608 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800609
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300610 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400611 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300612 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200613 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100614
Hardeningff39efa2013-09-18 23:56:35 +0200615 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200616 if (!output->current ||
617 output->current->stride != output->next->stride) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400618 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300619 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400620 &output->connector_id, 1,
621 &mode->mode_info);
622 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200623 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200624 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400625 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300626 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200627 }
628
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500629 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300630 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500631 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200632 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200633 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500634 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100635
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300636 output->page_flip_pending = 1;
637
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400638 drm_output_set_cursor(output);
639
Jesse Barnes58ef3792012-02-23 09:45:49 -0500640 /*
641 * Now, update all the sprite surfaces
642 */
643 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200644 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500645 drmVBlank vbl = {
646 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
647 .request.sequence = 1,
648 };
649
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200650 if ((!s->current && !s->next) ||
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200651 !drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500652 continue;
653
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200654 if (s->next && !compositor->sprites_hidden)
655 fb_id = s->next->fb_id;
656
Jesse Barnes58ef3792012-02-23 09:45:49 -0500657 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200658 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500659 s->dest_x, s->dest_y,
660 s->dest_w, s->dest_h,
661 s->src_x, s->src_y,
662 s->src_w, s->src_h);
663 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200664 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500665 ret, strerror(errno));
666
Rob Clark5ca1a472012-08-08 20:27:37 -0500667 if (output->pipe > 0)
668 vbl.request.type |= DRM_VBLANK_SECONDARY;
669
Jesse Barnes58ef3792012-02-23 09:45:49 -0500670 /*
671 * Queue a vblank signal so we know when the surface
672 * becomes active on the display or has been replaced.
673 */
674 vbl.request.signal = (unsigned long)s;
675 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
676 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200677 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500678 ret, strerror(errno));
679 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300680
681 s->output = output;
682 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500683 }
684
David Herrmann1edf44c2013-10-22 17:11:26 +0200685 return 0;
686
687err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800688 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200689 if (output->next) {
690 drm_output_release_fb(output, output->next);
691 output->next = NULL;
692 }
693
694 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400695}
696
697static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200698drm_output_start_repaint_loop(struct weston_output *output_base)
699{
700 struct drm_output *output = (struct drm_output *) output_base;
701 struct drm_compositor *compositor = (struct drm_compositor *)
702 output_base->compositor;
703 uint32_t fb_id;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300704 struct timespec ts;
705
Xiong Zhangabd5d472013-10-11 14:43:07 +0800706 if (output->destroy_pending)
707 return;
708
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300709 if (!output->current) {
710 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200711 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300712 }
713
714 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200715
716 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
717 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
718 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200719 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200720 }
David Herrmann3c688c52013-10-22 17:11:25 +0200721
722 return;
723
724finish_frame:
725 /* if we cannot page-flip, immediately finish frame */
Pekka Paalanen662f3842015-03-18 12:17:26 +0200726 weston_compositor_read_presentation_clock(&compositor->base, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200727 weston_output_finish_frame(output_base, &ts,
728 PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200729}
730
731static void
Pekka Paalanen641307c2014-09-23 22:08:47 -0400732drm_output_update_msc(struct drm_output *output, unsigned int seq)
733{
734 uint64_t msc_hi = output->base.msc >> 32;
735
736 if (seq < (output->base.msc & 0xffffffff))
737 msc_hi++;
738
739 output->base.msc = (msc_hi << 32) + seq;
740}
741
742static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500743vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
744 void *data)
745{
746 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300747 struct drm_output *output = s->output;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400748 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200749 uint32_t flags = PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
750 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300751
Pekka Paalanen641307c2014-09-23 22:08:47 -0400752 drm_output_update_msc(output, frame);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300753 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500754
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200755 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200756 s->current = s->next;
757 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300758
759 if (!output->page_flip_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400760 ts.tv_sec = sec;
761 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200762 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300763 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500764}
765
766static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800767drm_output_destroy(struct weston_output *output_base);
768
769static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400770page_flip_handler(int fd, unsigned int frame,
771 unsigned int sec, unsigned int usec, void *data)
772{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200773 struct drm_output *output = (struct drm_output *) data;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400774 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200775 uint32_t flags = PRESENTATION_FEEDBACK_KIND_VSYNC |
776 PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
777 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400778
Pekka Paalanen641307c2014-09-23 22:08:47 -0400779 drm_output_update_msc(output, frame);
780
Jonas Ådahle5a12252013-04-05 23:07:11 +0200781 /* We don't set page_flip_pending on start_repaint_loop, in that case
782 * we just want to page flip to the current buffer to get an accurate
783 * timestamp */
784 if (output->page_flip_pending) {
785 drm_output_release_fb(output, output->current);
786 output->current = output->next;
787 output->next = NULL;
788 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300789
Jonas Ådahle5a12252013-04-05 23:07:11 +0200790 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400791
Xiong Zhangabd5d472013-10-11 14:43:07 +0800792 if (output->destroy_pending)
793 drm_output_destroy(&output->base);
794 else if (!output->vblank_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400795 ts.tv_sec = sec;
796 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200797 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300798
799 /* We can't call this from frame_notify, because the output's
800 * repaint needed flag is cleared just after that */
801 if (output->recorder)
802 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300803 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200804}
805
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500806static uint32_t
807drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500808 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500809{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500810 uint32_t i, format;
811
812 format = gbm_bo_get_format(bo);
813
814 if (format == GBM_FORMAT_ARGB8888) {
815 pixman_region32_t r;
816
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500817 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600818 ev->surface->width,
819 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500820 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500821
822 if (!pixman_region32_not_empty(&r))
823 format = GBM_FORMAT_XRGB8888;
824
825 pixman_region32_fini(&r);
826 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500827
828 for (i = 0; i < s->count_formats; i++)
829 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500830 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500831
832 return 0;
833}
834
835static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500836drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500837{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500838 return !ev->transform.enabled ||
839 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500840}
841
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400842static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200843drm_output_prepare_overlay_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500844 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500845{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200846 struct weston_compositor *ec = output->base.compositor;
847 struct drm_compositor *c = (struct drm_compositor *)ec;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200848 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500849 struct drm_sprite *s;
850 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500851 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500852 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200853 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500854 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400855 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500856
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200857 if (c->gbm == NULL)
858 return NULL;
859
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200860 if (viewport->buffer.transform != output->base.transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200861 return NULL;
862
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200863 if (viewport->buffer.scale != output->base.current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200864 return NULL;
865
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500866 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400867 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500868
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200869 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400870 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300871
Jason Ekstranda7af7042013-10-12 22:38:11 -0500872 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400873 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500874
Jason Ekstranda7af7042013-10-12 22:38:11 -0500875 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200876 return NULL;
877
Jason Ekstranda7af7042013-10-12 22:38:11 -0500878 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500879 return NULL;
880
Jason Ekstranda7af7042013-10-12 22:38:11 -0500881 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400882 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500883
Jesse Barnes58ef3792012-02-23 09:45:49 -0500884 wl_list_for_each(s, &c->sprite_list, link) {
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200885 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500886 continue;
887
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200888 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500889 found = 1;
890 break;
891 }
892 }
893
894 /* No sprites available */
895 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400896 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500897
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400898 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500899 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700900 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400901 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400902 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400903
Jason Ekstranda7af7042013-10-12 22:38:11 -0500904 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500905 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200906 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400907 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500908 }
909
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200910 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200911 if (!s->next) {
912 gbm_bo_destroy(bo);
913 return NULL;
914 }
915
Jason Ekstranda7af7042013-10-12 22:38:11 -0500916 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500917
Jason Ekstranda7af7042013-10-12 22:38:11 -0500918 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400919 s->plane.x = box->x1;
920 s->plane.y = box->y1;
921
Jesse Barnes58ef3792012-02-23 09:45:49 -0500922 /*
923 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -0500924 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500925 * for us already).
926 */
927 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500928 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200929 &output->base.region);
930 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500931 box = pixman_region32_extents(&dest_rect);
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200932 tbox = weston_transformed_rect(output->base.width,
933 output->base.height,
934 output->base.transform,
935 output->base.current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200936 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200937 s->dest_x = tbox.x1;
938 s->dest_y = tbox.y1;
939 s->dest_w = tbox.x2 - tbox.x1;
940 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500941 pixman_region32_fini(&dest_rect);
942
943 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500944 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200945 &output->base.region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500946 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400947
Jason Ekstranda7af7042013-10-12 22:38:11 -0500948 weston_view_from_global_fixed(ev,
949 wl_fixed_from_int(box->x1),
950 wl_fixed_from_int(box->y1),
951 &sx1, &sy1);
952 weston_view_from_global_fixed(ev,
953 wl_fixed_from_int(box->x2),
954 wl_fixed_from_int(box->y2),
955 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400956
957 if (sx1 < 0)
958 sx1 = 0;
959 if (sy1 < 0)
960 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600961 if (sx2 > wl_fixed_from_int(ev->surface->width))
962 sx2 = wl_fixed_from_int(ev->surface->width);
963 if (sy2 > wl_fixed_from_int(ev->surface->height))
964 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400965
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200966 tbox.x1 = sx1;
967 tbox.y1 = sy1;
968 tbox.x2 = sx2;
969 tbox.y2 = sy2;
970
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600971 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
972 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200973 viewport->buffer.transform,
974 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100975 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200976
977 s->src_x = tbox.x1 << 8;
978 s->src_y = tbox.y1 << 8;
979 s->src_w = (tbox.x2 - tbox.x1) << 8;
980 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500981 pixman_region32_fini(&src_rect);
982
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400983 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500984}
985
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400986static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200987drm_output_prepare_cursor_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500988 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500989{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400990 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200991 (struct drm_compositor *)output->base.compositor;
Neil Robertsf37f82c2014-05-01 18:00:41 +0100992 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400993
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200994 if (c->gbm == NULL)
995 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200996 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
997 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200998 if (viewport->buffer.scale != output->base.current_scale)
Neil Robertsf37f82c2014-05-01 18:00:41 +0100999 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001000 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001001 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001002 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001003 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001004 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -04001005 return NULL;
Pekka Paalanen5580f222015-02-17 16:33:18 +02001006 if (ev->geometry.scissor_enabled)
1007 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001008 if (ev->surface->buffer_ref.buffer == NULL ||
1009 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001010 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001011 return NULL;
1012
Jason Ekstranda7af7042013-10-12 22:38:11 -05001013 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001014
1015 return &output->cursor_plane;
1016}
1017
1018static void
1019drm_output_set_cursor(struct drm_output *output)
1020{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001021 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001022 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001023 struct drm_compositor *c =
1024 (struct drm_compositor *) output->base.compositor;
1025 EGLint handle, stride;
1026 struct gbm_bo *bo;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001027 uint32_t buf[c->cursor_width * c->cursor_height];
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001028 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001029 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001030
Jason Ekstranda7af7042013-10-12 22:38:11 -05001031 output->cursor_view = NULL;
1032 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001033 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
1034 return;
1035 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001036
Neil Robertse5051712013-11-13 15:44:06 +00001037 buffer = ev->surface->buffer_ref.buffer;
1038
1039 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001040 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001041 pixman_region32_fini(&output->cursor_plane.damage);
1042 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001043 output->current_cursor ^= 1;
1044 bo = output->cursor_bo[output->current_cursor];
1045 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001046 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1047 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1048 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001049 for (i = 0; i < ev->surface->height; i++)
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001050 memcpy(buf + i * c->cursor_width, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001051 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001052 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001053
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001054 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001055 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001056
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001057 handle = gbm_bo_get_handle(bo).s32;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001058 if (drmModeSetCursor(c->drm.fd, output->crtc_id, handle,
1059 c->cursor_width, c->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001060 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001061 c->cursors_are_broken = 1;
1062 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001063 }
1064
Jason Ekstranda7af7042013-10-12 22:38:11 -05001065 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1066 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001067 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001068 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001069 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001070 c->cursors_are_broken = 1;
1071 }
1072
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001073 output->cursor_plane.x = x;
1074 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001075 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001076}
1077
Jesse Barnes58ef3792012-02-23 09:45:49 -05001078static void
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001079drm_assign_planes(struct weston_output *output_base)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001080{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001081 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001082 (struct drm_compositor *)output_base->compositor;
1083 struct drm_output *output = (struct drm_output *)output_base;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001084 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001085 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001086 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001087
1088 /*
1089 * Find a surface for each sprite in the output using some heuristics:
1090 * 1) size
1091 * 2) frequency of update
1092 * 3) opacity (though some hw might support alpha blending)
1093 * 4) clipping (this can be fixed with color keys)
1094 *
1095 * The idea is to save on blitting since this should save power.
1096 * If we can get a large video surface on the sprite for example,
1097 * the main display surface may not need to update at all, and
1098 * the client buffer can be used directly for the sprite surface
1099 * as we do for flipping full screen surfaces.
1100 */
1101 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001102 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001103
Jason Ekstranda7af7042013-10-12 22:38:11 -05001104 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001105 struct weston_surface *es = ev->surface;
1106
1107 /* Test whether this buffer can ever go into a plane:
1108 * non-shm, or small enough to be a cursor.
1109 *
1110 * Also, keep a reference when using the pixman renderer.
1111 * That makes it possible to do a seamless switch to the GL
1112 * renderer and since the pixman renderer keeps a reference
1113 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001114 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001115 if (c->use_pixman ||
1116 (es->buffer_ref.buffer &&
1117 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001118 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001119 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001120 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001121 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001122
Jesse Barnes58ef3792012-02-23 09:45:49 -05001123 pixman_region32_init(&surface_overlap);
1124 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001125 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001126
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001127 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001128 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001129 next_plane = primary;
1130 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001131 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001132 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001133 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001134 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001135 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001136 if (next_plane == NULL)
1137 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001138
Jason Ekstranda7af7042013-10-12 22:38:11 -05001139 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001140
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001141 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001142 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001143 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001144
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001145 if (next_plane == primary ||
1146 next_plane == &output->cursor_plane) {
1147 /* cursor plane involves a copy */
1148 ev->psf_flags = 0;
1149 } else {
1150 /* All other planes are a direct scanout of a
1151 * single client buffer.
1152 */
1153 ev->psf_flags = PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
1154 }
1155
Jesse Barnes58ef3792012-02-23 09:45:49 -05001156 pixman_region32_fini(&surface_overlap);
1157 }
1158 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001159}
1160
Matt Roper361d2ad2011-08-29 13:52:23 -07001161static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001162drm_output_fini_pixman(struct drm_output *output);
1163
1164static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001165drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001166{
1167 struct drm_output *output = (struct drm_output *) output_base;
1168 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001169 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001170 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001171
Xiong Zhangabd5d472013-10-11 14:43:07 +08001172 if (output->page_flip_pending) {
1173 output->destroy_pending = 1;
1174 weston_log("destroy output while page flip pending\n");
1175 return;
1176 }
1177
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001178 if (output->backlight)
1179 backlight_destroy(output->backlight);
1180
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001181 drmModeFreeProperty(output->dpms_prop);
1182
Matt Roper361d2ad2011-08-29 13:52:23 -07001183 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001184 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001185
1186 /* Restore original CRTC state */
1187 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001188 origcrtc->x, origcrtc->y,
1189 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001190 drmModeFreeCrtc(origcrtc);
1191
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001192 c->crtc_allocator &= ~(1 << output->crtc_id);
1193 c->connector_allocator &= ~(1 << output->connector_id);
1194
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001195 if (c->use_pixman) {
1196 drm_output_fini_pixman(output);
1197 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001198 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001199 gbm_surface_destroy(output->surface);
1200 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001201
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001202 weston_plane_release(&output->fb_plane);
1203 weston_plane_release(&output->cursor_plane);
1204
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001205 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001206
Matt Roper361d2ad2011-08-29 13:52:23 -07001207 free(output);
1208}
1209
Alex Wub7b8bda2012-04-17 17:20:48 +08001210static struct drm_mode *
1211choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1212{
1213 struct drm_mode *tmp_mode = NULL, *mode;
1214
Hardeningff39efa2013-09-18 23:56:35 +02001215 if (output->base.current_mode->width == target_mode->width &&
1216 output->base.current_mode->height == target_mode->height &&
1217 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001218 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001219 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001220
1221 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1222 if (mode->mode_info.hdisplay == target_mode->width &&
1223 mode->mode_info.vdisplay == target_mode->height) {
1224 if (mode->mode_info.vrefresh == target_mode->refresh ||
1225 target_mode->refresh == 0) {
1226 return mode;
1227 } else if (!tmp_mode)
1228 tmp_mode = mode;
1229 }
1230 }
1231
1232 return tmp_mode;
1233}
1234
1235static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001236drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001237static int
1238drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001239
1240static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001241drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1242{
1243 struct drm_output *output;
1244 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001245 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001246
1247 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001248 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001249 return -1;
1250 }
1251
1252 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001253 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001254 return -1;
1255 }
1256
1257 ec = (struct drm_compositor *)output_base->compositor;
1258 output = (struct drm_output *)output_base;
1259 drm_mode = choose_mode (output, mode);
1260
1261 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001262 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001263 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001264 }
1265
Hardeningff39efa2013-09-18 23:56:35 +02001266 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001267 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001268
Hardeningff39efa2013-09-18 23:56:35 +02001269 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001270
Hardeningff39efa2013-09-18 23:56:35 +02001271 output->base.current_mode = &drm_mode->base;
1272 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001273 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1274
Alex Wub7b8bda2012-04-17 17:20:48 +08001275 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001276 drm_output_release_fb(output, output->current);
1277 drm_output_release_fb(output, output->next);
1278 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001279
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001280 if (ec->use_pixman) {
1281 drm_output_fini_pixman(output);
1282 if (drm_output_init_pixman(output, ec) < 0) {
1283 weston_log("failed to init output pixman state with "
1284 "new mode\n");
1285 return -1;
1286 }
1287 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001288 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001289 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001290
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001291 if (drm_output_init_egl(output, ec) < 0) {
1292 weston_log("failed to init output egl state with "
1293 "new mode");
1294 return -1;
1295 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001296 }
1297
Alex Wub7b8bda2012-04-17 17:20:48 +08001298 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001299}
1300
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001301static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001302on_drm_input(int fd, uint32_t mask, void *data)
1303{
1304 drmEventContext evctx;
1305
1306 memset(&evctx, 0, sizeof evctx);
1307 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1308 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001309 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001310 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001311
1312 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001313}
1314
1315static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001316init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001317{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001318 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001319 uint64_t cap;
1320 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001321 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001322
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001323 sysnum = udev_device_get_sysnum(device);
1324 if (sysnum)
1325 ec->drm.id = atoi(sysnum);
1326 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001327 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001328 return -1;
1329 }
1330
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001331 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001332 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001333 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001334 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001335 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001336 udev_device_get_devnode(device));
1337 return -1;
1338 }
1339
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001340 weston_log("using %s\n", filename);
1341
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001342 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001343 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001344
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001345 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1346 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001347 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001348 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001349 clk_id = CLOCK_REALTIME;
1350
1351 if (weston_compositor_set_presentation_clock(&ec->base, clk_id) < 0) {
1352 weston_log("Error: failed to set presentation clock %d.\n",
1353 clk_id);
1354 return -1;
1355 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001356
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001357 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1358 if (ret == 0)
1359 ec->cursor_width = cap;
1360 else
1361 ec->cursor_width = 64;
1362
1363 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1364 if (ret == 0)
1365 ec->cursor_height = cap;
1366 else
1367 ec->cursor_height = 64;
1368
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001369 return 0;
1370}
1371
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001372static struct gbm_device *
1373create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001374{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001375 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001376
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001377 gl_renderer = weston_load_module("gl-renderer.so",
1378 "gl_renderer_interface");
1379 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001380 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001381
1382 /* GBM will load a dri driver, but even though they need symbols from
1383 * libglapi, in some version of Mesa they are not linked to it. Since
1384 * only the gl-renderer module links to it, the call above won't make
1385 * these symbols globally available, and loading the DRI driver fails.
1386 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1387 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1388
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001389 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001390
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001391 return gbm;
1392}
1393
1394static int
1395drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1396{
1397 EGLint format;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001398
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001399 format = ec->format;
Jonny Lamb70eba3f2015-03-20 15:26:50 +01001400 if (gl_renderer->create(&ec->base, EGL_PLATFORM_GBM_KHR, (void *) ec->gbm,
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001401 gl_renderer->opaque_attribs, &format) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001402 return -1;
1403 }
1404
1405 return 0;
1406}
1407
1408static int
1409init_egl(struct drm_compositor *ec)
1410{
1411 ec->gbm = create_gbm_device(ec->drm.fd);
1412
1413 if (!ec->gbm)
1414 return -1;
1415
1416 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001417 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001418 return -1;
1419 }
1420
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001421 return 0;
1422}
1423
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001424static int
1425init_pixman(struct drm_compositor *ec)
1426{
1427 return pixman_renderer_init(&ec->base);
1428}
1429
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001430static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001431drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001432{
1433 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001434 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001435
1436 mode = malloc(sizeof *mode);
1437 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001438 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001439
1440 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001441 mode->base.width = info->hdisplay;
1442 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001443
1444 /* Calculate higher precision (mHz) refresh rate */
1445 refresh = (info->clock * 1000000LL / info->htotal +
1446 info->vtotal / 2) / info->vtotal;
1447
1448 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1449 refresh *= 2;
1450 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1451 refresh /= 2;
1452 if (info->vscan > 1)
1453 refresh /= info->vscan;
1454
1455 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001456 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001457
1458 if (info->type & DRM_MODE_TYPE_PREFERRED)
1459 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1460
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001461 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1462
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001463 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001464}
1465
1466static int
1467drm_subpixel_to_wayland(int drm_value)
1468{
1469 switch (drm_value) {
1470 default:
1471 case DRM_MODE_SUBPIXEL_UNKNOWN:
1472 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1473 case DRM_MODE_SUBPIXEL_NONE:
1474 return WL_OUTPUT_SUBPIXEL_NONE;
1475 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1476 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1477 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1478 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1479 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1480 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1481 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1482 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1483 }
1484}
1485
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001486/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001487static uint32_t
1488drm_get_backlight(struct drm_output *output)
1489{
1490 long brightness, max_brightness, norm;
1491
1492 brightness = backlight_get_brightness(output->backlight);
1493 max_brightness = backlight_get_max_brightness(output->backlight);
1494
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001495 /* convert it on a scale of 0 to 255 */
1496 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001497
1498 return (uint32_t) norm;
1499}
1500
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001501/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001502static void
1503drm_set_backlight(struct weston_output *output_base, uint32_t value)
1504{
1505 struct drm_output *output = (struct drm_output *) output_base;
1506 long max_brightness, new_brightness;
1507
1508 if (!output->backlight)
1509 return;
1510
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001511 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001512 return;
1513
1514 max_brightness = backlight_get_max_brightness(output->backlight);
1515
1516 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001517 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001518
1519 backlight_set_brightness(output->backlight, new_brightness);
1520}
1521
1522static drmModePropertyPtr
1523drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1524{
1525 drmModePropertyPtr props;
1526 int i;
1527
1528 for (i = 0; i < connector->count_props; i++) {
1529 props = drmModeGetProperty(fd, connector->props[i]);
1530 if (!props)
1531 continue;
1532
1533 if (!strcmp(props->name, name))
1534 return props;
1535
1536 drmModeFreeProperty(props);
1537 }
1538
1539 return NULL;
1540}
1541
1542static void
1543drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1544{
1545 struct drm_output *output = (struct drm_output *) output_base;
1546 struct weston_compositor *ec = output_base->compositor;
1547 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001548
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001549 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001550 return;
1551
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001552 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1553 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001554}
1555
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001556static const char *connector_type_names[] = {
1557 "None",
1558 "VGA",
1559 "DVI",
1560 "DVI",
1561 "DVI",
1562 "Composite",
1563 "TV",
1564 "LVDS",
1565 "CTV",
1566 "DIN",
1567 "DP",
1568 "HDMI",
1569 "HDMI",
1570 "TV",
1571 "eDP",
1572};
1573
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001574static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001575find_crtc_for_connector(struct drm_compositor *ec,
1576 drmModeRes *resources, drmModeConnector *connector)
1577{
1578 drmModeEncoder *encoder;
1579 uint32_t possible_crtcs;
1580 int i, j;
1581
1582 for (j = 0; j < connector->count_encoders; j++) {
1583 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1584 if (encoder == NULL) {
1585 weston_log("Failed to get encoder.\n");
1586 return -1;
1587 }
1588 possible_crtcs = encoder->possible_crtcs;
1589 drmModeFreeEncoder(encoder);
1590
1591 for (i = 0; i < resources->count_crtcs; i++) {
1592 if (possible_crtcs & (1 << i) &&
1593 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1594 return i;
1595 }
1596 }
1597
1598 return -1;
1599}
1600
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001601/* Init output state that depends on gl or gbm */
1602static int
1603drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1604{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001605 EGLint format = output->format;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001606 int i, flags;
1607
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001608 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001609 output->base.current_mode->width,
1610 output->base.current_mode->height,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001611 format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001612 GBM_BO_USE_SCANOUT |
1613 GBM_BO_USE_RENDERING);
1614 if (!output->surface) {
1615 weston_log("failed to create gbm surface\n");
1616 return -1;
1617 }
1618
Jonny Lamb671148f2015-03-20 15:26:52 +01001619 if (gl_renderer->output_create(&output->base,
Jonny Lamb445fb692015-03-24 13:12:01 +01001620 (EGLNativeDisplayType)output->surface,
1621 output->surface,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001622 gl_renderer->opaque_attribs,
1623 &format) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001624 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001625 gbm_surface_destroy(output->surface);
1626 return -1;
1627 }
1628
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001629 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001630
1631 for (i = 0; i < 2; i++) {
1632 if (output->cursor_bo[i])
1633 continue;
1634
1635 output->cursor_bo[i] =
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001636 gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
1637 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001638 }
1639
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001640 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1641 weston_log("cursor buffers unavailable, using gl cursors\n");
1642 ec->cursors_are_broken = 1;
1643 }
1644
1645 return 0;
1646}
1647
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001648static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001649drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1650{
Hardeningff39efa2013-09-18 23:56:35 +02001651 int w = output->base.current_mode->width;
1652 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001653 unsigned int i;
1654
1655 /* FIXME error checking */
1656
1657 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001658 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001659 if (!output->dumb[i])
1660 goto err;
1661
1662 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001663 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001664 output->dumb[i]->map,
1665 output->dumb[i]->stride);
1666 if (!output->image[i])
1667 goto err;
1668 }
1669
1670 if (pixman_renderer_output_create(&output->base) < 0)
1671 goto err;
1672
1673 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001674 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001675
1676 return 0;
1677
1678err:
1679 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1680 if (output->dumb[i])
1681 drm_fb_destroy_dumb(output->dumb[i]);
1682 if (output->image[i])
1683 pixman_image_unref(output->image[i]);
1684
1685 output->dumb[i] = NULL;
1686 output->image[i] = NULL;
1687 }
1688
1689 return -1;
1690}
1691
1692static void
1693drm_output_fini_pixman(struct drm_output *output)
1694{
1695 unsigned int i;
1696
1697 pixman_renderer_output_destroy(&output->base);
1698 pixman_region32_fini(&output->previous_damage);
1699
1700 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1701 drm_fb_destroy_dumb(output->dumb[i]);
1702 pixman_image_unref(output->image[i]);
1703 output->dumb[i] = NULL;
1704 output->image[i] = NULL;
1705 }
1706}
1707
Richard Hughes2b2092a2013-04-24 14:58:02 +01001708static void
1709edid_parse_string(const uint8_t *data, char text[])
1710{
1711 int i;
1712 int replaced = 0;
1713
1714 /* this is always 12 bytes, but we can't guarantee it's null
1715 * terminated or not junk. */
1716 strncpy(text, (const char *) data, 12);
1717
1718 /* remove insane chars */
1719 for (i = 0; text[i] != '\0'; i++) {
1720 if (text[i] == '\n' ||
1721 text[i] == '\r') {
1722 text[i] = '\0';
1723 break;
1724 }
1725 }
1726
1727 /* ensure string is printable */
1728 for (i = 0; text[i] != '\0'; i++) {
1729 if (!isprint(text[i])) {
1730 text[i] = '-';
1731 replaced++;
1732 }
1733 }
1734
1735 /* if the string is random junk, ignore the string */
1736 if (replaced > 4)
1737 text[0] = '\0';
1738}
1739
1740#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1741#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1742#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1743#define EDID_OFFSET_DATA_BLOCKS 0x36
1744#define EDID_OFFSET_LAST_BLOCK 0x6c
1745#define EDID_OFFSET_PNPID 0x08
1746#define EDID_OFFSET_SERIAL 0x0c
1747
1748static int
1749edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1750{
1751 int i;
1752 uint32_t serial_number;
1753
1754 /* check header */
1755 if (length < 128)
1756 return -1;
1757 if (data[0] != 0x00 || data[1] != 0xff)
1758 return -1;
1759
1760 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1761 * /--08--\/--09--\
1762 * 7654321076543210
1763 * |\---/\---/\---/
1764 * R C1 C2 C3 */
1765 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1766 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1767 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1768 edid->pnp_id[3] = '\0';
1769
1770 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1771 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1772 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1773 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1774 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1775 if (serial_number > 0)
1776 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1777
1778 /* parse EDID data */
1779 for (i = EDID_OFFSET_DATA_BLOCKS;
1780 i <= EDID_OFFSET_LAST_BLOCK;
1781 i += 18) {
1782 /* ignore pixel clock data */
1783 if (data[i] != 0)
1784 continue;
1785 if (data[i+2] != 0)
1786 continue;
1787
1788 /* any useful blocks? */
1789 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1790 edid_parse_string(&data[i+5],
1791 edid->monitor_name);
1792 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1793 edid_parse_string(&data[i+5],
1794 edid->serial_number);
1795 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1796 edid_parse_string(&data[i+5],
1797 edid->eisa_id);
1798 }
1799 }
1800 return 0;
1801}
1802
1803static void
1804find_and_parse_output_edid(struct drm_compositor *ec,
1805 struct drm_output *output,
1806 drmModeConnector *connector)
1807{
1808 drmModePropertyBlobPtr edid_blob = NULL;
1809 drmModePropertyPtr property;
1810 int i;
1811 int rc;
1812
1813 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1814 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1815 if (!property)
1816 continue;
1817 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1818 !strcmp(property->name, "EDID")) {
1819 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1820 connector->prop_values[i]);
1821 }
1822 drmModeFreeProperty(property);
1823 }
1824 if (!edid_blob)
1825 return;
1826
1827 rc = edid_parse(&output->edid,
1828 edid_blob->data,
1829 edid_blob->length);
1830 if (!rc) {
1831 weston_log("EDID data '%s', '%s', '%s'\n",
1832 output->edid.pnp_id,
1833 output->edid.monitor_name,
1834 output->edid.serial_number);
1835 if (output->edid.pnp_id[0] != '\0')
1836 output->base.make = output->edid.pnp_id;
1837 if (output->edid.monitor_name[0] != '\0')
1838 output->base.model = output->edid.monitor_name;
1839 if (output->edid.serial_number[0] != '\0')
1840 output->base.serial_number = output->edid.serial_number;
1841 }
1842 drmModeFreePropertyBlob(edid_blob);
1843}
1844
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001845
1846
1847static int
1848parse_modeline(const char *s, drmModeModeInfo *mode)
1849{
1850 char hsync[16];
1851 char vsync[16];
1852 float fclock;
1853
1854 mode->type = DRM_MODE_TYPE_USERDEF;
1855 mode->hskew = 0;
1856 mode->vscan = 0;
1857 mode->vrefresh = 0;
1858 mode->flags = 0;
1859
Rob Bradford307e09e2013-07-26 16:29:40 +01001860 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001861 &fclock,
1862 &mode->hdisplay,
1863 &mode->hsync_start,
1864 &mode->hsync_end,
1865 &mode->htotal,
1866 &mode->vdisplay,
1867 &mode->vsync_start,
1868 &mode->vsync_end,
1869 &mode->vtotal, hsync, vsync) != 11)
1870 return -1;
1871
1872 mode->clock = fclock * 1000;
1873 if (strcmp(hsync, "+hsync") == 0)
1874 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1875 else if (strcmp(hsync, "-hsync") == 0)
1876 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1877 else
1878 return -1;
1879
1880 if (strcmp(vsync, "+vsync") == 0)
1881 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1882 else if (strcmp(vsync, "-vsync") == 0)
1883 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1884 else
1885 return -1;
1886
1887 return 0;
1888}
1889
Rob Bradford66bd9f52013-06-25 18:56:42 +01001890static void
1891setup_output_seat_constraint(struct drm_compositor *ec,
1892 struct weston_output *output,
1893 const char *s)
1894{
1895 if (strcmp(s, "") != 0) {
1896 struct udev_seat *seat;
1897
Jonas Ådahl58e15862014-03-12 22:08:40 +01001898 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001899 if (seat)
1900 seat->base.output = output;
1901
1902 if (seat && seat->base.pointer)
1903 weston_pointer_clamp(seat->base.pointer,
1904 &seat->base.pointer->x,
1905 &seat->base.pointer->y);
1906 }
1907}
1908
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001909static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001910get_gbm_format_from_section(struct weston_config_section *section,
1911 uint32_t default_value,
1912 uint32_t *format)
1913{
1914 char *s;
1915 int ret = 0;
1916
1917 weston_config_section_get_string(section,
1918 "gbm-format", &s, NULL);
1919
1920 if (s == NULL)
1921 *format = default_value;
1922 else if (strcmp(s, "xrgb8888") == 0)
1923 *format = GBM_FORMAT_XRGB8888;
1924 else if (strcmp(s, "rgb565") == 0)
1925 *format = GBM_FORMAT_RGB565;
1926 else if (strcmp(s, "xrgb2101010") == 0)
1927 *format = GBM_FORMAT_XRGB2101010;
1928 else {
1929 weston_log("fatal: unrecognized pixel format: %s\n", s);
1930 ret = -1;
1931 }
1932
1933 free(s);
1934
1935 return ret;
1936}
1937
1938static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001939create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001940 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001941 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001942 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001943{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001944 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001945 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001946 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001947 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001948 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001949 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001950 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001951 int i, width, height, scale;
1952 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001953 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001954 enum output_config config;
1955 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001956
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001957 i = find_crtc_for_connector(ec, resources, connector);
1958 if (i < 0) {
1959 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001960 return -1;
1961 }
1962
Peter Huttererf3d62272013-08-08 11:57:05 +10001963 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001964 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001965 return -1;
1966
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001967 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1968 output->base.make = "unknown";
1969 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001970 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001971 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001972
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001973 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1974 type_name = connector_type_names[connector->connector_type];
1975 else
1976 type_name = "UNKNOWN";
1977 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001978 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001979
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001980 section = weston_config_get_section(ec->base.config, "output", "name",
1981 output->base.name);
1982 weston_config_section_get_string(section, "mode", &s, "preferred");
1983 if (strcmp(s, "off") == 0)
1984 config = OUTPUT_CONFIG_OFF;
1985 else if (strcmp(s, "preferred") == 0)
1986 config = OUTPUT_CONFIG_PREFERRED;
1987 else if (strcmp(s, "current") == 0)
1988 config = OUTPUT_CONFIG_CURRENT;
1989 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1990 config = OUTPUT_CONFIG_MODE;
1991 else if (parse_modeline(s, &modeline) == 0)
1992 config = OUTPUT_CONFIG_MODELINE;
1993 else {
1994 weston_log("Invalid mode \"%s\" for output %s\n",
1995 s, output->base.name);
1996 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001997 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001998 free(s);
1999
2000 weston_config_section_get_int(section, "scale", &scale, 1);
2001 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05002002 if (weston_parse_transform(s, &transform) < 0)
2003 weston_log("Invalid transform \"%s\" for output %s\n",
2004 s, output->base.name);
2005
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002006 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002007
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002008 if (get_gbm_format_from_section(section,
2009 ec->format,
2010 &output->format) == -1)
2011 output->format = ec->format;
2012
Rob Bradford66bd9f52013-06-25 18:56:42 +01002013 weston_config_section_get_string(section, "seat", &s, "");
2014 setup_output_seat_constraint(ec, &output->base, s);
2015 free(s);
2016
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002017 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002018 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002019 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002020 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002021 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002022
Matt Roper361d2ad2011-08-29 13:52:23 -07002023 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03002024 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002025
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002026 /* Get the current mode on the crtc that's currently driving
2027 * this connector. */
2028 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002029 memset(&crtc_mode, 0, sizeof crtc_mode);
2030 if (encoder != NULL) {
2031 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
2032 drmModeFreeEncoder(encoder);
2033 if (crtc == NULL)
2034 goto err_free;
2035 if (crtc->mode_valid)
2036 crtc_mode = crtc->mode;
2037 drmModeFreeCrtc(crtc);
2038 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002039
David Herrmann0f0d54e2011-12-08 17:05:45 +01002040 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002041 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002042 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002043 goto err_free;
2044 }
2045
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002046 if (config == OUTPUT_CONFIG_OFF) {
2047 weston_log("Disabling output %s\n", output->base.name);
2048 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
2049 0, 0, 0, 0, 0, NULL);
2050 goto err_free;
2051 }
2052
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002053 preferred = NULL;
2054 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002055 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002056 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002057
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002058 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002059 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002060 width == drm_mode->base.width &&
2061 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002062 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002063 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002064 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002065 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002066 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002067 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002068 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002069
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002070 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002071 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002072 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002073 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002074 }
2075
Wang Quanxianacb805a2012-07-30 18:09:46 -04002076 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002077 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002078 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002079 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002080 }
2081
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002082 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002083 configured = current;
2084
Wang Quanxianacb805a2012-07-30 18:09:46 -04002085 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002086 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002087 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002088 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002089 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002090 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002091 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002092 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002093 else if (best)
2094 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002095
Hardeningff39efa2013-09-18 23:56:35 +02002096 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002097 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002098 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002099 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002100
Hardeningff39efa2013-09-18 23:56:35 +02002101 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002102
John Kåre Alsaker94659272012-11-13 19:10:18 +01002103 weston_output_init(&output->base, &ec->base, x, y,
2104 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002105 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002106
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002107 if (ec->use_pixman) {
2108 if (drm_output_init_pixman(output, ec) < 0) {
2109 weston_log("Failed to init output pixman state\n");
2110 goto err_output;
2111 }
2112 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002113 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002114 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002115 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002116
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002117 output->backlight = backlight_init(drm_device,
2118 connector->connector_type);
2119 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002120 weston_log("Initialized backlight, device %s\n",
2121 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002122 output->base.set_backlight = drm_set_backlight;
2123 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002124 } else {
2125 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002126 }
2127
Giulio Camuffob1147152015-05-06 21:41:57 +03002128 weston_compositor_add_output(&ec->base, &output->base);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002129
Richard Hughes2b2092a2013-04-24 14:58:02 +01002130 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002131 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2132 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002133
Jonas Ådahle5a12252013-04-05 23:07:11 +02002134 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002135 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002136 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002137 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002138 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002139 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002140
Richard Hughese7299962013-05-01 21:52:12 +01002141 output->base.gamma_size = output->original_crtc->gamma_size;
2142 output->base.set_gamma = drm_output_set_gamma;
2143
Xiong Zhang97116532013-10-23 13:58:31 +08002144 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2145 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002146
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002147 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2148 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2149 &ec->base.primary_plane);
2150
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002151 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002152 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002153 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002154 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002155 m->width, m->height, m->refresh / 1000.0,
2156 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2157 ", preferred" : "",
2158 m->flags & WL_OUTPUT_MODE_CURRENT ?
2159 ", current" : "",
2160 connector->count_modes == 0 ?
2161 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002162
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002163 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002164
John Kåre Alsaker94659272012-11-13 19:10:18 +01002165err_output:
2166 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002167err_free:
2168 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2169 base.link) {
2170 wl_list_remove(&drm_mode->base.link);
2171 free(drm_mode);
2172 }
2173
2174 drmModeFreeCrtc(output->original_crtc);
2175 ec->crtc_allocator &= ~(1 << output->crtc_id);
2176 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002177 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002178
David Herrmann0f0d54e2011-12-08 17:05:45 +01002179 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002180}
2181
Jesse Barnes58ef3792012-02-23 09:45:49 -05002182static void
2183create_sprites(struct drm_compositor *ec)
2184{
2185 struct drm_sprite *sprite;
2186 drmModePlaneRes *plane_res;
2187 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002188 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002189
2190 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2191 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002192 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002193 strerror(errno));
2194 return;
2195 }
2196
2197 for (i = 0; i < plane_res->count_planes; i++) {
2198 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2199 if (!plane)
2200 continue;
2201
Peter Huttererf3d62272013-08-08 11:57:05 +10002202 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002203 plane->count_formats));
2204 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002205 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002206 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002207 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002208 continue;
2209 }
2210
Jesse Barnes58ef3792012-02-23 09:45:49 -05002211 sprite->possible_crtcs = plane->possible_crtcs;
2212 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002213 sprite->current = NULL;
2214 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002215 sprite->compositor = ec;
2216 sprite->count_formats = plane->count_formats;
2217 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002218 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002219 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002220 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002221 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2222 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002223
2224 wl_list_insert(&ec->sprite_list, &sprite->link);
2225 }
2226
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002227 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002228}
2229
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002230static void
2231destroy_sprites(struct drm_compositor *compositor)
2232{
2233 struct drm_sprite *sprite, *next;
2234 struct drm_output *output;
2235
2236 output = container_of(compositor->base.output_list.next,
2237 struct drm_output, base.link);
2238
2239 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2240 drmModeSetPlane(compositor->drm.fd,
2241 sprite->plane_id,
2242 output->crtc_id, 0, 0,
2243 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002244 drm_output_release_fb(output, sprite->current);
2245 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002246 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002247 free(sprite);
2248 }
2249}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002250
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002251static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002252create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002253 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002254{
2255 drmModeConnector *connector;
2256 drmModeRes *resources;
2257 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002258 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002259
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002260 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002261 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002262 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002263 return -1;
2264 }
2265
Jesse Barnes58ef3792012-02-23 09:45:49 -05002266 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002267 if (!ec->crtcs) {
2268 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002269 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002270 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002271
Rob Clark4339add2012-08-09 14:18:28 -05002272 ec->min_width = resources->min_width;
2273 ec->max_width = resources->max_width;
2274 ec->min_height = resources->min_height;
2275 ec->max_height = resources->max_height;
2276
Jesse Barnes58ef3792012-02-23 09:45:49 -05002277 ec->num_crtcs = resources->count_crtcs;
2278 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2279
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002280 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002281 connector = drmModeGetConnector(ec->drm.fd,
2282 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002283 if (connector == NULL)
2284 continue;
2285
2286 if (connector->connection == DRM_MODE_CONNECTED &&
2287 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002288 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002289 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002290 connector, x, y,
2291 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002292 drmModeFreeConnector(connector);
2293 continue;
2294 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002295
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002296 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002297 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002298 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002299 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002300
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002301 drmModeFreeConnector(connector);
2302 }
2303
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002304 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002305 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002306 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002307 return -1;
2308 }
2309
2310 drmModeFreeResources(resources);
2311
2312 return 0;
2313}
2314
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002315static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002316update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002317{
2318 drmModeConnector *connector;
2319 drmModeRes *resources;
2320 struct drm_output *output, *next;
2321 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002322 uint32_t connected = 0, disconnects = 0;
2323 int i;
2324
2325 resources = drmModeGetResources(ec->drm.fd);
2326 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002327 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002328 return;
2329 }
2330
2331 /* collect new connects */
2332 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002333 int connector_id = resources->connectors[i];
2334
2335 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002336 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002337 continue;
2338
David Herrmann7551cff2011-12-08 17:05:43 +01002339 if (connector->connection != DRM_MODE_CONNECTED) {
2340 drmModeFreeConnector(connector);
2341 continue;
2342 }
2343
Benjamin Franzke117483d2011-08-30 11:38:26 +02002344 connected |= (1 << connector_id);
2345
2346 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002347 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002348 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002349 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002350
2351 /* XXX: not yet needed, we die with 0 outputs */
2352 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002353 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002354 else
2355 x = 0;
2356 y = 0;
2357 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002358 connector, x, y,
2359 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002360 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002361
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002362 }
2363 drmModeFreeConnector(connector);
2364 }
2365 drmModeFreeResources(resources);
2366
2367 disconnects = ec->connector_allocator & ~connected;
2368 if (disconnects) {
2369 wl_list_for_each_safe(output, next, &ec->base.output_list,
2370 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002371 if (disconnects & (1 << output->connector_id)) {
2372 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002373 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002374 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002375 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002376 }
2377 }
2378 }
2379
2380 /* FIXME: handle zero outputs, without terminating */
2381 if (ec->connector_allocator == 0)
2382 wl_display_terminate(ec->base.wl_display);
2383}
2384
2385static int
David Herrmannd7488c22012-03-11 20:05:21 +01002386udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002387{
David Herrmannd7488c22012-03-11 20:05:21 +01002388 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002389 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002390
2391 sysnum = udev_device_get_sysnum(device);
2392 if (!sysnum || atoi(sysnum) != ec->drm.id)
2393 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002394
David Herrmann6ac52db2012-03-11 20:05:22 +01002395 val = udev_device_get_property_value(device, "HOTPLUG");
2396 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002397 return 0;
2398
David Herrmann6ac52db2012-03-11 20:05:22 +01002399 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002400}
2401
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002402static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002403udev_drm_event(int fd, uint32_t mask, void *data)
2404{
2405 struct drm_compositor *ec = data;
2406 struct udev_device *event;
2407
2408 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002409
David Herrmannd7488c22012-03-11 20:05:21 +01002410 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002411 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002412
2413 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002414
2415 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002416}
2417
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002418static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002419drm_restore(struct weston_compositor *ec)
2420{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002421 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002422}
2423
2424static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002425drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002426{
2427 struct drm_compositor *d = (struct drm_compositor *) ec;
2428
Rob Bradfordd355b802013-05-31 18:09:55 +01002429 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002430
2431 wl_event_source_remove(d->udev_drm_source);
2432 wl_event_source_remove(d->drm_source);
2433
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002434 destroy_sprites(d);
2435
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002436 weston_compositor_shutdown(ec);
2437
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002438 if (d->gbm)
2439 gbm_device_destroy(d->gbm);
2440
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002441 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002442
Rob Bradford45c15b82013-07-26 16:29:35 +01002443 close(d->drm.fd);
2444
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002445 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002446}
2447
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002448static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002449drm_compositor_set_modes(struct drm_compositor *compositor)
2450{
2451 struct drm_output *output;
2452 struct drm_mode *drm_mode;
2453 int ret;
2454
2455 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002456 if (!output->current) {
2457 /* If something that would cause the output to
2458 * switch mode happened while in another vt, we
2459 * might not have a current drm_fb. In that case,
2460 * schedule a repaint and let drm_output_repaint
2461 * handle setting the mode. */
2462 weston_output_schedule_repaint(&output->base);
2463 continue;
2464 }
2465
Hardeningff39efa2013-09-18 23:56:35 +02002466 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002467 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002468 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002469 &output->connector_id, 1,
2470 &drm_mode->mode_info);
2471 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002472 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002473 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002474 drm_mode->base.width, drm_mode->base.height,
2475 output->base.x, output->base.y);
2476 }
2477 }
2478}
2479
2480static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002481session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002482{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002483 struct weston_compositor *compositor = data;
2484 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002485 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002486 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002487
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002488 if (ec->base.session_active) {
2489 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002490 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002491 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002492 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002493 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002494 } else {
2495 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002496 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002497
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002498 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002499 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002500
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002501 /* If we have a repaint scheduled (either from a
2502 * pending pageflip or the idle handler), make sure we
2503 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002504 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002505 * further attemps at repainting. When we switch
2506 * back, we schedule a repaint, which will process
2507 * pending frame callbacks. */
2508
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002509 wl_list_for_each(output, &ec->base.output_list, base.link) {
2510 output->base.repaint_needed = 0;
2511 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002512 }
2513
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002514 output = container_of(ec->base.output_list.next,
2515 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002516
2517 wl_list_for_each(sprite, &ec->sprite_list, link)
2518 drmModeSetPlane(ec->drm.fd,
2519 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002520 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002521 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002522 };
2523}
2524
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002525static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002526switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002527{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002528 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002529
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002530 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002531}
2532
David Herrmann0af066f2012-10-29 19:21:16 +01002533/*
2534 * Find primary GPU
2535 * Some systems may have multiple DRM devices attached to a single seat. This
2536 * function loops over all devices and tries to find a PCI device with the
2537 * boot_vga sysfs attribute set to 1.
2538 * If no such device is found, the first DRM device reported by udev is used.
2539 */
2540static struct udev_device*
2541find_primary_gpu(struct drm_compositor *ec, const char *seat)
2542{
2543 struct udev_enumerate *e;
2544 struct udev_list_entry *entry;
2545 const char *path, *device_seat, *id;
2546 struct udev_device *device, *drm_device, *pci;
2547
2548 e = udev_enumerate_new(ec->udev);
2549 udev_enumerate_add_match_subsystem(e, "drm");
2550 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2551
2552 udev_enumerate_scan_devices(e);
2553 drm_device = NULL;
2554 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2555 path = udev_list_entry_get_name(entry);
2556 device = udev_device_new_from_syspath(ec->udev, path);
2557 if (!device)
2558 continue;
2559 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2560 if (!device_seat)
2561 device_seat = default_seat;
2562 if (strcmp(device_seat, seat)) {
2563 udev_device_unref(device);
2564 continue;
2565 }
2566
2567 pci = udev_device_get_parent_with_subsystem_devtype(device,
2568 "pci", NULL);
2569 if (pci) {
2570 id = udev_device_get_sysattr_value(pci, "boot_vga");
2571 if (id && !strcmp(id, "1")) {
2572 if (drm_device)
2573 udev_device_unref(drm_device);
2574 drm_device = device;
2575 break;
2576 }
2577 }
2578
2579 if (!drm_device)
2580 drm_device = device;
2581 else
2582 udev_device_unref(device);
2583 }
2584
2585 udev_enumerate_unref(e);
2586 return drm_device;
2587}
2588
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002589static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002590planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002591{
2592 struct drm_compositor *c = data;
2593
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002594 switch (key) {
2595 case KEY_C:
2596 c->cursors_are_broken ^= 1;
2597 break;
2598 case KEY_V:
2599 c->sprites_are_broken ^= 1;
2600 break;
2601 case KEY_O:
2602 c->sprites_hidden ^= 1;
2603 break;
2604 default:
2605 break;
2606 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002607}
2608
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002609#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002610static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002611recorder_destroy(struct drm_output *output)
2612{
2613 vaapi_recorder_destroy(output->recorder);
2614 output->recorder = NULL;
2615
2616 output->base.disable_planes--;
2617
2618 wl_list_remove(&output->recorder_frame_listener.link);
2619 weston_log("[libva recorder] done\n");
2620}
2621
2622static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002623recorder_frame_notify(struct wl_listener *listener, void *data)
2624{
2625 struct drm_output *output;
2626 struct drm_compositor *c;
2627 int fd, ret;
2628
2629 output = container_of(listener, struct drm_output,
2630 recorder_frame_listener);
2631 c = (struct drm_compositor *) output->base.compositor;
2632
2633 if (!output->recorder)
2634 return;
2635
2636 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2637 DRM_CLOEXEC, &fd);
2638 if (ret) {
2639 weston_log("[libva recorder] "
2640 "failed to create prime fd for front buffer\n");
2641 return;
2642 }
2643
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002644 ret = vaapi_recorder_frame(output->recorder, fd,
2645 output->current->stride);
2646 if (ret < 0) {
2647 weston_log("[libva recorder] aborted: %m\n");
2648 recorder_destroy(output);
2649 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002650}
2651
2652static void *
2653create_recorder(struct drm_compositor *c, int width, int height,
2654 const char *filename)
2655{
2656 int fd;
2657 drm_magic_t magic;
2658
2659 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2660 if (fd < 0)
2661 return NULL;
2662
2663 drmGetMagic(fd, &magic);
2664 drmAuthMagic(c->drm.fd, magic);
2665
2666 return vaapi_recorder_create(fd, width, height, filename);
2667}
2668
2669static void
2670recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2671 void *data)
2672{
2673 struct drm_compositor *c = data;
2674 struct drm_output *output;
2675 int width, height;
2676
2677 output = container_of(c->base.output_list.next,
2678 struct drm_output, base.link);
2679
2680 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002681 if (output->format != GBM_FORMAT_XRGB8888) {
2682 weston_log("failed to start vaapi recorder: "
2683 "output format not supported\n");
2684 return;
2685 }
2686
Hardeningff39efa2013-09-18 23:56:35 +02002687 width = output->base.current_mode->width;
2688 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002689
2690 output->recorder =
2691 create_recorder(c, width, height, "capture.h264");
2692 if (!output->recorder) {
2693 weston_log("failed to create vaapi recorder\n");
2694 return;
2695 }
2696
2697 output->base.disable_planes++;
2698
2699 output->recorder_frame_listener.notify = recorder_frame_notify;
2700 wl_signal_add(&output->base.frame_signal,
2701 &output->recorder_frame_listener);
2702
2703 weston_output_schedule_repaint(&output->base);
2704
2705 weston_log("[libva recorder] initialized\n");
2706 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002707 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002708 }
2709}
2710#else
2711static void
2712recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2713 void *data)
2714{
2715 weston_log("Compiled without libva support\n");
2716}
2717#endif
2718
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002719static void
2720switch_to_gl_renderer(struct drm_compositor *c)
2721{
2722 struct drm_output *output;
2723
2724 if (!c->use_pixman)
2725 return;
2726
2727 weston_log("Switching to GL renderer\n");
2728
2729 c->gbm = create_gbm_device(c->drm.fd);
2730 if (!c->gbm) {
2731 weston_log("Failed to create gbm device. "
2732 "Aborting renderer switch\n");
2733 return;
2734 }
2735
2736 wl_list_for_each(output, &c->base.output_list, base.link)
2737 pixman_renderer_output_destroy(&output->base);
2738
2739 c->base.renderer->destroy(&c->base);
2740
2741 if (drm_compositor_create_gl_renderer(c) < 0) {
2742 gbm_device_destroy(c->gbm);
2743 weston_log("Failed to create GL renderer. Quitting.\n");
2744 /* FIXME: we need a function to shutdown cleanly */
2745 assert(0);
2746 }
2747
2748 wl_list_for_each(output, &c->base.output_list, base.link)
2749 drm_output_init_egl(output, c);
2750
2751 c->use_pixman = 0;
2752}
2753
2754static void
2755renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2756 void *data)
2757{
2758 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2759
2760 switch_to_gl_renderer(c);
2761}
2762
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002763static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002764drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002765 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002766 int *argc, char *argv[],
2767 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002768{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002769 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002770 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002771 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002772 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002773 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002774 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002775
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002776 weston_log("initializing drm backend\n");
2777
Peter Huttererf3d62272013-08-08 11:57:05 +10002778 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002779 if (ec == NULL)
2780 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002781
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002782 /* KMS support for sprites is not complete yet, so disable the
2783 * functionality for now. */
2784 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002785
2786 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002787 if (get_gbm_format_from_section(section,
2788 GBM_FORMAT_XRGB8888,
2789 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002790 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002791
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002792 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002793
Daniel Stone725c2c32012-06-22 14:04:36 +01002794 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002795 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002796 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002797 goto err_base;
2798 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002799
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002800 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002801 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
David Herrmann2ecb84a2014-12-30 14:33:22 +01002802 param->seat_id, true);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002803 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002804 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002805 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002806 goto err_compositor;
2807 }
2808
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002809 ec->udev = udev_new();
2810 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002811 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002812 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002813 }
2814
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002815 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002816 ec->session_listener.notify = session_notify;
2817 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002818
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002819 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002820 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002821 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002822 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002823 }
David Herrmann0af066f2012-10-29 19:21:16 +01002824 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002825
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002826 if (init_drm(ec, drm_device) < 0) {
2827 weston_log("failed to initialize kms\n");
2828 goto err_udev_dev;
2829 }
2830
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002831 if (ec->use_pixman) {
2832 if (init_pixman(ec) < 0) {
2833 weston_log("failed to initialize pixman renderer\n");
2834 goto err_udev_dev;
2835 }
2836 } else {
2837 if (init_egl(ec) < 0) {
2838 weston_log("failed to initialize egl\n");
2839 goto err_udev_dev;
2840 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002841 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002842
2843 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002844 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002845
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002846 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002847
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002848 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002849 weston_compositor_add_key_binding(&ec->base, key,
2850 MODIFIER_CTRL | MODIFIER_ALT,
2851 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002852
Jesse Barnes58ef3792012-02-23 09:45:49 -05002853 wl_list_init(&ec->sprite_list);
2854 create_sprites(ec);
2855
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002856 if (udev_input_init(&ec->input,
2857 &ec->base, ec->udev, param->seat_id) < 0) {
2858 weston_log("failed to create input devices\n");
2859 goto err_sprite;
2860 }
2861
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002862 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002863 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002864 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002865 }
2866
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002867 /* A this point we have some idea of whether or not we have a working
2868 * cursor plane. */
2869 if (!ec->cursors_are_broken)
2870 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2871
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002872 path = NULL;
2873
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002874 loop = wl_display_get_event_loop(ec->base.wl_display);
2875 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002876 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002877 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002878
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002879 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2880 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002881 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002882 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002883 }
2884 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2885 "drm", NULL);
2886 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002887 wl_event_loop_add_fd(loop,
2888 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002889 WL_EVENT_READABLE, udev_drm_event, ec);
2890
2891 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002892 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002893 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002894 }
2895
Daniel Stonea96b93c2012-06-22 14:04:37 +01002896 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002897
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002898 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002899 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002900 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002901 planes_binding, ec);
2902 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2903 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002904 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2905 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002906 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2907 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002908
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002909 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002910
2911err_udev_monitor:
2912 wl_event_source_remove(ec->udev_drm_source);
2913 udev_monitor_unref(ec->udev_monitor);
2914err_drm_source:
2915 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002916err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002917 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002918err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002919 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002920 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002921 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002922err_udev_dev:
2923 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002924err_launcher:
2925 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002926err_udev:
2927 udev_unref(ec->udev);
2928err_compositor:
2929 weston_compositor_shutdown(&ec->base);
2930err_base:
2931 free(ec);
2932 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002933}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002934
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002935WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002936backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002937 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002938{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002939 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002940
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002941 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002942 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2943 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2944 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002945 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002946 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002947 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002948
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002949 param.seat_id = default_seat;
2950
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002951 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002952
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002953 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002954}