blob: f24fa0b483002969a1679a82871c7bda13427dab [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 */
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +0200613static unsigned int drm_waitvblank_pipe(struct drm_output *output)
614{
615 if (output->pipe > 1)
616 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
617 DRM_VBLANK_HIGH_CRTC_MASK;
618 else if (output->pipe > 0)
619 return DRM_VBLANK_SECONDARY;
620 else
621 return 0;
622}
623
David Herrmann1edf44c2013-10-22 17:11:26 +0200624static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500625drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400626 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100627{
628 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500629 struct drm_compositor *compositor =
630 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500631 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400632 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500633 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100634
Xiong Zhangabd5d472013-10-11 14:43:07 +0800635 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200636 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800637
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300638 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400639 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300640 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200641 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100642
Hardeningff39efa2013-09-18 23:56:35 +0200643 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200644 if (!output->current ||
645 output->current->stride != output->next->stride) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400646 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300647 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400648 &output->connector_id, 1,
649 &mode->mode_info);
650 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200651 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200652 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400653 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300654 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200655 }
656
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500657 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300658 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500659 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200660 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200661 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500662 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100663
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300664 output->page_flip_pending = 1;
665
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400666 drm_output_set_cursor(output);
667
Jesse Barnes58ef3792012-02-23 09:45:49 -0500668 /*
669 * Now, update all the sprite surfaces
670 */
671 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200672 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500673 drmVBlank vbl = {
674 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
675 .request.sequence = 1,
676 };
677
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200678 if ((!s->current && !s->next) ||
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200679 !drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500680 continue;
681
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200682 if (s->next && !compositor->sprites_hidden)
683 fb_id = s->next->fb_id;
684
Jesse Barnes58ef3792012-02-23 09:45:49 -0500685 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200686 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500687 s->dest_x, s->dest_y,
688 s->dest_w, s->dest_h,
689 s->src_x, s->src_y,
690 s->src_w, s->src_h);
691 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200692 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500693 ret, strerror(errno));
694
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +0200695 vbl.request.type |= drm_waitvblank_pipe(output);
Rob Clark5ca1a472012-08-08 20:27:37 -0500696
Jesse Barnes58ef3792012-02-23 09:45:49 -0500697 /*
698 * Queue a vblank signal so we know when the surface
699 * becomes active on the display or has been replaced.
700 */
701 vbl.request.signal = (unsigned long)s;
702 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
703 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200704 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500705 ret, strerror(errno));
706 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300707
708 s->output = output;
709 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500710 }
711
David Herrmann1edf44c2013-10-22 17:11:26 +0200712 return 0;
713
714err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800715 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200716 if (output->next) {
717 drm_output_release_fb(output, output->next);
718 output->next = NULL;
719 }
720
721 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400722}
723
724static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200725drm_output_start_repaint_loop(struct weston_output *output_base)
726{
727 struct drm_output *output = (struct drm_output *) output_base;
728 struct drm_compositor *compositor = (struct drm_compositor *)
729 output_base->compositor;
730 uint32_t fb_id;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300731 struct timespec ts;
732
Xiong Zhangabd5d472013-10-11 14:43:07 +0800733 if (output->destroy_pending)
734 return;
735
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300736 if (!output->current) {
737 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200738 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300739 }
740
741 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200742
743 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
744 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
745 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200746 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200747 }
David Herrmann3c688c52013-10-22 17:11:25 +0200748
749 return;
750
751finish_frame:
752 /* if we cannot page-flip, immediately finish frame */
Pekka Paalanen662f3842015-03-18 12:17:26 +0200753 weston_compositor_read_presentation_clock(&compositor->base, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200754 weston_output_finish_frame(output_base, &ts,
755 PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200756}
757
758static void
Pekka Paalanen641307c2014-09-23 22:08:47 -0400759drm_output_update_msc(struct drm_output *output, unsigned int seq)
760{
761 uint64_t msc_hi = output->base.msc >> 32;
762
763 if (seq < (output->base.msc & 0xffffffff))
764 msc_hi++;
765
766 output->base.msc = (msc_hi << 32) + seq;
767}
768
769static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500770vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
771 void *data)
772{
773 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300774 struct drm_output *output = s->output;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400775 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200776 uint32_t flags = PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
777 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300778
Pekka Paalanen641307c2014-09-23 22:08:47 -0400779 drm_output_update_msc(output, frame);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300780 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500781
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200782 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200783 s->current = s->next;
784 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300785
786 if (!output->page_flip_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400787 ts.tv_sec = sec;
788 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200789 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300790 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500791}
792
793static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800794drm_output_destroy(struct weston_output *output_base);
795
796static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400797page_flip_handler(int fd, unsigned int frame,
798 unsigned int sec, unsigned int usec, void *data)
799{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200800 struct drm_output *output = (struct drm_output *) data;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400801 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200802 uint32_t flags = PRESENTATION_FEEDBACK_KIND_VSYNC |
803 PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
804 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400805
Pekka Paalanen641307c2014-09-23 22:08:47 -0400806 drm_output_update_msc(output, frame);
807
Jonas Ådahle5a12252013-04-05 23:07:11 +0200808 /* We don't set page_flip_pending on start_repaint_loop, in that case
809 * we just want to page flip to the current buffer to get an accurate
810 * timestamp */
811 if (output->page_flip_pending) {
812 drm_output_release_fb(output, output->current);
813 output->current = output->next;
814 output->next = NULL;
815 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300816
Jonas Ådahle5a12252013-04-05 23:07:11 +0200817 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400818
Xiong Zhangabd5d472013-10-11 14:43:07 +0800819 if (output->destroy_pending)
820 drm_output_destroy(&output->base);
821 else if (!output->vblank_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400822 ts.tv_sec = sec;
823 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200824 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300825
826 /* We can't call this from frame_notify, because the output's
827 * repaint needed flag is cleared just after that */
828 if (output->recorder)
829 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300830 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200831}
832
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500833static uint32_t
834drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500835 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500836{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500837 uint32_t i, format;
838
839 format = gbm_bo_get_format(bo);
840
841 if (format == GBM_FORMAT_ARGB8888) {
842 pixman_region32_t r;
843
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500844 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600845 ev->surface->width,
846 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500847 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500848
849 if (!pixman_region32_not_empty(&r))
850 format = GBM_FORMAT_XRGB8888;
851
852 pixman_region32_fini(&r);
853 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500854
855 for (i = 0; i < s->count_formats; i++)
856 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500857 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500858
859 return 0;
860}
861
862static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500863drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500864{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500865 return !ev->transform.enabled ||
866 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500867}
868
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400869static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200870drm_output_prepare_overlay_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500871 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500872{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200873 struct weston_compositor *ec = output->base.compositor;
874 struct drm_compositor *c = (struct drm_compositor *)ec;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200875 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500876 struct drm_sprite *s;
877 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500878 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500879 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200880 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500881 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400882 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500883
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200884 if (c->gbm == NULL)
885 return NULL;
886
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200887 if (viewport->buffer.transform != output->base.transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200888 return NULL;
889
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200890 if (viewport->buffer.scale != output->base.current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200891 return NULL;
892
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500893 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400894 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500895
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200896 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400897 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300898
Jason Ekstranda7af7042013-10-12 22:38:11 -0500899 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400900 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500901
Jason Ekstranda7af7042013-10-12 22:38:11 -0500902 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200903 return NULL;
904
Jason Ekstranda7af7042013-10-12 22:38:11 -0500905 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500906 return NULL;
907
Jason Ekstranda7af7042013-10-12 22:38:11 -0500908 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400909 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500910
Jesse Barnes58ef3792012-02-23 09:45:49 -0500911 wl_list_for_each(s, &c->sprite_list, link) {
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200912 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500913 continue;
914
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200915 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500916 found = 1;
917 break;
918 }
919 }
920
921 /* No sprites available */
922 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400923 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500924
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400925 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500926 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700927 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400928 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400929 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400930
Jason Ekstranda7af7042013-10-12 22:38:11 -0500931 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500932 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200933 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400934 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500935 }
936
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200937 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200938 if (!s->next) {
939 gbm_bo_destroy(bo);
940 return NULL;
941 }
942
Jason Ekstranda7af7042013-10-12 22:38:11 -0500943 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500944
Jason Ekstranda7af7042013-10-12 22:38:11 -0500945 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400946 s->plane.x = box->x1;
947 s->plane.y = box->y1;
948
Jesse Barnes58ef3792012-02-23 09:45:49 -0500949 /*
950 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -0500951 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500952 * for us already).
953 */
954 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500955 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200956 &output->base.region);
957 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500958 box = pixman_region32_extents(&dest_rect);
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200959 tbox = weston_transformed_rect(output->base.width,
960 output->base.height,
961 output->base.transform,
962 output->base.current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200963 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200964 s->dest_x = tbox.x1;
965 s->dest_y = tbox.y1;
966 s->dest_w = tbox.x2 - tbox.x1;
967 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500968 pixman_region32_fini(&dest_rect);
969
970 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500971 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200972 &output->base.region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500973 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400974
Jason Ekstranda7af7042013-10-12 22:38:11 -0500975 weston_view_from_global_fixed(ev,
976 wl_fixed_from_int(box->x1),
977 wl_fixed_from_int(box->y1),
978 &sx1, &sy1);
979 weston_view_from_global_fixed(ev,
980 wl_fixed_from_int(box->x2),
981 wl_fixed_from_int(box->y2),
982 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400983
984 if (sx1 < 0)
985 sx1 = 0;
986 if (sy1 < 0)
987 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600988 if (sx2 > wl_fixed_from_int(ev->surface->width))
989 sx2 = wl_fixed_from_int(ev->surface->width);
990 if (sy2 > wl_fixed_from_int(ev->surface->height))
991 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400992
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200993 tbox.x1 = sx1;
994 tbox.y1 = sy1;
995 tbox.x2 = sx2;
996 tbox.y2 = sy2;
997
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600998 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
999 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +02001000 viewport->buffer.transform,
1001 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +01001002 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +02001003
1004 s->src_x = tbox.x1 << 8;
1005 s->src_y = tbox.y1 << 8;
1006 s->src_w = (tbox.x2 - tbox.x1) << 8;
1007 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001008 pixman_region32_fini(&src_rect);
1009
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001010 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001011}
1012
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001013static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001014drm_output_prepare_cursor_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001015 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001016{
Kristian Høgsberg8a015802012-08-09 17:19:23 -04001017 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001018 (struct drm_compositor *)output->base.compositor;
Neil Robertsf37f82c2014-05-01 18:00:41 +01001019 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001020
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001021 if (c->gbm == NULL)
1022 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +02001023 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
1024 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001025 if (viewport->buffer.scale != output->base.current_scale)
Neil Robertsf37f82c2014-05-01 18:00:41 +01001026 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001027 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001028 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001029 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001030 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001031 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -04001032 return NULL;
Pekka Paalanen5580f222015-02-17 16:33:18 +02001033 if (ev->geometry.scissor_enabled)
1034 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001035 if (ev->surface->buffer_ref.buffer == NULL ||
1036 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001037 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001038 return NULL;
1039
Jason Ekstranda7af7042013-10-12 22:38:11 -05001040 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001041
1042 return &output->cursor_plane;
1043}
1044
1045static void
1046drm_output_set_cursor(struct drm_output *output)
1047{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001048 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001049 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001050 struct drm_compositor *c =
1051 (struct drm_compositor *) output->base.compositor;
1052 EGLint handle, stride;
1053 struct gbm_bo *bo;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001054 uint32_t buf[c->cursor_width * c->cursor_height];
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001055 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001056 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001057
Jason Ekstranda7af7042013-10-12 22:38:11 -05001058 output->cursor_view = NULL;
1059 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001060 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
1061 return;
1062 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001063
Neil Robertse5051712013-11-13 15:44:06 +00001064 buffer = ev->surface->buffer_ref.buffer;
1065
1066 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001067 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001068 pixman_region32_fini(&output->cursor_plane.damage);
1069 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001070 output->current_cursor ^= 1;
1071 bo = output->cursor_bo[output->current_cursor];
1072 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001073 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1074 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1075 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001076 for (i = 0; i < ev->surface->height; i++)
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001077 memcpy(buf + i * c->cursor_width, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001078 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001079 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001080
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001081 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001082 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001083
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001084 handle = gbm_bo_get_handle(bo).s32;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001085 if (drmModeSetCursor(c->drm.fd, output->crtc_id, handle,
1086 c->cursor_width, c->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001087 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001088 c->cursors_are_broken = 1;
1089 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001090 }
1091
Jason Ekstranda7af7042013-10-12 22:38:11 -05001092 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1093 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001094 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001095 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001096 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001097 c->cursors_are_broken = 1;
1098 }
1099
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001100 output->cursor_plane.x = x;
1101 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001102 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001103}
1104
Jesse Barnes58ef3792012-02-23 09:45:49 -05001105static void
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001106drm_assign_planes(struct weston_output *output_base)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001107{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001108 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001109 (struct drm_compositor *)output_base->compositor;
1110 struct drm_output *output = (struct drm_output *)output_base;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001111 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001112 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001113 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001114
1115 /*
1116 * Find a surface for each sprite in the output using some heuristics:
1117 * 1) size
1118 * 2) frequency of update
1119 * 3) opacity (though some hw might support alpha blending)
1120 * 4) clipping (this can be fixed with color keys)
1121 *
1122 * The idea is to save on blitting since this should save power.
1123 * If we can get a large video surface on the sprite for example,
1124 * the main display surface may not need to update at all, and
1125 * the client buffer can be used directly for the sprite surface
1126 * as we do for flipping full screen surfaces.
1127 */
1128 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001129 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001130
Jason Ekstranda7af7042013-10-12 22:38:11 -05001131 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001132 struct weston_surface *es = ev->surface;
1133
1134 /* Test whether this buffer can ever go into a plane:
1135 * non-shm, or small enough to be a cursor.
1136 *
1137 * Also, keep a reference when using the pixman renderer.
1138 * That makes it possible to do a seamless switch to the GL
1139 * renderer and since the pixman renderer keeps a reference
1140 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001141 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001142 if (c->use_pixman ||
1143 (es->buffer_ref.buffer &&
1144 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001145 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001146 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001147 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001148 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001149
Jesse Barnes58ef3792012-02-23 09:45:49 -05001150 pixman_region32_init(&surface_overlap);
1151 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001152 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001153
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001154 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001155 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001156 next_plane = primary;
1157 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001158 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001159 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001160 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001161 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001162 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001163 if (next_plane == NULL)
1164 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001165
Jason Ekstranda7af7042013-10-12 22:38:11 -05001166 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001167
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001168 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001169 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001170 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001171
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001172 if (next_plane == primary ||
1173 next_plane == &output->cursor_plane) {
1174 /* cursor plane involves a copy */
1175 ev->psf_flags = 0;
1176 } else {
1177 /* All other planes are a direct scanout of a
1178 * single client buffer.
1179 */
1180 ev->psf_flags = PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
1181 }
1182
Jesse Barnes58ef3792012-02-23 09:45:49 -05001183 pixman_region32_fini(&surface_overlap);
1184 }
1185 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001186}
1187
Matt Roper361d2ad2011-08-29 13:52:23 -07001188static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001189drm_output_fini_pixman(struct drm_output *output);
1190
1191static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001192drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001193{
1194 struct drm_output *output = (struct drm_output *) output_base;
1195 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001196 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001197 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001198
Xiong Zhangabd5d472013-10-11 14:43:07 +08001199 if (output->page_flip_pending) {
1200 output->destroy_pending = 1;
1201 weston_log("destroy output while page flip pending\n");
1202 return;
1203 }
1204
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001205 if (output->backlight)
1206 backlight_destroy(output->backlight);
1207
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001208 drmModeFreeProperty(output->dpms_prop);
1209
Matt Roper361d2ad2011-08-29 13:52:23 -07001210 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001211 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001212
1213 /* Restore original CRTC state */
1214 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001215 origcrtc->x, origcrtc->y,
1216 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001217 drmModeFreeCrtc(origcrtc);
1218
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001219 c->crtc_allocator &= ~(1 << output->crtc_id);
1220 c->connector_allocator &= ~(1 << output->connector_id);
1221
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001222 if (c->use_pixman) {
1223 drm_output_fini_pixman(output);
1224 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001225 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001226 gbm_surface_destroy(output->surface);
1227 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001228
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001229 weston_plane_release(&output->fb_plane);
1230 weston_plane_release(&output->cursor_plane);
1231
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001232 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001233
Matt Roper361d2ad2011-08-29 13:52:23 -07001234 free(output);
1235}
1236
Alex Wub7b8bda2012-04-17 17:20:48 +08001237static struct drm_mode *
1238choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1239{
1240 struct drm_mode *tmp_mode = NULL, *mode;
1241
Hardeningff39efa2013-09-18 23:56:35 +02001242 if (output->base.current_mode->width == target_mode->width &&
1243 output->base.current_mode->height == target_mode->height &&
1244 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001245 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001246 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001247
1248 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1249 if (mode->mode_info.hdisplay == target_mode->width &&
1250 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02001251 if (mode->base.refresh == target_mode->refresh ||
1252 target_mode->refresh == 0) {
Alex Wub7b8bda2012-04-17 17:20:48 +08001253 return mode;
Daniel Stonef556ebe2015-05-21 08:28:58 +01001254 } else if (!tmp_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001255 tmp_mode = mode;
1256 }
1257 }
1258
1259 return tmp_mode;
1260}
1261
1262static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001263drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001264static int
1265drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001266
1267static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001268drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1269{
1270 struct drm_output *output;
1271 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001272 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001273
1274 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001275 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001276 return -1;
1277 }
1278
1279 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001280 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001281 return -1;
1282 }
1283
1284 ec = (struct drm_compositor *)output_base->compositor;
1285 output = (struct drm_output *)output_base;
1286 drm_mode = choose_mode (output, mode);
1287
1288 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001289 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001290 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001291 }
1292
Hardeningff39efa2013-09-18 23:56:35 +02001293 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001294 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001295
Hardeningff39efa2013-09-18 23:56:35 +02001296 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001297
Hardeningff39efa2013-09-18 23:56:35 +02001298 output->base.current_mode = &drm_mode->base;
1299 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001300 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1301
Alex Wub7b8bda2012-04-17 17:20:48 +08001302 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001303 drm_output_release_fb(output, output->current);
1304 drm_output_release_fb(output, output->next);
1305 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001306
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001307 if (ec->use_pixman) {
1308 drm_output_fini_pixman(output);
1309 if (drm_output_init_pixman(output, ec) < 0) {
1310 weston_log("failed to init output pixman state with "
1311 "new mode\n");
1312 return -1;
1313 }
1314 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001315 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001316 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001317
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001318 if (drm_output_init_egl(output, ec) < 0) {
1319 weston_log("failed to init output egl state with "
1320 "new mode");
1321 return -1;
1322 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001323 }
1324
Alex Wub7b8bda2012-04-17 17:20:48 +08001325 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001326}
1327
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001328static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001329on_drm_input(int fd, uint32_t mask, void *data)
1330{
1331 drmEventContext evctx;
1332
1333 memset(&evctx, 0, sizeof evctx);
1334 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1335 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001336 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001337 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001338
1339 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001340}
1341
1342static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001343init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001344{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001345 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001346 uint64_t cap;
1347 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001348 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001349
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001350 sysnum = udev_device_get_sysnum(device);
1351 if (sysnum)
1352 ec->drm.id = atoi(sysnum);
1353 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001354 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001355 return -1;
1356 }
1357
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001358 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001359 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001360 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001361 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001362 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001363 udev_device_get_devnode(device));
1364 return -1;
1365 }
1366
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001367 weston_log("using %s\n", filename);
1368
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001369 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001370 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001371
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001372 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1373 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001374 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001375 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001376 clk_id = CLOCK_REALTIME;
1377
1378 if (weston_compositor_set_presentation_clock(&ec->base, clk_id) < 0) {
1379 weston_log("Error: failed to set presentation clock %d.\n",
1380 clk_id);
1381 return -1;
1382 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001383
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001384 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1385 if (ret == 0)
1386 ec->cursor_width = cap;
1387 else
1388 ec->cursor_width = 64;
1389
1390 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1391 if (ret == 0)
1392 ec->cursor_height = cap;
1393 else
1394 ec->cursor_height = 64;
1395
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001396 return 0;
1397}
1398
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001399static struct gbm_device *
1400create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001401{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001402 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001403
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001404 gl_renderer = weston_load_module("gl-renderer.so",
1405 "gl_renderer_interface");
1406 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001407 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001408
1409 /* GBM will load a dri driver, but even though they need symbols from
1410 * libglapi, in some version of Mesa they are not linked to it. Since
1411 * only the gl-renderer module links to it, the call above won't make
1412 * these symbols globally available, and loading the DRI driver fails.
1413 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1414 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1415
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001416 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001417
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001418 return gbm;
1419}
1420
Bryce Harringtonc056a982015-05-19 15:25:18 -07001421/* When initializing EGL, if the preferred buffer format isn't available
Derek Foremanc4cfe852015-05-15 12:12:40 -05001422 * we may be able to susbstitute an ARGB format for an XRGB one.
1423 *
1424 * This returns 0 if substitution isn't possible, but 0 might be a
1425 * legitimate format for other EGL platforms, so the caller is
1426 * responsible for checking for 0 before calling gl_renderer->create().
1427 *
1428 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
1429 * but it's entirely possible we'll see this again on other implementations.
1430 */
1431static int
1432fallback_format_for(uint32_t format)
1433{
1434 switch (format) {
1435 case GBM_FORMAT_XRGB8888:
1436 return GBM_FORMAT_ARGB8888;
1437 case GBM_FORMAT_XRGB2101010:
1438 return GBM_FORMAT_ARGB2101010;
1439 default:
1440 return 0;
1441 }
1442}
1443
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001444static int
1445drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1446{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001447 EGLint format[2] = {
1448 ec->format,
1449 fallback_format_for(ec->format),
1450 };
1451 int n_formats = 1;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001452
Derek Foremanc4cfe852015-05-15 12:12:40 -05001453 if (format[1])
1454 n_formats = 2;
1455 if (gl_renderer->create(&ec->base,
1456 EGL_PLATFORM_GBM_KHR,
1457 (void *)ec->gbm,
1458 gl_renderer->opaque_attribs,
1459 format,
1460 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001461 return -1;
1462 }
1463
1464 return 0;
1465}
1466
1467static int
1468init_egl(struct drm_compositor *ec)
1469{
1470 ec->gbm = create_gbm_device(ec->drm.fd);
1471
1472 if (!ec->gbm)
1473 return -1;
1474
1475 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001476 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001477 return -1;
1478 }
1479
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001480 return 0;
1481}
1482
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001483static int
1484init_pixman(struct drm_compositor *ec)
1485{
1486 return pixman_renderer_init(&ec->base);
1487}
1488
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001489static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001490drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001491{
1492 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001493 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001494
1495 mode = malloc(sizeof *mode);
1496 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001497 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001498
1499 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001500 mode->base.width = info->hdisplay;
1501 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001502
1503 /* Calculate higher precision (mHz) refresh rate */
1504 refresh = (info->clock * 1000000LL / info->htotal +
1505 info->vtotal / 2) / info->vtotal;
1506
1507 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1508 refresh *= 2;
1509 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1510 refresh /= 2;
1511 if (info->vscan > 1)
1512 refresh /= info->vscan;
1513
1514 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001515 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001516
1517 if (info->type & DRM_MODE_TYPE_PREFERRED)
1518 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1519
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001520 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1521
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001522 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001523}
1524
1525static int
1526drm_subpixel_to_wayland(int drm_value)
1527{
1528 switch (drm_value) {
1529 default:
1530 case DRM_MODE_SUBPIXEL_UNKNOWN:
1531 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1532 case DRM_MODE_SUBPIXEL_NONE:
1533 return WL_OUTPUT_SUBPIXEL_NONE;
1534 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1535 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1536 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1537 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1538 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1539 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1540 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1541 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1542 }
1543}
1544
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001545/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001546static uint32_t
1547drm_get_backlight(struct drm_output *output)
1548{
1549 long brightness, max_brightness, norm;
1550
1551 brightness = backlight_get_brightness(output->backlight);
1552 max_brightness = backlight_get_max_brightness(output->backlight);
1553
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001554 /* convert it on a scale of 0 to 255 */
1555 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001556
1557 return (uint32_t) norm;
1558}
1559
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001560/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001561static void
1562drm_set_backlight(struct weston_output *output_base, uint32_t value)
1563{
1564 struct drm_output *output = (struct drm_output *) output_base;
1565 long max_brightness, new_brightness;
1566
1567 if (!output->backlight)
1568 return;
1569
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001570 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001571 return;
1572
1573 max_brightness = backlight_get_max_brightness(output->backlight);
1574
1575 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001576 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001577
1578 backlight_set_brightness(output->backlight, new_brightness);
1579}
1580
1581static drmModePropertyPtr
1582drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1583{
1584 drmModePropertyPtr props;
1585 int i;
1586
1587 for (i = 0; i < connector->count_props; i++) {
1588 props = drmModeGetProperty(fd, connector->props[i]);
1589 if (!props)
1590 continue;
1591
1592 if (!strcmp(props->name, name))
1593 return props;
1594
1595 drmModeFreeProperty(props);
1596 }
1597
1598 return NULL;
1599}
1600
1601static void
1602drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1603{
1604 struct drm_output *output = (struct drm_output *) output_base;
1605 struct weston_compositor *ec = output_base->compositor;
1606 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001607
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001608 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001609 return;
1610
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001611 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1612 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001613}
1614
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001615static const char *connector_type_names[] = {
1616 "None",
1617 "VGA",
1618 "DVI",
1619 "DVI",
1620 "DVI",
1621 "Composite",
1622 "TV",
1623 "LVDS",
1624 "CTV",
1625 "DIN",
1626 "DP",
1627 "HDMI",
1628 "HDMI",
1629 "TV",
1630 "eDP",
1631};
1632
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001633static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001634find_crtc_for_connector(struct drm_compositor *ec,
1635 drmModeRes *resources, drmModeConnector *connector)
1636{
1637 drmModeEncoder *encoder;
1638 uint32_t possible_crtcs;
1639 int i, j;
1640
1641 for (j = 0; j < connector->count_encoders; j++) {
1642 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1643 if (encoder == NULL) {
1644 weston_log("Failed to get encoder.\n");
1645 return -1;
1646 }
1647 possible_crtcs = encoder->possible_crtcs;
1648 drmModeFreeEncoder(encoder);
1649
1650 for (i = 0; i < resources->count_crtcs; i++) {
1651 if (possible_crtcs & (1 << i) &&
1652 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1653 return i;
1654 }
1655 }
1656
1657 return -1;
1658}
1659
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001660/* Init output state that depends on gl or gbm */
1661static int
1662drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1663{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001664 EGLint format[2] = {
1665 output->format,
1666 fallback_format_for(output->format),
1667 };
1668 int i, flags, n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001669
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001670 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001671 output->base.current_mode->width,
1672 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001673 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001674 GBM_BO_USE_SCANOUT |
1675 GBM_BO_USE_RENDERING);
1676 if (!output->surface) {
1677 weston_log("failed to create gbm surface\n");
1678 return -1;
1679 }
1680
Derek Foremanc4cfe852015-05-15 12:12:40 -05001681 if (format[1])
1682 n_formats = 2;
Jonny Lamb671148f2015-03-20 15:26:52 +01001683 if (gl_renderer->output_create(&output->base,
Jonny Lamb445fb692015-03-24 13:12:01 +01001684 (EGLNativeDisplayType)output->surface,
1685 output->surface,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001686 gl_renderer->opaque_attribs,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001687 format,
1688 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001689 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001690 gbm_surface_destroy(output->surface);
1691 return -1;
1692 }
1693
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001694 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001695
1696 for (i = 0; i < 2; i++) {
1697 if (output->cursor_bo[i])
1698 continue;
1699
1700 output->cursor_bo[i] =
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001701 gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
1702 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001703 }
1704
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001705 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1706 weston_log("cursor buffers unavailable, using gl cursors\n");
1707 ec->cursors_are_broken = 1;
1708 }
1709
1710 return 0;
1711}
1712
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001713static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001714drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1715{
Hardeningff39efa2013-09-18 23:56:35 +02001716 int w = output->base.current_mode->width;
1717 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001718 unsigned int i;
1719
1720 /* FIXME error checking */
1721
1722 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001723 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001724 if (!output->dumb[i])
1725 goto err;
1726
1727 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001728 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001729 output->dumb[i]->map,
1730 output->dumb[i]->stride);
1731 if (!output->image[i])
1732 goto err;
1733 }
1734
1735 if (pixman_renderer_output_create(&output->base) < 0)
1736 goto err;
1737
1738 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001739 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001740
1741 return 0;
1742
1743err:
1744 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1745 if (output->dumb[i])
1746 drm_fb_destroy_dumb(output->dumb[i]);
1747 if (output->image[i])
1748 pixman_image_unref(output->image[i]);
1749
1750 output->dumb[i] = NULL;
1751 output->image[i] = NULL;
1752 }
1753
1754 return -1;
1755}
1756
1757static void
1758drm_output_fini_pixman(struct drm_output *output)
1759{
1760 unsigned int i;
1761
1762 pixman_renderer_output_destroy(&output->base);
1763 pixman_region32_fini(&output->previous_damage);
1764
1765 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1766 drm_fb_destroy_dumb(output->dumb[i]);
1767 pixman_image_unref(output->image[i]);
1768 output->dumb[i] = NULL;
1769 output->image[i] = NULL;
1770 }
1771}
1772
Richard Hughes2b2092a2013-04-24 14:58:02 +01001773static void
1774edid_parse_string(const uint8_t *data, char text[])
1775{
1776 int i;
1777 int replaced = 0;
1778
1779 /* this is always 12 bytes, but we can't guarantee it's null
1780 * terminated or not junk. */
1781 strncpy(text, (const char *) data, 12);
1782
1783 /* remove insane chars */
1784 for (i = 0; text[i] != '\0'; i++) {
1785 if (text[i] == '\n' ||
1786 text[i] == '\r') {
1787 text[i] = '\0';
1788 break;
1789 }
1790 }
1791
1792 /* ensure string is printable */
1793 for (i = 0; text[i] != '\0'; i++) {
1794 if (!isprint(text[i])) {
1795 text[i] = '-';
1796 replaced++;
1797 }
1798 }
1799
1800 /* if the string is random junk, ignore the string */
1801 if (replaced > 4)
1802 text[0] = '\0';
1803}
1804
1805#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1806#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1807#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1808#define EDID_OFFSET_DATA_BLOCKS 0x36
1809#define EDID_OFFSET_LAST_BLOCK 0x6c
1810#define EDID_OFFSET_PNPID 0x08
1811#define EDID_OFFSET_SERIAL 0x0c
1812
1813static int
1814edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1815{
1816 int i;
1817 uint32_t serial_number;
1818
1819 /* check header */
1820 if (length < 128)
1821 return -1;
1822 if (data[0] != 0x00 || data[1] != 0xff)
1823 return -1;
1824
1825 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1826 * /--08--\/--09--\
1827 * 7654321076543210
1828 * |\---/\---/\---/
1829 * R C1 C2 C3 */
1830 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1831 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1832 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1833 edid->pnp_id[3] = '\0';
1834
1835 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1836 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1837 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1838 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1839 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1840 if (serial_number > 0)
1841 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1842
1843 /* parse EDID data */
1844 for (i = EDID_OFFSET_DATA_BLOCKS;
1845 i <= EDID_OFFSET_LAST_BLOCK;
1846 i += 18) {
1847 /* ignore pixel clock data */
1848 if (data[i] != 0)
1849 continue;
1850 if (data[i+2] != 0)
1851 continue;
1852
1853 /* any useful blocks? */
1854 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1855 edid_parse_string(&data[i+5],
1856 edid->monitor_name);
1857 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1858 edid_parse_string(&data[i+5],
1859 edid->serial_number);
1860 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1861 edid_parse_string(&data[i+5],
1862 edid->eisa_id);
1863 }
1864 }
1865 return 0;
1866}
1867
1868static void
1869find_and_parse_output_edid(struct drm_compositor *ec,
1870 struct drm_output *output,
1871 drmModeConnector *connector)
1872{
1873 drmModePropertyBlobPtr edid_blob = NULL;
1874 drmModePropertyPtr property;
1875 int i;
1876 int rc;
1877
1878 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1879 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1880 if (!property)
1881 continue;
1882 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1883 !strcmp(property->name, "EDID")) {
1884 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1885 connector->prop_values[i]);
1886 }
1887 drmModeFreeProperty(property);
1888 }
1889 if (!edid_blob)
1890 return;
1891
1892 rc = edid_parse(&output->edid,
1893 edid_blob->data,
1894 edid_blob->length);
1895 if (!rc) {
1896 weston_log("EDID data '%s', '%s', '%s'\n",
1897 output->edid.pnp_id,
1898 output->edid.monitor_name,
1899 output->edid.serial_number);
1900 if (output->edid.pnp_id[0] != '\0')
1901 output->base.make = output->edid.pnp_id;
1902 if (output->edid.monitor_name[0] != '\0')
1903 output->base.model = output->edid.monitor_name;
1904 if (output->edid.serial_number[0] != '\0')
1905 output->base.serial_number = output->edid.serial_number;
1906 }
1907 drmModeFreePropertyBlob(edid_blob);
1908}
1909
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001910
1911
1912static int
1913parse_modeline(const char *s, drmModeModeInfo *mode)
1914{
1915 char hsync[16];
1916 char vsync[16];
1917 float fclock;
1918
1919 mode->type = DRM_MODE_TYPE_USERDEF;
1920 mode->hskew = 0;
1921 mode->vscan = 0;
1922 mode->vrefresh = 0;
1923 mode->flags = 0;
1924
Rob Bradford307e09e2013-07-26 16:29:40 +01001925 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001926 &fclock,
1927 &mode->hdisplay,
1928 &mode->hsync_start,
1929 &mode->hsync_end,
1930 &mode->htotal,
1931 &mode->vdisplay,
1932 &mode->vsync_start,
1933 &mode->vsync_end,
1934 &mode->vtotal, hsync, vsync) != 11)
1935 return -1;
1936
1937 mode->clock = fclock * 1000;
1938 if (strcmp(hsync, "+hsync") == 0)
1939 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1940 else if (strcmp(hsync, "-hsync") == 0)
1941 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1942 else
1943 return -1;
1944
1945 if (strcmp(vsync, "+vsync") == 0)
1946 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1947 else if (strcmp(vsync, "-vsync") == 0)
1948 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1949 else
1950 return -1;
1951
1952 return 0;
1953}
1954
Rob Bradford66bd9f52013-06-25 18:56:42 +01001955static void
1956setup_output_seat_constraint(struct drm_compositor *ec,
1957 struct weston_output *output,
1958 const char *s)
1959{
1960 if (strcmp(s, "") != 0) {
1961 struct udev_seat *seat;
1962
Jonas Ådahl58e15862014-03-12 22:08:40 +01001963 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001964 if (seat)
1965 seat->base.output = output;
1966
1967 if (seat && seat->base.pointer)
1968 weston_pointer_clamp(seat->base.pointer,
1969 &seat->base.pointer->x,
1970 &seat->base.pointer->y);
1971 }
1972}
1973
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001974static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001975get_gbm_format_from_section(struct weston_config_section *section,
1976 uint32_t default_value,
1977 uint32_t *format)
1978{
1979 char *s;
1980 int ret = 0;
1981
1982 weston_config_section_get_string(section,
1983 "gbm-format", &s, NULL);
1984
1985 if (s == NULL)
1986 *format = default_value;
1987 else if (strcmp(s, "xrgb8888") == 0)
1988 *format = GBM_FORMAT_XRGB8888;
1989 else if (strcmp(s, "rgb565") == 0)
1990 *format = GBM_FORMAT_RGB565;
1991 else if (strcmp(s, "xrgb2101010") == 0)
1992 *format = GBM_FORMAT_XRGB2101010;
1993 else {
1994 weston_log("fatal: unrecognized pixel format: %s\n", s);
1995 ret = -1;
1996 }
1997
1998 free(s);
1999
2000 return ret;
2001}
2002
2003static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002004create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002005 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002006 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002007 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002008{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002009 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002010 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002011 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002012 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002013 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002014 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002015 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002016 int i, width, height, scale;
2017 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002018 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002019 enum output_config config;
2020 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002021
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002022 i = find_crtc_for_connector(ec, resources, connector);
2023 if (i < 0) {
2024 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002025 return -1;
2026 }
2027
Peter Huttererf3d62272013-08-08 11:57:05 +10002028 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002029 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002030 return -1;
2031
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002032 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
2033 output->base.make = "unknown";
2034 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01002035 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002036 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002037
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002038 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
2039 type_name = connector_type_names[connector->connector_type];
2040 else
2041 type_name = "UNKNOWN";
2042 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01002043 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002044
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002045 section = weston_config_get_section(ec->base.config, "output", "name",
2046 output->base.name);
2047 weston_config_section_get_string(section, "mode", &s, "preferred");
2048 if (strcmp(s, "off") == 0)
2049 config = OUTPUT_CONFIG_OFF;
2050 else if (strcmp(s, "preferred") == 0)
2051 config = OUTPUT_CONFIG_PREFERRED;
2052 else if (strcmp(s, "current") == 0)
2053 config = OUTPUT_CONFIG_CURRENT;
2054 else if (sscanf(s, "%dx%d", &width, &height) == 2)
2055 config = OUTPUT_CONFIG_MODE;
2056 else if (parse_modeline(s, &modeline) == 0)
2057 config = OUTPUT_CONFIG_MODELINE;
2058 else {
2059 weston_log("Invalid mode \"%s\" for output %s\n",
2060 s, output->base.name);
2061 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002062 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002063 free(s);
2064
2065 weston_config_section_get_int(section, "scale", &scale, 1);
2066 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05002067 if (weston_parse_transform(s, &transform) < 0)
2068 weston_log("Invalid transform \"%s\" for output %s\n",
2069 s, output->base.name);
2070
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002071 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002072
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002073 if (get_gbm_format_from_section(section,
2074 ec->format,
2075 &output->format) == -1)
2076 output->format = ec->format;
2077
Rob Bradford66bd9f52013-06-25 18:56:42 +01002078 weston_config_section_get_string(section, "seat", &s, "");
2079 setup_output_seat_constraint(ec, &output->base, s);
2080 free(s);
2081
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002082 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002083 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002084 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002085 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002086 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002087
Matt Roper361d2ad2011-08-29 13:52:23 -07002088 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03002089 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002090
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002091 /* Get the current mode on the crtc that's currently driving
2092 * this connector. */
2093 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002094 memset(&crtc_mode, 0, sizeof crtc_mode);
2095 if (encoder != NULL) {
2096 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
2097 drmModeFreeEncoder(encoder);
2098 if (crtc == NULL)
2099 goto err_free;
2100 if (crtc->mode_valid)
2101 crtc_mode = crtc->mode;
2102 drmModeFreeCrtc(crtc);
2103 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002104
David Herrmann0f0d54e2011-12-08 17:05:45 +01002105 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002106 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002107 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002108 goto err_free;
2109 }
2110
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002111 if (config == OUTPUT_CONFIG_OFF) {
2112 weston_log("Disabling output %s\n", output->base.name);
2113 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
2114 0, 0, 0, 0, 0, NULL);
2115 goto err_free;
2116 }
2117
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002118 preferred = NULL;
2119 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002120 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002121 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002122
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002123 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002124 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002125 width == drm_mode->base.width &&
2126 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002127 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002128 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002129 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002130 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002131 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002132 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002133 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002134
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002135 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002136 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002137 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002138 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002139 }
2140
Wang Quanxianacb805a2012-07-30 18:09:46 -04002141 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002142 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002143 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002144 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002145 }
2146
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002147 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002148 configured = current;
2149
Wang Quanxianacb805a2012-07-30 18:09:46 -04002150 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002151 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002152 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002153 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002154 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002155 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002156 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002157 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002158 else if (best)
2159 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002160
Hardeningff39efa2013-09-18 23:56:35 +02002161 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002162 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002163 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002164 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002165
Hardeningff39efa2013-09-18 23:56:35 +02002166 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002167
John Kåre Alsaker94659272012-11-13 19:10:18 +01002168 weston_output_init(&output->base, &ec->base, x, y,
2169 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002170 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002171
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002172 if (ec->use_pixman) {
2173 if (drm_output_init_pixman(output, ec) < 0) {
2174 weston_log("Failed to init output pixman state\n");
2175 goto err_output;
2176 }
2177 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002178 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002179 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002180 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002181
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002182 output->backlight = backlight_init(drm_device,
2183 connector->connector_type);
2184 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002185 weston_log("Initialized backlight, device %s\n",
2186 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002187 output->base.set_backlight = drm_set_backlight;
2188 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002189 } else {
2190 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002191 }
2192
Giulio Camuffob1147152015-05-06 21:41:57 +03002193 weston_compositor_add_output(&ec->base, &output->base);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002194
Richard Hughes2b2092a2013-04-24 14:58:02 +01002195 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002196 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2197 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002198
Jonas Ådahle5a12252013-04-05 23:07:11 +02002199 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002200 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002201 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002202 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002203 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002204 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002205
Richard Hughese7299962013-05-01 21:52:12 +01002206 output->base.gamma_size = output->original_crtc->gamma_size;
2207 output->base.set_gamma = drm_output_set_gamma;
2208
Xiong Zhang97116532013-10-23 13:58:31 +08002209 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2210 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002211
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002212 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2213 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2214 &ec->base.primary_plane);
2215
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002216 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002217 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002218 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002219 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002220 m->width, m->height, m->refresh / 1000.0,
2221 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2222 ", preferred" : "",
2223 m->flags & WL_OUTPUT_MODE_CURRENT ?
2224 ", current" : "",
2225 connector->count_modes == 0 ?
2226 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002227
Mario Kleiner80817042015-06-21 21:25:11 +02002228 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
2229 output->base.native_mode = output->base.current_mode;
2230 output->base.native_scale = output->base.current_scale;
2231
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002232 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002233
John Kåre Alsaker94659272012-11-13 19:10:18 +01002234err_output:
2235 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002236err_free:
2237 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2238 base.link) {
2239 wl_list_remove(&drm_mode->base.link);
2240 free(drm_mode);
2241 }
2242
2243 drmModeFreeCrtc(output->original_crtc);
2244 ec->crtc_allocator &= ~(1 << output->crtc_id);
2245 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002246 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002247
David Herrmann0f0d54e2011-12-08 17:05:45 +01002248 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002249}
2250
Jesse Barnes58ef3792012-02-23 09:45:49 -05002251static void
2252create_sprites(struct drm_compositor *ec)
2253{
2254 struct drm_sprite *sprite;
2255 drmModePlaneRes *plane_res;
2256 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002257 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002258
2259 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2260 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002261 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002262 strerror(errno));
2263 return;
2264 }
2265
2266 for (i = 0; i < plane_res->count_planes; i++) {
2267 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2268 if (!plane)
2269 continue;
2270
Peter Huttererf3d62272013-08-08 11:57:05 +10002271 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002272 plane->count_formats));
2273 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002274 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002275 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002276 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002277 continue;
2278 }
2279
Jesse Barnes58ef3792012-02-23 09:45:49 -05002280 sprite->possible_crtcs = plane->possible_crtcs;
2281 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002282 sprite->current = NULL;
2283 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002284 sprite->compositor = ec;
2285 sprite->count_formats = plane->count_formats;
2286 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002287 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002288 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002289 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002290 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2291 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002292
2293 wl_list_insert(&ec->sprite_list, &sprite->link);
2294 }
2295
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002296 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002297}
2298
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002299static void
2300destroy_sprites(struct drm_compositor *compositor)
2301{
2302 struct drm_sprite *sprite, *next;
2303 struct drm_output *output;
2304
2305 output = container_of(compositor->base.output_list.next,
2306 struct drm_output, base.link);
2307
2308 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2309 drmModeSetPlane(compositor->drm.fd,
2310 sprite->plane_id,
2311 output->crtc_id, 0, 0,
2312 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002313 drm_output_release_fb(output, sprite->current);
2314 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002315 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002316 free(sprite);
2317 }
2318}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002319
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002320static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002321create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002322 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002323{
2324 drmModeConnector *connector;
2325 drmModeRes *resources;
2326 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002327 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002328
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002329 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002330 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002331 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002332 return -1;
2333 }
2334
Jesse Barnes58ef3792012-02-23 09:45:49 -05002335 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002336 if (!ec->crtcs) {
2337 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002338 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002339 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002340
Rob Clark4339add2012-08-09 14:18:28 -05002341 ec->min_width = resources->min_width;
2342 ec->max_width = resources->max_width;
2343 ec->min_height = resources->min_height;
2344 ec->max_height = resources->max_height;
2345
Jesse Barnes58ef3792012-02-23 09:45:49 -05002346 ec->num_crtcs = resources->count_crtcs;
2347 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2348
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002349 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002350 connector = drmModeGetConnector(ec->drm.fd,
2351 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002352 if (connector == NULL)
2353 continue;
2354
2355 if (connector->connection == DRM_MODE_CONNECTED &&
2356 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002357 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002358 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002359 connector, x, y,
2360 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002361 drmModeFreeConnector(connector);
2362 continue;
2363 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002364
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002365 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002366 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002367 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002368 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002369
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002370 drmModeFreeConnector(connector);
2371 }
2372
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002373 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002374 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002375 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002376 return -1;
2377 }
2378
2379 drmModeFreeResources(resources);
2380
2381 return 0;
2382}
2383
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002384static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002385update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002386{
2387 drmModeConnector *connector;
2388 drmModeRes *resources;
2389 struct drm_output *output, *next;
2390 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002391 uint32_t connected = 0, disconnects = 0;
2392 int i;
2393
2394 resources = drmModeGetResources(ec->drm.fd);
2395 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002396 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002397 return;
2398 }
2399
2400 /* collect new connects */
2401 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002402 int connector_id = resources->connectors[i];
2403
2404 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002405 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002406 continue;
2407
David Herrmann7551cff2011-12-08 17:05:43 +01002408 if (connector->connection != DRM_MODE_CONNECTED) {
2409 drmModeFreeConnector(connector);
2410 continue;
2411 }
2412
Benjamin Franzke117483d2011-08-30 11:38:26 +02002413 connected |= (1 << connector_id);
2414
2415 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002416 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002417 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002418 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002419
2420 /* XXX: not yet needed, we die with 0 outputs */
2421 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002422 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002423 else
2424 x = 0;
2425 y = 0;
2426 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002427 connector, x, y,
2428 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002429 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002430
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002431 }
2432 drmModeFreeConnector(connector);
2433 }
2434 drmModeFreeResources(resources);
2435
2436 disconnects = ec->connector_allocator & ~connected;
2437 if (disconnects) {
2438 wl_list_for_each_safe(output, next, &ec->base.output_list,
2439 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002440 if (disconnects & (1 << output->connector_id)) {
2441 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002442 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002443 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002444 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002445 }
2446 }
2447 }
2448
Daniel Stonef556ebe2015-05-21 08:28:58 +01002449 /* FIXME: handle zero outputs, without terminating */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002450 if (ec->connector_allocator == 0)
2451 wl_display_terminate(ec->base.wl_display);
2452}
2453
2454static int
David Herrmannd7488c22012-03-11 20:05:21 +01002455udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002456{
David Herrmannd7488c22012-03-11 20:05:21 +01002457 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002458 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002459
2460 sysnum = udev_device_get_sysnum(device);
2461 if (!sysnum || atoi(sysnum) != ec->drm.id)
2462 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002463
David Herrmann6ac52db2012-03-11 20:05:22 +01002464 val = udev_device_get_property_value(device, "HOTPLUG");
2465 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002466 return 0;
2467
David Herrmann6ac52db2012-03-11 20:05:22 +01002468 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002469}
2470
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002471static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002472udev_drm_event(int fd, uint32_t mask, void *data)
2473{
2474 struct drm_compositor *ec = data;
2475 struct udev_device *event;
2476
2477 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002478
David Herrmannd7488c22012-03-11 20:05:21 +01002479 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002480 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002481
2482 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002483
2484 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002485}
2486
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002487static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002488drm_restore(struct weston_compositor *ec)
2489{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002490 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002491}
2492
2493static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002494drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002495{
2496 struct drm_compositor *d = (struct drm_compositor *) ec;
2497
Rob Bradfordd355b802013-05-31 18:09:55 +01002498 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002499
2500 wl_event_source_remove(d->udev_drm_source);
2501 wl_event_source_remove(d->drm_source);
2502
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002503 destroy_sprites(d);
2504
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002505 weston_compositor_shutdown(ec);
2506
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002507 if (d->gbm)
2508 gbm_device_destroy(d->gbm);
2509
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002510 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002511
Rob Bradford45c15b82013-07-26 16:29:35 +01002512 close(d->drm.fd);
2513
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002514 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002515}
2516
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002517static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002518drm_compositor_set_modes(struct drm_compositor *compositor)
2519{
2520 struct drm_output *output;
2521 struct drm_mode *drm_mode;
2522 int ret;
2523
2524 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002525 if (!output->current) {
2526 /* If something that would cause the output to
2527 * switch mode happened while in another vt, we
2528 * might not have a current drm_fb. In that case,
2529 * schedule a repaint and let drm_output_repaint
2530 * handle setting the mode. */
2531 weston_output_schedule_repaint(&output->base);
2532 continue;
2533 }
2534
Hardeningff39efa2013-09-18 23:56:35 +02002535 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002536 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002537 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002538 &output->connector_id, 1,
2539 &drm_mode->mode_info);
2540 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002541 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002542 "failed to set mode %dx%d for output at %d,%d: %m\n",
Daniel Stonef556ebe2015-05-21 08:28:58 +01002543 drm_mode->base.width, drm_mode->base.height,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002544 output->base.x, output->base.y);
2545 }
2546 }
2547}
2548
2549static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002550session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002551{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002552 struct weston_compositor *compositor = data;
2553 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002554 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002555 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002556
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002557 if (ec->base.session_active) {
2558 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002559 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002560 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002561 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002562 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002563 } else {
2564 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002565 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002566
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002567 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002568 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002569
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002570 /* If we have a repaint scheduled (either from a
2571 * pending pageflip or the idle handler), make sure we
2572 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002573 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002574 * further attemps at repainting. When we switch
2575 * back, we schedule a repaint, which will process
2576 * pending frame callbacks. */
2577
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002578 wl_list_for_each(output, &ec->base.output_list, base.link) {
2579 output->base.repaint_needed = 0;
2580 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002581 }
2582
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002583 output = container_of(ec->base.output_list.next,
2584 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002585
2586 wl_list_for_each(sprite, &ec->sprite_list, link)
2587 drmModeSetPlane(ec->drm.fd,
2588 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002589 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002590 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002591 };
2592}
2593
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002594static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002595switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002596{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002597 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002598
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002599 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002600}
2601
David Herrmann0af066f2012-10-29 19:21:16 +01002602/*
2603 * Find primary GPU
2604 * Some systems may have multiple DRM devices attached to a single seat. This
2605 * function loops over all devices and tries to find a PCI device with the
2606 * boot_vga sysfs attribute set to 1.
2607 * If no such device is found, the first DRM device reported by udev is used.
2608 */
2609static struct udev_device*
2610find_primary_gpu(struct drm_compositor *ec, const char *seat)
2611{
2612 struct udev_enumerate *e;
2613 struct udev_list_entry *entry;
2614 const char *path, *device_seat, *id;
2615 struct udev_device *device, *drm_device, *pci;
2616
2617 e = udev_enumerate_new(ec->udev);
2618 udev_enumerate_add_match_subsystem(e, "drm");
2619 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2620
2621 udev_enumerate_scan_devices(e);
2622 drm_device = NULL;
2623 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2624 path = udev_list_entry_get_name(entry);
2625 device = udev_device_new_from_syspath(ec->udev, path);
2626 if (!device)
2627 continue;
2628 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2629 if (!device_seat)
2630 device_seat = default_seat;
2631 if (strcmp(device_seat, seat)) {
2632 udev_device_unref(device);
2633 continue;
2634 }
2635
2636 pci = udev_device_get_parent_with_subsystem_devtype(device,
2637 "pci", NULL);
2638 if (pci) {
2639 id = udev_device_get_sysattr_value(pci, "boot_vga");
2640 if (id && !strcmp(id, "1")) {
2641 if (drm_device)
2642 udev_device_unref(drm_device);
2643 drm_device = device;
2644 break;
2645 }
2646 }
2647
2648 if (!drm_device)
2649 drm_device = device;
2650 else
2651 udev_device_unref(device);
2652 }
2653
2654 udev_enumerate_unref(e);
2655 return drm_device;
2656}
2657
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002658static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002659planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002660{
2661 struct drm_compositor *c = data;
2662
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002663 switch (key) {
2664 case KEY_C:
2665 c->cursors_are_broken ^= 1;
2666 break;
2667 case KEY_V:
2668 c->sprites_are_broken ^= 1;
2669 break;
2670 case KEY_O:
2671 c->sprites_hidden ^= 1;
2672 break;
2673 default:
2674 break;
2675 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002676}
2677
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002678#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002679static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002680recorder_destroy(struct drm_output *output)
2681{
2682 vaapi_recorder_destroy(output->recorder);
2683 output->recorder = NULL;
2684
2685 output->base.disable_planes--;
2686
2687 wl_list_remove(&output->recorder_frame_listener.link);
2688 weston_log("[libva recorder] done\n");
2689}
2690
2691static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002692recorder_frame_notify(struct wl_listener *listener, void *data)
2693{
2694 struct drm_output *output;
2695 struct drm_compositor *c;
2696 int fd, ret;
2697
2698 output = container_of(listener, struct drm_output,
2699 recorder_frame_listener);
2700 c = (struct drm_compositor *) output->base.compositor;
2701
2702 if (!output->recorder)
2703 return;
2704
2705 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2706 DRM_CLOEXEC, &fd);
2707 if (ret) {
2708 weston_log("[libva recorder] "
2709 "failed to create prime fd for front buffer\n");
2710 return;
2711 }
2712
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002713 ret = vaapi_recorder_frame(output->recorder, fd,
2714 output->current->stride);
2715 if (ret < 0) {
2716 weston_log("[libva recorder] aborted: %m\n");
2717 recorder_destroy(output);
2718 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002719}
2720
2721static void *
2722create_recorder(struct drm_compositor *c, int width, int height,
2723 const char *filename)
2724{
2725 int fd;
2726 drm_magic_t magic;
2727
2728 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2729 if (fd < 0)
2730 return NULL;
2731
2732 drmGetMagic(fd, &magic);
2733 drmAuthMagic(c->drm.fd, magic);
2734
2735 return vaapi_recorder_create(fd, width, height, filename);
2736}
2737
2738static void
2739recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2740 void *data)
2741{
2742 struct drm_compositor *c = data;
2743 struct drm_output *output;
2744 int width, height;
2745
2746 output = container_of(c->base.output_list.next,
2747 struct drm_output, base.link);
2748
2749 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002750 if (output->format != GBM_FORMAT_XRGB8888) {
2751 weston_log("failed to start vaapi recorder: "
2752 "output format not supported\n");
2753 return;
2754 }
2755
Hardeningff39efa2013-09-18 23:56:35 +02002756 width = output->base.current_mode->width;
2757 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002758
2759 output->recorder =
2760 create_recorder(c, width, height, "capture.h264");
2761 if (!output->recorder) {
2762 weston_log("failed to create vaapi recorder\n");
2763 return;
2764 }
2765
2766 output->base.disable_planes++;
2767
2768 output->recorder_frame_listener.notify = recorder_frame_notify;
2769 wl_signal_add(&output->base.frame_signal,
2770 &output->recorder_frame_listener);
2771
2772 weston_output_schedule_repaint(&output->base);
2773
2774 weston_log("[libva recorder] initialized\n");
2775 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002776 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002777 }
2778}
2779#else
2780static void
2781recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2782 void *data)
2783{
2784 weston_log("Compiled without libva support\n");
2785}
2786#endif
2787
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002788static void
2789switch_to_gl_renderer(struct drm_compositor *c)
2790{
2791 struct drm_output *output;
2792
2793 if (!c->use_pixman)
2794 return;
2795
2796 weston_log("Switching to GL renderer\n");
2797
2798 c->gbm = create_gbm_device(c->drm.fd);
2799 if (!c->gbm) {
2800 weston_log("Failed to create gbm device. "
2801 "Aborting renderer switch\n");
2802 return;
2803 }
2804
2805 wl_list_for_each(output, &c->base.output_list, base.link)
2806 pixman_renderer_output_destroy(&output->base);
2807
2808 c->base.renderer->destroy(&c->base);
2809
2810 if (drm_compositor_create_gl_renderer(c) < 0) {
2811 gbm_device_destroy(c->gbm);
2812 weston_log("Failed to create GL renderer. Quitting.\n");
2813 /* FIXME: we need a function to shutdown cleanly */
2814 assert(0);
2815 }
2816
2817 wl_list_for_each(output, &c->base.output_list, base.link)
2818 drm_output_init_egl(output, c);
2819
2820 c->use_pixman = 0;
2821}
2822
2823static void
2824renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2825 void *data)
2826{
2827 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2828
2829 switch_to_gl_renderer(c);
2830}
2831
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002832static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002833drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002834 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002835 int *argc, char *argv[],
2836 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002837{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002838 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002839 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002840 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002841 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002842 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002843 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002844
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002845 weston_log("initializing drm backend\n");
2846
Peter Huttererf3d62272013-08-08 11:57:05 +10002847 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002848 if (ec == NULL)
2849 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002850
Pekka Paalanen68583832015-05-19 09:53:16 +03002851 /*
2852 * KMS support for hardware planes cannot properly synchronize
2853 * without nuclear page flip. Without nuclear/atomic, hw plane
2854 * and cursor plane updates would either tear or cause extra
2855 * waits for vblanks which means dropping the compositor framerate
2856 * to a fraction.
2857 *
2858 * These can be enabled again when nuclear/atomic support lands.
2859 */
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002860 ec->sprites_are_broken = 1;
Pekka Paalanen68583832015-05-19 09:53:16 +03002861 ec->cursors_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002862
2863 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002864 if (get_gbm_format_from_section(section,
2865 GBM_FORMAT_XRGB8888,
2866 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002867 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002868
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002869 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002870
Daniel Stone725c2c32012-06-22 14:04:36 +01002871 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002872 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002873 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002874 goto err_base;
2875 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002876
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002877 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002878 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
David Herrmann2ecb84a2014-12-30 14:33:22 +01002879 param->seat_id, true);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002880 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002881 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002882 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002883 goto err_compositor;
2884 }
2885
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002886 ec->udev = udev_new();
2887 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002888 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002889 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002890 }
2891
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002892 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002893 ec->session_listener.notify = session_notify;
2894 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002895
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002896 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002897 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002898 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002899 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002900 }
David Herrmann0af066f2012-10-29 19:21:16 +01002901 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002902
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002903 if (init_drm(ec, drm_device) < 0) {
2904 weston_log("failed to initialize kms\n");
2905 goto err_udev_dev;
2906 }
2907
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002908 if (ec->use_pixman) {
2909 if (init_pixman(ec) < 0) {
2910 weston_log("failed to initialize pixman renderer\n");
2911 goto err_udev_dev;
2912 }
2913 } else {
2914 if (init_egl(ec) < 0) {
2915 weston_log("failed to initialize egl\n");
2916 goto err_udev_dev;
2917 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002918 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002919
2920 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002921 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002922
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002923 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002924
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002925 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002926 weston_compositor_add_key_binding(&ec->base, key,
2927 MODIFIER_CTRL | MODIFIER_ALT,
2928 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002929
Jesse Barnes58ef3792012-02-23 09:45:49 -05002930 wl_list_init(&ec->sprite_list);
2931 create_sprites(ec);
2932
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002933 if (udev_input_init(&ec->input,
2934 &ec->base, ec->udev, param->seat_id) < 0) {
2935 weston_log("failed to create input devices\n");
2936 goto err_sprite;
2937 }
2938
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002939 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002940 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002941 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002942 }
2943
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002944 /* A this point we have some idea of whether or not we have a working
2945 * cursor plane. */
2946 if (!ec->cursors_are_broken)
2947 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2948
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002949 path = NULL;
2950
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002951 loop = wl_display_get_event_loop(ec->base.wl_display);
2952 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002953 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002954 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002955
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002956 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2957 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002958 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002959 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002960 }
2961 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2962 "drm", NULL);
2963 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002964 wl_event_loop_add_fd(loop,
2965 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002966 WL_EVENT_READABLE, udev_drm_event, ec);
2967
2968 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002969 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002970 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002971 }
2972
Daniel Stonea96b93c2012-06-22 14:04:37 +01002973 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002974
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002975 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002976 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002977 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002978 planes_binding, ec);
2979 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2980 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002981 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2982 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002983 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2984 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002985
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002986 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002987
2988err_udev_monitor:
2989 wl_event_source_remove(ec->udev_drm_source);
2990 udev_monitor_unref(ec->udev_monitor);
2991err_drm_source:
2992 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002993err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002994 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002995err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002996 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002997 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002998 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002999err_udev_dev:
3000 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07003001err_launcher:
3002 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01003003err_udev:
3004 udev_unref(ec->udev);
3005err_compositor:
3006 weston_compositor_shutdown(&ec->base);
3007err_base:
3008 free(ec);
3009 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04003010}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003011
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05003012WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05003013backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04003014 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003015{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003016 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003017
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003018 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003019 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
3020 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
3021 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003022 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003023 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003024 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02003025
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003026 param.seat_id = default_seat;
3027
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003028 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003029
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003030 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003031}