blob: 3b91fe4f6b91d1634c563a1a065e2001d2d3e6f8 [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 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -07005 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040012 *
Bryce Harringtona0bbfea2015-06-11 15:35:43 -070013 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040025 */
26
Daniel Stonec228e232013-05-22 18:03:19 +030027#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040028
Jesse Barnes58ef3792012-02-23 09:45:49 -050029#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040030#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010031#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040032#include <string.h>
33#include <fcntl.h>
34#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040035#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070036#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030037#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020038#include <sys/mman.h>
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030039#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030040#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040041
Benjamin Franzkec649a922011-03-02 11:56:04 +010042#include <xf86drm.h>
43#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050044#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010045
Benjamin Franzke060cf802011-04-30 09:32:11 +020046#include <gbm.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040047#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020048
Jon Cruz35b2eaa2015-06-15 15:37:08 -070049#include "shared/helpers.h"
Mario Kleinerf507ec32015-06-21 21:25:14 +020050#include "shared/timespec-util.h"
Kristian Høgsberg36d5fac2014-01-27 23:02:35 -080051#include "libbacklight.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040052#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010053#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020054#include "pixman-renderer.h"
Peter Hutterer823ad332014-11-26 07:06:31 +100055#include "libinput-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010056#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030057#include "vaapi-recorder.h"
Pekka Paalanen363aa7b2014-12-17 16:20:40 +020058#include "presentation_timing-server-protocol.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040059
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030060#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
61#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
62#endif
63
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030064#ifndef DRM_CAP_CURSOR_WIDTH
65#define DRM_CAP_CURSOR_WIDTH 0x8
66#endif
67
68#ifndef DRM_CAP_CURSOR_HEIGHT
69#define DRM_CAP_CURSOR_HEIGHT 0x9
70#endif
71
72#ifndef GBM_BO_USE_CURSOR
73#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
74#endif
75
Kristian Høgsberg061c4252012-06-28 11:28:15 -040076static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060077
78enum output_config {
79 OUTPUT_CONFIG_INVALID = 0,
80 OUTPUT_CONFIG_OFF,
81 OUTPUT_CONFIG_PREFERRED,
82 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060083 OUTPUT_CONFIG_MODE,
84 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060085};
86
Giulio Camuffo954f1832014-10-11 18:27:30 +030087struct drm_backend {
88 struct weston_backend base;
89 struct weston_compositor *compositor;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040090
91 struct udev *udev;
92 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040093
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010094 struct udev_monitor *udev_monitor;
95 struct wl_event_source *udev_drm_source;
96
Benjamin Franzke2af7f102011-03-02 11:14:59 +010097 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010098 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010099 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300100 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +0100101 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +0200102 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500103 uint32_t *crtcs;
104 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -0500105 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100106 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700107 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700108 uint32_t format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200109
Rob Clark4339add2012-08-09 14:18:28 -0500110 /* we need these parameters in order to not fail drmModeAddFB2()
111 * due to out of bounds dimensions, and then mistakenly set
112 * sprites_are_broken:
113 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200114 uint32_t min_width, max_width;
115 uint32_t min_height, max_height;
116 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500117
Jesse Barnes58ef3792012-02-23 09:45:49 -0500118 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500119 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200120 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500121
Rob Clarkab5b1e32012-08-09 13:24:45 -0500122 int cursors_are_broken;
123
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200124 int use_pixman;
125
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200126 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300127
Rob Bradfordd355b802013-05-31 18:09:55 +0100128 struct udev_input input;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -0300129
130 uint32_t cursor_width;
131 uint32_t cursor_height;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400132};
133
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400134struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500135 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400136 drmModeModeInfo mode_info;
137};
138
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300139struct drm_output;
140
141struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300142 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200143 uint32_t fb_id, stride, handle, size;
144 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300145 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200146 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200147
148 /* Used by gbm fbs */
149 struct gbm_bo *bo;
150
151 /* Used by dumb fbs */
152 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300153};
154
Richard Hughes2b2092a2013-04-24 14:58:02 +0100155struct drm_edid {
156 char eisa_id[13];
157 char monitor_name[13];
158 char pnp_id[5];
159 char serial_number[13];
160};
161
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400162struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500163 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400164
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400165 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500166 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400167 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700168 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100169 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300170 drmModePropertyPtr dpms_prop;
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000171 uint32_t format;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200172
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300173 int vblank_pending;
174 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800175 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300176
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400177 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400178 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400179 struct weston_plane cursor_plane;
180 struct weston_plane fb_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500181 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400182 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300183 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200184 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200185
186 struct drm_fb *dumb[2];
187 pixman_image_t *image[2];
188 int current_image;
189 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300190
191 struct vaapi_recorder *recorder;
192 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400193};
194
Jesse Barnes58ef3792012-02-23 09:45:49 -0500195/*
196 * An output has a primary display plane plus zero or more sprites for
197 * blending display contents.
198 */
199struct drm_sprite {
200 struct wl_list link;
201
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400202 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500203
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200204 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300205 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300206 struct drm_backend *backend;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500207
Jesse Barnes58ef3792012-02-23 09:45:49 -0500208 uint32_t possible_crtcs;
209 uint32_t plane_id;
210 uint32_t count_formats;
211
212 int32_t src_x, src_y;
213 uint32_t src_w, src_h;
214 uint32_t dest_x, dest_y;
215 uint32_t dest_w, dest_h;
216
217 uint32_t formats[];
218};
219
Kristian Høgsbergd8e98332013-10-16 16:15:11 -0700220struct drm_parameters {
221 int connector;
222 int tty;
223 int use_pixman;
224 const char *seat_id;
225};
226
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300227static struct gl_renderer_interface *gl_renderer;
228
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500229static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400230
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400231static void
232drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400233
Mario Kleinerf507ec32015-06-21 21:25:14 +0200234static void
235drm_output_update_msc(struct drm_output *output, unsigned int seq);
236
Jesse Barnes58ef3792012-02-23 09:45:49 -0500237static int
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200238drm_sprite_crtc_supported(struct drm_output *output, uint32_t supported)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500239{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200240 struct weston_compositor *ec = output->base.compositor;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300241 struct drm_backend *b =(struct drm_backend *)ec->backend;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500242 int crtc;
243
Giulio Camuffo954f1832014-10-11 18:27:30 +0300244 for (crtc = 0; crtc < b->num_crtcs; crtc++) {
245 if (b->crtcs[crtc] != output->crtc_id)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500246 continue;
247
248 if (supported & (1 << crtc))
249 return -1;
250 }
251
252 return 0;
253}
254
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300255static void
256drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
257{
258 struct drm_fb *fb = data;
259 struct gbm_device *gbm = gbm_bo_get_device(bo);
260
261 if (fb->fb_id)
262 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
263
Pekka Paalanende685b82012-12-04 15:58:12 +0200264 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300265
266 free(data);
267}
268
269static struct drm_fb *
Giulio Camuffo954f1832014-10-11 18:27:30 +0300270drm_fb_create_dumb(struct drm_backend *b, unsigned width, unsigned height)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200271{
272 struct drm_fb *fb;
273 int ret;
274
275 struct drm_mode_create_dumb create_arg;
276 struct drm_mode_destroy_dumb destroy_arg;
277 struct drm_mode_map_dumb map_arg;
278
Peter Huttererf3d62272013-08-08 11:57:05 +1000279 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200280 if (!fb)
281 return NULL;
282
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700283 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200284 create_arg.bpp = 32;
285 create_arg.width = width;
286 create_arg.height = height;
287
Giulio Camuffo954f1832014-10-11 18:27:30 +0300288 ret = drmIoctl(b->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200289 if (ret)
290 goto err_fb;
291
292 fb->handle = create_arg.handle;
293 fb->stride = create_arg.pitch;
294 fb->size = create_arg.size;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300295 fb->fd = b->drm.fd;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200296
Giulio Camuffo954f1832014-10-11 18:27:30 +0300297 ret = drmModeAddFB(b->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200298 fb->stride, fb->handle, &fb->fb_id);
299 if (ret)
300 goto err_bo;
301
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700302 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200303 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400304 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200305 if (ret)
306 goto err_add_fb;
307
308 fb->map = mmap(0, fb->size, PROT_WRITE,
Giulio Camuffo954f1832014-10-11 18:27:30 +0300309 MAP_SHARED, b->drm.fd, map_arg.offset);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200310 if (fb->map == MAP_FAILED)
311 goto err_add_fb;
312
313 return fb;
314
315err_add_fb:
Giulio Camuffo954f1832014-10-11 18:27:30 +0300316 drmModeRmFB(b->drm.fd, fb->fb_id);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200317err_bo:
318 memset(&destroy_arg, 0, sizeof(destroy_arg));
319 destroy_arg.handle = create_arg.handle;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300320 drmIoctl(b->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200321err_fb:
322 free(fb);
323 return NULL;
324}
325
326static void
327drm_fb_destroy_dumb(struct drm_fb *fb)
328{
329 struct drm_mode_destroy_dumb destroy_arg;
330
331 if (!fb->map)
332 return;
333
334 if (fb->fb_id)
335 drmModeRmFB(fb->fd, fb->fb_id);
336
337 weston_buffer_reference(&fb->buffer_ref, NULL);
338
339 munmap(fb->map, fb->size);
340
341 memset(&destroy_arg, 0, sizeof(destroy_arg));
342 destroy_arg.handle = fb->handle;
343 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
344
345 free(fb);
346}
347
348static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500349drm_fb_get_from_bo(struct gbm_bo *bo,
Giulio Camuffo954f1832014-10-11 18:27:30 +0300350 struct drm_backend *backend, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300351{
352 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200353 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200354 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300355 int ret;
356
357 if (fb)
358 return fb;
359
Bryce Harringtonde16d892014-11-20 22:21:57 -0800360 fb = zalloc(sizeof *fb);
361 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200362 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300363
364 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300365
366 width = gbm_bo_get_width(bo);
367 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200368 fb->stride = gbm_bo_get_stride(bo);
369 fb->handle = gbm_bo_get_handle(bo).u32;
370 fb->size = fb->stride * height;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300371 fb->fd = backend->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300372
Giulio Camuffo954f1832014-10-11 18:27:30 +0300373 if (backend->min_width > width || width > backend->max_width ||
374 backend->min_height > height ||
375 height > backend->max_height) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376 weston_log("bo geometry out of bounds\n");
377 goto err_free;
378 }
379
380 ret = -1;
381
Giulio Camuffo954f1832014-10-11 18:27:30 +0300382 if (format && !backend->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200383 handles[0] = fb->handle;
384 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200385 offsets[0] = 0;
386
Giulio Camuffo954f1832014-10-11 18:27:30 +0300387 ret = drmModeAddFB2(backend->drm.fd, width, height,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200388 format, handles, pitches, offsets,
389 &fb->fb_id, 0);
390 if (ret) {
391 weston_log("addfb2 failed: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +0300392 backend->no_addfb2 = 1;
393 backend->sprites_are_broken = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200394 }
395 }
396
397 if (ret)
Giulio Camuffo954f1832014-10-11 18:27:30 +0300398 ret = drmModeAddFB(backend->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200399 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200400
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300401 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200402 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200403 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300404 }
405
406 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
407
408 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200409
410err_free:
411 free(fb);
412 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300413}
414
415static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500416drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200417{
Pekka Paalanende685b82012-12-04 15:58:12 +0200418 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200419
420 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200421
Pekka Paalanende685b82012-12-04 15:58:12 +0200422 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200423}
424
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200425static void
426drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
427{
428 if (!fb)
429 return;
430
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200431 if (fb->map &&
432 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200433 drm_fb_destroy_dumb(fb);
434 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200435 if (fb->is_client_buffer)
436 gbm_bo_destroy(fb->bo);
437 else
438 gbm_surface_release_buffer(output->surface,
Jason Ekstrand3ec57f52013-11-14 20:52:35 -0600439 fb->bo);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200440 }
441}
442
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500443static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200444drm_output_check_scanout_format(struct drm_output *output,
445 struct weston_surface *es, struct gbm_bo *bo)
446{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200447 uint32_t format;
448 pixman_region32_t r;
449
450 format = gbm_bo_get_format(bo);
451
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700452 if (format == GBM_FORMAT_ARGB8888) {
453 /* We can scanout an ARGB buffer if the surface's
454 * opaque region covers the whole output, but we have
455 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -0800456 pixman_region32_init_rect(&r, 0, 0,
457 output->base.width,
458 output->base.height);
459 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200460
461 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500462 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200463
464 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500465 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700466
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000467 if (output->format == format)
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700468 return format;
469
470 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200471}
472
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400473static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200474drm_output_prepare_scanout_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500475 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500476{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300477 struct drm_backend *b =
478 (struct drm_backend *)output->base.compositor->backend;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500479 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200480 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300481 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500482 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500483
Jason Ekstranda7af7042013-10-12 22:38:11 -0500484 if (ev->geometry.x != output->base.x ||
485 ev->geometry.y != output->base.y ||
Giulio Camuffo954f1832014-10-11 18:27:30 +0300486 buffer == NULL || b->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200487 buffer->width != output->base.current_mode->width ||
488 buffer->height != output->base.current_mode->height ||
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200489 output->base.transform != viewport->buffer.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500490 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400491 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500492
Pekka Paalanen5580f222015-02-17 16:33:18 +0200493 if (ev->geometry.scissor_enabled)
494 return NULL;
495
Giulio Camuffo954f1832014-10-11 18:27:30 +0300496 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700497 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500498
Rob Bradford9b101872012-09-14 23:25:41 +0100499 /* Unable to use the buffer for scanout */
500 if (!bo)
501 return NULL;
502
Jason Ekstranda7af7042013-10-12 22:38:11 -0500503 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500504 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300505 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400506 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300507 }
508
Giulio Camuffo954f1832014-10-11 18:27:30 +0300509 output->next = drm_fb_get_from_bo(bo, b, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300510 if (!output->next) {
511 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400512 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300513 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500514
Pekka Paalanende685b82012-12-04 15:58:12 +0200515 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500516
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400517 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500518}
519
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500520static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200521drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400522{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300523 struct drm_backend *b =
524 (struct drm_backend *)output->base.compositor->backend;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300525 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400526
Giulio Camuffo954f1832014-10-11 18:27:30 +0300527 output->base.compositor->renderer->repaint_output(&output->base,
528 damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400529
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300530 bo = gbm_surface_lock_front_buffer(output->surface);
531 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200532 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400533 return;
534 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300535
Giulio Camuffo954f1832014-10-11 18:27:30 +0300536 output->next = drm_fb_get_from_bo(bo, b, output->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300537 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200538 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300539 gbm_surface_release_buffer(output->surface, bo);
540 return;
541 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400542}
543
544static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200545drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
546{
547 struct weston_compositor *ec = output->base.compositor;
548 pixman_region32_t total_damage, previous_damage;
549
550 pixman_region32_init(&total_damage);
551 pixman_region32_init(&previous_damage);
552
553 pixman_region32_copy(&previous_damage, damage);
554
555 pixman_region32_union(&total_damage, damage, &output->previous_damage);
556 pixman_region32_copy(&output->previous_damage, &previous_damage);
557
558 output->current_image ^= 1;
559
560 output->next = output->dumb[output->current_image];
561 pixman_renderer_output_set_buffer(&output->base,
562 output->image[output->current_image]);
563
564 ec->renderer->repaint_output(&output->base, &total_damage);
565
566 pixman_region32_fini(&total_damage);
567 pixman_region32_fini(&previous_damage);
568}
569
570static void
571drm_output_render(struct drm_output *output, pixman_region32_t *damage)
572{
Giulio Camuffo954f1832014-10-11 18:27:30 +0300573 struct weston_compositor *c = output->base.compositor;
574 struct drm_backend *b = (struct drm_backend *)c->backend;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200575
Giulio Camuffo954f1832014-10-11 18:27:30 +0300576 if (b->use_pixman)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200577 drm_output_render_pixman(output, damage);
578 else
579 drm_output_render_gl(output, damage);
580
Giulio Camuffo954f1832014-10-11 18:27:30 +0300581 pixman_region32_subtract(&c->primary_plane.damage,
582 &c->primary_plane.damage, damage);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200583}
584
585static void
Richard Hughese7299962013-05-01 21:52:12 +0100586drm_output_set_gamma(struct weston_output *output_base,
587 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
588{
589 int rc;
590 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300591 struct drm_backend *backend =
592 (struct drm_backend *) output->base.compositor->backend;
Richard Hughese7299962013-05-01 21:52:12 +0100593
594 /* check */
595 if (output_base->gamma_size != size)
596 return;
597 if (!output->original_crtc)
598 return;
599
Giulio Camuffo954f1832014-10-11 18:27:30 +0300600 rc = drmModeCrtcSetGamma(backend->drm.fd,
Richard Hughese7299962013-05-01 21:52:12 +0100601 output->crtc_id,
602 size, r, g, b);
603 if (rc)
604 weston_log("set gamma failed: %m\n");
605}
606
Bryce Harringtonada4f072015-06-30 13:25:46 -0700607/* Determine the type of vblank synchronization to use for the output.
608 *
609 * The pipe parameter indicates which CRTC is in use. Knowing this, we
610 * can determine which vblank sequence type to use for it. Traditional
611 * cards had only two CRTCs, with CRTC 0 using no special flags, and
612 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
613 * parameter indicates this.
614 *
615 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
616 * 0-31. If this is non-zero it indicates we're dealing with a
617 * multi-gpu situation and we need to calculate the vblank sync
618 * using DRM_BLANK_HIGH_CRTC_MASK.
619 */
Pekka Paalanenc8a1ff02015-07-02 15:06:08 +0300620static unsigned int
621drm_waitvblank_pipe(struct drm_output *output)
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +0200622{
623 if (output->pipe > 1)
624 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
625 DRM_VBLANK_HIGH_CRTC_MASK;
626 else if (output->pipe > 0)
627 return DRM_VBLANK_SECONDARY;
628 else
629 return 0;
630}
631
David Herrmann1edf44c2013-10-22 17:11:26 +0200632static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500633drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400634 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100635{
636 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300637 struct drm_backend *backend =
638 (struct drm_backend *)output->base.compositor->backend;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500639 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400640 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500641 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100642
Xiong Zhangabd5d472013-10-11 14:43:07 +0800643 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200644 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800645
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300646 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400647 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300648 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200649 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100650
Hardeningff39efa2013-09-18 23:56:35 +0200651 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200652 if (!output->current ||
653 output->current->stride != output->next->stride) {
Giulio Camuffo954f1832014-10-11 18:27:30 +0300654 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300655 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400656 &output->connector_id, 1,
657 &mode->mode_info);
658 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200659 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200660 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400661 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300662 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200663 }
664
Giulio Camuffo954f1832014-10-11 18:27:30 +0300665 if (drmModePageFlip(backend->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300666 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500667 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200668 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200669 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500670 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100671
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300672 output->page_flip_pending = 1;
673
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400674 drm_output_set_cursor(output);
675
Jesse Barnes58ef3792012-02-23 09:45:49 -0500676 /*
677 * Now, update all the sprite surfaces
678 */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300679 wl_list_for_each(s, &backend->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200680 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500681 drmVBlank vbl = {
682 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
683 .request.sequence = 1,
684 };
685
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200686 if ((!s->current && !s->next) ||
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200687 !drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500688 continue;
689
Giulio Camuffo954f1832014-10-11 18:27:30 +0300690 if (s->next && !backend->sprites_hidden)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200691 fb_id = s->next->fb_id;
692
Giulio Camuffo954f1832014-10-11 18:27:30 +0300693 ret = drmModeSetPlane(backend->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200694 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500695 s->dest_x, s->dest_y,
696 s->dest_w, s->dest_h,
697 s->src_x, s->src_y,
698 s->src_w, s->src_h);
699 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200700 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500701 ret, strerror(errno));
702
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +0200703 vbl.request.type |= drm_waitvblank_pipe(output);
Rob Clark5ca1a472012-08-08 20:27:37 -0500704
Jesse Barnes58ef3792012-02-23 09:45:49 -0500705 /*
706 * Queue a vblank signal so we know when the surface
707 * becomes active on the display or has been replaced.
708 */
709 vbl.request.signal = (unsigned long)s;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300710 ret = drmWaitVBlank(backend->drm.fd, &vbl);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500711 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200712 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500713 ret, strerror(errno));
714 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300715
716 s->output = output;
717 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500718 }
719
David Herrmann1edf44c2013-10-22 17:11:26 +0200720 return 0;
721
722err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800723 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200724 if (output->next) {
725 drm_output_release_fb(output, output->next);
726 output->next = NULL;
727 }
728
729 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400730}
731
732static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200733drm_output_start_repaint_loop(struct weston_output *output_base)
734{
735 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300736 struct drm_backend *backend = (struct drm_backend *)
737 output_base->compositor->backend;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200738 uint32_t fb_id;
Mario Kleinerf507ec32015-06-21 21:25:14 +0200739 struct timespec ts, tnow;
740 struct timespec vbl2now;
741 int64_t refresh_nsec;
742 int ret;
743 drmVBlank vbl = {
744 .request.type = DRM_VBLANK_RELATIVE,
745 .request.sequence = 0,
746 .request.signal = 0,
747 };
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300748
Xiong Zhangabd5d472013-10-11 14:43:07 +0800749 if (output->destroy_pending)
750 return;
751
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300752 if (!output->current) {
753 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200754 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300755 }
756
Mario Kleinerf507ec32015-06-21 21:25:14 +0200757 /* Try to get current msc and timestamp via instant query */
758 vbl.request.type |= drm_waitvblank_pipe(output);
759 ret = drmWaitVBlank(backend->drm.fd, &vbl);
760
761 /* Error ret or zero timestamp means failure to get valid timestamp */
762 if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
763 ts.tv_sec = vbl.reply.tval_sec;
764 ts.tv_nsec = vbl.reply.tval_usec * 1000;
765
766 /* Valid timestamp for most recent vblank - not stale?
767 * Stale ts could happen on Linux 3.17+, so make sure it
768 * is not older than 1 refresh duration since now.
769 */
770 weston_compositor_read_presentation_clock(backend->compositor,
771 &tnow);
772 timespec_sub(&vbl2now, &tnow, &ts);
773 refresh_nsec =
774 millihz_to_nsec(output->base.current_mode->refresh);
775 if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
776 drm_output_update_msc(output, vbl.reply.sequence);
777 weston_output_finish_frame(output_base, &ts,
778 PRESENTATION_FEEDBACK_INVALID);
779 return;
780 }
781 }
782
783 /* Immediate query didn't provide valid timestamp.
784 * Use pageflip fallback.
785 */
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300786 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200787
Giulio Camuffo954f1832014-10-11 18:27:30 +0300788 if (drmModePageFlip(backend->drm.fd, output->crtc_id, fb_id,
Jonas Ådahle5a12252013-04-05 23:07:11 +0200789 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
790 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200791 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200792 }
David Herrmann3c688c52013-10-22 17:11:25 +0200793
794 return;
795
796finish_frame:
797 /* if we cannot page-flip, immediately finish frame */
Giulio Camuffo954f1832014-10-11 18:27:30 +0300798 weston_compositor_read_presentation_clock(output_base->compositor, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200799 weston_output_finish_frame(output_base, &ts,
800 PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200801}
802
803static void
Pekka Paalanen641307c2014-09-23 22:08:47 -0400804drm_output_update_msc(struct drm_output *output, unsigned int seq)
805{
806 uint64_t msc_hi = output->base.msc >> 32;
807
808 if (seq < (output->base.msc & 0xffffffff))
809 msc_hi++;
810
811 output->base.msc = (msc_hi << 32) + seq;
812}
813
814static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500815vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
816 void *data)
817{
818 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300819 struct drm_output *output = s->output;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400820 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200821 uint32_t flags = PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
822 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300823
Pekka Paalanen641307c2014-09-23 22:08:47 -0400824 drm_output_update_msc(output, frame);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300825 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500826
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200827 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200828 s->current = s->next;
829 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300830
831 if (!output->page_flip_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400832 ts.tv_sec = sec;
833 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200834 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300835 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500836}
837
838static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800839drm_output_destroy(struct weston_output *output_base);
840
841static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400842page_flip_handler(int fd, unsigned int frame,
843 unsigned int sec, unsigned int usec, void *data)
844{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200845 struct drm_output *output = (struct drm_output *) data;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400846 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200847 uint32_t flags = PRESENTATION_FEEDBACK_KIND_VSYNC |
848 PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
849 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400850
Pekka Paalanen641307c2014-09-23 22:08:47 -0400851 drm_output_update_msc(output, frame);
852
Jonas Ådahle5a12252013-04-05 23:07:11 +0200853 /* We don't set page_flip_pending on start_repaint_loop, in that case
854 * we just want to page flip to the current buffer to get an accurate
855 * timestamp */
856 if (output->page_flip_pending) {
857 drm_output_release_fb(output, output->current);
858 output->current = output->next;
859 output->next = NULL;
860 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300861
Jonas Ådahle5a12252013-04-05 23:07:11 +0200862 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400863
Xiong Zhangabd5d472013-10-11 14:43:07 +0800864 if (output->destroy_pending)
865 drm_output_destroy(&output->base);
866 else if (!output->vblank_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400867 ts.tv_sec = sec;
868 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200869 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300870
871 /* We can't call this from frame_notify, because the output's
872 * repaint needed flag is cleared just after that */
873 if (output->recorder)
874 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300875 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200876}
877
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500878static uint32_t
879drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500880 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500881{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500882 uint32_t i, format;
883
884 format = gbm_bo_get_format(bo);
885
886 if (format == GBM_FORMAT_ARGB8888) {
887 pixman_region32_t r;
888
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500889 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600890 ev->surface->width,
891 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500892 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500893
894 if (!pixman_region32_not_empty(&r))
895 format = GBM_FORMAT_XRGB8888;
896
897 pixman_region32_fini(&r);
898 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500899
900 for (i = 0; i < s->count_formats; i++)
901 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500902 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500903
904 return 0;
905}
906
907static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500908drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500909{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500910 return !ev->transform.enabled ||
911 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500912}
913
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400914static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200915drm_output_prepare_overlay_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500916 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500917{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200918 struct weston_compositor *ec = output->base.compositor;
Giulio Camuffo954f1832014-10-11 18:27:30 +0300919 struct drm_backend *b = (struct drm_backend *)ec->backend;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200920 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500921 struct drm_sprite *s;
922 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500923 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500924 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200925 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500926 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400927 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500928
Giulio Camuffo954f1832014-10-11 18:27:30 +0300929 if (b->gbm == NULL)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200930 return NULL;
931
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200932 if (viewport->buffer.transform != output->base.transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200933 return NULL;
934
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200935 if (viewport->buffer.scale != output->base.current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200936 return NULL;
937
Giulio Camuffo954f1832014-10-11 18:27:30 +0300938 if (b->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400939 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500940
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200941 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400942 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300943
Jason Ekstranda7af7042013-10-12 22:38:11 -0500944 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400945 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500946
Jason Ekstranda7af7042013-10-12 22:38:11 -0500947 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200948 return NULL;
949
Jason Ekstranda7af7042013-10-12 22:38:11 -0500950 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500951 return NULL;
952
Jason Ekstranda7af7042013-10-12 22:38:11 -0500953 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400954 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500955
Giulio Camuffo954f1832014-10-11 18:27:30 +0300956 wl_list_for_each(s, &b->sprite_list, link) {
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200957 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500958 continue;
959
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200960 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500961 found = 1;
962 break;
963 }
964 }
965
966 /* No sprites available */
967 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400968 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500969
Giulio Camuffo954f1832014-10-11 18:27:30 +0300970 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500971 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700972 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400973 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400974 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400975
Jason Ekstranda7af7042013-10-12 22:38:11 -0500976 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500977 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200978 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400979 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500980 }
981
Giulio Camuffo954f1832014-10-11 18:27:30 +0300982 s->next = drm_fb_get_from_bo(bo, b, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200983 if (!s->next) {
984 gbm_bo_destroy(bo);
985 return NULL;
986 }
987
Jason Ekstranda7af7042013-10-12 22:38:11 -0500988 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500989
Jason Ekstranda7af7042013-10-12 22:38:11 -0500990 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400991 s->plane.x = box->x1;
992 s->plane.y = box->y1;
993
Jesse Barnes58ef3792012-02-23 09:45:49 -0500994 /*
995 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -0500996 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500997 * for us already).
998 */
999 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001000 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001001 &output->base.region);
1002 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001003 box = pixman_region32_extents(&dest_rect);
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001004 tbox = weston_transformed_rect(output->base.width,
1005 output->base.height,
1006 output->base.transform,
1007 output->base.current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001008 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001009 s->dest_x = tbox.x1;
1010 s->dest_y = tbox.y1;
1011 s->dest_w = tbox.x2 - tbox.x1;
1012 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001013 pixman_region32_fini(&dest_rect);
1014
1015 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -05001016 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001017 &output->base.region);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001018 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04001019
Jason Ekstranda7af7042013-10-12 22:38:11 -05001020 weston_view_from_global_fixed(ev,
1021 wl_fixed_from_int(box->x1),
1022 wl_fixed_from_int(box->y1),
1023 &sx1, &sy1);
1024 weston_view_from_global_fixed(ev,
1025 wl_fixed_from_int(box->x2),
1026 wl_fixed_from_int(box->y2),
1027 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04001028
1029 if (sx1 < 0)
1030 sx1 = 0;
1031 if (sy1 < 0)
1032 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001033 if (sx2 > wl_fixed_from_int(ev->surface->width))
1034 sx2 = wl_fixed_from_int(ev->surface->width);
1035 if (sy2 > wl_fixed_from_int(ev->surface->height))
1036 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -04001037
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001038 tbox.x1 = sx1;
1039 tbox.y1 = sy1;
1040 tbox.x2 = sx2;
1041 tbox.y2 = sy2;
1042
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001043 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
1044 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +02001045 viewport->buffer.transform,
1046 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +01001047 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001048
1049 s->src_x = tbox.x1 << 8;
1050 s->src_y = tbox.y1 << 8;
1051 s->src_w = (tbox.x2 - tbox.x1) << 8;
1052 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001053 pixman_region32_fini(&src_rect);
1054
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001055 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001056}
1057
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001058static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001059drm_output_prepare_cursor_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001060 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001061{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001062 struct drm_backend *b =
1063 (struct drm_backend *)output->base.compositor->backend;
Neil Robertsf37f82c2014-05-01 18:00:41 +01001064 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001065
Giulio Camuffo954f1832014-10-11 18:27:30 +03001066 if (b->gbm == NULL)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001067 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +02001068 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
1069 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001070 if (viewport->buffer.scale != output->base.current_scale)
Neil Robertsf37f82c2014-05-01 18:00:41 +01001071 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001072 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001073 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001074 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001075 return NULL;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001076 if (b->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -04001077 return NULL;
Pekka Paalanen5580f222015-02-17 16:33:18 +02001078 if (ev->geometry.scissor_enabled)
1079 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001080 if (ev->surface->buffer_ref.buffer == NULL ||
1081 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001082 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001083 return NULL;
1084
Jason Ekstranda7af7042013-10-12 22:38:11 -05001085 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001086
1087 return &output->cursor_plane;
1088}
1089
1090static void
1091drm_output_set_cursor(struct drm_output *output)
1092{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001093 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001094 struct weston_buffer *buffer;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001095 struct drm_backend *b =
1096 (struct drm_backend *) output->base.compositor->backend;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001097 EGLint handle, stride;
1098 struct gbm_bo *bo;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001099 uint32_t buf[b->cursor_width * b->cursor_height];
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001100 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001101 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001102
Jason Ekstranda7af7042013-10-12 22:38:11 -05001103 output->cursor_view = NULL;
1104 if (ev == NULL) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001105 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001106 return;
1107 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001108
Neil Robertse5051712013-11-13 15:44:06 +00001109 buffer = ev->surface->buffer_ref.buffer;
1110
1111 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001112 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001113 pixman_region32_fini(&output->cursor_plane.damage);
1114 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001115 output->current_cursor ^= 1;
1116 bo = output->cursor_bo[output->current_cursor];
1117 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001118 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1119 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1120 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001121 for (i = 0; i < ev->surface->height; i++)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001122 memcpy(buf + i * b->cursor_width, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001123 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001124 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001125
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001126 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001127 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001128
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001129 handle = gbm_bo_get_handle(bo).s32;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001130 if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
1131 b->cursor_width, b->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001132 weston_log("failed to set cursor: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001133 b->cursors_are_broken = 1;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001134 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001135 }
1136
Jason Ekstranda7af7042013-10-12 22:38:11 -05001137 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1138 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001139 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001140 if (drmModeMoveCursor(b->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001141 weston_log("failed to move cursor: %m\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001142 b->cursors_are_broken = 1;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001143 }
1144
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001145 output->cursor_plane.x = x;
1146 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001147 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001148}
1149
Jesse Barnes58ef3792012-02-23 09:45:49 -05001150static void
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001151drm_assign_planes(struct weston_output *output_base)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001152{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001153 struct drm_backend *b =
1154 (struct drm_backend *)output_base->compositor->backend;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001155 struct drm_output *output = (struct drm_output *)output_base;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001156 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001157 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001158 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001159
1160 /*
1161 * Find a surface for each sprite in the output using some heuristics:
1162 * 1) size
1163 * 2) frequency of update
1164 * 3) opacity (though some hw might support alpha blending)
1165 * 4) clipping (this can be fixed with color keys)
1166 *
1167 * The idea is to save on blitting since this should save power.
1168 * If we can get a large video surface on the sprite for example,
1169 * the main display surface may not need to update at all, and
1170 * the client buffer can be used directly for the sprite surface
1171 * as we do for flipping full screen surfaces.
1172 */
1173 pixman_region32_init(&overlap);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001174 primary = &output_base->compositor->primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001175
Giulio Camuffo954f1832014-10-11 18:27:30 +03001176 wl_list_for_each_safe(ev, next, &output_base->compositor->view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001177 struct weston_surface *es = ev->surface;
1178
1179 /* Test whether this buffer can ever go into a plane:
1180 * non-shm, or small enough to be a cursor.
1181 *
1182 * Also, keep a reference when using the pixman renderer.
1183 * That makes it possible to do a seamless switch to the GL
1184 * renderer and since the pixman renderer keeps a reference
1185 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001186 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001187 if (b->use_pixman ||
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001188 (es->buffer_ref.buffer &&
1189 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001190 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001191 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001192 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001193 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001194
Jesse Barnes58ef3792012-02-23 09:45:49 -05001195 pixman_region32_init(&surface_overlap);
1196 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001197 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001198
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001199 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001200 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001201 next_plane = primary;
1202 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001203 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001204 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001205 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001206 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001207 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001208 if (next_plane == NULL)
1209 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001210
Jason Ekstranda7af7042013-10-12 22:38:11 -05001211 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001212
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001213 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001214 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001215 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001216
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001217 if (next_plane == primary ||
1218 next_plane == &output->cursor_plane) {
1219 /* cursor plane involves a copy */
1220 ev->psf_flags = 0;
1221 } else {
1222 /* All other planes are a direct scanout of a
1223 * single client buffer.
1224 */
1225 ev->psf_flags = PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
1226 }
1227
Jesse Barnes58ef3792012-02-23 09:45:49 -05001228 pixman_region32_fini(&surface_overlap);
1229 }
1230 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001231}
1232
Matt Roper361d2ad2011-08-29 13:52:23 -07001233static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001234drm_output_fini_pixman(struct drm_output *output);
1235
1236static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001237drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001238{
1239 struct drm_output *output = (struct drm_output *) output_base;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001240 struct drm_backend *b =
1241 (struct drm_backend *)output->base.compositor->backend;
Matt Roper361d2ad2011-08-29 13:52:23 -07001242 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001243
Xiong Zhangabd5d472013-10-11 14:43:07 +08001244 if (output->page_flip_pending) {
1245 output->destroy_pending = 1;
1246 weston_log("destroy output while page flip pending\n");
1247 return;
1248 }
1249
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001250 if (output->backlight)
1251 backlight_destroy(output->backlight);
1252
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001253 drmModeFreeProperty(output->dpms_prop);
1254
Matt Roper361d2ad2011-08-29 13:52:23 -07001255 /* Turn off hardware cursor */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001256 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001257
1258 /* Restore original CRTC state */
Giulio Camuffo954f1832014-10-11 18:27:30 +03001259 drmModeSetCrtc(b->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001260 origcrtc->x, origcrtc->y,
1261 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001262 drmModeFreeCrtc(origcrtc);
1263
Giulio Camuffo954f1832014-10-11 18:27:30 +03001264 b->crtc_allocator &= ~(1 << output->crtc_id);
1265 b->connector_allocator &= ~(1 << output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001266
Giulio Camuffo954f1832014-10-11 18:27:30 +03001267 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001268 drm_output_fini_pixman(output);
1269 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001270 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001271 gbm_surface_destroy(output->surface);
1272 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001273
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001274 weston_plane_release(&output->fb_plane);
1275 weston_plane_release(&output->cursor_plane);
1276
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001277 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001278
Matt Roper361d2ad2011-08-29 13:52:23 -07001279 free(output);
1280}
1281
Alex Wub7b8bda2012-04-17 17:20:48 +08001282static struct drm_mode *
1283choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1284{
1285 struct drm_mode *tmp_mode = NULL, *mode;
1286
Hardeningff39efa2013-09-18 23:56:35 +02001287 if (output->base.current_mode->width == target_mode->width &&
1288 output->base.current_mode->height == target_mode->height &&
1289 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001290 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001291 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001292
1293 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1294 if (mode->mode_info.hdisplay == target_mode->width &&
1295 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02001296 if (mode->base.refresh == target_mode->refresh ||
1297 target_mode->refresh == 0) {
Alex Wub7b8bda2012-04-17 17:20:48 +08001298 return mode;
Daniel Stonef556ebe2015-05-21 08:28:58 +01001299 } else if (!tmp_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001300 tmp_mode = mode;
1301 }
1302 }
1303
1304 return tmp_mode;
1305}
1306
1307static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001308drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001309static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001310drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001311
1312static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001313drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1314{
1315 struct drm_output *output;
1316 struct drm_mode *drm_mode;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001317 struct drm_backend *b;
Alex Wub7b8bda2012-04-17 17:20:48 +08001318
1319 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001320 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001321 return -1;
1322 }
1323
1324 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001325 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001326 return -1;
1327 }
1328
Giulio Camuffo954f1832014-10-11 18:27:30 +03001329 b = (struct drm_backend *)output_base->compositor->backend;
Alex Wub7b8bda2012-04-17 17:20:48 +08001330 output = (struct drm_output *)output_base;
1331 drm_mode = choose_mode (output, mode);
1332
1333 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001334 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001335 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001336 }
1337
Hardeningff39efa2013-09-18 23:56:35 +02001338 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001339 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001340
Hardeningff39efa2013-09-18 23:56:35 +02001341 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001342
Hardeningff39efa2013-09-18 23:56:35 +02001343 output->base.current_mode = &drm_mode->base;
1344 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001345 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1346
Alex Wub7b8bda2012-04-17 17:20:48 +08001347 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001348 drm_output_release_fb(output, output->current);
1349 drm_output_release_fb(output, output->next);
1350 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001351
Giulio Camuffo954f1832014-10-11 18:27:30 +03001352 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001353 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001354 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001355 weston_log("failed to init output pixman state with "
1356 "new mode\n");
1357 return -1;
1358 }
1359 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001360 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001361 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001362
Giulio Camuffo954f1832014-10-11 18:27:30 +03001363 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001364 weston_log("failed to init output egl state with "
1365 "new mode");
1366 return -1;
1367 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001368 }
1369
Alex Wub7b8bda2012-04-17 17:20:48 +08001370 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001371}
1372
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001373static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001374on_drm_input(int fd, uint32_t mask, void *data)
1375{
1376 drmEventContext evctx;
1377
1378 memset(&evctx, 0, sizeof evctx);
1379 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1380 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001381 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001382 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001383
1384 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001385}
1386
1387static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001388init_drm(struct drm_backend *b, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001389{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001390 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001391 uint64_t cap;
1392 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001393 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001394
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001395 sysnum = udev_device_get_sysnum(device);
1396 if (sysnum)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001397 b->drm.id = atoi(sysnum);
1398 if (!sysnum || b->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001399 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001400 return -1;
1401 }
1402
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001403 filename = udev_device_get_devnode(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001404 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001405 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001406 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001407 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001408 udev_device_get_devnode(device));
1409 return -1;
1410 }
1411
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001412 weston_log("using %s\n", filename);
1413
Giulio Camuffo954f1832014-10-11 18:27:30 +03001414 b->drm.fd = fd;
1415 b->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001416
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001417 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1418 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001419 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001420 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001421 clk_id = CLOCK_REALTIME;
1422
Giulio Camuffo954f1832014-10-11 18:27:30 +03001423 if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001424 weston_log("Error: failed to set presentation clock %d.\n",
1425 clk_id);
1426 return -1;
1427 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001428
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001429 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1430 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001431 b->cursor_width = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001432 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03001433 b->cursor_width = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001434
1435 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1436 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001437 b->cursor_height = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001438 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03001439 b->cursor_height = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001440
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001441 return 0;
1442}
1443
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001444static struct gbm_device *
1445create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001446{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001447 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001448
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001449 gl_renderer = weston_load_module("gl-renderer.so",
1450 "gl_renderer_interface");
1451 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001452 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001453
1454 /* GBM will load a dri driver, but even though they need symbols from
1455 * libglapi, in some version of Mesa they are not linked to it. Since
1456 * only the gl-renderer module links to it, the call above won't make
1457 * these symbols globally available, and loading the DRI driver fails.
1458 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1459 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1460
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001461 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001462
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001463 return gbm;
1464}
1465
Bryce Harringtonc056a982015-05-19 15:25:18 -07001466/* When initializing EGL, if the preferred buffer format isn't available
Derek Foremanc4cfe852015-05-15 12:12:40 -05001467 * we may be able to susbstitute an ARGB format for an XRGB one.
1468 *
1469 * This returns 0 if substitution isn't possible, but 0 might be a
1470 * legitimate format for other EGL platforms, so the caller is
1471 * responsible for checking for 0 before calling gl_renderer->create().
1472 *
1473 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
1474 * but it's entirely possible we'll see this again on other implementations.
1475 */
1476static int
1477fallback_format_for(uint32_t format)
1478{
1479 switch (format) {
1480 case GBM_FORMAT_XRGB8888:
1481 return GBM_FORMAT_ARGB8888;
1482 case GBM_FORMAT_XRGB2101010:
1483 return GBM_FORMAT_ARGB2101010;
1484 default:
1485 return 0;
1486 }
1487}
1488
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001489static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001490drm_backend_create_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001491{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001492 EGLint format[2] = {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001493 b->format,
1494 fallback_format_for(b->format),
Derek Foremanc4cfe852015-05-15 12:12:40 -05001495 };
1496 int n_formats = 1;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001497
Derek Foremanc4cfe852015-05-15 12:12:40 -05001498 if (format[1])
1499 n_formats = 2;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001500 if (gl_renderer->create(b->compositor,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001501 EGL_PLATFORM_GBM_KHR,
Giulio Camuffo954f1832014-10-11 18:27:30 +03001502 (void *)b->gbm,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001503 gl_renderer->opaque_attribs,
1504 format,
1505 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001506 return -1;
1507 }
1508
1509 return 0;
1510}
1511
1512static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001513init_egl(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001514{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001515 b->gbm = create_gbm_device(b->drm.fd);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001516
Giulio Camuffo954f1832014-10-11 18:27:30 +03001517 if (!b->gbm)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001518 return -1;
1519
Giulio Camuffo954f1832014-10-11 18:27:30 +03001520 if (drm_backend_create_gl_renderer(b) < 0) {
1521 gbm_device_destroy(b->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001522 return -1;
1523 }
1524
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001525 return 0;
1526}
1527
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001528static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001529init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001530{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001531 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001532}
1533
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001534static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001535drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001536{
1537 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001538 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001539
1540 mode = malloc(sizeof *mode);
1541 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001542 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001543
1544 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001545 mode->base.width = info->hdisplay;
1546 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001547
1548 /* Calculate higher precision (mHz) refresh rate */
1549 refresh = (info->clock * 1000000LL / info->htotal +
1550 info->vtotal / 2) / info->vtotal;
1551
1552 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1553 refresh *= 2;
1554 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1555 refresh /= 2;
1556 if (info->vscan > 1)
1557 refresh /= info->vscan;
1558
1559 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001560 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001561
1562 if (info->type & DRM_MODE_TYPE_PREFERRED)
1563 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1564
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001565 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1566
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001567 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001568}
1569
1570static int
1571drm_subpixel_to_wayland(int drm_value)
1572{
1573 switch (drm_value) {
1574 default:
1575 case DRM_MODE_SUBPIXEL_UNKNOWN:
1576 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1577 case DRM_MODE_SUBPIXEL_NONE:
1578 return WL_OUTPUT_SUBPIXEL_NONE;
1579 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1580 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1581 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1582 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1583 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1584 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1585 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1586 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1587 }
1588}
1589
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001590/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001591static uint32_t
1592drm_get_backlight(struct drm_output *output)
1593{
1594 long brightness, max_brightness, norm;
1595
1596 brightness = backlight_get_brightness(output->backlight);
1597 max_brightness = backlight_get_max_brightness(output->backlight);
1598
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001599 /* convert it on a scale of 0 to 255 */
1600 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001601
1602 return (uint32_t) norm;
1603}
1604
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001605/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001606static void
1607drm_set_backlight(struct weston_output *output_base, uint32_t value)
1608{
1609 struct drm_output *output = (struct drm_output *) output_base;
1610 long max_brightness, new_brightness;
1611
1612 if (!output->backlight)
1613 return;
1614
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001615 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001616 return;
1617
1618 max_brightness = backlight_get_max_brightness(output->backlight);
1619
1620 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001621 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001622
1623 backlight_set_brightness(output->backlight, new_brightness);
1624}
1625
1626static drmModePropertyPtr
1627drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1628{
1629 drmModePropertyPtr props;
1630 int i;
1631
1632 for (i = 0; i < connector->count_props; i++) {
1633 props = drmModeGetProperty(fd, connector->props[i]);
1634 if (!props)
1635 continue;
1636
1637 if (!strcmp(props->name, name))
1638 return props;
1639
1640 drmModeFreeProperty(props);
1641 }
1642
1643 return NULL;
1644}
1645
1646static void
1647drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1648{
1649 struct drm_output *output = (struct drm_output *) output_base;
1650 struct weston_compositor *ec = output_base->compositor;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001651 struct drm_backend *b = (struct drm_backend *)ec->backend;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001652
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001653 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001654 return;
1655
Giulio Camuffo954f1832014-10-11 18:27:30 +03001656 drmModeConnectorSetProperty(b->drm.fd, output->connector_id,
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001657 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001658}
1659
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001660static const char *connector_type_names[] = {
1661 "None",
1662 "VGA",
1663 "DVI",
1664 "DVI",
1665 "DVI",
1666 "Composite",
1667 "TV",
1668 "LVDS",
1669 "CTV",
1670 "DIN",
1671 "DP",
1672 "HDMI",
1673 "HDMI",
1674 "TV",
1675 "eDP",
1676};
1677
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001678static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001679find_crtc_for_connector(struct drm_backend *b,
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001680 drmModeRes *resources, drmModeConnector *connector)
1681{
1682 drmModeEncoder *encoder;
1683 uint32_t possible_crtcs;
1684 int i, j;
1685
1686 for (j = 0; j < connector->count_encoders; j++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001687 encoder = drmModeGetEncoder(b->drm.fd, connector->encoders[j]);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001688 if (encoder == NULL) {
1689 weston_log("Failed to get encoder.\n");
1690 return -1;
1691 }
1692 possible_crtcs = encoder->possible_crtcs;
1693 drmModeFreeEncoder(encoder);
1694
1695 for (i = 0; i < resources->count_crtcs; i++) {
1696 if (possible_crtcs & (1 << i) &&
Giulio Camuffo954f1832014-10-11 18:27:30 +03001697 !(b->crtc_allocator & (1 << resources->crtcs[i])))
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001698 return i;
1699 }
1700 }
1701
1702 return -1;
1703}
1704
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001705/* Init output state that depends on gl or gbm */
1706static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001707drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001708{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001709 EGLint format[2] = {
1710 output->format,
1711 fallback_format_for(output->format),
1712 };
1713 int i, flags, n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001714
Giulio Camuffo954f1832014-10-11 18:27:30 +03001715 output->surface = gbm_surface_create(b->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001716 output->base.current_mode->width,
1717 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001718 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001719 GBM_BO_USE_SCANOUT |
1720 GBM_BO_USE_RENDERING);
1721 if (!output->surface) {
1722 weston_log("failed to create gbm surface\n");
1723 return -1;
1724 }
1725
Derek Foremanc4cfe852015-05-15 12:12:40 -05001726 if (format[1])
1727 n_formats = 2;
Jonny Lamb671148f2015-03-20 15:26:52 +01001728 if (gl_renderer->output_create(&output->base,
Jonny Lamb445fb692015-03-24 13:12:01 +01001729 (EGLNativeDisplayType)output->surface,
1730 output->surface,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001731 gl_renderer->opaque_attribs,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001732 format,
1733 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001734 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001735 gbm_surface_destroy(output->surface);
1736 return -1;
1737 }
1738
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001739 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001740
1741 for (i = 0; i < 2; i++) {
1742 if (output->cursor_bo[i])
1743 continue;
1744
1745 output->cursor_bo[i] =
Giulio Camuffo954f1832014-10-11 18:27:30 +03001746 gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001747 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001748 }
1749
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001750 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1751 weston_log("cursor buffers unavailable, using gl cursors\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001752 b->cursors_are_broken = 1;
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001753 }
1754
1755 return 0;
1756}
1757
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001758static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001759drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001760{
Hardeningff39efa2013-09-18 23:56:35 +02001761 int w = output->base.current_mode->width;
1762 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001763 unsigned int i;
1764
1765 /* FIXME error checking */
1766
1767 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001768 output->dumb[i] = drm_fb_create_dumb(b, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001769 if (!output->dumb[i])
1770 goto err;
1771
1772 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001773 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001774 output->dumb[i]->map,
1775 output->dumb[i]->stride);
1776 if (!output->image[i])
1777 goto err;
1778 }
1779
1780 if (pixman_renderer_output_create(&output->base) < 0)
1781 goto err;
1782
1783 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001784 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001785
1786 return 0;
1787
1788err:
1789 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1790 if (output->dumb[i])
1791 drm_fb_destroy_dumb(output->dumb[i]);
1792 if (output->image[i])
1793 pixman_image_unref(output->image[i]);
1794
1795 output->dumb[i] = NULL;
1796 output->image[i] = NULL;
1797 }
1798
1799 return -1;
1800}
1801
1802static void
1803drm_output_fini_pixman(struct drm_output *output)
1804{
1805 unsigned int i;
1806
1807 pixman_renderer_output_destroy(&output->base);
1808 pixman_region32_fini(&output->previous_damage);
1809
1810 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1811 drm_fb_destroy_dumb(output->dumb[i]);
1812 pixman_image_unref(output->image[i]);
1813 output->dumb[i] = NULL;
1814 output->image[i] = NULL;
1815 }
1816}
1817
Richard Hughes2b2092a2013-04-24 14:58:02 +01001818static void
1819edid_parse_string(const uint8_t *data, char text[])
1820{
1821 int i;
1822 int replaced = 0;
1823
1824 /* this is always 12 bytes, but we can't guarantee it's null
1825 * terminated or not junk. */
1826 strncpy(text, (const char *) data, 12);
1827
1828 /* remove insane chars */
1829 for (i = 0; text[i] != '\0'; i++) {
1830 if (text[i] == '\n' ||
1831 text[i] == '\r') {
1832 text[i] = '\0';
1833 break;
1834 }
1835 }
1836
1837 /* ensure string is printable */
1838 for (i = 0; text[i] != '\0'; i++) {
1839 if (!isprint(text[i])) {
1840 text[i] = '-';
1841 replaced++;
1842 }
1843 }
1844
1845 /* if the string is random junk, ignore the string */
1846 if (replaced > 4)
1847 text[0] = '\0';
1848}
1849
1850#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1851#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1852#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1853#define EDID_OFFSET_DATA_BLOCKS 0x36
1854#define EDID_OFFSET_LAST_BLOCK 0x6c
1855#define EDID_OFFSET_PNPID 0x08
1856#define EDID_OFFSET_SERIAL 0x0c
1857
1858static int
1859edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1860{
1861 int i;
1862 uint32_t serial_number;
1863
1864 /* check header */
1865 if (length < 128)
1866 return -1;
1867 if (data[0] != 0x00 || data[1] != 0xff)
1868 return -1;
1869
1870 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1871 * /--08--\/--09--\
1872 * 7654321076543210
1873 * |\---/\---/\---/
1874 * R C1 C2 C3 */
1875 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1876 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1877 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1878 edid->pnp_id[3] = '\0';
1879
1880 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1881 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1882 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1883 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1884 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1885 if (serial_number > 0)
1886 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1887
1888 /* parse EDID data */
1889 for (i = EDID_OFFSET_DATA_BLOCKS;
1890 i <= EDID_OFFSET_LAST_BLOCK;
1891 i += 18) {
1892 /* ignore pixel clock data */
1893 if (data[i] != 0)
1894 continue;
1895 if (data[i+2] != 0)
1896 continue;
1897
1898 /* any useful blocks? */
1899 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1900 edid_parse_string(&data[i+5],
1901 edid->monitor_name);
1902 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1903 edid_parse_string(&data[i+5],
1904 edid->serial_number);
1905 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1906 edid_parse_string(&data[i+5],
1907 edid->eisa_id);
1908 }
1909 }
1910 return 0;
1911}
1912
1913static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03001914find_and_parse_output_edid(struct drm_backend *b,
Richard Hughes2b2092a2013-04-24 14:58:02 +01001915 struct drm_output *output,
1916 drmModeConnector *connector)
1917{
1918 drmModePropertyBlobPtr edid_blob = NULL;
1919 drmModePropertyPtr property;
1920 int i;
1921 int rc;
1922
1923 for (i = 0; i < connector->count_props && !edid_blob; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001924 property = drmModeGetProperty(b->drm.fd, connector->props[i]);
Richard Hughes2b2092a2013-04-24 14:58:02 +01001925 if (!property)
1926 continue;
1927 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1928 !strcmp(property->name, "EDID")) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001929 edid_blob = drmModeGetPropertyBlob(b->drm.fd,
Richard Hughes2b2092a2013-04-24 14:58:02 +01001930 connector->prop_values[i]);
1931 }
1932 drmModeFreeProperty(property);
1933 }
1934 if (!edid_blob)
1935 return;
1936
1937 rc = edid_parse(&output->edid,
1938 edid_blob->data,
1939 edid_blob->length);
1940 if (!rc) {
1941 weston_log("EDID data '%s', '%s', '%s'\n",
1942 output->edid.pnp_id,
1943 output->edid.monitor_name,
1944 output->edid.serial_number);
1945 if (output->edid.pnp_id[0] != '\0')
1946 output->base.make = output->edid.pnp_id;
1947 if (output->edid.monitor_name[0] != '\0')
1948 output->base.model = output->edid.monitor_name;
1949 if (output->edid.serial_number[0] != '\0')
1950 output->base.serial_number = output->edid.serial_number;
1951 }
1952 drmModeFreePropertyBlob(edid_blob);
1953}
1954
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001955
1956
1957static int
1958parse_modeline(const char *s, drmModeModeInfo *mode)
1959{
1960 char hsync[16];
1961 char vsync[16];
1962 float fclock;
1963
1964 mode->type = DRM_MODE_TYPE_USERDEF;
1965 mode->hskew = 0;
1966 mode->vscan = 0;
1967 mode->vrefresh = 0;
1968 mode->flags = 0;
1969
Rob Bradford307e09e2013-07-26 16:29:40 +01001970 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001971 &fclock,
1972 &mode->hdisplay,
1973 &mode->hsync_start,
1974 &mode->hsync_end,
1975 &mode->htotal,
1976 &mode->vdisplay,
1977 &mode->vsync_start,
1978 &mode->vsync_end,
1979 &mode->vtotal, hsync, vsync) != 11)
1980 return -1;
1981
1982 mode->clock = fclock * 1000;
1983 if (strcmp(hsync, "+hsync") == 0)
1984 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1985 else if (strcmp(hsync, "-hsync") == 0)
1986 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1987 else
1988 return -1;
1989
1990 if (strcmp(vsync, "+vsync") == 0)
1991 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1992 else if (strcmp(vsync, "-vsync") == 0)
1993 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1994 else
1995 return -1;
1996
1997 return 0;
1998}
1999
Rob Bradford66bd9f52013-06-25 18:56:42 +01002000static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002001setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01002002 struct weston_output *output,
2003 const char *s)
2004{
2005 if (strcmp(s, "") != 0) {
2006 struct udev_seat *seat;
2007
Giulio Camuffo954f1832014-10-11 18:27:30 +03002008 seat = udev_seat_get_named(&b->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01002009 if (seat)
2010 seat->base.output = output;
2011
2012 if (seat && seat->base.pointer)
2013 weston_pointer_clamp(seat->base.pointer,
2014 &seat->base.pointer->x,
2015 &seat->base.pointer->y);
2016 }
2017}
2018
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002019static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002020get_gbm_format_from_section(struct weston_config_section *section,
2021 uint32_t default_value,
2022 uint32_t *format)
2023{
2024 char *s;
2025 int ret = 0;
2026
2027 weston_config_section_get_string(section,
2028 "gbm-format", &s, NULL);
2029
2030 if (s == NULL)
2031 *format = default_value;
2032 else if (strcmp(s, "xrgb8888") == 0)
2033 *format = GBM_FORMAT_XRGB8888;
2034 else if (strcmp(s, "rgb565") == 0)
2035 *format = GBM_FORMAT_RGB565;
2036 else if (strcmp(s, "xrgb2101010") == 0)
2037 *format = GBM_FORMAT_XRGB2101010;
2038 else {
2039 weston_log("fatal: unrecognized pixel format: %s\n", s);
2040 ret = -1;
2041 }
2042
2043 free(s);
2044
2045 return ret;
2046}
2047
2048static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002049create_output_for_connector(struct drm_backend *b,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002050 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002051 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002052 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002053{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002054 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002055 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002056 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002057 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002058 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002059 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002060 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002061 int i, width, height, scale;
2062 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002063 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002064 enum output_config config;
2065 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002066
Giulio Camuffo954f1832014-10-11 18:27:30 +03002067 i = find_crtc_for_connector(b, resources, connector);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002068 if (i < 0) {
2069 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002070 return -1;
2071 }
2072
Peter Huttererf3d62272013-08-08 11:57:05 +10002073 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002074 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002075 return -1;
2076
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002077 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
2078 output->base.make = "unknown";
2079 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01002080 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002081 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002082
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002083 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
2084 type_name = connector_type_names[connector->connector_type];
2085 else
2086 type_name = "UNKNOWN";
2087 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01002088 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002089
Giulio Camuffo954f1832014-10-11 18:27:30 +03002090 section = weston_config_get_section(b->compositor->config, "output", "name",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002091 output->base.name);
2092 weston_config_section_get_string(section, "mode", &s, "preferred");
2093 if (strcmp(s, "off") == 0)
2094 config = OUTPUT_CONFIG_OFF;
2095 else if (strcmp(s, "preferred") == 0)
2096 config = OUTPUT_CONFIG_PREFERRED;
2097 else if (strcmp(s, "current") == 0)
2098 config = OUTPUT_CONFIG_CURRENT;
2099 else if (sscanf(s, "%dx%d", &width, &height) == 2)
2100 config = OUTPUT_CONFIG_MODE;
2101 else if (parse_modeline(s, &modeline) == 0)
2102 config = OUTPUT_CONFIG_MODELINE;
2103 else {
2104 weston_log("Invalid mode \"%s\" for output %s\n",
2105 s, output->base.name);
2106 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002107 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002108 free(s);
2109
2110 weston_config_section_get_int(section, "scale", &scale, 1);
2111 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05002112 if (weston_parse_transform(s, &transform) < 0)
2113 weston_log("Invalid transform \"%s\" for output %s\n",
2114 s, output->base.name);
2115
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002116 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002117
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002118 if (get_gbm_format_from_section(section,
Giulio Camuffo954f1832014-10-11 18:27:30 +03002119 b->format,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002120 &output->format) == -1)
Giulio Camuffo954f1832014-10-11 18:27:30 +03002121 output->format = b->format;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002122
Rob Bradford66bd9f52013-06-25 18:56:42 +01002123 weston_config_section_get_string(section, "seat", &s, "");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002124 setup_output_seat_constraint(b, &output->base, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01002125 free(s);
2126
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002127 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002128 output->pipe = i;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002129 b->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002130 output->connector_id = connector->connector_id;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002131 b->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002132
Giulio Camuffo954f1832014-10-11 18:27:30 +03002133 output->original_crtc = drmModeGetCrtc(b->drm.fd, output->crtc_id);
2134 output->dpms_prop = drm_get_prop(b->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002135
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002136 /* Get the current mode on the crtc that's currently driving
2137 * this connector. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002138 encoder = drmModeGetEncoder(b->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002139 memset(&crtc_mode, 0, sizeof crtc_mode);
2140 if (encoder != NULL) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002141 crtc = drmModeGetCrtc(b->drm.fd, encoder->crtc_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002142 drmModeFreeEncoder(encoder);
2143 if (crtc == NULL)
2144 goto err_free;
2145 if (crtc->mode_valid)
2146 crtc_mode = crtc->mode;
2147 drmModeFreeCrtc(crtc);
2148 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002149
David Herrmann0f0d54e2011-12-08 17:05:45 +01002150 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002151 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002152 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002153 goto err_free;
2154 }
2155
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002156 if (config == OUTPUT_CONFIG_OFF) {
2157 weston_log("Disabling output %s\n", output->base.name);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002158 drmModeSetCrtc(b->drm.fd, output->crtc_id,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002159 0, 0, 0, 0, 0, NULL);
2160 goto err_free;
2161 }
2162
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002163 preferred = NULL;
2164 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002165 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002166 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002167
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002168 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002169 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002170 width == drm_mode->base.width &&
2171 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002172 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002173 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002174 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002175 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002176 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002177 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002178 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002179
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002180 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002181 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002182 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002183 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002184 }
2185
Wang Quanxianacb805a2012-07-30 18:09:46 -04002186 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002187 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002188 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002189 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002190 }
2191
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002192 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002193 configured = current;
2194
Wang Quanxianacb805a2012-07-30 18:09:46 -04002195 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002196 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002197 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002198 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002199 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002200 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002201 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002202 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002203 else if (best)
2204 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002205
Hardeningff39efa2013-09-18 23:56:35 +02002206 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002207 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002208 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002209 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002210
Hardeningff39efa2013-09-18 23:56:35 +02002211 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002212
Giulio Camuffo954f1832014-10-11 18:27:30 +03002213 weston_output_init(&output->base, b->compositor, x, y,
John Kåre Alsaker94659272012-11-13 19:10:18 +01002214 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002215 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002216
Giulio Camuffo954f1832014-10-11 18:27:30 +03002217 if (b->use_pixman) {
2218 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002219 weston_log("Failed to init output pixman state\n");
2220 goto err_output;
2221 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03002222 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002223 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002224 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002225 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002226
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002227 output->backlight = backlight_init(drm_device,
2228 connector->connector_type);
2229 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002230 weston_log("Initialized backlight, device %s\n",
2231 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002232 output->base.set_backlight = drm_set_backlight;
2233 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002234 } else {
2235 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002236 }
2237
Giulio Camuffo954f1832014-10-11 18:27:30 +03002238 weston_compositor_add_output(b->compositor, &output->base);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002239
Giulio Camuffo954f1832014-10-11 18:27:30 +03002240 find_and_parse_output_edid(b, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002241 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2242 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002243
Jonas Ådahle5a12252013-04-05 23:07:11 +02002244 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002245 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002246 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002247 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002248 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002249 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002250
Richard Hughese7299962013-05-01 21:52:12 +01002251 output->base.gamma_size = output->original_crtc->gamma_size;
2252 output->base.set_gamma = drm_output_set_gamma;
2253
Giulio Camuffo954f1832014-10-11 18:27:30 +03002254 weston_plane_init(&output->cursor_plane, b->compositor, 0, 0);
2255 weston_plane_init(&output->fb_plane, b->compositor, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002256
Giulio Camuffo954f1832014-10-11 18:27:30 +03002257 weston_compositor_stack_plane(b->compositor, &output->cursor_plane, NULL);
2258 weston_compositor_stack_plane(b->compositor, &output->fb_plane,
2259 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002260
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002261 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002262 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002263 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002264 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002265 m->width, m->height, m->refresh / 1000.0,
2266 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2267 ", preferred" : "",
2268 m->flags & WL_OUTPUT_MODE_CURRENT ?
2269 ", current" : "",
2270 connector->count_modes == 0 ?
2271 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002272
Mario Kleiner80817042015-06-21 21:25:11 +02002273 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
2274 output->base.native_mode = output->base.current_mode;
2275 output->base.native_scale = output->base.current_scale;
2276
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002277 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002278
John Kåre Alsaker94659272012-11-13 19:10:18 +01002279err_output:
2280 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002281err_free:
2282 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2283 base.link) {
2284 wl_list_remove(&drm_mode->base.link);
2285 free(drm_mode);
2286 }
2287
2288 drmModeFreeCrtc(output->original_crtc);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002289 b->crtc_allocator &= ~(1 << output->crtc_id);
2290 b->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002291 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002292
David Herrmann0f0d54e2011-12-08 17:05:45 +01002293 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002294}
2295
Jesse Barnes58ef3792012-02-23 09:45:49 -05002296static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002297create_sprites(struct drm_backend *b)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002298{
2299 struct drm_sprite *sprite;
2300 drmModePlaneRes *plane_res;
2301 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002302 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002303
Giulio Camuffo954f1832014-10-11 18:27:30 +03002304 plane_res = drmModeGetPlaneResources(b->drm.fd);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002305 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002306 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002307 strerror(errno));
2308 return;
2309 }
2310
2311 for (i = 0; i < plane_res->count_planes; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002312 plane = drmModeGetPlane(b->drm.fd, plane_res->planes[i]);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002313 if (!plane)
2314 continue;
2315
Peter Huttererf3d62272013-08-08 11:57:05 +10002316 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002317 plane->count_formats));
2318 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002319 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002320 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002321 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002322 continue;
2323 }
2324
Jesse Barnes58ef3792012-02-23 09:45:49 -05002325 sprite->possible_crtcs = plane->possible_crtcs;
2326 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002327 sprite->current = NULL;
2328 sprite->next = NULL;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002329 sprite->backend = b;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002330 sprite->count_formats = plane->count_formats;
2331 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002332 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002333 drmModeFreePlane(plane);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002334 weston_plane_init(&sprite->plane, b->compositor, 0, 0);
2335 weston_compositor_stack_plane(b->compositor, &sprite->plane,
2336 &b->compositor->primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002337
Giulio Camuffo954f1832014-10-11 18:27:30 +03002338 wl_list_insert(&b->sprite_list, &sprite->link);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002339 }
2340
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002341 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002342}
2343
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002344static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002345destroy_sprites(struct drm_backend *backend)
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002346{
2347 struct drm_sprite *sprite, *next;
2348 struct drm_output *output;
2349
Giulio Camuffo954f1832014-10-11 18:27:30 +03002350 output = container_of(backend->compositor->output_list.next,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002351 struct drm_output, base.link);
2352
Giulio Camuffo954f1832014-10-11 18:27:30 +03002353 wl_list_for_each_safe(sprite, next, &backend->sprite_list, link) {
2354 drmModeSetPlane(backend->drm.fd,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002355 sprite->plane_id,
2356 output->crtc_id, 0, 0,
2357 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002358 drm_output_release_fb(output, sprite->current);
2359 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002360 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002361 free(sprite);
2362 }
2363}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002364
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002365static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002366create_outputs(struct drm_backend *b, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002367 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002368{
2369 drmModeConnector *connector;
2370 drmModeRes *resources;
2371 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002372 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002373
Giulio Camuffo954f1832014-10-11 18:27:30 +03002374 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002375 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002376 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002377 return -1;
2378 }
2379
Giulio Camuffo954f1832014-10-11 18:27:30 +03002380 b->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
2381 if (!b->crtcs) {
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002382 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002383 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002384 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002385
Giulio Camuffo954f1832014-10-11 18:27:30 +03002386 b->min_width = resources->min_width;
2387 b->max_width = resources->max_width;
2388 b->min_height = resources->min_height;
2389 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05002390
Giulio Camuffo954f1832014-10-11 18:27:30 +03002391 b->num_crtcs = resources->count_crtcs;
2392 memcpy(b->crtcs, resources->crtcs, sizeof(uint32_t) * b->num_crtcs);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002393
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002394 for (i = 0; i < resources->count_connectors; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002395 connector = drmModeGetConnector(b->drm.fd,
Benjamin Franzke117483d2011-08-30 11:38:26 +02002396 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002397 if (connector == NULL)
2398 continue;
2399
2400 if (connector->connection == DRM_MODE_CONNECTED &&
2401 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002402 connector->connector_id == option_connector)) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002403 if (create_output_for_connector(b, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002404 connector, x, y,
2405 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002406 drmModeFreeConnector(connector);
2407 continue;
2408 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002409
Giulio Camuffo954f1832014-10-11 18:27:30 +03002410 x += container_of(b->compositor->output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002411 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002412 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002413 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002414
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002415 drmModeFreeConnector(connector);
2416 }
2417
Giulio Camuffo954f1832014-10-11 18:27:30 +03002418 if (wl_list_empty(&b->compositor->output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002419 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002420 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002421 return -1;
2422 }
2423
2424 drmModeFreeResources(resources);
2425
2426 return 0;
2427}
2428
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002429static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002430update_outputs(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002431{
2432 drmModeConnector *connector;
2433 drmModeRes *resources;
2434 struct drm_output *output, *next;
2435 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002436 uint32_t connected = 0, disconnects = 0;
2437 int i;
2438
Giulio Camuffo954f1832014-10-11 18:27:30 +03002439 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002440 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002441 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002442 return;
2443 }
2444
2445 /* collect new connects */
2446 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002447 int connector_id = resources->connectors[i];
2448
Giulio Camuffo954f1832014-10-11 18:27:30 +03002449 connector = drmModeGetConnector(b->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002450 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002451 continue;
2452
David Herrmann7551cff2011-12-08 17:05:43 +01002453 if (connector->connection != DRM_MODE_CONNECTED) {
2454 drmModeFreeConnector(connector);
2455 continue;
2456 }
2457
Benjamin Franzke117483d2011-08-30 11:38:26 +02002458 connected |= (1 << connector_id);
2459
Giulio Camuffo954f1832014-10-11 18:27:30 +03002460 if (!(b->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002461 struct weston_output *last =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002462 container_of(b->compositor->output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002463 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002464
2465 /* XXX: not yet needed, we die with 0 outputs */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002466 if (!wl_list_empty(&b->compositor->output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002467 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002468 else
2469 x = 0;
2470 y = 0;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002471 create_output_for_connector(b, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002472 connector, x, y,
2473 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002474 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002475
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002476 }
2477 drmModeFreeConnector(connector);
2478 }
2479 drmModeFreeResources(resources);
2480
Giulio Camuffo954f1832014-10-11 18:27:30 +03002481 disconnects = b->connector_allocator & ~connected;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002482 if (disconnects) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002483 wl_list_for_each_safe(output, next, &b->compositor->output_list,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002484 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002485 if (disconnects & (1 << output->connector_id)) {
2486 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002487 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002488 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002489 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002490 }
2491 }
2492 }
2493
Daniel Stonef556ebe2015-05-21 08:28:58 +01002494 /* FIXME: handle zero outputs, without terminating */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002495 if (b->connector_allocator == 0)
Giulio Camuffo459137b2014-10-11 23:56:24 +03002496 weston_compositor_exit(b->compositor);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002497}
2498
2499static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002500udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002501{
David Herrmannd7488c22012-03-11 20:05:21 +01002502 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002503 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002504
2505 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002506 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01002507 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002508
David Herrmann6ac52db2012-03-11 20:05:22 +01002509 val = udev_device_get_property_value(device, "HOTPLUG");
2510 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002511 return 0;
2512
David Herrmann6ac52db2012-03-11 20:05:22 +01002513 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002514}
2515
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002516static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002517udev_drm_event(int fd, uint32_t mask, void *data)
2518{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002519 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002520 struct udev_device *event;
2521
Giulio Camuffo954f1832014-10-11 18:27:30 +03002522 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002523
Giulio Camuffo954f1832014-10-11 18:27:30 +03002524 if (udev_event_is_hotplug(b, event))
2525 update_outputs(b, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002526
2527 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002528
2529 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002530}
2531
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002532static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002533drm_restore(struct weston_compositor *ec)
2534{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002535 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002536}
2537
2538static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002539drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002540{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002541 struct drm_backend *b = (struct drm_backend *) ec->backend;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002542
Giulio Camuffo954f1832014-10-11 18:27:30 +03002543 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002544
Giulio Camuffo954f1832014-10-11 18:27:30 +03002545 wl_event_source_remove(b->udev_drm_source);
2546 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002547
Giulio Camuffo954f1832014-10-11 18:27:30 +03002548 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002549
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002550 weston_compositor_shutdown(ec);
2551
Giulio Camuffo954f1832014-10-11 18:27:30 +03002552 if (b->gbm)
2553 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002554
Giulio Camuffo954f1832014-10-11 18:27:30 +03002555 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002556
Giulio Camuffo954f1832014-10-11 18:27:30 +03002557 close(b->drm.fd);
Rob Bradford45c15b82013-07-26 16:29:35 +01002558
Giulio Camuffo954f1832014-10-11 18:27:30 +03002559 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002560}
2561
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002562static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002563drm_backend_set_modes(struct drm_backend *backend)
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002564{
2565 struct drm_output *output;
2566 struct drm_mode *drm_mode;
2567 int ret;
2568
Giulio Camuffo954f1832014-10-11 18:27:30 +03002569 wl_list_for_each(output, &backend->compositor->output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002570 if (!output->current) {
2571 /* If something that would cause the output to
2572 * switch mode happened while in another vt, we
2573 * might not have a current drm_fb. In that case,
2574 * schedule a repaint and let drm_output_repaint
2575 * handle setting the mode. */
2576 weston_output_schedule_repaint(&output->base);
2577 continue;
2578 }
2579
Hardeningff39efa2013-09-18 23:56:35 +02002580 drm_mode = (struct drm_mode *) output->base.current_mode;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002581 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002582 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002583 &output->connector_id, 1,
2584 &drm_mode->mode_info);
2585 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002586 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002587 "failed to set mode %dx%d for output at %d,%d: %m\n",
Daniel Stonef556ebe2015-05-21 08:28:58 +01002588 drm_mode->base.width, drm_mode->base.height,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002589 output->base.x, output->base.y);
2590 }
2591 }
2592}
2593
2594static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002595session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002596{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002597 struct weston_compositor *compositor = data;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002598 struct drm_backend *b = (struct drm_backend *)compositor->backend;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002599 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002600 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002601
Giulio Camuffo954f1832014-10-11 18:27:30 +03002602 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002603 weston_log("activating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002604 compositor->state = b->prev_state;
2605 drm_backend_set_modes(b);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002606 weston_compositor_damage_all(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002607 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002608 } else {
2609 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002610 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002611
Giulio Camuffo954f1832014-10-11 18:27:30 +03002612 b->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002613 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002614
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002615 /* If we have a repaint scheduled (either from a
2616 * pending pageflip or the idle handler), make sure we
2617 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002618 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002619 * further attemps at repainting. When we switch
2620 * back, we schedule a repaint, which will process
2621 * pending frame callbacks. */
2622
Giulio Camuffo954f1832014-10-11 18:27:30 +03002623 wl_list_for_each(output, &compositor->output_list, base.link) {
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002624 output->base.repaint_needed = 0;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002625 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002626 }
2627
Giulio Camuffo954f1832014-10-11 18:27:30 +03002628 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002629 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002630
Giulio Camuffo954f1832014-10-11 18:27:30 +03002631 wl_list_for_each(sprite, &b->sprite_list, link)
2632 drmModeSetPlane(b->drm.fd,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002633 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002634 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002635 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002636 };
2637}
2638
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002639static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002640switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002641{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002642 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002643
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002644 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002645}
2646
David Herrmann0af066f2012-10-29 19:21:16 +01002647/*
2648 * Find primary GPU
2649 * Some systems may have multiple DRM devices attached to a single seat. This
2650 * function loops over all devices and tries to find a PCI device with the
2651 * boot_vga sysfs attribute set to 1.
2652 * If no such device is found, the first DRM device reported by udev is used.
2653 */
2654static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03002655find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01002656{
2657 struct udev_enumerate *e;
2658 struct udev_list_entry *entry;
2659 const char *path, *device_seat, *id;
2660 struct udev_device *device, *drm_device, *pci;
2661
Giulio Camuffo954f1832014-10-11 18:27:30 +03002662 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01002663 udev_enumerate_add_match_subsystem(e, "drm");
2664 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2665
2666 udev_enumerate_scan_devices(e);
2667 drm_device = NULL;
2668 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2669 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002670 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01002671 if (!device)
2672 continue;
2673 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2674 if (!device_seat)
2675 device_seat = default_seat;
2676 if (strcmp(device_seat, seat)) {
2677 udev_device_unref(device);
2678 continue;
2679 }
2680
2681 pci = udev_device_get_parent_with_subsystem_devtype(device,
2682 "pci", NULL);
2683 if (pci) {
2684 id = udev_device_get_sysattr_value(pci, "boot_vga");
2685 if (id && !strcmp(id, "1")) {
2686 if (drm_device)
2687 udev_device_unref(drm_device);
2688 drm_device = device;
2689 break;
2690 }
2691 }
2692
2693 if (!drm_device)
2694 drm_device = device;
2695 else
2696 udev_device_unref(device);
2697 }
2698
2699 udev_enumerate_unref(e);
2700 return drm_device;
2701}
2702
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002703static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002704planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002705{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002706 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002707
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002708 switch (key) {
2709 case KEY_C:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002710 b->cursors_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002711 break;
2712 case KEY_V:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002713 b->sprites_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002714 break;
2715 case KEY_O:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002716 b->sprites_hidden ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002717 break;
2718 default:
2719 break;
2720 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002721}
2722
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002723#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002724static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002725recorder_destroy(struct drm_output *output)
2726{
2727 vaapi_recorder_destroy(output->recorder);
2728 output->recorder = NULL;
2729
2730 output->base.disable_planes--;
2731
2732 wl_list_remove(&output->recorder_frame_listener.link);
2733 weston_log("[libva recorder] done\n");
2734}
2735
2736static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002737recorder_frame_notify(struct wl_listener *listener, void *data)
2738{
2739 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002740 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002741 int fd, ret;
2742
2743 output = container_of(listener, struct drm_output,
2744 recorder_frame_listener);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002745 b = (struct drm_backend *)output->base.compositor->backend;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002746
2747 if (!output->recorder)
2748 return;
2749
Giulio Camuffo954f1832014-10-11 18:27:30 +03002750 ret = drmPrimeHandleToFD(b->drm.fd, output->current->handle,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002751 DRM_CLOEXEC, &fd);
2752 if (ret) {
2753 weston_log("[libva recorder] "
2754 "failed to create prime fd for front buffer\n");
2755 return;
2756 }
2757
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002758 ret = vaapi_recorder_frame(output->recorder, fd,
2759 output->current->stride);
2760 if (ret < 0) {
2761 weston_log("[libva recorder] aborted: %m\n");
2762 recorder_destroy(output);
2763 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002764}
2765
2766static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03002767create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002768 const char *filename)
2769{
2770 int fd;
2771 drm_magic_t magic;
2772
Giulio Camuffo954f1832014-10-11 18:27:30 +03002773 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002774 if (fd < 0)
2775 return NULL;
2776
2777 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002778 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002779
2780 return vaapi_recorder_create(fd, width, height, filename);
2781}
2782
2783static void
2784recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2785 void *data)
2786{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002787 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002788 struct drm_output *output;
2789 int width, height;
2790
Giulio Camuffo954f1832014-10-11 18:27:30 +03002791 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002792 struct drm_output, base.link);
2793
2794 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002795 if (output->format != GBM_FORMAT_XRGB8888) {
2796 weston_log("failed to start vaapi recorder: "
2797 "output format not supported\n");
2798 return;
2799 }
2800
Hardeningff39efa2013-09-18 23:56:35 +02002801 width = output->base.current_mode->width;
2802 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002803
2804 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002805 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002806 if (!output->recorder) {
2807 weston_log("failed to create vaapi recorder\n");
2808 return;
2809 }
2810
2811 output->base.disable_planes++;
2812
2813 output->recorder_frame_listener.notify = recorder_frame_notify;
2814 wl_signal_add(&output->base.frame_signal,
2815 &output->recorder_frame_listener);
2816
2817 weston_output_schedule_repaint(&output->base);
2818
2819 weston_log("[libva recorder] initialized\n");
2820 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002821 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002822 }
2823}
2824#else
2825static void
2826recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2827 void *data)
2828{
2829 weston_log("Compiled without libva support\n");
2830}
2831#endif
2832
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002833static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002834switch_to_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002835{
2836 struct drm_output *output;
2837
Giulio Camuffo954f1832014-10-11 18:27:30 +03002838 if (!b->use_pixman)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002839 return;
2840
2841 weston_log("Switching to GL renderer\n");
2842
Giulio Camuffo954f1832014-10-11 18:27:30 +03002843 b->gbm = create_gbm_device(b->drm.fd);
2844 if (!b->gbm) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002845 weston_log("Failed to create gbm device. "
2846 "Aborting renderer switch\n");
2847 return;
2848 }
2849
Giulio Camuffo954f1832014-10-11 18:27:30 +03002850 wl_list_for_each(output, &b->compositor->output_list, base.link)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002851 pixman_renderer_output_destroy(&output->base);
2852
Giulio Camuffo954f1832014-10-11 18:27:30 +03002853 b->compositor->renderer->destroy(b->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002854
Giulio Camuffo954f1832014-10-11 18:27:30 +03002855 if (drm_backend_create_gl_renderer(b) < 0) {
2856 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002857 weston_log("Failed to create GL renderer. Quitting.\n");
2858 /* FIXME: we need a function to shutdown cleanly */
2859 assert(0);
2860 }
2861
Giulio Camuffo954f1832014-10-11 18:27:30 +03002862 wl_list_for_each(output, &b->compositor->output_list, base.link)
2863 drm_output_init_egl(output, b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002864
Giulio Camuffo954f1832014-10-11 18:27:30 +03002865 b->use_pixman = 0;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002866}
2867
2868static void
2869renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2870 void *data)
2871{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002872 struct drm_backend *b = (struct drm_backend *)seat->compositor->backend;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002873
Giulio Camuffo954f1832014-10-11 18:27:30 +03002874 switch_to_gl_renderer(b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002875}
2876
Giulio Camuffo954f1832014-10-11 18:27:30 +03002877static struct drm_backend *
2878drm_backend_create(struct weston_compositor *compositor,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002879 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002880 int *argc, char *argv[],
2881 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002882{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002883 struct drm_backend *b;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002884 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002885 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002886 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002887 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002888 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002889
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002890 weston_log("initializing drm backend\n");
2891
Giulio Camuffo954f1832014-10-11 18:27:30 +03002892 b = zalloc(sizeof *b);
2893 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002894 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002895
Pekka Paalanen68583832015-05-19 09:53:16 +03002896 /*
2897 * KMS support for hardware planes cannot properly synchronize
2898 * without nuclear page flip. Without nuclear/atomic, hw plane
2899 * and cursor plane updates would either tear or cause extra
2900 * waits for vblanks which means dropping the compositor framerate
2901 * to a fraction.
2902 *
2903 * These can be enabled again when nuclear/atomic support lands.
2904 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002905 b->sprites_are_broken = 1;
2906 b->cursors_are_broken = 1;
2907 b->compositor = compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002908
2909 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002910 if (get_gbm_format_from_section(section,
2911 GBM_FORMAT_XRGB8888,
Giulio Camuffo954f1832014-10-11 18:27:30 +03002912 &b->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002913 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002914
Giulio Camuffo954f1832014-10-11 18:27:30 +03002915 b->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002916
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002917 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002918 compositor->launcher = weston_launcher_connect(compositor, param->tty,
2919 param->seat_id, true);
2920 if (compositor->launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002921 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002922 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002923 goto err_compositor;
2924 }
2925
Giulio Camuffo954f1832014-10-11 18:27:30 +03002926 b->udev = udev_new();
2927 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002928 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002929 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002930 }
2931
Giulio Camuffo954f1832014-10-11 18:27:30 +03002932 b->session_listener.notify = session_notify;
2933 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002934
Giulio Camuffo954f1832014-10-11 18:27:30 +03002935 drm_device = find_primary_gpu(b, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002936 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002937 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002938 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002939 }
David Herrmann0af066f2012-10-29 19:21:16 +01002940 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002941
Giulio Camuffo954f1832014-10-11 18:27:30 +03002942 if (init_drm(b, drm_device) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002943 weston_log("failed to initialize kms\n");
2944 goto err_udev_dev;
2945 }
2946
Giulio Camuffo954f1832014-10-11 18:27:30 +03002947 if (b->use_pixman) {
2948 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002949 weston_log("failed to initialize pixman renderer\n");
2950 goto err_udev_dev;
2951 }
2952 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002953 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002954 weston_log("failed to initialize egl\n");
2955 goto err_udev_dev;
2956 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002957 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002958
Giulio Camuffo954f1832014-10-11 18:27:30 +03002959 b->base.destroy = drm_destroy;
2960 b->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002961
Giulio Camuffo954f1832014-10-11 18:27:30 +03002962 b->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002963
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002964 for (key = KEY_F1; key < KEY_F9; key++)
Giulio Camuffo954f1832014-10-11 18:27:30 +03002965 weston_compositor_add_key_binding(compositor, key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01002966 MODIFIER_CTRL | MODIFIER_ALT,
Giulio Camuffo954f1832014-10-11 18:27:30 +03002967 switch_vt_binding, compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002968
Giulio Camuffo954f1832014-10-11 18:27:30 +03002969 wl_list_init(&b->sprite_list);
2970 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002971
Giulio Camuffo954f1832014-10-11 18:27:30 +03002972 if (udev_input_init(&b->input,
2973 compositor, b->udev, param->seat_id) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002974 weston_log("failed to create input devices\n");
2975 goto err_sprite;
2976 }
2977
Giulio Camuffo954f1832014-10-11 18:27:30 +03002978 if (create_outputs(b, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002979 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002980 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002981 }
2982
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002983 /* A this point we have some idea of whether or not we have a working
2984 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002985 if (!b->cursors_are_broken)
2986 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002987
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002988 path = NULL;
2989
Giulio Camuffo954f1832014-10-11 18:27:30 +03002990 loop = wl_display_get_event_loop(compositor->wl_display);
2991 b->drm_source =
2992 wl_event_loop_add_fd(loop, b->drm.fd,
2993 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002994
Giulio Camuffo954f1832014-10-11 18:27:30 +03002995 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
2996 if (b->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002997 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002998 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002999 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03003000 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003001 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003002 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02003003 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003004 udev_monitor_get_fd(b->udev_monitor),
3005 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003006
Giulio Camuffo954f1832014-10-11 18:27:30 +03003007 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003008 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003009 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003010 }
3011
Daniel Stonea96b93c2012-06-22 14:04:37 +01003012 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003013
Giulio Camuffo954f1832014-10-11 18:27:30 +03003014 weston_compositor_add_debug_binding(compositor, KEY_O,
3015 planes_binding, b);
3016 weston_compositor_add_debug_binding(compositor, KEY_C,
3017 planes_binding, b);
3018 weston_compositor_add_debug_binding(compositor, KEY_V,
3019 planes_binding, b);
3020 weston_compositor_add_debug_binding(compositor, KEY_Q,
3021 recorder_binding, b);
3022 weston_compositor_add_debug_binding(compositor, KEY_W,
3023 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02003024
Giulio Camuffo954f1832014-10-11 18:27:30 +03003025 compositor->backend = &b->base;
3026 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01003027
3028err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003029 wl_event_source_remove(b->udev_drm_source);
3030 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003031err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003032 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003033err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003034 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003035err_sprite:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003036 compositor->renderer->destroy(compositor);
3037 gbm_device_destroy(b->gbm);
3038 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003039err_udev_dev:
3040 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003041err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003042 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003043err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003044 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003045err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003046 weston_compositor_shutdown(compositor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003047err_base:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003048 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003049 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003050}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003051
Giulio Camuffo954f1832014-10-11 18:27:30 +03003052WL_EXPORT int
3053backend_init(struct weston_compositor *compositor, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04003054 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003055{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003056 struct drm_backend *b;
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003057 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003058
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003059 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003060 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
3061 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
3062 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003063 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003064 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003065 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02003066
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003067 param.seat_id = default_seat;
3068
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003069 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003070
Giulio Camuffo954f1832014-10-11 18:27:30 +03003071 b = drm_backend_create(compositor, &param, argc, argv, config);
3072 if (b == NULL)
3073 return -1;
3074 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003075}