blob: 63ac364215069b255d1d5b6c36aabe34d9a09459 [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
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001282/**
1283 * Find the closest-matching mode for a given target
1284 *
1285 * Given a target mode, find the most suitable mode amongst the output's
1286 * current mode list to use, preferring the current mode if possible, to
1287 * avoid an expensive mode switch.
1288 *
1289 * @param output DRM output
1290 * @param target_mode Mode to attempt to match
1291 * @returns Pointer to a mode from the output's mode list
1292 */
Alex Wub7b8bda2012-04-17 17:20:48 +08001293static struct drm_mode *
1294choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1295{
1296 struct drm_mode *tmp_mode = NULL, *mode;
1297
Hardeningff39efa2013-09-18 23:56:35 +02001298 if (output->base.current_mode->width == target_mode->width &&
1299 output->base.current_mode->height == target_mode->height &&
1300 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001301 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001302 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001303
1304 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1305 if (mode->mode_info.hdisplay == target_mode->width &&
1306 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02001307 if (mode->base.refresh == target_mode->refresh ||
1308 target_mode->refresh == 0) {
Alex Wub7b8bda2012-04-17 17:20:48 +08001309 return mode;
Daniel Stonef556ebe2015-05-21 08:28:58 +01001310 } else if (!tmp_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001311 tmp_mode = mode;
1312 }
1313 }
1314
1315 return tmp_mode;
1316}
1317
1318static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001319drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001320static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001321drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001322
1323static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001324drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1325{
1326 struct drm_output *output;
1327 struct drm_mode *drm_mode;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001328 struct drm_backend *b;
Alex Wub7b8bda2012-04-17 17:20:48 +08001329
1330 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001331 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001332 return -1;
1333 }
1334
1335 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001336 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001337 return -1;
1338 }
1339
Giulio Camuffo954f1832014-10-11 18:27:30 +03001340 b = (struct drm_backend *)output_base->compositor->backend;
Alex Wub7b8bda2012-04-17 17:20:48 +08001341 output = (struct drm_output *)output_base;
1342 drm_mode = choose_mode (output, mode);
1343
1344 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001345 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001346 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001347 }
1348
Hardeningff39efa2013-09-18 23:56:35 +02001349 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001350 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001351
Hardeningff39efa2013-09-18 23:56:35 +02001352 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001353
Hardeningff39efa2013-09-18 23:56:35 +02001354 output->base.current_mode = &drm_mode->base;
1355 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001356 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1357
Alex Wub7b8bda2012-04-17 17:20:48 +08001358 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001359 drm_output_release_fb(output, output->current);
1360 drm_output_release_fb(output, output->next);
1361 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001362
Giulio Camuffo954f1832014-10-11 18:27:30 +03001363 if (b->use_pixman) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001364 drm_output_fini_pixman(output);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001365 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001366 weston_log("failed to init output pixman state with "
1367 "new mode\n");
1368 return -1;
1369 }
1370 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001371 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001372 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001373
Giulio Camuffo954f1832014-10-11 18:27:30 +03001374 if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001375 weston_log("failed to init output egl state with "
1376 "new mode");
1377 return -1;
1378 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001379 }
1380
Alex Wub7b8bda2012-04-17 17:20:48 +08001381 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001382}
1383
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001384static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001385on_drm_input(int fd, uint32_t mask, void *data)
1386{
1387 drmEventContext evctx;
1388
1389 memset(&evctx, 0, sizeof evctx);
1390 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1391 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001392 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001393 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001394
1395 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001396}
1397
1398static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001399init_drm(struct drm_backend *b, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001400{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001401 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001402 uint64_t cap;
1403 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001404 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001405
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001406 sysnum = udev_device_get_sysnum(device);
1407 if (sysnum)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001408 b->drm.id = atoi(sysnum);
1409 if (!sysnum || b->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001410 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001411 return -1;
1412 }
1413
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001414 filename = udev_device_get_devnode(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03001415 fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001416 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001417 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001418 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001419 udev_device_get_devnode(device));
1420 return -1;
1421 }
1422
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001423 weston_log("using %s\n", filename);
1424
Giulio Camuffo954f1832014-10-11 18:27:30 +03001425 b->drm.fd = fd;
1426 b->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001427
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001428 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1429 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001430 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001431 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001432 clk_id = CLOCK_REALTIME;
1433
Giulio Camuffo954f1832014-10-11 18:27:30 +03001434 if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001435 weston_log("Error: failed to set presentation clock %d.\n",
1436 clk_id);
1437 return -1;
1438 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001439
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001440 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1441 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001442 b->cursor_width = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001443 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03001444 b->cursor_width = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001445
1446 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1447 if (ret == 0)
Giulio Camuffo954f1832014-10-11 18:27:30 +03001448 b->cursor_height = cap;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001449 else
Giulio Camuffo954f1832014-10-11 18:27:30 +03001450 b->cursor_height = 64;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001451
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001452 return 0;
1453}
1454
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001455static struct gbm_device *
1456create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001457{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001458 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001459
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001460 gl_renderer = weston_load_module("gl-renderer.so",
1461 "gl_renderer_interface");
1462 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001463 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001464
1465 /* GBM will load a dri driver, but even though they need symbols from
1466 * libglapi, in some version of Mesa they are not linked to it. Since
1467 * only the gl-renderer module links to it, the call above won't make
1468 * these symbols globally available, and loading the DRI driver fails.
1469 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1470 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1471
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001472 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001473
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001474 return gbm;
1475}
1476
Bryce Harringtonc056a982015-05-19 15:25:18 -07001477/* When initializing EGL, if the preferred buffer format isn't available
Derek Foremanc4cfe852015-05-15 12:12:40 -05001478 * we may be able to susbstitute an ARGB format for an XRGB one.
1479 *
1480 * This returns 0 if substitution isn't possible, but 0 might be a
1481 * legitimate format for other EGL platforms, so the caller is
1482 * responsible for checking for 0 before calling gl_renderer->create().
1483 *
1484 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
1485 * but it's entirely possible we'll see this again on other implementations.
1486 */
1487static int
1488fallback_format_for(uint32_t format)
1489{
1490 switch (format) {
1491 case GBM_FORMAT_XRGB8888:
1492 return GBM_FORMAT_ARGB8888;
1493 case GBM_FORMAT_XRGB2101010:
1494 return GBM_FORMAT_ARGB2101010;
1495 default:
1496 return 0;
1497 }
1498}
1499
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001500static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001501drm_backend_create_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001502{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001503 EGLint format[2] = {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001504 b->format,
1505 fallback_format_for(b->format),
Derek Foremanc4cfe852015-05-15 12:12:40 -05001506 };
1507 int n_formats = 1;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001508
Derek Foremanc4cfe852015-05-15 12:12:40 -05001509 if (format[1])
1510 n_formats = 2;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001511 if (gl_renderer->create(b->compositor,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001512 EGL_PLATFORM_GBM_KHR,
Giulio Camuffo954f1832014-10-11 18:27:30 +03001513 (void *)b->gbm,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001514 gl_renderer->opaque_attribs,
1515 format,
1516 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001517 return -1;
1518 }
1519
1520 return 0;
1521}
1522
1523static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001524init_egl(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001525{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001526 b->gbm = create_gbm_device(b->drm.fd);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001527
Giulio Camuffo954f1832014-10-11 18:27:30 +03001528 if (!b->gbm)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001529 return -1;
1530
Giulio Camuffo954f1832014-10-11 18:27:30 +03001531 if (drm_backend_create_gl_renderer(b) < 0) {
1532 gbm_device_destroy(b->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001533 return -1;
1534 }
1535
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001536 return 0;
1537}
1538
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001539static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001540init_pixman(struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001541{
Giulio Camuffo954f1832014-10-11 18:27:30 +03001542 return pixman_renderer_init(b->compositor);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001543}
1544
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001545/**
1546 * Add a mode to output's mode list
1547 *
1548 * Copy the supplied DRM mode into a Weston mode structure, and add it to the
1549 * output's mode list.
1550 *
1551 * @param output DRM output to add mode to
1552 * @param info DRM mode structure to add
1553 * @returns Newly-allocated Weston/DRM mode structure
1554 */
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001555static struct drm_mode *
Pekka Paalanen7b36b422014-06-04 14:00:53 +03001556drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001557{
1558 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001559 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001560
1561 mode = malloc(sizeof *mode);
1562 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001563 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001564
1565 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001566 mode->base.width = info->hdisplay;
1567 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001568
1569 /* Calculate higher precision (mHz) refresh rate */
1570 refresh = (info->clock * 1000000LL / info->htotal +
1571 info->vtotal / 2) / info->vtotal;
1572
1573 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1574 refresh *= 2;
1575 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1576 refresh /= 2;
1577 if (info->vscan > 1)
1578 refresh /= info->vscan;
1579
1580 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001581 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001582
1583 if (info->type & DRM_MODE_TYPE_PREFERRED)
1584 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1585
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001586 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1587
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001588 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001589}
1590
1591static int
1592drm_subpixel_to_wayland(int drm_value)
1593{
1594 switch (drm_value) {
1595 default:
1596 case DRM_MODE_SUBPIXEL_UNKNOWN:
1597 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1598 case DRM_MODE_SUBPIXEL_NONE:
1599 return WL_OUTPUT_SUBPIXEL_NONE;
1600 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1601 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1602 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1603 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1604 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1605 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1606 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1607 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1608 }
1609}
1610
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001611/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001612static uint32_t
1613drm_get_backlight(struct drm_output *output)
1614{
1615 long brightness, max_brightness, norm;
1616
1617 brightness = backlight_get_brightness(output->backlight);
1618 max_brightness = backlight_get_max_brightness(output->backlight);
1619
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001620 /* convert it on a scale of 0 to 255 */
1621 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001622
1623 return (uint32_t) norm;
1624}
1625
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001626/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001627static void
1628drm_set_backlight(struct weston_output *output_base, uint32_t value)
1629{
1630 struct drm_output *output = (struct drm_output *) output_base;
1631 long max_brightness, new_brightness;
1632
1633 if (!output->backlight)
1634 return;
1635
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001636 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001637 return;
1638
1639 max_brightness = backlight_get_max_brightness(output->backlight);
1640
1641 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001642 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001643
1644 backlight_set_brightness(output->backlight, new_brightness);
1645}
1646
1647static drmModePropertyPtr
1648drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1649{
1650 drmModePropertyPtr props;
1651 int i;
1652
1653 for (i = 0; i < connector->count_props; i++) {
1654 props = drmModeGetProperty(fd, connector->props[i]);
1655 if (!props)
1656 continue;
1657
1658 if (!strcmp(props->name, name))
1659 return props;
1660
1661 drmModeFreeProperty(props);
1662 }
1663
1664 return NULL;
1665}
1666
1667static void
1668drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1669{
1670 struct drm_output *output = (struct drm_output *) output_base;
1671 struct weston_compositor *ec = output_base->compositor;
Giulio Camuffo954f1832014-10-11 18:27:30 +03001672 struct drm_backend *b = (struct drm_backend *)ec->backend;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001673
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001674 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001675 return;
1676
Giulio Camuffo954f1832014-10-11 18:27:30 +03001677 drmModeConnectorSetProperty(b->drm.fd, output->connector_id,
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001678 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001679}
1680
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001681static const char * const connector_type_names[] = {
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001682 "None",
1683 "VGA",
1684 "DVI",
1685 "DVI",
1686 "DVI",
1687 "Composite",
1688 "TV",
1689 "LVDS",
1690 "CTV",
1691 "DIN",
1692 "DP",
1693 "HDMI",
1694 "HDMI",
1695 "TV",
1696 "eDP",
1697};
1698
Pekka Paalanen3ce63622014-06-04 16:29:49 +03001699static char *
1700make_connector_name(const drmModeConnector *con)
1701{
1702 char name[32];
1703 const char *type_name;
1704
1705 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
1706 type_name = connector_type_names[con->connector_type];
1707 else
1708 type_name = "UNKNOWN";
1709 snprintf(name, sizeof name, "%s%d", type_name, con->connector_type_id);
1710
1711 return strdup(name);
1712}
1713
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001714static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001715find_crtc_for_connector(struct drm_backend *b,
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001716 drmModeRes *resources, drmModeConnector *connector)
1717{
1718 drmModeEncoder *encoder;
1719 uint32_t possible_crtcs;
1720 int i, j;
1721
1722 for (j = 0; j < connector->count_encoders; j++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001723 encoder = drmModeGetEncoder(b->drm.fd, connector->encoders[j]);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001724 if (encoder == NULL) {
1725 weston_log("Failed to get encoder.\n");
1726 return -1;
1727 }
1728 possible_crtcs = encoder->possible_crtcs;
1729 drmModeFreeEncoder(encoder);
1730
1731 for (i = 0; i < resources->count_crtcs; i++) {
1732 if (possible_crtcs & (1 << i) &&
Giulio Camuffo954f1832014-10-11 18:27:30 +03001733 !(b->crtc_allocator & (1 << resources->crtcs[i])))
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001734 return i;
1735 }
1736 }
1737
1738 return -1;
1739}
1740
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001741/* Init output state that depends on gl or gbm */
1742static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001743drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001744{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001745 EGLint format[2] = {
1746 output->format,
1747 fallback_format_for(output->format),
1748 };
1749 int i, flags, n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001750
Giulio Camuffo954f1832014-10-11 18:27:30 +03001751 output->surface = gbm_surface_create(b->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001752 output->base.current_mode->width,
1753 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001754 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001755 GBM_BO_USE_SCANOUT |
1756 GBM_BO_USE_RENDERING);
1757 if (!output->surface) {
1758 weston_log("failed to create gbm surface\n");
1759 return -1;
1760 }
1761
Derek Foremanc4cfe852015-05-15 12:12:40 -05001762 if (format[1])
1763 n_formats = 2;
Jonny Lamb671148f2015-03-20 15:26:52 +01001764 if (gl_renderer->output_create(&output->base,
Jonny Lamb445fb692015-03-24 13:12:01 +01001765 (EGLNativeDisplayType)output->surface,
1766 output->surface,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001767 gl_renderer->opaque_attribs,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001768 format,
1769 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001770 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001771 gbm_surface_destroy(output->surface);
1772 return -1;
1773 }
1774
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001775 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001776
1777 for (i = 0; i < 2; i++) {
1778 if (output->cursor_bo[i])
1779 continue;
1780
1781 output->cursor_bo[i] =
Giulio Camuffo954f1832014-10-11 18:27:30 +03001782 gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001783 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001784 }
1785
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001786 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1787 weston_log("cursor buffers unavailable, using gl cursors\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03001788 b->cursors_are_broken = 1;
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001789 }
1790
1791 return 0;
1792}
1793
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001794static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03001795drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001796{
Hardeningff39efa2013-09-18 23:56:35 +02001797 int w = output->base.current_mode->width;
1798 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001799 unsigned int i;
1800
1801 /* FIXME error checking */
1802
1803 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001804 output->dumb[i] = drm_fb_create_dumb(b, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001805 if (!output->dumb[i])
1806 goto err;
1807
1808 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001809 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001810 output->dumb[i]->map,
1811 output->dumb[i]->stride);
1812 if (!output->image[i])
1813 goto err;
1814 }
1815
1816 if (pixman_renderer_output_create(&output->base) < 0)
1817 goto err;
1818
1819 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001820 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001821
1822 return 0;
1823
1824err:
1825 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1826 if (output->dumb[i])
1827 drm_fb_destroy_dumb(output->dumb[i]);
1828 if (output->image[i])
1829 pixman_image_unref(output->image[i]);
1830
1831 output->dumb[i] = NULL;
1832 output->image[i] = NULL;
1833 }
1834
1835 return -1;
1836}
1837
1838static void
1839drm_output_fini_pixman(struct drm_output *output)
1840{
1841 unsigned int i;
1842
1843 pixman_renderer_output_destroy(&output->base);
1844 pixman_region32_fini(&output->previous_damage);
1845
1846 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1847 drm_fb_destroy_dumb(output->dumb[i]);
1848 pixman_image_unref(output->image[i]);
1849 output->dumb[i] = NULL;
1850 output->image[i] = NULL;
1851 }
1852}
1853
Richard Hughes2b2092a2013-04-24 14:58:02 +01001854static void
1855edid_parse_string(const uint8_t *data, char text[])
1856{
1857 int i;
1858 int replaced = 0;
1859
1860 /* this is always 12 bytes, but we can't guarantee it's null
1861 * terminated or not junk. */
1862 strncpy(text, (const char *) data, 12);
1863
1864 /* remove insane chars */
1865 for (i = 0; text[i] != '\0'; i++) {
1866 if (text[i] == '\n' ||
1867 text[i] == '\r') {
1868 text[i] = '\0';
1869 break;
1870 }
1871 }
1872
1873 /* ensure string is printable */
1874 for (i = 0; text[i] != '\0'; i++) {
1875 if (!isprint(text[i])) {
1876 text[i] = '-';
1877 replaced++;
1878 }
1879 }
1880
1881 /* if the string is random junk, ignore the string */
1882 if (replaced > 4)
1883 text[0] = '\0';
1884}
1885
1886#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1887#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1888#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1889#define EDID_OFFSET_DATA_BLOCKS 0x36
1890#define EDID_OFFSET_LAST_BLOCK 0x6c
1891#define EDID_OFFSET_PNPID 0x08
1892#define EDID_OFFSET_SERIAL 0x0c
1893
1894static int
1895edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1896{
1897 int i;
1898 uint32_t serial_number;
1899
1900 /* check header */
1901 if (length < 128)
1902 return -1;
1903 if (data[0] != 0x00 || data[1] != 0xff)
1904 return -1;
1905
1906 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1907 * /--08--\/--09--\
1908 * 7654321076543210
1909 * |\---/\---/\---/
1910 * R C1 C2 C3 */
1911 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1912 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1913 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1914 edid->pnp_id[3] = '\0';
1915
1916 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1917 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1918 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1919 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1920 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1921 if (serial_number > 0)
1922 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1923
1924 /* parse EDID data */
1925 for (i = EDID_OFFSET_DATA_BLOCKS;
1926 i <= EDID_OFFSET_LAST_BLOCK;
1927 i += 18) {
1928 /* ignore pixel clock data */
1929 if (data[i] != 0)
1930 continue;
1931 if (data[i+2] != 0)
1932 continue;
1933
1934 /* any useful blocks? */
1935 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1936 edid_parse_string(&data[i+5],
1937 edid->monitor_name);
1938 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1939 edid_parse_string(&data[i+5],
1940 edid->serial_number);
1941 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1942 edid_parse_string(&data[i+5],
1943 edid->eisa_id);
1944 }
1945 }
1946 return 0;
1947}
1948
1949static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03001950find_and_parse_output_edid(struct drm_backend *b,
Richard Hughes2b2092a2013-04-24 14:58:02 +01001951 struct drm_output *output,
1952 drmModeConnector *connector)
1953{
1954 drmModePropertyBlobPtr edid_blob = NULL;
1955 drmModePropertyPtr property;
1956 int i;
1957 int rc;
1958
1959 for (i = 0; i < connector->count_props && !edid_blob; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001960 property = drmModeGetProperty(b->drm.fd, connector->props[i]);
Richard Hughes2b2092a2013-04-24 14:58:02 +01001961 if (!property)
1962 continue;
1963 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1964 !strcmp(property->name, "EDID")) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03001965 edid_blob = drmModeGetPropertyBlob(b->drm.fd,
Richard Hughes2b2092a2013-04-24 14:58:02 +01001966 connector->prop_values[i]);
1967 }
1968 drmModeFreeProperty(property);
1969 }
1970 if (!edid_blob)
1971 return;
1972
1973 rc = edid_parse(&output->edid,
1974 edid_blob->data,
1975 edid_blob->length);
1976 if (!rc) {
1977 weston_log("EDID data '%s', '%s', '%s'\n",
1978 output->edid.pnp_id,
1979 output->edid.monitor_name,
1980 output->edid.serial_number);
1981 if (output->edid.pnp_id[0] != '\0')
1982 output->base.make = output->edid.pnp_id;
1983 if (output->edid.monitor_name[0] != '\0')
1984 output->base.model = output->edid.monitor_name;
1985 if (output->edid.serial_number[0] != '\0')
1986 output->base.serial_number = output->edid.serial_number;
1987 }
1988 drmModeFreePropertyBlob(edid_blob);
1989}
1990
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001991
1992
1993static int
1994parse_modeline(const char *s, drmModeModeInfo *mode)
1995{
1996 char hsync[16];
1997 char vsync[16];
1998 float fclock;
1999
2000 mode->type = DRM_MODE_TYPE_USERDEF;
2001 mode->hskew = 0;
2002 mode->vscan = 0;
2003 mode->vrefresh = 0;
2004 mode->flags = 0;
2005
Rob Bradford307e09e2013-07-26 16:29:40 +01002006 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002007 &fclock,
2008 &mode->hdisplay,
2009 &mode->hsync_start,
2010 &mode->hsync_end,
2011 &mode->htotal,
2012 &mode->vdisplay,
2013 &mode->vsync_start,
2014 &mode->vsync_end,
2015 &mode->vtotal, hsync, vsync) != 11)
2016 return -1;
2017
2018 mode->clock = fclock * 1000;
2019 if (strcmp(hsync, "+hsync") == 0)
2020 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2021 else if (strcmp(hsync, "-hsync") == 0)
2022 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2023 else
2024 return -1;
2025
2026 if (strcmp(vsync, "+vsync") == 0)
2027 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2028 else if (strcmp(vsync, "-vsync") == 0)
2029 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2030 else
2031 return -1;
2032
2033 return 0;
2034}
2035
Rob Bradford66bd9f52013-06-25 18:56:42 +01002036static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002037setup_output_seat_constraint(struct drm_backend *b,
Rob Bradford66bd9f52013-06-25 18:56:42 +01002038 struct weston_output *output,
2039 const char *s)
2040{
2041 if (strcmp(s, "") != 0) {
2042 struct udev_seat *seat;
2043
Giulio Camuffo954f1832014-10-11 18:27:30 +03002044 seat = udev_seat_get_named(&b->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01002045 if (seat)
2046 seat->base.output = output;
2047
2048 if (seat && seat->base.pointer)
2049 weston_pointer_clamp(seat->base.pointer,
2050 &seat->base.pointer->x,
2051 &seat->base.pointer->y);
2052 }
2053}
2054
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002055static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002056get_gbm_format_from_section(struct weston_config_section *section,
2057 uint32_t default_value,
2058 uint32_t *format)
2059{
2060 char *s;
2061 int ret = 0;
2062
2063 weston_config_section_get_string(section,
2064 "gbm-format", &s, NULL);
2065
2066 if (s == NULL)
2067 *format = default_value;
2068 else if (strcmp(s, "xrgb8888") == 0)
2069 *format = GBM_FORMAT_XRGB8888;
2070 else if (strcmp(s, "rgb565") == 0)
2071 *format = GBM_FORMAT_RGB565;
2072 else if (strcmp(s, "xrgb2101010") == 0)
2073 *format = GBM_FORMAT_XRGB2101010;
2074 else {
2075 weston_log("fatal: unrecognized pixel format: %s\n", s);
2076 ret = -1;
2077 }
2078
2079 free(s);
2080
2081 return ret;
2082}
2083
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002084/**
2085 * Choose suitable mode for an output
2086 *
2087 * Find the most suitable mode to use for initial setup (or reconfiguration on
2088 * hotplug etc) for a DRM output.
2089 *
2090 * @param output DRM output to choose mode for
2091 * @param kind Strategy and preference to use when choosing mode
2092 * @param width Desired width for this output
2093 * @param height Desired height for this output
2094 * @param current_mode Mode currently being displayed on this output
2095 * @param modeline Manually-entered mode (may be NULL)
2096 * @returns A mode from the output's mode list, or NULL if none available
2097 */
2098static struct drm_mode *
2099drm_output_choose_initial_mode(struct drm_output *output,
2100 enum output_config kind,
2101 int width, int height,
2102 const drmModeModeInfo *current_mode,
2103 const drmModeModeInfo *modeline)
2104{
2105 struct drm_mode *preferred = NULL;
2106 struct drm_mode *current = NULL;
2107 struct drm_mode *configured = NULL;
2108 struct drm_mode *best = NULL;
2109 struct drm_mode *drm_mode;
2110
2111 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
2112 if (kind == OUTPUT_CONFIG_MODE &&
2113 width == drm_mode->base.width &&
2114 height == drm_mode->base.height)
2115 configured = drm_mode;
2116
2117 if (memcmp(&current_mode, &drm_mode->mode_info,
2118 sizeof *current_mode) == 0)
2119 current = drm_mode;
2120
2121 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
2122 preferred = drm_mode;
2123
2124 best = drm_mode;
2125 }
2126
2127 if (kind == OUTPUT_CONFIG_MODELINE) {
2128 configured = drm_output_add_mode(output, modeline);
2129 if (!configured)
2130 return NULL;
2131 }
2132
2133 if (current == NULL && current_mode->clock != 0) {
2134 current = drm_output_add_mode(output, current_mode);
2135 if (!current)
2136 return NULL;
2137 }
2138
2139 if (kind == OUTPUT_CONFIG_CURRENT)
2140 configured = current;
2141
2142 if (option_current_mode && current)
2143 return current;
2144
2145 if (configured)
2146 return configured;
2147
2148 if (preferred)
2149 return preferred;
2150
2151 if (current)
2152 return current;
2153
2154 if (best)
2155 return best;
2156
2157 weston_log("no available modes for %s\n", output->base.name);
2158 return NULL;
2159}
2160
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002161static int
2162connector_get_current_mode(drmModeConnector *connector, int drm_fd,
2163 drmModeModeInfo *mode)
2164{
2165 drmModeEncoder *encoder;
2166 drmModeCrtc *crtc;
2167
2168 /* Get the current mode on the crtc that's currently driving
2169 * this connector. */
2170 encoder = drmModeGetEncoder(drm_fd, connector->encoder_id);
2171 memset(mode, 0, sizeof *mode);
2172 if (encoder != NULL) {
2173 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
2174 drmModeFreeEncoder(encoder);
2175 if (crtc == NULL)
2176 return -1;
2177 if (crtc->mode_valid)
2178 *mode = crtc->mode;
2179 drmModeFreeCrtc(crtc);
2180 }
2181
2182 return 0;
2183}
2184
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002185/**
2186 * Create and configure a Weston output structure
2187 *
2188 * Given a DRM connector, create a matching drm_output structure and add it
2189 * to Weston's output list.
2190 *
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002191 * @param b Weston backend structure structure
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002192 * @param resources DRM resources for this device
2193 * @param connector DRM connector to use for this new output
2194 * @param x Horizontal offset to use into global co-ordinate space
2195 * @param y Vertical offset to use into global co-ordinate space
2196 * @param drm_device udev device pointer
2197 * @returns 0 on success, or -1 on failure
2198 */
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002199static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002200create_output_for_connector(struct drm_backend *b,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002201 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002202 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002203 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002204{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002205 struct drm_output *output;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002206 struct drm_mode *drm_mode, *next, *current;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002207 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002208 struct weston_config_section *section;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002209 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002210 int i, width, height, scale;
Pekka Paalanen3ce63622014-06-04 16:29:49 +03002211 char *s;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002212 enum output_config config;
2213 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002214
Giulio Camuffo954f1832014-10-11 18:27:30 +03002215 i = find_crtc_for_connector(b, resources, connector);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002216 if (i < 0) {
2217 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002218 return -1;
2219 }
2220
Peter Huttererf3d62272013-08-08 11:57:05 +10002221 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002222 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002223 return -1;
2224
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002225 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
Pekka Paalanen3ce63622014-06-04 16:29:49 +03002226 output->base.name = make_connector_name(connector);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002227 output->base.make = "unknown";
2228 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01002229 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002230 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002231
Giulio Camuffo954f1832014-10-11 18:27:30 +03002232 section = weston_config_get_section(b->compositor->config, "output", "name",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002233 output->base.name);
2234 weston_config_section_get_string(section, "mode", &s, "preferred");
2235 if (strcmp(s, "off") == 0)
2236 config = OUTPUT_CONFIG_OFF;
2237 else if (strcmp(s, "preferred") == 0)
2238 config = OUTPUT_CONFIG_PREFERRED;
2239 else if (strcmp(s, "current") == 0)
2240 config = OUTPUT_CONFIG_CURRENT;
2241 else if (sscanf(s, "%dx%d", &width, &height) == 2)
2242 config = OUTPUT_CONFIG_MODE;
2243 else if (parse_modeline(s, &modeline) == 0)
2244 config = OUTPUT_CONFIG_MODELINE;
2245 else {
2246 weston_log("Invalid mode \"%s\" for output %s\n",
2247 s, output->base.name);
2248 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002249 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002250 free(s);
2251
2252 weston_config_section_get_int(section, "scale", &scale, 1);
2253 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05002254 if (weston_parse_transform(s, &transform) < 0)
2255 weston_log("Invalid transform \"%s\" for output %s\n",
2256 s, output->base.name);
2257
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002258 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002259
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002260 if (get_gbm_format_from_section(section,
Giulio Camuffo954f1832014-10-11 18:27:30 +03002261 b->format,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002262 &output->format) == -1)
Giulio Camuffo954f1832014-10-11 18:27:30 +03002263 output->format = b->format;
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002264
Rob Bradford66bd9f52013-06-25 18:56:42 +01002265 weston_config_section_get_string(section, "seat", &s, "");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002266 setup_output_seat_constraint(b, &output->base, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01002267 free(s);
2268
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002269 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002270 output->pipe = i;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002271 b->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002272 output->connector_id = connector->connector_id;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002273 b->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002274
Giulio Camuffo954f1832014-10-11 18:27:30 +03002275 output->original_crtc = drmModeGetCrtc(b->drm.fd, output->crtc_id);
2276 output->dpms_prop = drm_get_prop(b->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002277
Pekka Paalaneneee580b2014-06-04 16:43:06 +03002278 if (connector_get_current_mode(connector, b->drm.fd, &crtc_mode) < 0)
2279 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002280
David Herrmann0f0d54e2011-12-08 17:05:45 +01002281 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002282 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002283 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002284 goto err_free;
2285 }
2286
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002287 if (config == OUTPUT_CONFIG_OFF) {
2288 weston_log("Disabling output %s\n", output->base.name);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002289 drmModeSetCrtc(b->drm.fd, output->crtc_id,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002290 0, 0, 0, 0, 0, NULL);
2291 goto err_free;
2292 }
2293
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002294 current = drm_output_choose_initial_mode(output, config,
2295 width, height,
2296 &crtc_mode, &modeline);
2297 if (!current)
Wang Quanxianacb805a2012-07-30 18:09:46 -04002298 goto err_free;
Pekka Paalanen7b36b422014-06-04 14:00:53 +03002299 output->base.current_mode = &current->base;
Hardeningff39efa2013-09-18 23:56:35 +02002300 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002301
Giulio Camuffo954f1832014-10-11 18:27:30 +03002302 weston_output_init(&output->base, b->compositor, x, y,
John Kåre Alsaker94659272012-11-13 19:10:18 +01002303 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002304 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002305
Giulio Camuffo954f1832014-10-11 18:27:30 +03002306 if (b->use_pixman) {
2307 if (drm_output_init_pixman(output, b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002308 weston_log("Failed to init output pixman state\n");
2309 goto err_output;
2310 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03002311 } else if (drm_output_init_egl(output, b) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002312 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002313 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002314 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002315
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002316 output->backlight = backlight_init(drm_device,
2317 connector->connector_type);
2318 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002319 weston_log("Initialized backlight, device %s\n",
2320 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002321 output->base.set_backlight = drm_set_backlight;
2322 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002323 } else {
2324 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002325 }
2326
Giulio Camuffo954f1832014-10-11 18:27:30 +03002327 weston_compositor_add_output(b->compositor, &output->base);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002328
Giulio Camuffo954f1832014-10-11 18:27:30 +03002329 find_and_parse_output_edid(b, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002330 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2331 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002332
Jonas Ådahle5a12252013-04-05 23:07:11 +02002333 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002334 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002335 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002336 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002337 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002338 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002339
Richard Hughese7299962013-05-01 21:52:12 +01002340 output->base.gamma_size = output->original_crtc->gamma_size;
2341 output->base.set_gamma = drm_output_set_gamma;
2342
Giulio Camuffo954f1832014-10-11 18:27:30 +03002343 weston_plane_init(&output->cursor_plane, b->compositor, 0, 0);
2344 weston_plane_init(&output->fb_plane, b->compositor, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002345
Giulio Camuffo954f1832014-10-11 18:27:30 +03002346 weston_compositor_stack_plane(b->compositor, &output->cursor_plane, NULL);
2347 weston_compositor_stack_plane(b->compositor, &output->fb_plane,
2348 &b->compositor->primary_plane);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002349
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002350 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002351 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002352 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002353 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002354 m->width, m->height, m->refresh / 1000.0,
2355 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2356 ", preferred" : "",
2357 m->flags & WL_OUTPUT_MODE_CURRENT ?
2358 ", current" : "",
2359 connector->count_modes == 0 ?
2360 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002361
Mario Kleiner80817042015-06-21 21:25:11 +02002362 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
2363 output->base.native_mode = output->base.current_mode;
2364 output->base.native_scale = output->base.current_scale;
2365
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002366 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002367
John Kåre Alsaker94659272012-11-13 19:10:18 +01002368err_output:
2369 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002370err_free:
2371 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2372 base.link) {
2373 wl_list_remove(&drm_mode->base.link);
2374 free(drm_mode);
2375 }
2376
2377 drmModeFreeCrtc(output->original_crtc);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002378 b->crtc_allocator &= ~(1 << output->crtc_id);
2379 b->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002380 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002381
David Herrmann0f0d54e2011-12-08 17:05:45 +01002382 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002383}
2384
Jesse Barnes58ef3792012-02-23 09:45:49 -05002385static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002386create_sprites(struct drm_backend *b)
Jesse Barnes58ef3792012-02-23 09:45:49 -05002387{
2388 struct drm_sprite *sprite;
2389 drmModePlaneRes *plane_res;
2390 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002391 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002392
Giulio Camuffo954f1832014-10-11 18:27:30 +03002393 plane_res = drmModeGetPlaneResources(b->drm.fd);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002394 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002395 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002396 strerror(errno));
2397 return;
2398 }
2399
2400 for (i = 0; i < plane_res->count_planes; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002401 plane = drmModeGetPlane(b->drm.fd, plane_res->planes[i]);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002402 if (!plane)
2403 continue;
2404
Peter Huttererf3d62272013-08-08 11:57:05 +10002405 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002406 plane->count_formats));
2407 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002408 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002409 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002410 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002411 continue;
2412 }
2413
Jesse Barnes58ef3792012-02-23 09:45:49 -05002414 sprite->possible_crtcs = plane->possible_crtcs;
2415 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002416 sprite->current = NULL;
2417 sprite->next = NULL;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002418 sprite->backend = b;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002419 sprite->count_formats = plane->count_formats;
2420 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002421 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002422 drmModeFreePlane(plane);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002423 weston_plane_init(&sprite->plane, b->compositor, 0, 0);
2424 weston_compositor_stack_plane(b->compositor, &sprite->plane,
2425 &b->compositor->primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002426
Giulio Camuffo954f1832014-10-11 18:27:30 +03002427 wl_list_insert(&b->sprite_list, &sprite->link);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002428 }
2429
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002430 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002431}
2432
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002433static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002434destroy_sprites(struct drm_backend *backend)
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002435{
2436 struct drm_sprite *sprite, *next;
2437 struct drm_output *output;
2438
Giulio Camuffo954f1832014-10-11 18:27:30 +03002439 output = container_of(backend->compositor->output_list.next,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002440 struct drm_output, base.link);
2441
Giulio Camuffo954f1832014-10-11 18:27:30 +03002442 wl_list_for_each_safe(sprite, next, &backend->sprite_list, link) {
2443 drmModeSetPlane(backend->drm.fd,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002444 sprite->plane_id,
2445 output->crtc_id, 0, 0,
2446 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002447 drm_output_release_fb(output, sprite->current);
2448 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002449 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002450 free(sprite);
2451 }
2452}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002453
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002454static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002455create_outputs(struct drm_backend *b, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002456 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002457{
2458 drmModeConnector *connector;
2459 drmModeRes *resources;
2460 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002461 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002462
Giulio Camuffo954f1832014-10-11 18:27:30 +03002463 resources = drmModeGetResources(b->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002464 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002465 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002466 return -1;
2467 }
2468
Giulio Camuffo954f1832014-10-11 18:27:30 +03002469 b->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
2470 if (!b->crtcs) {
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002471 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002472 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002473 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002474
Giulio Camuffo954f1832014-10-11 18:27:30 +03002475 b->min_width = resources->min_width;
2476 b->max_width = resources->max_width;
2477 b->min_height = resources->min_height;
2478 b->max_height = resources->max_height;
Rob Clark4339add2012-08-09 14:18:28 -05002479
Giulio Camuffo954f1832014-10-11 18:27:30 +03002480 b->num_crtcs = resources->count_crtcs;
2481 memcpy(b->crtcs, resources->crtcs, sizeof(uint32_t) * b->num_crtcs);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002482
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002483 for (i = 0; i < resources->count_connectors; i++) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002484 connector = drmModeGetConnector(b->drm.fd,
Benjamin Franzke117483d2011-08-30 11:38:26 +02002485 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002486 if (connector == NULL)
2487 continue;
2488
2489 if (connector->connection == DRM_MODE_CONNECTED &&
2490 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002491 connector->connector_id == option_connector)) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002492 if (create_output_for_connector(b, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002493 connector, x, y,
2494 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002495 drmModeFreeConnector(connector);
2496 continue;
2497 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002498
Giulio Camuffo954f1832014-10-11 18:27:30 +03002499 x += container_of(b->compositor->output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002500 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002501 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002502 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002503
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002504 drmModeFreeConnector(connector);
2505 }
2506
Giulio Camuffo954f1832014-10-11 18:27:30 +03002507 if (wl_list_empty(&b->compositor->output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002508 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002509 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002510 return -1;
2511 }
2512
2513 drmModeFreeResources(resources);
2514
2515 return 0;
2516}
2517
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002518static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002519update_outputs(struct drm_backend *b, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002520{
2521 drmModeConnector *connector;
2522 drmModeRes *resources;
2523 struct drm_output *output, *next;
2524 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002525 uint32_t connected = 0, disconnects = 0;
2526 int i;
2527
Giulio Camuffo954f1832014-10-11 18:27:30 +03002528 resources = drmModeGetResources(b->drm.fd);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002529 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002530 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002531 return;
2532 }
2533
2534 /* collect new connects */
2535 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002536 int connector_id = resources->connectors[i];
2537
Giulio Camuffo954f1832014-10-11 18:27:30 +03002538 connector = drmModeGetConnector(b->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002539 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002540 continue;
2541
David Herrmann7551cff2011-12-08 17:05:43 +01002542 if (connector->connection != DRM_MODE_CONNECTED) {
2543 drmModeFreeConnector(connector);
2544 continue;
2545 }
2546
Benjamin Franzke117483d2011-08-30 11:38:26 +02002547 connected |= (1 << connector_id);
2548
Giulio Camuffo954f1832014-10-11 18:27:30 +03002549 if (!(b->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002550 struct weston_output *last =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002551 container_of(b->compositor->output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002552 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002553
2554 /* XXX: not yet needed, we die with 0 outputs */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002555 if (!wl_list_empty(&b->compositor->output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002556 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002557 else
2558 x = 0;
2559 y = 0;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002560 create_output_for_connector(b, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002561 connector, x, y,
2562 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002563 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002564
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002565 }
2566 drmModeFreeConnector(connector);
2567 }
2568 drmModeFreeResources(resources);
2569
Giulio Camuffo954f1832014-10-11 18:27:30 +03002570 disconnects = b->connector_allocator & ~connected;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002571 if (disconnects) {
Giulio Camuffo954f1832014-10-11 18:27:30 +03002572 wl_list_for_each_safe(output, next, &b->compositor->output_list,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002573 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002574 if (disconnects & (1 << output->connector_id)) {
2575 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002576 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002577 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002578 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002579 }
2580 }
2581 }
2582
Daniel Stonef556ebe2015-05-21 08:28:58 +01002583 /* FIXME: handle zero outputs, without terminating */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002584 if (b->connector_allocator == 0)
Giulio Camuffo459137b2014-10-11 23:56:24 +03002585 weston_compositor_exit(b->compositor);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002586}
2587
2588static int
Giulio Camuffo954f1832014-10-11 18:27:30 +03002589udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002590{
David Herrmannd7488c22012-03-11 20:05:21 +01002591 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002592 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002593
2594 sysnum = udev_device_get_sysnum(device);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002595 if (!sysnum || atoi(sysnum) != b->drm.id)
David Herrmannd7488c22012-03-11 20:05:21 +01002596 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002597
David Herrmann6ac52db2012-03-11 20:05:22 +01002598 val = udev_device_get_property_value(device, "HOTPLUG");
2599 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002600 return 0;
2601
David Herrmann6ac52db2012-03-11 20:05:22 +01002602 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002603}
2604
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002605static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002606udev_drm_event(int fd, uint32_t mask, void *data)
2607{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002608 struct drm_backend *b = data;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002609 struct udev_device *event;
2610
Giulio Camuffo954f1832014-10-11 18:27:30 +03002611 event = udev_monitor_receive_device(b->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002612
Giulio Camuffo954f1832014-10-11 18:27:30 +03002613 if (udev_event_is_hotplug(b, event))
2614 update_outputs(b, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002615
2616 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002617
2618 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002619}
2620
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002621static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002622drm_restore(struct weston_compositor *ec)
2623{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002624 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002625}
2626
2627static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002628drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002629{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002630 struct drm_backend *b = (struct drm_backend *) ec->backend;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002631
Giulio Camuffo954f1832014-10-11 18:27:30 +03002632 udev_input_destroy(&b->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002633
Giulio Camuffo954f1832014-10-11 18:27:30 +03002634 wl_event_source_remove(b->udev_drm_source);
2635 wl_event_source_remove(b->drm_source);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002636
Giulio Camuffo954f1832014-10-11 18:27:30 +03002637 destroy_sprites(b);
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002638
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002639 weston_compositor_shutdown(ec);
2640
Giulio Camuffo954f1832014-10-11 18:27:30 +03002641 if (b->gbm)
2642 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002643
Giulio Camuffo954f1832014-10-11 18:27:30 +03002644 weston_launcher_destroy(ec->launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002645
Giulio Camuffo954f1832014-10-11 18:27:30 +03002646 close(b->drm.fd);
Rob Bradford45c15b82013-07-26 16:29:35 +01002647
Giulio Camuffo954f1832014-10-11 18:27:30 +03002648 free(b);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002649}
2650
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002651static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002652drm_backend_set_modes(struct drm_backend *backend)
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002653{
2654 struct drm_output *output;
2655 struct drm_mode *drm_mode;
2656 int ret;
2657
Giulio Camuffo954f1832014-10-11 18:27:30 +03002658 wl_list_for_each(output, &backend->compositor->output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002659 if (!output->current) {
2660 /* If something that would cause the output to
2661 * switch mode happened while in another vt, we
2662 * might not have a current drm_fb. In that case,
2663 * schedule a repaint and let drm_output_repaint
2664 * handle setting the mode. */
2665 weston_output_schedule_repaint(&output->base);
2666 continue;
2667 }
2668
Hardeningff39efa2013-09-18 23:56:35 +02002669 drm_mode = (struct drm_mode *) output->base.current_mode;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002670 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002671 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002672 &output->connector_id, 1,
2673 &drm_mode->mode_info);
2674 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002675 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002676 "failed to set mode %dx%d for output at %d,%d: %m\n",
Daniel Stonef556ebe2015-05-21 08:28:58 +01002677 drm_mode->base.width, drm_mode->base.height,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002678 output->base.x, output->base.y);
2679 }
2680 }
2681}
2682
2683static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002684session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002685{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002686 struct weston_compositor *compositor = data;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002687 struct drm_backend *b = (struct drm_backend *)compositor->backend;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002688 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002689 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002690
Giulio Camuffo954f1832014-10-11 18:27:30 +03002691 if (compositor->session_active) {
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002692 weston_log("activating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002693 compositor->state = b->prev_state;
2694 drm_backend_set_modes(b);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002695 weston_compositor_damage_all(compositor);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002696 udev_input_enable(&b->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002697 } else {
2698 weston_log("deactivating session\n");
Giulio Camuffo954f1832014-10-11 18:27:30 +03002699 udev_input_disable(&b->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002700
Giulio Camuffo954f1832014-10-11 18:27:30 +03002701 b->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002702 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002703
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002704 /* If we have a repaint scheduled (either from a
2705 * pending pageflip or the idle handler), make sure we
2706 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002707 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002708 * further attemps at repainting. When we switch
2709 * back, we schedule a repaint, which will process
2710 * pending frame callbacks. */
2711
Giulio Camuffo954f1832014-10-11 18:27:30 +03002712 wl_list_for_each(output, &compositor->output_list, base.link) {
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002713 output->base.repaint_needed = 0;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002714 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002715 }
2716
Giulio Camuffo954f1832014-10-11 18:27:30 +03002717 output = container_of(compositor->output_list.next,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002718 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002719
Giulio Camuffo954f1832014-10-11 18:27:30 +03002720 wl_list_for_each(sprite, &b->sprite_list, link)
2721 drmModeSetPlane(b->drm.fd,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002722 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002723 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002724 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002725 };
2726}
2727
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002728static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002729switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002730{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002731 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002732
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002733 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002734}
2735
David Herrmann0af066f2012-10-29 19:21:16 +01002736/*
2737 * Find primary GPU
2738 * Some systems may have multiple DRM devices attached to a single seat. This
2739 * function loops over all devices and tries to find a PCI device with the
2740 * boot_vga sysfs attribute set to 1.
2741 * If no such device is found, the first DRM device reported by udev is used.
2742 */
2743static struct udev_device*
Giulio Camuffo954f1832014-10-11 18:27:30 +03002744find_primary_gpu(struct drm_backend *b, const char *seat)
David Herrmann0af066f2012-10-29 19:21:16 +01002745{
2746 struct udev_enumerate *e;
2747 struct udev_list_entry *entry;
2748 const char *path, *device_seat, *id;
2749 struct udev_device *device, *drm_device, *pci;
2750
Giulio Camuffo954f1832014-10-11 18:27:30 +03002751 e = udev_enumerate_new(b->udev);
David Herrmann0af066f2012-10-29 19:21:16 +01002752 udev_enumerate_add_match_subsystem(e, "drm");
2753 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2754
2755 udev_enumerate_scan_devices(e);
2756 drm_device = NULL;
2757 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2758 path = udev_list_entry_get_name(entry);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002759 device = udev_device_new_from_syspath(b->udev, path);
David Herrmann0af066f2012-10-29 19:21:16 +01002760 if (!device)
2761 continue;
2762 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2763 if (!device_seat)
2764 device_seat = default_seat;
2765 if (strcmp(device_seat, seat)) {
2766 udev_device_unref(device);
2767 continue;
2768 }
2769
2770 pci = udev_device_get_parent_with_subsystem_devtype(device,
2771 "pci", NULL);
2772 if (pci) {
2773 id = udev_device_get_sysattr_value(pci, "boot_vga");
2774 if (id && !strcmp(id, "1")) {
2775 if (drm_device)
2776 udev_device_unref(drm_device);
2777 drm_device = device;
2778 break;
2779 }
2780 }
2781
2782 if (!drm_device)
2783 drm_device = device;
2784 else
2785 udev_device_unref(device);
2786 }
2787
2788 udev_enumerate_unref(e);
2789 return drm_device;
2790}
2791
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002792static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002793planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002794{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002795 struct drm_backend *b = data;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002796
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002797 switch (key) {
2798 case KEY_C:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002799 b->cursors_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002800 break;
2801 case KEY_V:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002802 b->sprites_are_broken ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002803 break;
2804 case KEY_O:
Giulio Camuffo954f1832014-10-11 18:27:30 +03002805 b->sprites_hidden ^= 1;
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002806 break;
2807 default:
2808 break;
2809 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002810}
2811
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002812#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002813static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002814recorder_destroy(struct drm_output *output)
2815{
2816 vaapi_recorder_destroy(output->recorder);
2817 output->recorder = NULL;
2818
2819 output->base.disable_planes--;
2820
2821 wl_list_remove(&output->recorder_frame_listener.link);
2822 weston_log("[libva recorder] done\n");
2823}
2824
2825static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002826recorder_frame_notify(struct wl_listener *listener, void *data)
2827{
2828 struct drm_output *output;
Giulio Camuffo954f1832014-10-11 18:27:30 +03002829 struct drm_backend *b;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002830 int fd, ret;
2831
2832 output = container_of(listener, struct drm_output,
2833 recorder_frame_listener);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002834 b = (struct drm_backend *)output->base.compositor->backend;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002835
2836 if (!output->recorder)
2837 return;
2838
Giulio Camuffo954f1832014-10-11 18:27:30 +03002839 ret = drmPrimeHandleToFD(b->drm.fd, output->current->handle,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002840 DRM_CLOEXEC, &fd);
2841 if (ret) {
2842 weston_log("[libva recorder] "
2843 "failed to create prime fd for front buffer\n");
2844 return;
2845 }
2846
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002847 ret = vaapi_recorder_frame(output->recorder, fd,
2848 output->current->stride);
2849 if (ret < 0) {
2850 weston_log("[libva recorder] aborted: %m\n");
2851 recorder_destroy(output);
2852 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002853}
2854
2855static void *
Giulio Camuffo954f1832014-10-11 18:27:30 +03002856create_recorder(struct drm_backend *b, int width, int height,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002857 const char *filename)
2858{
2859 int fd;
2860 drm_magic_t magic;
2861
Giulio Camuffo954f1832014-10-11 18:27:30 +03002862 fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002863 if (fd < 0)
2864 return NULL;
2865
2866 drmGetMagic(fd, &magic);
Giulio Camuffo954f1832014-10-11 18:27:30 +03002867 drmAuthMagic(b->drm.fd, magic);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002868
2869 return vaapi_recorder_create(fd, width, height, filename);
2870}
2871
2872static void
2873recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2874 void *data)
2875{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002876 struct drm_backend *b = data;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002877 struct drm_output *output;
2878 int width, height;
2879
Giulio Camuffo954f1832014-10-11 18:27:30 +03002880 output = container_of(b->compositor->output_list.next,
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002881 struct drm_output, base.link);
2882
2883 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002884 if (output->format != GBM_FORMAT_XRGB8888) {
2885 weston_log("failed to start vaapi recorder: "
2886 "output format not supported\n");
2887 return;
2888 }
2889
Hardeningff39efa2013-09-18 23:56:35 +02002890 width = output->base.current_mode->width;
2891 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002892
2893 output->recorder =
Giulio Camuffo954f1832014-10-11 18:27:30 +03002894 create_recorder(b, width, height, "capture.h264");
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002895 if (!output->recorder) {
2896 weston_log("failed to create vaapi recorder\n");
2897 return;
2898 }
2899
2900 output->base.disable_planes++;
2901
2902 output->recorder_frame_listener.notify = recorder_frame_notify;
2903 wl_signal_add(&output->base.frame_signal,
2904 &output->recorder_frame_listener);
2905
2906 weston_output_schedule_repaint(&output->base);
2907
2908 weston_log("[libva recorder] initialized\n");
2909 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002910 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002911 }
2912}
2913#else
2914static void
2915recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2916 void *data)
2917{
2918 weston_log("Compiled without libva support\n");
2919}
2920#endif
2921
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002922static void
Giulio Camuffo954f1832014-10-11 18:27:30 +03002923switch_to_gl_renderer(struct drm_backend *b)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002924{
2925 struct drm_output *output;
2926
Giulio Camuffo954f1832014-10-11 18:27:30 +03002927 if (!b->use_pixman)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002928 return;
2929
2930 weston_log("Switching to GL renderer\n");
2931
Giulio Camuffo954f1832014-10-11 18:27:30 +03002932 b->gbm = create_gbm_device(b->drm.fd);
2933 if (!b->gbm) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002934 weston_log("Failed to create gbm device. "
2935 "Aborting renderer switch\n");
2936 return;
2937 }
2938
Giulio Camuffo954f1832014-10-11 18:27:30 +03002939 wl_list_for_each(output, &b->compositor->output_list, base.link)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002940 pixman_renderer_output_destroy(&output->base);
2941
Giulio Camuffo954f1832014-10-11 18:27:30 +03002942 b->compositor->renderer->destroy(b->compositor);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002943
Giulio Camuffo954f1832014-10-11 18:27:30 +03002944 if (drm_backend_create_gl_renderer(b) < 0) {
2945 gbm_device_destroy(b->gbm);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002946 weston_log("Failed to create GL renderer. Quitting.\n");
2947 /* FIXME: we need a function to shutdown cleanly */
2948 assert(0);
2949 }
2950
Giulio Camuffo954f1832014-10-11 18:27:30 +03002951 wl_list_for_each(output, &b->compositor->output_list, base.link)
2952 drm_output_init_egl(output, b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002953
Giulio Camuffo954f1832014-10-11 18:27:30 +03002954 b->use_pixman = 0;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002955}
2956
2957static void
2958renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2959 void *data)
2960{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002961 struct drm_backend *b = (struct drm_backend *)seat->compositor->backend;
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002962
Giulio Camuffo954f1832014-10-11 18:27:30 +03002963 switch_to_gl_renderer(b);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002964}
2965
Giulio Camuffo954f1832014-10-11 18:27:30 +03002966static struct drm_backend *
2967drm_backend_create(struct weston_compositor *compositor,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002968 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002969 int *argc, char *argv[],
2970 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002971{
Giulio Camuffo954f1832014-10-11 18:27:30 +03002972 struct drm_backend *b;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002973 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002974 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002975 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002976 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002977 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002978
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002979 weston_log("initializing drm backend\n");
2980
Giulio Camuffo954f1832014-10-11 18:27:30 +03002981 b = zalloc(sizeof *b);
2982 if (b == NULL)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002983 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002984
Pekka Paalanen68583832015-05-19 09:53:16 +03002985 /*
2986 * KMS support for hardware planes cannot properly synchronize
2987 * without nuclear page flip. Without nuclear/atomic, hw plane
2988 * and cursor plane updates would either tear or cause extra
2989 * waits for vblanks which means dropping the compositor framerate
2990 * to a fraction.
2991 *
2992 * These can be enabled again when nuclear/atomic support lands.
2993 */
Giulio Camuffo954f1832014-10-11 18:27:30 +03002994 b->sprites_are_broken = 1;
2995 b->cursors_are_broken = 1;
2996 b->compositor = compositor;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002997
2998 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002999 if (get_gbm_format_from_section(section,
3000 GBM_FORMAT_XRGB8888,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003001 &b->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003002 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07003003
Giulio Camuffo954f1832014-10-11 18:27:30 +03003004 b->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003005
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003006 /* Check if we run drm-backend using weston-launch */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003007 compositor->launcher = weston_launcher_connect(compositor, param->tty,
3008 param->seat_id, true);
3009 if (compositor->launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003010 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04003011 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01003012 goto err_compositor;
3013 }
3014
Giulio Camuffo954f1832014-10-11 18:27:30 +03003015 b->udev = udev_new();
3016 if (b->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003017 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003018 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003019 }
3020
Giulio Camuffo954f1832014-10-11 18:27:30 +03003021 b->session_listener.notify = session_notify;
3022 wl_signal_add(&compositor->session_signal, &b->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05003023
Giulio Camuffo954f1832014-10-11 18:27:30 +03003024 drm_device = find_primary_gpu(b, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04003025 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003026 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003027 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003028 }
David Herrmann0af066f2012-10-29 19:21:16 +01003029 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003030
Giulio Camuffo954f1832014-10-11 18:27:30 +03003031 if (init_drm(b, drm_device) < 0) {
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02003032 weston_log("failed to initialize kms\n");
3033 goto err_udev_dev;
3034 }
3035
Giulio Camuffo954f1832014-10-11 18:27:30 +03003036 if (b->use_pixman) {
3037 if (init_pixman(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003038 weston_log("failed to initialize pixman renderer\n");
3039 goto err_udev_dev;
3040 }
3041 } else {
Giulio Camuffo954f1832014-10-11 18:27:30 +03003042 if (init_egl(b) < 0) {
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02003043 weston_log("failed to initialize egl\n");
3044 goto err_udev_dev;
3045 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003046 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05003047
Giulio Camuffo954f1832014-10-11 18:27:30 +03003048 b->base.destroy = drm_destroy;
3049 b->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02003050
Giulio Camuffo954f1832014-10-11 18:27:30 +03003051 b->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02003052
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003053 for (key = KEY_F1; key < KEY_F9; key++)
Giulio Camuffo954f1832014-10-11 18:27:30 +03003054 weston_compositor_add_key_binding(compositor, key,
Daniel Stone325fc2d2012-05-30 16:31:58 +01003055 MODIFIER_CTRL | MODIFIER_ALT,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003056 switch_vt_binding, compositor);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04003057
Giulio Camuffo954f1832014-10-11 18:27:30 +03003058 wl_list_init(&b->sprite_list);
3059 create_sprites(b);
Jesse Barnes58ef3792012-02-23 09:45:49 -05003060
Giulio Camuffo954f1832014-10-11 18:27:30 +03003061 if (udev_input_init(&b->input,
3062 compositor, b->udev, param->seat_id) < 0) {
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003063 weston_log("failed to create input devices\n");
3064 goto err_sprite;
3065 }
3066
Giulio Camuffo954f1832014-10-11 18:27:30 +03003067 if (create_outputs(b, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003068 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003069 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003070 }
3071
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003072 /* A this point we have some idea of whether or not we have a working
3073 * cursor plane. */
Giulio Camuffo954f1832014-10-11 18:27:30 +03003074 if (!b->cursors_are_broken)
3075 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
Jason Ekstrand9fc71512014-04-02 19:53:46 -05003076
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02003077 path = NULL;
3078
Giulio Camuffo954f1832014-10-11 18:27:30 +03003079 loop = wl_display_get_event_loop(compositor->wl_display);
3080 b->drm_source =
3081 wl_event_loop_add_fd(loop, b->drm.fd,
3082 WL_EVENT_READABLE, on_drm_input, b);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04003083
Giulio Camuffo954f1832014-10-11 18:27:30 +03003084 b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
3085 if (b->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02003086 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003087 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003088 }
Giulio Camuffo954f1832014-10-11 18:27:30 +03003089 udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003090 "drm", NULL);
Giulio Camuffo954f1832014-10-11 18:27:30 +03003091 b->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02003092 wl_event_loop_add_fd(loop,
Giulio Camuffo954f1832014-10-11 18:27:30 +03003093 udev_monitor_get_fd(b->udev_monitor),
3094 WL_EVENT_READABLE, udev_drm_event, b);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003095
Giulio Camuffo954f1832014-10-11 18:27:30 +03003096 if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02003097 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01003098 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01003099 }
3100
Daniel Stonea96b93c2012-06-22 14:04:37 +01003101 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003102
Giulio Camuffo954f1832014-10-11 18:27:30 +03003103 weston_compositor_add_debug_binding(compositor, KEY_O,
3104 planes_binding, b);
3105 weston_compositor_add_debug_binding(compositor, KEY_C,
3106 planes_binding, b);
3107 weston_compositor_add_debug_binding(compositor, KEY_V,
3108 planes_binding, b);
3109 weston_compositor_add_debug_binding(compositor, KEY_Q,
3110 recorder_binding, b);
3111 weston_compositor_add_debug_binding(compositor, KEY_W,
3112 renderer_switch_binding, b);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02003113
Giulio Camuffo954f1832014-10-11 18:27:30 +03003114 compositor->backend = &b->base;
3115 return b;
Daniel Stonea96b93c2012-06-22 14:04:37 +01003116
3117err_udev_monitor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003118 wl_event_source_remove(b->udev_drm_source);
3119 udev_monitor_unref(b->udev_monitor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003120err_drm_source:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003121 wl_event_source_remove(b->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03003122err_udev_input:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003123 udev_input_destroy(&b->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04003124err_sprite:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003125 compositor->renderer->destroy(compositor);
3126 gbm_device_destroy(b->gbm);
3127 destroy_sprites(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003128err_udev_dev:
3129 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003130err_launcher:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003131 weston_launcher_destroy(compositor->launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003132err_udev:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003133 udev_unref(b->udev);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003134err_compositor:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003135 weston_compositor_shutdown(compositor);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003136err_base:
Giulio Camuffo954f1832014-10-11 18:27:30 +03003137 free(b);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003138 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003139}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003140
Giulio Camuffo954f1832014-10-11 18:27:30 +03003141WL_EXPORT int
3142backend_init(struct weston_compositor *compositor, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04003143 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003144{
Giulio Camuffo954f1832014-10-11 18:27:30 +03003145 struct drm_backend *b;
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003146 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003147
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003148 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003149 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
3150 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
3151 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003152 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003153 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003154 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02003155
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003156 param.seat_id = default_seat;
3157
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003158 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003159
Giulio Camuffo954f1832014-10-11 18:27:30 +03003160 b = drm_backend_create(compositor, &param, argc, argv, config);
3161 if (b == NULL)
3162 return -1;
3163 return 0;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003164}