blob: 66eb5d739ecf3350076b034baa31470afbc433e2 [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"
Kristian Høgsberg36d5fac2014-01-27 23:02:35 -080050#include "libbacklight.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040051#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010052#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020053#include "pixman-renderer.h"
Peter Hutterer823ad332014-11-26 07:06:31 +100054#include "libinput-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010055#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030056#include "vaapi-recorder.h"
Pekka Paalanen363aa7b2014-12-17 16:20:40 +020057#include "presentation_timing-server-protocol.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040058
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030059#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
60#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
61#endif
62
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030063#ifndef DRM_CAP_CURSOR_WIDTH
64#define DRM_CAP_CURSOR_WIDTH 0x8
65#endif
66
67#ifndef DRM_CAP_CURSOR_HEIGHT
68#define DRM_CAP_CURSOR_HEIGHT 0x9
69#endif
70
71#ifndef GBM_BO_USE_CURSOR
72#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
73#endif
74
Kristian Høgsberg061c4252012-06-28 11:28:15 -040075static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060076
77enum output_config {
78 OUTPUT_CONFIG_INVALID = 0,
79 OUTPUT_CONFIG_OFF,
80 OUTPUT_CONFIG_PREFERRED,
81 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060082 OUTPUT_CONFIG_MODE,
83 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060084};
85
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040086struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050087 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040088
89 struct udev *udev;
90 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040091
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010092 struct udev_monitor *udev_monitor;
93 struct wl_event_source *udev_drm_source;
94
Benjamin Franzke2af7f102011-03-02 11:14:59 +010095 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010096 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010097 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030098 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010099 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +0200100 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500101 uint32_t *crtcs;
102 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -0500103 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100104 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -0700105 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700106 uint32_t format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200107
Rob Clark4339add2012-08-09 14:18:28 -0500108 /* we need these parameters in order to not fail drmModeAddFB2()
109 * due to out of bounds dimensions, and then mistakenly set
110 * sprites_are_broken:
111 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200112 uint32_t min_width, max_width;
113 uint32_t min_height, max_height;
114 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500115
Jesse Barnes58ef3792012-02-23 09:45:49 -0500116 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500117 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200118 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500119
Rob Clarkab5b1e32012-08-09 13:24:45 -0500120 int cursors_are_broken;
121
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200122 int use_pixman;
123
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200124 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300125
Rob Bradfordd355b802013-05-31 18:09:55 +0100126 struct udev_input input;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -0300127
128 uint32_t cursor_width;
129 uint32_t cursor_height;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400130};
131
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400132struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500133 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400134 drmModeModeInfo mode_info;
135};
136
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300137struct drm_output;
138
139struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300140 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200141 uint32_t fb_id, stride, handle, size;
142 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300143 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200144 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200145
146 /* Used by gbm fbs */
147 struct gbm_bo *bo;
148
149 /* Used by dumb fbs */
150 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300151};
152
Richard Hughes2b2092a2013-04-24 14:58:02 +0100153struct drm_edid {
154 char eisa_id[13];
155 char monitor_name[13];
156 char pnp_id[5];
157 char serial_number[13];
158};
159
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400160struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500161 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400162
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400163 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500164 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400165 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700166 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100167 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300168 drmModePropertyPtr dpms_prop;
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000169 uint32_t format;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200170
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300171 int vblank_pending;
172 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800173 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300174
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400175 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400176 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400177 struct weston_plane cursor_plane;
178 struct weston_plane fb_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500179 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400180 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300181 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200182 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200183
184 struct drm_fb *dumb[2];
185 pixman_image_t *image[2];
186 int current_image;
187 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300188
189 struct vaapi_recorder *recorder;
190 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400191};
192
Jesse Barnes58ef3792012-02-23 09:45:49 -0500193/*
194 * An output has a primary display plane plus zero or more sprites for
195 * blending display contents.
196 */
197struct drm_sprite {
198 struct wl_list link;
199
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400200 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500201
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200202 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300203 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500204 struct drm_compositor *compositor;
205
Jesse Barnes58ef3792012-02-23 09:45:49 -0500206 uint32_t possible_crtcs;
207 uint32_t plane_id;
208 uint32_t count_formats;
209
210 int32_t src_x, src_y;
211 uint32_t src_w, src_h;
212 uint32_t dest_x, dest_y;
213 uint32_t dest_w, dest_h;
214
215 uint32_t formats[];
216};
217
Kristian Høgsbergd8e98332013-10-16 16:15:11 -0700218struct drm_parameters {
219 int connector;
220 int tty;
221 int use_pixman;
222 const char *seat_id;
223};
224
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300225static struct gl_renderer_interface *gl_renderer;
226
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500227static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400228
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400229static void
230drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400231
Jesse Barnes58ef3792012-02-23 09:45:49 -0500232static int
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200233drm_sprite_crtc_supported(struct drm_output *output, uint32_t supported)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500234{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200235 struct weston_compositor *ec = output->base.compositor;
236 struct drm_compositor *c = (struct drm_compositor *)ec;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500237 int crtc;
238
239 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
240 if (c->crtcs[crtc] != output->crtc_id)
241 continue;
242
243 if (supported & (1 << crtc))
244 return -1;
245 }
246
247 return 0;
248}
249
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300250static void
251drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
252{
253 struct drm_fb *fb = data;
254 struct gbm_device *gbm = gbm_bo_get_device(bo);
255
256 if (fb->fb_id)
257 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
258
Pekka Paalanende685b82012-12-04 15:58:12 +0200259 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300260
261 free(data);
262}
263
264static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200265drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
266{
267 struct drm_fb *fb;
268 int ret;
269
270 struct drm_mode_create_dumb create_arg;
271 struct drm_mode_destroy_dumb destroy_arg;
272 struct drm_mode_map_dumb map_arg;
273
Peter Huttererf3d62272013-08-08 11:57:05 +1000274 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200275 if (!fb)
276 return NULL;
277
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700278 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200279 create_arg.bpp = 32;
280 create_arg.width = width;
281 create_arg.height = height;
282
283 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
284 if (ret)
285 goto err_fb;
286
287 fb->handle = create_arg.handle;
288 fb->stride = create_arg.pitch;
289 fb->size = create_arg.size;
290 fb->fd = ec->drm.fd;
291
292 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
293 fb->stride, fb->handle, &fb->fb_id);
294 if (ret)
295 goto err_bo;
296
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700297 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200298 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400299 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200300 if (ret)
301 goto err_add_fb;
302
303 fb->map = mmap(0, fb->size, PROT_WRITE,
304 MAP_SHARED, ec->drm.fd, map_arg.offset);
305 if (fb->map == MAP_FAILED)
306 goto err_add_fb;
307
308 return fb;
309
310err_add_fb:
311 drmModeRmFB(ec->drm.fd, fb->fb_id);
312err_bo:
313 memset(&destroy_arg, 0, sizeof(destroy_arg));
314 destroy_arg.handle = create_arg.handle;
315 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
316err_fb:
317 free(fb);
318 return NULL;
319}
320
321static void
322drm_fb_destroy_dumb(struct drm_fb *fb)
323{
324 struct drm_mode_destroy_dumb destroy_arg;
325
326 if (!fb->map)
327 return;
328
329 if (fb->fb_id)
330 drmModeRmFB(fb->fd, fb->fb_id);
331
332 weston_buffer_reference(&fb->buffer_ref, NULL);
333
334 munmap(fb->map, fb->size);
335
336 memset(&destroy_arg, 0, sizeof(destroy_arg));
337 destroy_arg.handle = fb->handle;
338 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
339
340 free(fb);
341}
342
343static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500344drm_fb_get_from_bo(struct gbm_bo *bo,
345 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300346{
347 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200348 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200349 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300350 int ret;
351
352 if (fb)
353 return fb;
354
Bryce Harringtonde16d892014-11-20 22:21:57 -0800355 fb = zalloc(sizeof *fb);
356 if (fb == NULL)
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200357 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300358
359 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300360
361 width = gbm_bo_get_width(bo);
362 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200363 fb->stride = gbm_bo_get_stride(bo);
364 fb->handle = gbm_bo_get_handle(bo).u32;
365 fb->size = fb->stride * height;
366 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300367
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200368 if (compositor->min_width > width || width > compositor->max_width ||
369 compositor->min_height > height ||
370 height > compositor->max_height) {
371 weston_log("bo geometry out of bounds\n");
372 goto err_free;
373 }
374
375 ret = -1;
376
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200377 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200378 handles[0] = fb->handle;
379 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200380 offsets[0] = 0;
381
382 ret = drmModeAddFB2(compositor->drm.fd, width, height,
383 format, handles, pitches, offsets,
384 &fb->fb_id, 0);
385 if (ret) {
386 weston_log("addfb2 failed: %m\n");
387 compositor->no_addfb2 = 1;
388 compositor->sprites_are_broken = 1;
389 }
390 }
391
392 if (ret)
393 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200394 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200395
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300396 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200397 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200398 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300399 }
400
401 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
402
403 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200404
405err_free:
406 free(fb);
407 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300408}
409
410static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500411drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200412{
Pekka Paalanende685b82012-12-04 15:58:12 +0200413 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200414
415 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200416
Pekka Paalanende685b82012-12-04 15:58:12 +0200417 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200418}
419
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200420static void
421drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
422{
423 if (!fb)
424 return;
425
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200426 if (fb->map &&
427 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200428 drm_fb_destroy_dumb(fb);
429 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200430 if (fb->is_client_buffer)
431 gbm_bo_destroy(fb->bo);
432 else
433 gbm_surface_release_buffer(output->surface,
Jason Ekstrand3ec57f52013-11-14 20:52:35 -0600434 fb->bo);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200435 }
436}
437
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500438static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200439drm_output_check_scanout_format(struct drm_output *output,
440 struct weston_surface *es, struct gbm_bo *bo)
441{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200442 uint32_t format;
443 pixman_region32_t r;
444
445 format = gbm_bo_get_format(bo);
446
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700447 if (format == GBM_FORMAT_ARGB8888) {
448 /* We can scanout an ARGB buffer if the surface's
449 * opaque region covers the whole output, but we have
450 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -0800451 pixman_region32_init_rect(&r, 0, 0,
452 output->base.width,
453 output->base.height);
454 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200455
456 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500457 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200458
459 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500460 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700461
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000462 if (output->format == format)
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700463 return format;
464
465 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200466}
467
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400468static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200469drm_output_prepare_scanout_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500470 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500471{
472 struct drm_compositor *c =
473 (struct drm_compositor *) output->base.compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500474 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200475 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300476 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500477 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500478
Jason Ekstranda7af7042013-10-12 22:38:11 -0500479 if (ev->geometry.x != output->base.x ||
480 ev->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200481 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200482 buffer->width != output->base.current_mode->width ||
483 buffer->height != output->base.current_mode->height ||
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200484 output->base.transform != viewport->buffer.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500485 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400486 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500487
Pekka Paalanen5580f222015-02-17 16:33:18 +0200488 if (ev->geometry.scissor_enabled)
489 return NULL;
490
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400491 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700492 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500493
Rob Bradford9b101872012-09-14 23:25:41 +0100494 /* Unable to use the buffer for scanout */
495 if (!bo)
496 return NULL;
497
Jason Ekstranda7af7042013-10-12 22:38:11 -0500498 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500499 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300500 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400501 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300502 }
503
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500504 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300505 if (!output->next) {
506 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400507 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300508 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500509
Pekka Paalanende685b82012-12-04 15:58:12 +0200510 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500511
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400512 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500513}
514
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500515static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200516drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400517{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200518 struct drm_compositor *c =
519 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300520 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400521
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200522 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400523
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300524 bo = gbm_surface_lock_front_buffer(output->surface);
525 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200526 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400527 return;
528 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300529
Neil Roberts77c1a5b2014-03-07 18:05:50 +0000530 output->next = drm_fb_get_from_bo(bo, c, output->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300531 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200532 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300533 gbm_surface_release_buffer(output->surface, bo);
534 return;
535 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400536}
537
538static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200539drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
540{
541 struct weston_compositor *ec = output->base.compositor;
542 pixman_region32_t total_damage, previous_damage;
543
544 pixman_region32_init(&total_damage);
545 pixman_region32_init(&previous_damage);
546
547 pixman_region32_copy(&previous_damage, damage);
548
549 pixman_region32_union(&total_damage, damage, &output->previous_damage);
550 pixman_region32_copy(&output->previous_damage, &previous_damage);
551
552 output->current_image ^= 1;
553
554 output->next = output->dumb[output->current_image];
555 pixman_renderer_output_set_buffer(&output->base,
556 output->image[output->current_image]);
557
558 ec->renderer->repaint_output(&output->base, &total_damage);
559
560 pixman_region32_fini(&total_damage);
561 pixman_region32_fini(&previous_damage);
562}
563
564static void
565drm_output_render(struct drm_output *output, pixman_region32_t *damage)
566{
567 struct drm_compositor *c =
568 (struct drm_compositor *) output->base.compositor;
569
570 if (c->use_pixman)
571 drm_output_render_pixman(output, damage);
572 else
573 drm_output_render_gl(output, damage);
574
575 pixman_region32_subtract(&c->base.primary_plane.damage,
576 &c->base.primary_plane.damage, damage);
577}
578
579static void
Richard Hughese7299962013-05-01 21:52:12 +0100580drm_output_set_gamma(struct weston_output *output_base,
581 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
582{
583 int rc;
584 struct drm_output *output = (struct drm_output *) output_base;
585 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
586
587 /* check */
588 if (output_base->gamma_size != size)
589 return;
590 if (!output->original_crtc)
591 return;
592
593 rc = drmModeCrtcSetGamma(compositor->drm.fd,
594 output->crtc_id,
595 size, r, g, b);
596 if (rc)
597 weston_log("set gamma failed: %m\n");
598}
599
Bryce Harringtonada4f072015-06-30 13:25:46 -0700600/* Determine the type of vblank synchronization to use for the output.
601 *
602 * The pipe parameter indicates which CRTC is in use. Knowing this, we
603 * can determine which vblank sequence type to use for it. Traditional
604 * cards had only two CRTCs, with CRTC 0 using no special flags, and
605 * CRTC 1 using DRM_VBLANK_SECONDARY. The first bit of the pipe
606 * parameter indicates this.
607 *
608 * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
609 * 0-31. If this is non-zero it indicates we're dealing with a
610 * multi-gpu situation and we need to calculate the vblank sync
611 * using DRM_BLANK_HIGH_CRTC_MASK.
612 */
Pekka Paalanenc8a1ff02015-07-02 15:06:08 +0300613static unsigned int
614drm_waitvblank_pipe(struct drm_output *output)
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +0200615{
616 if (output->pipe > 1)
617 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
618 DRM_VBLANK_HIGH_CRTC_MASK;
619 else if (output->pipe > 0)
620 return DRM_VBLANK_SECONDARY;
621 else
622 return 0;
623}
624
David Herrmann1edf44c2013-10-22 17:11:26 +0200625static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500626drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400627 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100628{
629 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500630 struct drm_compositor *compositor =
631 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500632 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400633 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100635
Xiong Zhangabd5d472013-10-11 14:43:07 +0800636 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200637 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800638
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300639 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400640 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300641 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200642 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100643
Hardeningff39efa2013-09-18 23:56:35 +0200644 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200645 if (!output->current ||
646 output->current->stride != output->next->stride) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400647 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300648 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400649 &output->connector_id, 1,
650 &mode->mode_info);
651 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200652 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200653 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400654 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300655 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200656 }
657
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500658 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300659 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500660 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200661 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200662 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500663 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100664
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300665 output->page_flip_pending = 1;
666
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400667 drm_output_set_cursor(output);
668
Jesse Barnes58ef3792012-02-23 09:45:49 -0500669 /*
670 * Now, update all the sprite surfaces
671 */
672 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200673 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500674 drmVBlank vbl = {
675 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
676 .request.sequence = 1,
677 };
678
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200679 if ((!s->current && !s->next) ||
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200680 !drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500681 continue;
682
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200683 if (s->next && !compositor->sprites_hidden)
684 fb_id = s->next->fb_id;
685
Jesse Barnes58ef3792012-02-23 09:45:49 -0500686 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200687 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500688 s->dest_x, s->dest_y,
689 s->dest_w, s->dest_h,
690 s->src_x, s->src_y,
691 s->src_w, s->src_h);
692 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200693 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500694 ret, strerror(errno));
695
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +0200696 vbl.request.type |= drm_waitvblank_pipe(output);
Rob Clark5ca1a472012-08-08 20:27:37 -0500697
Jesse Barnes58ef3792012-02-23 09:45:49 -0500698 /*
699 * Queue a vblank signal so we know when the surface
700 * becomes active on the display or has been replaced.
701 */
702 vbl.request.signal = (unsigned long)s;
703 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
704 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200705 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500706 ret, strerror(errno));
707 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300708
709 s->output = output;
710 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500711 }
712
David Herrmann1edf44c2013-10-22 17:11:26 +0200713 return 0;
714
715err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800716 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200717 if (output->next) {
718 drm_output_release_fb(output, output->next);
719 output->next = NULL;
720 }
721
722 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400723}
724
725static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200726drm_output_start_repaint_loop(struct weston_output *output_base)
727{
728 struct drm_output *output = (struct drm_output *) output_base;
729 struct drm_compositor *compositor = (struct drm_compositor *)
730 output_base->compositor;
731 uint32_t fb_id;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300732 struct timespec ts;
733
Xiong Zhangabd5d472013-10-11 14:43:07 +0800734 if (output->destroy_pending)
735 return;
736
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300737 if (!output->current) {
738 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200739 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300740 }
741
742 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200743
744 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
745 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
746 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200747 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200748 }
David Herrmann3c688c52013-10-22 17:11:25 +0200749
750 return;
751
752finish_frame:
753 /* if we cannot page-flip, immediately finish frame */
Pekka Paalanen662f3842015-03-18 12:17:26 +0200754 weston_compositor_read_presentation_clock(&compositor->base, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200755 weston_output_finish_frame(output_base, &ts,
756 PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200757}
758
759static void
Pekka Paalanen641307c2014-09-23 22:08:47 -0400760drm_output_update_msc(struct drm_output *output, unsigned int seq)
761{
762 uint64_t msc_hi = output->base.msc >> 32;
763
764 if (seq < (output->base.msc & 0xffffffff))
765 msc_hi++;
766
767 output->base.msc = (msc_hi << 32) + seq;
768}
769
770static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500771vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
772 void *data)
773{
774 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300775 struct drm_output *output = s->output;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400776 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200777 uint32_t flags = PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
778 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300779
Pekka Paalanen641307c2014-09-23 22:08:47 -0400780 drm_output_update_msc(output, frame);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300781 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500782
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200783 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200784 s->current = s->next;
785 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300786
787 if (!output->page_flip_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400788 ts.tv_sec = sec;
789 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200790 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300791 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500792}
793
794static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800795drm_output_destroy(struct weston_output *output_base);
796
797static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400798page_flip_handler(int fd, unsigned int frame,
799 unsigned int sec, unsigned int usec, void *data)
800{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200801 struct drm_output *output = (struct drm_output *) data;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400802 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200803 uint32_t flags = PRESENTATION_FEEDBACK_KIND_VSYNC |
804 PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
805 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400806
Pekka Paalanen641307c2014-09-23 22:08:47 -0400807 drm_output_update_msc(output, frame);
808
Jonas Ådahle5a12252013-04-05 23:07:11 +0200809 /* We don't set page_flip_pending on start_repaint_loop, in that case
810 * we just want to page flip to the current buffer to get an accurate
811 * timestamp */
812 if (output->page_flip_pending) {
813 drm_output_release_fb(output, output->current);
814 output->current = output->next;
815 output->next = NULL;
816 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300817
Jonas Ådahle5a12252013-04-05 23:07:11 +0200818 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400819
Xiong Zhangabd5d472013-10-11 14:43:07 +0800820 if (output->destroy_pending)
821 drm_output_destroy(&output->base);
822 else if (!output->vblank_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400823 ts.tv_sec = sec;
824 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200825 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300826
827 /* We can't call this from frame_notify, because the output's
828 * repaint needed flag is cleared just after that */
829 if (output->recorder)
830 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300831 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200832}
833
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500834static uint32_t
835drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500836 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500837{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500838 uint32_t i, format;
839
840 format = gbm_bo_get_format(bo);
841
842 if (format == GBM_FORMAT_ARGB8888) {
843 pixman_region32_t r;
844
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500845 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600846 ev->surface->width,
847 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500848 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500849
850 if (!pixman_region32_not_empty(&r))
851 format = GBM_FORMAT_XRGB8888;
852
853 pixman_region32_fini(&r);
854 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500855
856 for (i = 0; i < s->count_formats; i++)
857 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500858 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500859
860 return 0;
861}
862
863static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500864drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500865{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500866 return !ev->transform.enabled ||
867 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500868}
869
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400870static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200871drm_output_prepare_overlay_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500872 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500873{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200874 struct weston_compositor *ec = output->base.compositor;
875 struct drm_compositor *c = (struct drm_compositor *)ec;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200876 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500877 struct drm_sprite *s;
878 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500879 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500880 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200881 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500882 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400883 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500884
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200885 if (c->gbm == NULL)
886 return NULL;
887
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200888 if (viewport->buffer.transform != output->base.transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200889 return NULL;
890
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200891 if (viewport->buffer.scale != output->base.current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200892 return NULL;
893
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500894 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400895 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500896
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200897 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400898 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300899
Jason Ekstranda7af7042013-10-12 22:38:11 -0500900 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400901 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500902
Jason Ekstranda7af7042013-10-12 22:38:11 -0500903 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200904 return NULL;
905
Jason Ekstranda7af7042013-10-12 22:38:11 -0500906 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500907 return NULL;
908
Jason Ekstranda7af7042013-10-12 22:38:11 -0500909 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400910 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500911
Jesse Barnes58ef3792012-02-23 09:45:49 -0500912 wl_list_for_each(s, &c->sprite_list, link) {
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200913 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500914 continue;
915
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200916 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500917 found = 1;
918 break;
919 }
920 }
921
922 /* No sprites available */
923 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400924 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500925
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400926 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500927 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700928 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400929 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400930 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400931
Jason Ekstranda7af7042013-10-12 22:38:11 -0500932 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500933 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200934 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400935 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500936 }
937
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200938 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200939 if (!s->next) {
940 gbm_bo_destroy(bo);
941 return NULL;
942 }
943
Jason Ekstranda7af7042013-10-12 22:38:11 -0500944 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500945
Jason Ekstranda7af7042013-10-12 22:38:11 -0500946 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400947 s->plane.x = box->x1;
948 s->plane.y = box->y1;
949
Jesse Barnes58ef3792012-02-23 09:45:49 -0500950 /*
951 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -0500952 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500953 * for us already).
954 */
955 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500956 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200957 &output->base.region);
958 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500959 box = pixman_region32_extents(&dest_rect);
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200960 tbox = weston_transformed_rect(output->base.width,
961 output->base.height,
962 output->base.transform,
963 output->base.current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200964 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200965 s->dest_x = tbox.x1;
966 s->dest_y = tbox.y1;
967 s->dest_w = tbox.x2 - tbox.x1;
968 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500969 pixman_region32_fini(&dest_rect);
970
971 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500972 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200973 &output->base.region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500974 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400975
Jason Ekstranda7af7042013-10-12 22:38:11 -0500976 weston_view_from_global_fixed(ev,
977 wl_fixed_from_int(box->x1),
978 wl_fixed_from_int(box->y1),
979 &sx1, &sy1);
980 weston_view_from_global_fixed(ev,
981 wl_fixed_from_int(box->x2),
982 wl_fixed_from_int(box->y2),
983 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400984
985 if (sx1 < 0)
986 sx1 = 0;
987 if (sy1 < 0)
988 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600989 if (sx2 > wl_fixed_from_int(ev->surface->width))
990 sx2 = wl_fixed_from_int(ev->surface->width);
991 if (sy2 > wl_fixed_from_int(ev->surface->height))
992 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400993
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200994 tbox.x1 = sx1;
995 tbox.y1 = sy1;
996 tbox.x2 = sx2;
997 tbox.y2 = sy2;
998
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600999 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
1000 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +02001001 viewport->buffer.transform,
1002 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +01001003 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001004
1005 s->src_x = tbox.x1 << 8;
1006 s->src_y = tbox.y1 << 8;
1007 s->src_w = (tbox.x2 - tbox.x1) << 8;
1008 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001009 pixman_region32_fini(&src_rect);
1010
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001011 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001012}
1013
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001014static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001015drm_output_prepare_cursor_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001016 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001017{
Kristian Høgsberg8a015802012-08-09 17:19:23 -04001018 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001019 (struct drm_compositor *)output->base.compositor;
Neil Robertsf37f82c2014-05-01 18:00:41 +01001020 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001021
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001022 if (c->gbm == NULL)
1023 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +02001024 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
1025 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001026 if (viewport->buffer.scale != output->base.current_scale)
Neil Robertsf37f82c2014-05-01 18:00:41 +01001027 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001028 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001029 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001030 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001031 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001032 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -04001033 return NULL;
Pekka Paalanen5580f222015-02-17 16:33:18 +02001034 if (ev->geometry.scissor_enabled)
1035 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001036 if (ev->surface->buffer_ref.buffer == NULL ||
1037 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001038 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001039 return NULL;
1040
Jason Ekstranda7af7042013-10-12 22:38:11 -05001041 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001042
1043 return &output->cursor_plane;
1044}
1045
1046static void
1047drm_output_set_cursor(struct drm_output *output)
1048{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001049 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001050 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001051 struct drm_compositor *c =
1052 (struct drm_compositor *) output->base.compositor;
1053 EGLint handle, stride;
1054 struct gbm_bo *bo;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001055 uint32_t buf[c->cursor_width * c->cursor_height];
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001056 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001057 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001058
Jason Ekstranda7af7042013-10-12 22:38:11 -05001059 output->cursor_view = NULL;
1060 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001061 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
1062 return;
1063 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001064
Neil Robertse5051712013-11-13 15:44:06 +00001065 buffer = ev->surface->buffer_ref.buffer;
1066
1067 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001068 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001069 pixman_region32_fini(&output->cursor_plane.damage);
1070 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001071 output->current_cursor ^= 1;
1072 bo = output->cursor_bo[output->current_cursor];
1073 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001074 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1075 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1076 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001077 for (i = 0; i < ev->surface->height; i++)
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001078 memcpy(buf + i * c->cursor_width, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001079 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001080 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001081
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001082 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001083 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001084
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001085 handle = gbm_bo_get_handle(bo).s32;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001086 if (drmModeSetCursor(c->drm.fd, output->crtc_id, handle,
1087 c->cursor_width, c->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001088 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001089 c->cursors_are_broken = 1;
1090 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001091 }
1092
Jason Ekstranda7af7042013-10-12 22:38:11 -05001093 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1094 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001095 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001096 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001097 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001098 c->cursors_are_broken = 1;
1099 }
1100
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001101 output->cursor_plane.x = x;
1102 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001103 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001104}
1105
Jesse Barnes58ef3792012-02-23 09:45:49 -05001106static void
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001107drm_assign_planes(struct weston_output *output_base)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001108{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001109 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001110 (struct drm_compositor *)output_base->compositor;
1111 struct drm_output *output = (struct drm_output *)output_base;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001112 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001113 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001114 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001115
1116 /*
1117 * Find a surface for each sprite in the output using some heuristics:
1118 * 1) size
1119 * 2) frequency of update
1120 * 3) opacity (though some hw might support alpha blending)
1121 * 4) clipping (this can be fixed with color keys)
1122 *
1123 * The idea is to save on blitting since this should save power.
1124 * If we can get a large video surface on the sprite for example,
1125 * the main display surface may not need to update at all, and
1126 * the client buffer can be used directly for the sprite surface
1127 * as we do for flipping full screen surfaces.
1128 */
1129 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001130 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001131
Jason Ekstranda7af7042013-10-12 22:38:11 -05001132 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001133 struct weston_surface *es = ev->surface;
1134
1135 /* Test whether this buffer can ever go into a plane:
1136 * non-shm, or small enough to be a cursor.
1137 *
1138 * Also, keep a reference when using the pixman renderer.
1139 * That makes it possible to do a seamless switch to the GL
1140 * renderer and since the pixman renderer keeps a reference
1141 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001142 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001143 if (c->use_pixman ||
1144 (es->buffer_ref.buffer &&
1145 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001146 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001147 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001148 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001149 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001150
Jesse Barnes58ef3792012-02-23 09:45:49 -05001151 pixman_region32_init(&surface_overlap);
1152 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001153 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001154
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001155 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001156 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001157 next_plane = primary;
1158 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001159 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001160 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001161 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001162 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001163 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001164 if (next_plane == NULL)
1165 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001166
Jason Ekstranda7af7042013-10-12 22:38:11 -05001167 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001168
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001169 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001170 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001171 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001172
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001173 if (next_plane == primary ||
1174 next_plane == &output->cursor_plane) {
1175 /* cursor plane involves a copy */
1176 ev->psf_flags = 0;
1177 } else {
1178 /* All other planes are a direct scanout of a
1179 * single client buffer.
1180 */
1181 ev->psf_flags = PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
1182 }
1183
Jesse Barnes58ef3792012-02-23 09:45:49 -05001184 pixman_region32_fini(&surface_overlap);
1185 }
1186 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001187}
1188
Matt Roper361d2ad2011-08-29 13:52:23 -07001189static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001190drm_output_fini_pixman(struct drm_output *output);
1191
1192static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001193drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001194{
1195 struct drm_output *output = (struct drm_output *) output_base;
1196 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001197 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001198 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001199
Xiong Zhangabd5d472013-10-11 14:43:07 +08001200 if (output->page_flip_pending) {
1201 output->destroy_pending = 1;
1202 weston_log("destroy output while page flip pending\n");
1203 return;
1204 }
1205
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001206 if (output->backlight)
1207 backlight_destroy(output->backlight);
1208
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001209 drmModeFreeProperty(output->dpms_prop);
1210
Matt Roper361d2ad2011-08-29 13:52:23 -07001211 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001212 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001213
1214 /* Restore original CRTC state */
1215 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001216 origcrtc->x, origcrtc->y,
1217 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001218 drmModeFreeCrtc(origcrtc);
1219
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001220 c->crtc_allocator &= ~(1 << output->crtc_id);
1221 c->connector_allocator &= ~(1 << output->connector_id);
1222
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001223 if (c->use_pixman) {
1224 drm_output_fini_pixman(output);
1225 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001226 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001227 gbm_surface_destroy(output->surface);
1228 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001229
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001230 weston_plane_release(&output->fb_plane);
1231 weston_plane_release(&output->cursor_plane);
1232
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001233 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001234
Matt Roper361d2ad2011-08-29 13:52:23 -07001235 free(output);
1236}
1237
Alex Wub7b8bda2012-04-17 17:20:48 +08001238static struct drm_mode *
1239choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1240{
1241 struct drm_mode *tmp_mode = NULL, *mode;
1242
Hardeningff39efa2013-09-18 23:56:35 +02001243 if (output->base.current_mode->width == target_mode->width &&
1244 output->base.current_mode->height == target_mode->height &&
1245 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001246 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001247 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001248
1249 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1250 if (mode->mode_info.hdisplay == target_mode->width &&
1251 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02001252 if (mode->base.refresh == target_mode->refresh ||
1253 target_mode->refresh == 0) {
Alex Wub7b8bda2012-04-17 17:20:48 +08001254 return mode;
Daniel Stonef556ebe2015-05-21 08:28:58 +01001255 } else if (!tmp_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001256 tmp_mode = mode;
1257 }
1258 }
1259
1260 return tmp_mode;
1261}
1262
1263static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001264drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001265static int
1266drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001267
1268static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001269drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1270{
1271 struct drm_output *output;
1272 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001273 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001274
1275 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001276 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001277 return -1;
1278 }
1279
1280 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001281 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001282 return -1;
1283 }
1284
1285 ec = (struct drm_compositor *)output_base->compositor;
1286 output = (struct drm_output *)output_base;
1287 drm_mode = choose_mode (output, mode);
1288
1289 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001290 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001291 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001292 }
1293
Hardeningff39efa2013-09-18 23:56:35 +02001294 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001295 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001296
Hardeningff39efa2013-09-18 23:56:35 +02001297 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001298
Hardeningff39efa2013-09-18 23:56:35 +02001299 output->base.current_mode = &drm_mode->base;
1300 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001301 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1302
Alex Wub7b8bda2012-04-17 17:20:48 +08001303 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001304 drm_output_release_fb(output, output->current);
1305 drm_output_release_fb(output, output->next);
1306 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001307
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001308 if (ec->use_pixman) {
1309 drm_output_fini_pixman(output);
1310 if (drm_output_init_pixman(output, ec) < 0) {
1311 weston_log("failed to init output pixman state with "
1312 "new mode\n");
1313 return -1;
1314 }
1315 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001316 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001317 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001318
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001319 if (drm_output_init_egl(output, ec) < 0) {
1320 weston_log("failed to init output egl state with "
1321 "new mode");
1322 return -1;
1323 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001324 }
1325
Alex Wub7b8bda2012-04-17 17:20:48 +08001326 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001327}
1328
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001329static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001330on_drm_input(int fd, uint32_t mask, void *data)
1331{
1332 drmEventContext evctx;
1333
1334 memset(&evctx, 0, sizeof evctx);
1335 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1336 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001337 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001338 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001339
1340 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001341}
1342
1343static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001344init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001345{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001346 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001347 uint64_t cap;
1348 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001349 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001350
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001351 sysnum = udev_device_get_sysnum(device);
1352 if (sysnum)
1353 ec->drm.id = atoi(sysnum);
1354 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001355 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001356 return -1;
1357 }
1358
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001359 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001360 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001361 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001362 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001363 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001364 udev_device_get_devnode(device));
1365 return -1;
1366 }
1367
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001368 weston_log("using %s\n", filename);
1369
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001370 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001371 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001372
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001373 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1374 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001375 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001376 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001377 clk_id = CLOCK_REALTIME;
1378
1379 if (weston_compositor_set_presentation_clock(&ec->base, clk_id) < 0) {
1380 weston_log("Error: failed to set presentation clock %d.\n",
1381 clk_id);
1382 return -1;
1383 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001384
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001385 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1386 if (ret == 0)
1387 ec->cursor_width = cap;
1388 else
1389 ec->cursor_width = 64;
1390
1391 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1392 if (ret == 0)
1393 ec->cursor_height = cap;
1394 else
1395 ec->cursor_height = 64;
1396
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001397 return 0;
1398}
1399
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001400static struct gbm_device *
1401create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001402{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001403 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001404
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001405 gl_renderer = weston_load_module("gl-renderer.so",
1406 "gl_renderer_interface");
1407 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001408 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001409
1410 /* GBM will load a dri driver, but even though they need symbols from
1411 * libglapi, in some version of Mesa they are not linked to it. Since
1412 * only the gl-renderer module links to it, the call above won't make
1413 * these symbols globally available, and loading the DRI driver fails.
1414 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1415 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1416
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001417 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001418
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001419 return gbm;
1420}
1421
Bryce Harringtonc056a982015-05-19 15:25:18 -07001422/* When initializing EGL, if the preferred buffer format isn't available
Derek Foremanc4cfe852015-05-15 12:12:40 -05001423 * we may be able to susbstitute an ARGB format for an XRGB one.
1424 *
1425 * This returns 0 if substitution isn't possible, but 0 might be a
1426 * legitimate format for other EGL platforms, so the caller is
1427 * responsible for checking for 0 before calling gl_renderer->create().
1428 *
1429 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
1430 * but it's entirely possible we'll see this again on other implementations.
1431 */
1432static int
1433fallback_format_for(uint32_t format)
1434{
1435 switch (format) {
1436 case GBM_FORMAT_XRGB8888:
1437 return GBM_FORMAT_ARGB8888;
1438 case GBM_FORMAT_XRGB2101010:
1439 return GBM_FORMAT_ARGB2101010;
1440 default:
1441 return 0;
1442 }
1443}
1444
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001445static int
1446drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1447{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001448 EGLint format[2] = {
1449 ec->format,
1450 fallback_format_for(ec->format),
1451 };
1452 int n_formats = 1;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001453
Derek Foremanc4cfe852015-05-15 12:12:40 -05001454 if (format[1])
1455 n_formats = 2;
1456 if (gl_renderer->create(&ec->base,
1457 EGL_PLATFORM_GBM_KHR,
1458 (void *)ec->gbm,
1459 gl_renderer->opaque_attribs,
1460 format,
1461 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001462 return -1;
1463 }
1464
1465 return 0;
1466}
1467
1468static int
1469init_egl(struct drm_compositor *ec)
1470{
1471 ec->gbm = create_gbm_device(ec->drm.fd);
1472
1473 if (!ec->gbm)
1474 return -1;
1475
1476 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001477 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001478 return -1;
1479 }
1480
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001481 return 0;
1482}
1483
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001484static int
1485init_pixman(struct drm_compositor *ec)
1486{
1487 return pixman_renderer_init(&ec->base);
1488}
1489
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001490static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001491drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001492{
1493 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001494 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001495
1496 mode = malloc(sizeof *mode);
1497 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001498 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001499
1500 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001501 mode->base.width = info->hdisplay;
1502 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001503
1504 /* Calculate higher precision (mHz) refresh rate */
1505 refresh = (info->clock * 1000000LL / info->htotal +
1506 info->vtotal / 2) / info->vtotal;
1507
1508 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1509 refresh *= 2;
1510 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1511 refresh /= 2;
1512 if (info->vscan > 1)
1513 refresh /= info->vscan;
1514
1515 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001516 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001517
1518 if (info->type & DRM_MODE_TYPE_PREFERRED)
1519 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1520
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001521 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1522
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001523 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001524}
1525
1526static int
1527drm_subpixel_to_wayland(int drm_value)
1528{
1529 switch (drm_value) {
1530 default:
1531 case DRM_MODE_SUBPIXEL_UNKNOWN:
1532 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1533 case DRM_MODE_SUBPIXEL_NONE:
1534 return WL_OUTPUT_SUBPIXEL_NONE;
1535 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1536 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1537 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1538 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1539 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1540 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1541 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1542 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1543 }
1544}
1545
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001546/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001547static uint32_t
1548drm_get_backlight(struct drm_output *output)
1549{
1550 long brightness, max_brightness, norm;
1551
1552 brightness = backlight_get_brightness(output->backlight);
1553 max_brightness = backlight_get_max_brightness(output->backlight);
1554
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001555 /* convert it on a scale of 0 to 255 */
1556 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001557
1558 return (uint32_t) norm;
1559}
1560
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001561/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001562static void
1563drm_set_backlight(struct weston_output *output_base, uint32_t value)
1564{
1565 struct drm_output *output = (struct drm_output *) output_base;
1566 long max_brightness, new_brightness;
1567
1568 if (!output->backlight)
1569 return;
1570
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001571 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001572 return;
1573
1574 max_brightness = backlight_get_max_brightness(output->backlight);
1575
1576 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001577 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001578
1579 backlight_set_brightness(output->backlight, new_brightness);
1580}
1581
1582static drmModePropertyPtr
1583drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1584{
1585 drmModePropertyPtr props;
1586 int i;
1587
1588 for (i = 0; i < connector->count_props; i++) {
1589 props = drmModeGetProperty(fd, connector->props[i]);
1590 if (!props)
1591 continue;
1592
1593 if (!strcmp(props->name, name))
1594 return props;
1595
1596 drmModeFreeProperty(props);
1597 }
1598
1599 return NULL;
1600}
1601
1602static void
1603drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1604{
1605 struct drm_output *output = (struct drm_output *) output_base;
1606 struct weston_compositor *ec = output_base->compositor;
1607 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001608
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001609 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001610 return;
1611
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001612 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1613 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001614}
1615
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001616static const char *connector_type_names[] = {
1617 "None",
1618 "VGA",
1619 "DVI",
1620 "DVI",
1621 "DVI",
1622 "Composite",
1623 "TV",
1624 "LVDS",
1625 "CTV",
1626 "DIN",
1627 "DP",
1628 "HDMI",
1629 "HDMI",
1630 "TV",
1631 "eDP",
1632};
1633
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001634static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001635find_crtc_for_connector(struct drm_compositor *ec,
1636 drmModeRes *resources, drmModeConnector *connector)
1637{
1638 drmModeEncoder *encoder;
1639 uint32_t possible_crtcs;
1640 int i, j;
1641
1642 for (j = 0; j < connector->count_encoders; j++) {
1643 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1644 if (encoder == NULL) {
1645 weston_log("Failed to get encoder.\n");
1646 return -1;
1647 }
1648 possible_crtcs = encoder->possible_crtcs;
1649 drmModeFreeEncoder(encoder);
1650
1651 for (i = 0; i < resources->count_crtcs; i++) {
1652 if (possible_crtcs & (1 << i) &&
1653 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1654 return i;
1655 }
1656 }
1657
1658 return -1;
1659}
1660
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001661/* Init output state that depends on gl or gbm */
1662static int
1663drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1664{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001665 EGLint format[2] = {
1666 output->format,
1667 fallback_format_for(output->format),
1668 };
1669 int i, flags, n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001670
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001671 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001672 output->base.current_mode->width,
1673 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001674 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001675 GBM_BO_USE_SCANOUT |
1676 GBM_BO_USE_RENDERING);
1677 if (!output->surface) {
1678 weston_log("failed to create gbm surface\n");
1679 return -1;
1680 }
1681
Derek Foremanc4cfe852015-05-15 12:12:40 -05001682 if (format[1])
1683 n_formats = 2;
Jonny Lamb671148f2015-03-20 15:26:52 +01001684 if (gl_renderer->output_create(&output->base,
Jonny Lamb445fb692015-03-24 13:12:01 +01001685 (EGLNativeDisplayType)output->surface,
1686 output->surface,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001687 gl_renderer->opaque_attribs,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001688 format,
1689 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001690 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001691 gbm_surface_destroy(output->surface);
1692 return -1;
1693 }
1694
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001695 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001696
1697 for (i = 0; i < 2; i++) {
1698 if (output->cursor_bo[i])
1699 continue;
1700
1701 output->cursor_bo[i] =
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001702 gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
1703 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001704 }
1705
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001706 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1707 weston_log("cursor buffers unavailable, using gl cursors\n");
1708 ec->cursors_are_broken = 1;
1709 }
1710
1711 return 0;
1712}
1713
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001714static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001715drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1716{
Hardeningff39efa2013-09-18 23:56:35 +02001717 int w = output->base.current_mode->width;
1718 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001719 unsigned int i;
1720
1721 /* FIXME error checking */
1722
1723 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001724 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001725 if (!output->dumb[i])
1726 goto err;
1727
1728 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001729 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001730 output->dumb[i]->map,
1731 output->dumb[i]->stride);
1732 if (!output->image[i])
1733 goto err;
1734 }
1735
1736 if (pixman_renderer_output_create(&output->base) < 0)
1737 goto err;
1738
1739 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001740 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001741
1742 return 0;
1743
1744err:
1745 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1746 if (output->dumb[i])
1747 drm_fb_destroy_dumb(output->dumb[i]);
1748 if (output->image[i])
1749 pixman_image_unref(output->image[i]);
1750
1751 output->dumb[i] = NULL;
1752 output->image[i] = NULL;
1753 }
1754
1755 return -1;
1756}
1757
1758static void
1759drm_output_fini_pixman(struct drm_output *output)
1760{
1761 unsigned int i;
1762
1763 pixman_renderer_output_destroy(&output->base);
1764 pixman_region32_fini(&output->previous_damage);
1765
1766 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1767 drm_fb_destroy_dumb(output->dumb[i]);
1768 pixman_image_unref(output->image[i]);
1769 output->dumb[i] = NULL;
1770 output->image[i] = NULL;
1771 }
1772}
1773
Richard Hughes2b2092a2013-04-24 14:58:02 +01001774static void
1775edid_parse_string(const uint8_t *data, char text[])
1776{
1777 int i;
1778 int replaced = 0;
1779
1780 /* this is always 12 bytes, but we can't guarantee it's null
1781 * terminated or not junk. */
1782 strncpy(text, (const char *) data, 12);
1783
1784 /* remove insane chars */
1785 for (i = 0; text[i] != '\0'; i++) {
1786 if (text[i] == '\n' ||
1787 text[i] == '\r') {
1788 text[i] = '\0';
1789 break;
1790 }
1791 }
1792
1793 /* ensure string is printable */
1794 for (i = 0; text[i] != '\0'; i++) {
1795 if (!isprint(text[i])) {
1796 text[i] = '-';
1797 replaced++;
1798 }
1799 }
1800
1801 /* if the string is random junk, ignore the string */
1802 if (replaced > 4)
1803 text[0] = '\0';
1804}
1805
1806#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1807#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1808#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1809#define EDID_OFFSET_DATA_BLOCKS 0x36
1810#define EDID_OFFSET_LAST_BLOCK 0x6c
1811#define EDID_OFFSET_PNPID 0x08
1812#define EDID_OFFSET_SERIAL 0x0c
1813
1814static int
1815edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1816{
1817 int i;
1818 uint32_t serial_number;
1819
1820 /* check header */
1821 if (length < 128)
1822 return -1;
1823 if (data[0] != 0x00 || data[1] != 0xff)
1824 return -1;
1825
1826 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1827 * /--08--\/--09--\
1828 * 7654321076543210
1829 * |\---/\---/\---/
1830 * R C1 C2 C3 */
1831 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1832 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1833 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1834 edid->pnp_id[3] = '\0';
1835
1836 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1837 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1838 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1839 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1840 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1841 if (serial_number > 0)
1842 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1843
1844 /* parse EDID data */
1845 for (i = EDID_OFFSET_DATA_BLOCKS;
1846 i <= EDID_OFFSET_LAST_BLOCK;
1847 i += 18) {
1848 /* ignore pixel clock data */
1849 if (data[i] != 0)
1850 continue;
1851 if (data[i+2] != 0)
1852 continue;
1853
1854 /* any useful blocks? */
1855 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1856 edid_parse_string(&data[i+5],
1857 edid->monitor_name);
1858 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1859 edid_parse_string(&data[i+5],
1860 edid->serial_number);
1861 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1862 edid_parse_string(&data[i+5],
1863 edid->eisa_id);
1864 }
1865 }
1866 return 0;
1867}
1868
1869static void
1870find_and_parse_output_edid(struct drm_compositor *ec,
1871 struct drm_output *output,
1872 drmModeConnector *connector)
1873{
1874 drmModePropertyBlobPtr edid_blob = NULL;
1875 drmModePropertyPtr property;
1876 int i;
1877 int rc;
1878
1879 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1880 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1881 if (!property)
1882 continue;
1883 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1884 !strcmp(property->name, "EDID")) {
1885 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1886 connector->prop_values[i]);
1887 }
1888 drmModeFreeProperty(property);
1889 }
1890 if (!edid_blob)
1891 return;
1892
1893 rc = edid_parse(&output->edid,
1894 edid_blob->data,
1895 edid_blob->length);
1896 if (!rc) {
1897 weston_log("EDID data '%s', '%s', '%s'\n",
1898 output->edid.pnp_id,
1899 output->edid.monitor_name,
1900 output->edid.serial_number);
1901 if (output->edid.pnp_id[0] != '\0')
1902 output->base.make = output->edid.pnp_id;
1903 if (output->edid.monitor_name[0] != '\0')
1904 output->base.model = output->edid.monitor_name;
1905 if (output->edid.serial_number[0] != '\0')
1906 output->base.serial_number = output->edid.serial_number;
1907 }
1908 drmModeFreePropertyBlob(edid_blob);
1909}
1910
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001911
1912
1913static int
1914parse_modeline(const char *s, drmModeModeInfo *mode)
1915{
1916 char hsync[16];
1917 char vsync[16];
1918 float fclock;
1919
1920 mode->type = DRM_MODE_TYPE_USERDEF;
1921 mode->hskew = 0;
1922 mode->vscan = 0;
1923 mode->vrefresh = 0;
1924 mode->flags = 0;
1925
Rob Bradford307e09e2013-07-26 16:29:40 +01001926 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001927 &fclock,
1928 &mode->hdisplay,
1929 &mode->hsync_start,
1930 &mode->hsync_end,
1931 &mode->htotal,
1932 &mode->vdisplay,
1933 &mode->vsync_start,
1934 &mode->vsync_end,
1935 &mode->vtotal, hsync, vsync) != 11)
1936 return -1;
1937
1938 mode->clock = fclock * 1000;
1939 if (strcmp(hsync, "+hsync") == 0)
1940 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1941 else if (strcmp(hsync, "-hsync") == 0)
1942 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1943 else
1944 return -1;
1945
1946 if (strcmp(vsync, "+vsync") == 0)
1947 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1948 else if (strcmp(vsync, "-vsync") == 0)
1949 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1950 else
1951 return -1;
1952
1953 return 0;
1954}
1955
Rob Bradford66bd9f52013-06-25 18:56:42 +01001956static void
1957setup_output_seat_constraint(struct drm_compositor *ec,
1958 struct weston_output *output,
1959 const char *s)
1960{
1961 if (strcmp(s, "") != 0) {
1962 struct udev_seat *seat;
1963
Jonas Ådahl58e15862014-03-12 22:08:40 +01001964 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001965 if (seat)
1966 seat->base.output = output;
1967
1968 if (seat && seat->base.pointer)
1969 weston_pointer_clamp(seat->base.pointer,
1970 &seat->base.pointer->x,
1971 &seat->base.pointer->y);
1972 }
1973}
1974
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001975static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001976get_gbm_format_from_section(struct weston_config_section *section,
1977 uint32_t default_value,
1978 uint32_t *format)
1979{
1980 char *s;
1981 int ret = 0;
1982
1983 weston_config_section_get_string(section,
1984 "gbm-format", &s, NULL);
1985
1986 if (s == NULL)
1987 *format = default_value;
1988 else if (strcmp(s, "xrgb8888") == 0)
1989 *format = GBM_FORMAT_XRGB8888;
1990 else if (strcmp(s, "rgb565") == 0)
1991 *format = GBM_FORMAT_RGB565;
1992 else if (strcmp(s, "xrgb2101010") == 0)
1993 *format = GBM_FORMAT_XRGB2101010;
1994 else {
1995 weston_log("fatal: unrecognized pixel format: %s\n", s);
1996 ret = -1;
1997 }
1998
1999 free(s);
2000
2001 return ret;
2002}
2003
2004static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002005create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002006 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002007 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002008 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002009{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002010 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002011 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002012 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002013 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002014 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002015 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002016 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002017 int i, width, height, scale;
2018 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002019 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002020 enum output_config config;
2021 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002022
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002023 i = find_crtc_for_connector(ec, resources, connector);
2024 if (i < 0) {
2025 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002026 return -1;
2027 }
2028
Peter Huttererf3d62272013-08-08 11:57:05 +10002029 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002030 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002031 return -1;
2032
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002033 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
2034 output->base.make = "unknown";
2035 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01002036 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002037 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002038
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002039 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
2040 type_name = connector_type_names[connector->connector_type];
2041 else
2042 type_name = "UNKNOWN";
2043 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01002044 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002045
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002046 section = weston_config_get_section(ec->base.config, "output", "name",
2047 output->base.name);
2048 weston_config_section_get_string(section, "mode", &s, "preferred");
2049 if (strcmp(s, "off") == 0)
2050 config = OUTPUT_CONFIG_OFF;
2051 else if (strcmp(s, "preferred") == 0)
2052 config = OUTPUT_CONFIG_PREFERRED;
2053 else if (strcmp(s, "current") == 0)
2054 config = OUTPUT_CONFIG_CURRENT;
2055 else if (sscanf(s, "%dx%d", &width, &height) == 2)
2056 config = OUTPUT_CONFIG_MODE;
2057 else if (parse_modeline(s, &modeline) == 0)
2058 config = OUTPUT_CONFIG_MODELINE;
2059 else {
2060 weston_log("Invalid mode \"%s\" for output %s\n",
2061 s, output->base.name);
2062 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002063 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002064 free(s);
2065
2066 weston_config_section_get_int(section, "scale", &scale, 1);
2067 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05002068 if (weston_parse_transform(s, &transform) < 0)
2069 weston_log("Invalid transform \"%s\" for output %s\n",
2070 s, output->base.name);
2071
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002072 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002073
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002074 if (get_gbm_format_from_section(section,
2075 ec->format,
2076 &output->format) == -1)
2077 output->format = ec->format;
2078
Rob Bradford66bd9f52013-06-25 18:56:42 +01002079 weston_config_section_get_string(section, "seat", &s, "");
2080 setup_output_seat_constraint(ec, &output->base, s);
2081 free(s);
2082
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002083 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002084 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002085 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002086 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002087 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002088
Matt Roper361d2ad2011-08-29 13:52:23 -07002089 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03002090 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002091
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002092 /* Get the current mode on the crtc that's currently driving
2093 * this connector. */
2094 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002095 memset(&crtc_mode, 0, sizeof crtc_mode);
2096 if (encoder != NULL) {
2097 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
2098 drmModeFreeEncoder(encoder);
2099 if (crtc == NULL)
2100 goto err_free;
2101 if (crtc->mode_valid)
2102 crtc_mode = crtc->mode;
2103 drmModeFreeCrtc(crtc);
2104 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002105
David Herrmann0f0d54e2011-12-08 17:05:45 +01002106 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002107 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002108 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002109 goto err_free;
2110 }
2111
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002112 if (config == OUTPUT_CONFIG_OFF) {
2113 weston_log("Disabling output %s\n", output->base.name);
2114 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
2115 0, 0, 0, 0, 0, NULL);
2116 goto err_free;
2117 }
2118
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002119 preferred = NULL;
2120 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002121 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002122 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002123
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002124 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002125 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002126 width == drm_mode->base.width &&
2127 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002128 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002129 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002130 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002131 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002132 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002133 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002134 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002135
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002136 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002137 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002138 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002139 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002140 }
2141
Wang Quanxianacb805a2012-07-30 18:09:46 -04002142 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002143 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002144 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002145 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002146 }
2147
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002148 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002149 configured = current;
2150
Wang Quanxianacb805a2012-07-30 18:09:46 -04002151 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002152 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002153 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002154 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002155 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002156 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002157 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002158 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002159 else if (best)
2160 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002161
Hardeningff39efa2013-09-18 23:56:35 +02002162 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002163 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002164 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002165 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002166
Hardeningff39efa2013-09-18 23:56:35 +02002167 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002168
John Kåre Alsaker94659272012-11-13 19:10:18 +01002169 weston_output_init(&output->base, &ec->base, x, y,
2170 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002171 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002172
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002173 if (ec->use_pixman) {
2174 if (drm_output_init_pixman(output, ec) < 0) {
2175 weston_log("Failed to init output pixman state\n");
2176 goto err_output;
2177 }
2178 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002179 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002180 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002181 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002182
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002183 output->backlight = backlight_init(drm_device,
2184 connector->connector_type);
2185 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002186 weston_log("Initialized backlight, device %s\n",
2187 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002188 output->base.set_backlight = drm_set_backlight;
2189 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002190 } else {
2191 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002192 }
2193
Giulio Camuffob1147152015-05-06 21:41:57 +03002194 weston_compositor_add_output(&ec->base, &output->base);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002195
Richard Hughes2b2092a2013-04-24 14:58:02 +01002196 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002197 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2198 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002199
Jonas Ådahle5a12252013-04-05 23:07:11 +02002200 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002201 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002202 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002203 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002204 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002205 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002206
Richard Hughese7299962013-05-01 21:52:12 +01002207 output->base.gamma_size = output->original_crtc->gamma_size;
2208 output->base.set_gamma = drm_output_set_gamma;
2209
Xiong Zhang97116532013-10-23 13:58:31 +08002210 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2211 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002212
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002213 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2214 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2215 &ec->base.primary_plane);
2216
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002217 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002218 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002219 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002220 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002221 m->width, m->height, m->refresh / 1000.0,
2222 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2223 ", preferred" : "",
2224 m->flags & WL_OUTPUT_MODE_CURRENT ?
2225 ", current" : "",
2226 connector->count_modes == 0 ?
2227 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002228
Mario Kleiner80817042015-06-21 21:25:11 +02002229 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
2230 output->base.native_mode = output->base.current_mode;
2231 output->base.native_scale = output->base.current_scale;
2232
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002233 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002234
John Kåre Alsaker94659272012-11-13 19:10:18 +01002235err_output:
2236 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002237err_free:
2238 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2239 base.link) {
2240 wl_list_remove(&drm_mode->base.link);
2241 free(drm_mode);
2242 }
2243
2244 drmModeFreeCrtc(output->original_crtc);
2245 ec->crtc_allocator &= ~(1 << output->crtc_id);
2246 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002247 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002248
David Herrmann0f0d54e2011-12-08 17:05:45 +01002249 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002250}
2251
Jesse Barnes58ef3792012-02-23 09:45:49 -05002252static void
2253create_sprites(struct drm_compositor *ec)
2254{
2255 struct drm_sprite *sprite;
2256 drmModePlaneRes *plane_res;
2257 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002258 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002259
2260 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2261 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002262 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002263 strerror(errno));
2264 return;
2265 }
2266
2267 for (i = 0; i < plane_res->count_planes; i++) {
2268 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2269 if (!plane)
2270 continue;
2271
Peter Huttererf3d62272013-08-08 11:57:05 +10002272 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002273 plane->count_formats));
2274 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002275 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002276 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002277 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002278 continue;
2279 }
2280
Jesse Barnes58ef3792012-02-23 09:45:49 -05002281 sprite->possible_crtcs = plane->possible_crtcs;
2282 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002283 sprite->current = NULL;
2284 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002285 sprite->compositor = ec;
2286 sprite->count_formats = plane->count_formats;
2287 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002288 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002289 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002290 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002291 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2292 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002293
2294 wl_list_insert(&ec->sprite_list, &sprite->link);
2295 }
2296
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002297 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002298}
2299
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002300static void
2301destroy_sprites(struct drm_compositor *compositor)
2302{
2303 struct drm_sprite *sprite, *next;
2304 struct drm_output *output;
2305
2306 output = container_of(compositor->base.output_list.next,
2307 struct drm_output, base.link);
2308
2309 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2310 drmModeSetPlane(compositor->drm.fd,
2311 sprite->plane_id,
2312 output->crtc_id, 0, 0,
2313 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002314 drm_output_release_fb(output, sprite->current);
2315 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002316 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002317 free(sprite);
2318 }
2319}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002320
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002321static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002322create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002323 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002324{
2325 drmModeConnector *connector;
2326 drmModeRes *resources;
2327 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002328 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002329
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002330 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002331 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002332 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002333 return -1;
2334 }
2335
Jesse Barnes58ef3792012-02-23 09:45:49 -05002336 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002337 if (!ec->crtcs) {
2338 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002339 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002340 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002341
Rob Clark4339add2012-08-09 14:18:28 -05002342 ec->min_width = resources->min_width;
2343 ec->max_width = resources->max_width;
2344 ec->min_height = resources->min_height;
2345 ec->max_height = resources->max_height;
2346
Jesse Barnes58ef3792012-02-23 09:45:49 -05002347 ec->num_crtcs = resources->count_crtcs;
2348 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2349
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002350 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002351 connector = drmModeGetConnector(ec->drm.fd,
2352 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002353 if (connector == NULL)
2354 continue;
2355
2356 if (connector->connection == DRM_MODE_CONNECTED &&
2357 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002358 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002359 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002360 connector, x, y,
2361 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002362 drmModeFreeConnector(connector);
2363 continue;
2364 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002365
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002366 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002367 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002368 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002369 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002370
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002371 drmModeFreeConnector(connector);
2372 }
2373
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002374 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002375 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002376 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002377 return -1;
2378 }
2379
2380 drmModeFreeResources(resources);
2381
2382 return 0;
2383}
2384
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002385static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002386update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002387{
2388 drmModeConnector *connector;
2389 drmModeRes *resources;
2390 struct drm_output *output, *next;
2391 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002392 uint32_t connected = 0, disconnects = 0;
2393 int i;
2394
2395 resources = drmModeGetResources(ec->drm.fd);
2396 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002397 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002398 return;
2399 }
2400
2401 /* collect new connects */
2402 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002403 int connector_id = resources->connectors[i];
2404
2405 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002406 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002407 continue;
2408
David Herrmann7551cff2011-12-08 17:05:43 +01002409 if (connector->connection != DRM_MODE_CONNECTED) {
2410 drmModeFreeConnector(connector);
2411 continue;
2412 }
2413
Benjamin Franzke117483d2011-08-30 11:38:26 +02002414 connected |= (1 << connector_id);
2415
2416 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002417 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002418 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002419 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002420
2421 /* XXX: not yet needed, we die with 0 outputs */
2422 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002423 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002424 else
2425 x = 0;
2426 y = 0;
2427 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002428 connector, x, y,
2429 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002430 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002431
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002432 }
2433 drmModeFreeConnector(connector);
2434 }
2435 drmModeFreeResources(resources);
2436
2437 disconnects = ec->connector_allocator & ~connected;
2438 if (disconnects) {
2439 wl_list_for_each_safe(output, next, &ec->base.output_list,
2440 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002441 if (disconnects & (1 << output->connector_id)) {
2442 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002443 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002444 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002445 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002446 }
2447 }
2448 }
2449
Daniel Stonef556ebe2015-05-21 08:28:58 +01002450 /* FIXME: handle zero outputs, without terminating */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002451 if (ec->connector_allocator == 0)
2452 wl_display_terminate(ec->base.wl_display);
2453}
2454
2455static int
David Herrmannd7488c22012-03-11 20:05:21 +01002456udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002457{
David Herrmannd7488c22012-03-11 20:05:21 +01002458 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002459 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002460
2461 sysnum = udev_device_get_sysnum(device);
2462 if (!sysnum || atoi(sysnum) != ec->drm.id)
2463 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002464
David Herrmann6ac52db2012-03-11 20:05:22 +01002465 val = udev_device_get_property_value(device, "HOTPLUG");
2466 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002467 return 0;
2468
David Herrmann6ac52db2012-03-11 20:05:22 +01002469 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002470}
2471
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002472static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002473udev_drm_event(int fd, uint32_t mask, void *data)
2474{
2475 struct drm_compositor *ec = data;
2476 struct udev_device *event;
2477
2478 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002479
David Herrmannd7488c22012-03-11 20:05:21 +01002480 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002481 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002482
2483 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002484
2485 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002486}
2487
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002488static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002489drm_restore(struct weston_compositor *ec)
2490{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002491 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002492}
2493
2494static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002495drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002496{
2497 struct drm_compositor *d = (struct drm_compositor *) ec;
2498
Rob Bradfordd355b802013-05-31 18:09:55 +01002499 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002500
2501 wl_event_source_remove(d->udev_drm_source);
2502 wl_event_source_remove(d->drm_source);
2503
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002504 destroy_sprites(d);
2505
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002506 weston_compositor_shutdown(ec);
2507
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002508 if (d->gbm)
2509 gbm_device_destroy(d->gbm);
2510
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002511 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002512
Rob Bradford45c15b82013-07-26 16:29:35 +01002513 close(d->drm.fd);
2514
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002515 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002516}
2517
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002518static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002519drm_compositor_set_modes(struct drm_compositor *compositor)
2520{
2521 struct drm_output *output;
2522 struct drm_mode *drm_mode;
2523 int ret;
2524
2525 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002526 if (!output->current) {
2527 /* If something that would cause the output to
2528 * switch mode happened while in another vt, we
2529 * might not have a current drm_fb. In that case,
2530 * schedule a repaint and let drm_output_repaint
2531 * handle setting the mode. */
2532 weston_output_schedule_repaint(&output->base);
2533 continue;
2534 }
2535
Hardeningff39efa2013-09-18 23:56:35 +02002536 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002537 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002538 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002539 &output->connector_id, 1,
2540 &drm_mode->mode_info);
2541 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002542 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002543 "failed to set mode %dx%d for output at %d,%d: %m\n",
Daniel Stonef556ebe2015-05-21 08:28:58 +01002544 drm_mode->base.width, drm_mode->base.height,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002545 output->base.x, output->base.y);
2546 }
2547 }
2548}
2549
2550static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002551session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002552{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002553 struct weston_compositor *compositor = data;
2554 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002555 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002556 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002557
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002558 if (ec->base.session_active) {
2559 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002560 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002561 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002562 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002563 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002564 } else {
2565 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002566 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002567
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002568 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002569 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002570
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002571 /* If we have a repaint scheduled (either from a
2572 * pending pageflip or the idle handler), make sure we
2573 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002574 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002575 * further attemps at repainting. When we switch
2576 * back, we schedule a repaint, which will process
2577 * pending frame callbacks. */
2578
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002579 wl_list_for_each(output, &ec->base.output_list, base.link) {
2580 output->base.repaint_needed = 0;
2581 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002582 }
2583
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002584 output = container_of(ec->base.output_list.next,
2585 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002586
2587 wl_list_for_each(sprite, &ec->sprite_list, link)
2588 drmModeSetPlane(ec->drm.fd,
2589 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002590 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002591 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002592 };
2593}
2594
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002595static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002596switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002597{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002598 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002599
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002600 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002601}
2602
David Herrmann0af066f2012-10-29 19:21:16 +01002603/*
2604 * Find primary GPU
2605 * Some systems may have multiple DRM devices attached to a single seat. This
2606 * function loops over all devices and tries to find a PCI device with the
2607 * boot_vga sysfs attribute set to 1.
2608 * If no such device is found, the first DRM device reported by udev is used.
2609 */
2610static struct udev_device*
2611find_primary_gpu(struct drm_compositor *ec, const char *seat)
2612{
2613 struct udev_enumerate *e;
2614 struct udev_list_entry *entry;
2615 const char *path, *device_seat, *id;
2616 struct udev_device *device, *drm_device, *pci;
2617
2618 e = udev_enumerate_new(ec->udev);
2619 udev_enumerate_add_match_subsystem(e, "drm");
2620 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2621
2622 udev_enumerate_scan_devices(e);
2623 drm_device = NULL;
2624 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2625 path = udev_list_entry_get_name(entry);
2626 device = udev_device_new_from_syspath(ec->udev, path);
2627 if (!device)
2628 continue;
2629 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2630 if (!device_seat)
2631 device_seat = default_seat;
2632 if (strcmp(device_seat, seat)) {
2633 udev_device_unref(device);
2634 continue;
2635 }
2636
2637 pci = udev_device_get_parent_with_subsystem_devtype(device,
2638 "pci", NULL);
2639 if (pci) {
2640 id = udev_device_get_sysattr_value(pci, "boot_vga");
2641 if (id && !strcmp(id, "1")) {
2642 if (drm_device)
2643 udev_device_unref(drm_device);
2644 drm_device = device;
2645 break;
2646 }
2647 }
2648
2649 if (!drm_device)
2650 drm_device = device;
2651 else
2652 udev_device_unref(device);
2653 }
2654
2655 udev_enumerate_unref(e);
2656 return drm_device;
2657}
2658
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002659static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002660planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002661{
2662 struct drm_compositor *c = data;
2663
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002664 switch (key) {
2665 case KEY_C:
2666 c->cursors_are_broken ^= 1;
2667 break;
2668 case KEY_V:
2669 c->sprites_are_broken ^= 1;
2670 break;
2671 case KEY_O:
2672 c->sprites_hidden ^= 1;
2673 break;
2674 default:
2675 break;
2676 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002677}
2678
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002679#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002680static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002681recorder_destroy(struct drm_output *output)
2682{
2683 vaapi_recorder_destroy(output->recorder);
2684 output->recorder = NULL;
2685
2686 output->base.disable_planes--;
2687
2688 wl_list_remove(&output->recorder_frame_listener.link);
2689 weston_log("[libva recorder] done\n");
2690}
2691
2692static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002693recorder_frame_notify(struct wl_listener *listener, void *data)
2694{
2695 struct drm_output *output;
2696 struct drm_compositor *c;
2697 int fd, ret;
2698
2699 output = container_of(listener, struct drm_output,
2700 recorder_frame_listener);
2701 c = (struct drm_compositor *) output->base.compositor;
2702
2703 if (!output->recorder)
2704 return;
2705
2706 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2707 DRM_CLOEXEC, &fd);
2708 if (ret) {
2709 weston_log("[libva recorder] "
2710 "failed to create prime fd for front buffer\n");
2711 return;
2712 }
2713
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002714 ret = vaapi_recorder_frame(output->recorder, fd,
2715 output->current->stride);
2716 if (ret < 0) {
2717 weston_log("[libva recorder] aborted: %m\n");
2718 recorder_destroy(output);
2719 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002720}
2721
2722static void *
2723create_recorder(struct drm_compositor *c, int width, int height,
2724 const char *filename)
2725{
2726 int fd;
2727 drm_magic_t magic;
2728
2729 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2730 if (fd < 0)
2731 return NULL;
2732
2733 drmGetMagic(fd, &magic);
2734 drmAuthMagic(c->drm.fd, magic);
2735
2736 return vaapi_recorder_create(fd, width, height, filename);
2737}
2738
2739static void
2740recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2741 void *data)
2742{
2743 struct drm_compositor *c = data;
2744 struct drm_output *output;
2745 int width, height;
2746
2747 output = container_of(c->base.output_list.next,
2748 struct drm_output, base.link);
2749
2750 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002751 if (output->format != GBM_FORMAT_XRGB8888) {
2752 weston_log("failed to start vaapi recorder: "
2753 "output format not supported\n");
2754 return;
2755 }
2756
Hardeningff39efa2013-09-18 23:56:35 +02002757 width = output->base.current_mode->width;
2758 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002759
2760 output->recorder =
2761 create_recorder(c, width, height, "capture.h264");
2762 if (!output->recorder) {
2763 weston_log("failed to create vaapi recorder\n");
2764 return;
2765 }
2766
2767 output->base.disable_planes++;
2768
2769 output->recorder_frame_listener.notify = recorder_frame_notify;
2770 wl_signal_add(&output->base.frame_signal,
2771 &output->recorder_frame_listener);
2772
2773 weston_output_schedule_repaint(&output->base);
2774
2775 weston_log("[libva recorder] initialized\n");
2776 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002777 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002778 }
2779}
2780#else
2781static void
2782recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2783 void *data)
2784{
2785 weston_log("Compiled without libva support\n");
2786}
2787#endif
2788
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002789static void
2790switch_to_gl_renderer(struct drm_compositor *c)
2791{
2792 struct drm_output *output;
2793
2794 if (!c->use_pixman)
2795 return;
2796
2797 weston_log("Switching to GL renderer\n");
2798
2799 c->gbm = create_gbm_device(c->drm.fd);
2800 if (!c->gbm) {
2801 weston_log("Failed to create gbm device. "
2802 "Aborting renderer switch\n");
2803 return;
2804 }
2805
2806 wl_list_for_each(output, &c->base.output_list, base.link)
2807 pixman_renderer_output_destroy(&output->base);
2808
2809 c->base.renderer->destroy(&c->base);
2810
2811 if (drm_compositor_create_gl_renderer(c) < 0) {
2812 gbm_device_destroy(c->gbm);
2813 weston_log("Failed to create GL renderer. Quitting.\n");
2814 /* FIXME: we need a function to shutdown cleanly */
2815 assert(0);
2816 }
2817
2818 wl_list_for_each(output, &c->base.output_list, base.link)
2819 drm_output_init_egl(output, c);
2820
2821 c->use_pixman = 0;
2822}
2823
2824static void
2825renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2826 void *data)
2827{
2828 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2829
2830 switch_to_gl_renderer(c);
2831}
2832
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002833static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002834drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002835 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002836 int *argc, char *argv[],
2837 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002838{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002839 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002840 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002841 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002842 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002843 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002844 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002845
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002846 weston_log("initializing drm backend\n");
2847
Peter Huttererf3d62272013-08-08 11:57:05 +10002848 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002849 if (ec == NULL)
2850 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002851
Pekka Paalanen68583832015-05-19 09:53:16 +03002852 /*
2853 * KMS support for hardware planes cannot properly synchronize
2854 * without nuclear page flip. Without nuclear/atomic, hw plane
2855 * and cursor plane updates would either tear or cause extra
2856 * waits for vblanks which means dropping the compositor framerate
2857 * to a fraction.
2858 *
2859 * These can be enabled again when nuclear/atomic support lands.
2860 */
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002861 ec->sprites_are_broken = 1;
Pekka Paalanen68583832015-05-19 09:53:16 +03002862 ec->cursors_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002863
2864 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002865 if (get_gbm_format_from_section(section,
2866 GBM_FORMAT_XRGB8888,
2867 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002868 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002869
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002870 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002871
Daniel Stone725c2c32012-06-22 14:04:36 +01002872 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002873 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002874 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002875 goto err_base;
2876 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002877
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002878 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002879 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
David Herrmann2ecb84a2014-12-30 14:33:22 +01002880 param->seat_id, true);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002881 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002882 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002883 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002884 goto err_compositor;
2885 }
2886
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002887 ec->udev = udev_new();
2888 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002889 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002890 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002891 }
2892
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002893 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002894 ec->session_listener.notify = session_notify;
2895 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002896
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002897 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002898 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002899 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002900 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002901 }
David Herrmann0af066f2012-10-29 19:21:16 +01002902 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002903
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002904 if (init_drm(ec, drm_device) < 0) {
2905 weston_log("failed to initialize kms\n");
2906 goto err_udev_dev;
2907 }
2908
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002909 if (ec->use_pixman) {
2910 if (init_pixman(ec) < 0) {
2911 weston_log("failed to initialize pixman renderer\n");
2912 goto err_udev_dev;
2913 }
2914 } else {
2915 if (init_egl(ec) < 0) {
2916 weston_log("failed to initialize egl\n");
2917 goto err_udev_dev;
2918 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002919 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002920
2921 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002922 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002923
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002924 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002925
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002926 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002927 weston_compositor_add_key_binding(&ec->base, key,
2928 MODIFIER_CTRL | MODIFIER_ALT,
2929 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002930
Jesse Barnes58ef3792012-02-23 09:45:49 -05002931 wl_list_init(&ec->sprite_list);
2932 create_sprites(ec);
2933
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002934 if (udev_input_init(&ec->input,
2935 &ec->base, ec->udev, param->seat_id) < 0) {
2936 weston_log("failed to create input devices\n");
2937 goto err_sprite;
2938 }
2939
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002940 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002941 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002942 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002943 }
2944
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002945 /* A this point we have some idea of whether or not we have a working
2946 * cursor plane. */
2947 if (!ec->cursors_are_broken)
2948 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2949
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002950 path = NULL;
2951
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002952 loop = wl_display_get_event_loop(ec->base.wl_display);
2953 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002954 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002955 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002956
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002957 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2958 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002959 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002960 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002961 }
2962 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2963 "drm", NULL);
2964 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002965 wl_event_loop_add_fd(loop,
2966 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002967 WL_EVENT_READABLE, udev_drm_event, ec);
2968
2969 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002970 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002971 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002972 }
2973
Daniel Stonea96b93c2012-06-22 14:04:37 +01002974 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002975
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002976 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002977 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002978 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002979 planes_binding, ec);
2980 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2981 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002982 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2983 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002984 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2985 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002986
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002987 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002988
2989err_udev_monitor:
2990 wl_event_source_remove(ec->udev_drm_source);
2991 udev_monitor_unref(ec->udev_monitor);
2992err_drm_source:
2993 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002994err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002995 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002996err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002997 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002998 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002999 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003000err_udev_dev:
3001 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003002err_launcher:
3003 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003004err_udev:
3005 udev_unref(ec->udev);
3006err_compositor:
3007 weston_compositor_shutdown(&ec->base);
3008err_base:
3009 free(ec);
3010 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003011}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003012
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003013WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05003014backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04003015 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003016{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003017 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003018
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003019 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003020 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
3021 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
3022 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003023 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003024 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003025 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02003026
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003027 param.seat_id = default_seat;
3028
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003029 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003030
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003031 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003032}