blob: aa6d010bd694d445639880708abb39aade3e8f13 [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
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +0200600static unsigned int drm_waitvblank_pipe(struct drm_output *output)
601{
602 if (output->pipe > 1)
603 return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
604 DRM_VBLANK_HIGH_CRTC_MASK;
605 else if (output->pipe > 0)
606 return DRM_VBLANK_SECONDARY;
607 else
608 return 0;
609}
610
David Herrmann1edf44c2013-10-22 17:11:26 +0200611static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500612drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400613 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100614{
615 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500616 struct drm_compositor *compositor =
617 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500618 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400619 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500620 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100621
Xiong Zhangabd5d472013-10-11 14:43:07 +0800622 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200623 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800624
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300625 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400626 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300627 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200628 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100629
Hardeningff39efa2013-09-18 23:56:35 +0200630 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200631 if (!output->current ||
632 output->current->stride != output->next->stride) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400633 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300634 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400635 &output->connector_id, 1,
636 &mode->mode_info);
637 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200638 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200639 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400640 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300641 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200642 }
643
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500644 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300645 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500646 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200647 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200648 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500649 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100650
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300651 output->page_flip_pending = 1;
652
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400653 drm_output_set_cursor(output);
654
Jesse Barnes58ef3792012-02-23 09:45:49 -0500655 /*
656 * Now, update all the sprite surfaces
657 */
658 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200659 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500660 drmVBlank vbl = {
661 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
662 .request.sequence = 1,
663 };
664
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200665 if ((!s->current && !s->next) ||
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200666 !drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500667 continue;
668
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200669 if (s->next && !compositor->sprites_hidden)
670 fb_id = s->next->fb_id;
671
Jesse Barnes58ef3792012-02-23 09:45:49 -0500672 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200673 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500674 s->dest_x, s->dest_y,
675 s->dest_w, s->dest_h,
676 s->src_x, s->src_y,
677 s->src_w, s->src_h);
678 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200679 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500680 ret, strerror(errno));
681
Mario Kleiner2ab4f4e2015-06-21 21:25:13 +0200682 vbl.request.type |= drm_waitvblank_pipe(output);
Rob Clark5ca1a472012-08-08 20:27:37 -0500683
Jesse Barnes58ef3792012-02-23 09:45:49 -0500684 /*
685 * Queue a vblank signal so we know when the surface
686 * becomes active on the display or has been replaced.
687 */
688 vbl.request.signal = (unsigned long)s;
689 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
690 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200691 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500692 ret, strerror(errno));
693 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300694
695 s->output = output;
696 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500697 }
698
David Herrmann1edf44c2013-10-22 17:11:26 +0200699 return 0;
700
701err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800702 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200703 if (output->next) {
704 drm_output_release_fb(output, output->next);
705 output->next = NULL;
706 }
707
708 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400709}
710
711static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200712drm_output_start_repaint_loop(struct weston_output *output_base)
713{
714 struct drm_output *output = (struct drm_output *) output_base;
715 struct drm_compositor *compositor = (struct drm_compositor *)
716 output_base->compositor;
717 uint32_t fb_id;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300718 struct timespec ts;
719
Xiong Zhangabd5d472013-10-11 14:43:07 +0800720 if (output->destroy_pending)
721 return;
722
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300723 if (!output->current) {
724 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200725 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300726 }
727
728 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200729
730 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
731 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
732 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200733 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200734 }
David Herrmann3c688c52013-10-22 17:11:25 +0200735
736 return;
737
738finish_frame:
739 /* if we cannot page-flip, immediately finish frame */
Pekka Paalanen662f3842015-03-18 12:17:26 +0200740 weston_compositor_read_presentation_clock(&compositor->base, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200741 weston_output_finish_frame(output_base, &ts,
742 PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200743}
744
745static void
Pekka Paalanen641307c2014-09-23 22:08:47 -0400746drm_output_update_msc(struct drm_output *output, unsigned int seq)
747{
748 uint64_t msc_hi = output->base.msc >> 32;
749
750 if (seq < (output->base.msc & 0xffffffff))
751 msc_hi++;
752
753 output->base.msc = (msc_hi << 32) + seq;
754}
755
756static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500757vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
758 void *data)
759{
760 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300761 struct drm_output *output = s->output;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400762 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200763 uint32_t flags = PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
764 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300765
Pekka Paalanen641307c2014-09-23 22:08:47 -0400766 drm_output_update_msc(output, frame);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300767 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500768
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200769 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200770 s->current = s->next;
771 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300772
773 if (!output->page_flip_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400774 ts.tv_sec = sec;
775 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200776 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300777 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500778}
779
780static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800781drm_output_destroy(struct weston_output *output_base);
782
783static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400784page_flip_handler(int fd, unsigned int frame,
785 unsigned int sec, unsigned int usec, void *data)
786{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200787 struct drm_output *output = (struct drm_output *) data;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400788 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200789 uint32_t flags = PRESENTATION_FEEDBACK_KIND_VSYNC |
790 PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
791 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400792
Pekka Paalanen641307c2014-09-23 22:08:47 -0400793 drm_output_update_msc(output, frame);
794
Jonas Ådahle5a12252013-04-05 23:07:11 +0200795 /* We don't set page_flip_pending on start_repaint_loop, in that case
796 * we just want to page flip to the current buffer to get an accurate
797 * timestamp */
798 if (output->page_flip_pending) {
799 drm_output_release_fb(output, output->current);
800 output->current = output->next;
801 output->next = NULL;
802 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300803
Jonas Ådahle5a12252013-04-05 23:07:11 +0200804 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400805
Xiong Zhangabd5d472013-10-11 14:43:07 +0800806 if (output->destroy_pending)
807 drm_output_destroy(&output->base);
808 else if (!output->vblank_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400809 ts.tv_sec = sec;
810 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200811 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300812
813 /* We can't call this from frame_notify, because the output's
814 * repaint needed flag is cleared just after that */
815 if (output->recorder)
816 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300817 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200818}
819
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500820static uint32_t
821drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500822 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500823{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500824 uint32_t i, format;
825
826 format = gbm_bo_get_format(bo);
827
828 if (format == GBM_FORMAT_ARGB8888) {
829 pixman_region32_t r;
830
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500831 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600832 ev->surface->width,
833 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500834 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500835
836 if (!pixman_region32_not_empty(&r))
837 format = GBM_FORMAT_XRGB8888;
838
839 pixman_region32_fini(&r);
840 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500841
842 for (i = 0; i < s->count_formats; i++)
843 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500844 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500845
846 return 0;
847}
848
849static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500850drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500851{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500852 return !ev->transform.enabled ||
853 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500854}
855
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400856static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200857drm_output_prepare_overlay_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500858 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500859{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200860 struct weston_compositor *ec = output->base.compositor;
861 struct drm_compositor *c = (struct drm_compositor *)ec;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200862 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500863 struct drm_sprite *s;
864 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500865 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500866 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200867 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500868 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400869 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500870
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200871 if (c->gbm == NULL)
872 return NULL;
873
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200874 if (viewport->buffer.transform != output->base.transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200875 return NULL;
876
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200877 if (viewport->buffer.scale != output->base.current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200878 return NULL;
879
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500880 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400881 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500882
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200883 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400884 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300885
Jason Ekstranda7af7042013-10-12 22:38:11 -0500886 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400887 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500888
Jason Ekstranda7af7042013-10-12 22:38:11 -0500889 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200890 return NULL;
891
Jason Ekstranda7af7042013-10-12 22:38:11 -0500892 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500893 return NULL;
894
Jason Ekstranda7af7042013-10-12 22:38:11 -0500895 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400896 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500897
Jesse Barnes58ef3792012-02-23 09:45:49 -0500898 wl_list_for_each(s, &c->sprite_list, link) {
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200899 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500900 continue;
901
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200902 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500903 found = 1;
904 break;
905 }
906 }
907
908 /* No sprites available */
909 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400910 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500911
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400912 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500913 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700914 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400915 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400916 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400917
Jason Ekstranda7af7042013-10-12 22:38:11 -0500918 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500919 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200920 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400921 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500922 }
923
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200924 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200925 if (!s->next) {
926 gbm_bo_destroy(bo);
927 return NULL;
928 }
929
Jason Ekstranda7af7042013-10-12 22:38:11 -0500930 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500931
Jason Ekstranda7af7042013-10-12 22:38:11 -0500932 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400933 s->plane.x = box->x1;
934 s->plane.y = box->y1;
935
Jesse Barnes58ef3792012-02-23 09:45:49 -0500936 /*
937 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -0500938 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500939 * for us already).
940 */
941 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500942 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200943 &output->base.region);
944 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500945 box = pixman_region32_extents(&dest_rect);
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200946 tbox = weston_transformed_rect(output->base.width,
947 output->base.height,
948 output->base.transform,
949 output->base.current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200950 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200951 s->dest_x = tbox.x1;
952 s->dest_y = tbox.y1;
953 s->dest_w = tbox.x2 - tbox.x1;
954 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500955 pixman_region32_fini(&dest_rect);
956
957 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500958 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200959 &output->base.region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500960 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400961
Jason Ekstranda7af7042013-10-12 22:38:11 -0500962 weston_view_from_global_fixed(ev,
963 wl_fixed_from_int(box->x1),
964 wl_fixed_from_int(box->y1),
965 &sx1, &sy1);
966 weston_view_from_global_fixed(ev,
967 wl_fixed_from_int(box->x2),
968 wl_fixed_from_int(box->y2),
969 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400970
971 if (sx1 < 0)
972 sx1 = 0;
973 if (sy1 < 0)
974 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600975 if (sx2 > wl_fixed_from_int(ev->surface->width))
976 sx2 = wl_fixed_from_int(ev->surface->width);
977 if (sy2 > wl_fixed_from_int(ev->surface->height))
978 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400979
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200980 tbox.x1 = sx1;
981 tbox.y1 = sy1;
982 tbox.x2 = sx2;
983 tbox.y2 = sy2;
984
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600985 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
986 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200987 viewport->buffer.transform,
988 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100989 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200990
991 s->src_x = tbox.x1 << 8;
992 s->src_y = tbox.y1 << 8;
993 s->src_w = (tbox.x2 - tbox.x1) << 8;
994 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500995 pixman_region32_fini(&src_rect);
996
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400997 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500998}
999
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001000static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001001drm_output_prepare_cursor_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001002 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001003{
Kristian Høgsberg8a015802012-08-09 17:19:23 -04001004 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001005 (struct drm_compositor *)output->base.compositor;
Neil Robertsf37f82c2014-05-01 18:00:41 +01001006 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001007
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001008 if (c->gbm == NULL)
1009 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +02001010 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
1011 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001012 if (viewport->buffer.scale != output->base.current_scale)
Neil Robertsf37f82c2014-05-01 18:00:41 +01001013 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001014 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001015 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001016 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001017 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001018 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -04001019 return NULL;
Pekka Paalanen5580f222015-02-17 16:33:18 +02001020 if (ev->geometry.scissor_enabled)
1021 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001022 if (ev->surface->buffer_ref.buffer == NULL ||
1023 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001024 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001025 return NULL;
1026
Jason Ekstranda7af7042013-10-12 22:38:11 -05001027 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001028
1029 return &output->cursor_plane;
1030}
1031
1032static void
1033drm_output_set_cursor(struct drm_output *output)
1034{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001035 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001036 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001037 struct drm_compositor *c =
1038 (struct drm_compositor *) output->base.compositor;
1039 EGLint handle, stride;
1040 struct gbm_bo *bo;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001041 uint32_t buf[c->cursor_width * c->cursor_height];
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001042 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001043 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001044
Jason Ekstranda7af7042013-10-12 22:38:11 -05001045 output->cursor_view = NULL;
1046 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001047 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
1048 return;
1049 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001050
Neil Robertse5051712013-11-13 15:44:06 +00001051 buffer = ev->surface->buffer_ref.buffer;
1052
1053 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001054 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001055 pixman_region32_fini(&output->cursor_plane.damage);
1056 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001057 output->current_cursor ^= 1;
1058 bo = output->cursor_bo[output->current_cursor];
1059 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001060 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1061 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1062 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001063 for (i = 0; i < ev->surface->height; i++)
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001064 memcpy(buf + i * c->cursor_width, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001065 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001066 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001067
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001068 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001069 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001070
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001071 handle = gbm_bo_get_handle(bo).s32;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001072 if (drmModeSetCursor(c->drm.fd, output->crtc_id, handle,
1073 c->cursor_width, c->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001074 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001075 c->cursors_are_broken = 1;
1076 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001077 }
1078
Jason Ekstranda7af7042013-10-12 22:38:11 -05001079 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1080 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001081 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001082 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001083 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001084 c->cursors_are_broken = 1;
1085 }
1086
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001087 output->cursor_plane.x = x;
1088 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001089 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001090}
1091
Jesse Barnes58ef3792012-02-23 09:45:49 -05001092static void
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001093drm_assign_planes(struct weston_output *output_base)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001094{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001095 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001096 (struct drm_compositor *)output_base->compositor;
1097 struct drm_output *output = (struct drm_output *)output_base;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001098 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001099 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001100 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001101
1102 /*
1103 * Find a surface for each sprite in the output using some heuristics:
1104 * 1) size
1105 * 2) frequency of update
1106 * 3) opacity (though some hw might support alpha blending)
1107 * 4) clipping (this can be fixed with color keys)
1108 *
1109 * The idea is to save on blitting since this should save power.
1110 * If we can get a large video surface on the sprite for example,
1111 * the main display surface may not need to update at all, and
1112 * the client buffer can be used directly for the sprite surface
1113 * as we do for flipping full screen surfaces.
1114 */
1115 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001116 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001117
Jason Ekstranda7af7042013-10-12 22:38:11 -05001118 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001119 struct weston_surface *es = ev->surface;
1120
1121 /* Test whether this buffer can ever go into a plane:
1122 * non-shm, or small enough to be a cursor.
1123 *
1124 * Also, keep a reference when using the pixman renderer.
1125 * That makes it possible to do a seamless switch to the GL
1126 * renderer and since the pixman renderer keeps a reference
1127 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001128 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001129 if (c->use_pixman ||
1130 (es->buffer_ref.buffer &&
1131 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001132 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001133 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001134 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001135 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001136
Jesse Barnes58ef3792012-02-23 09:45:49 -05001137 pixman_region32_init(&surface_overlap);
1138 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001139 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001140
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001141 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001142 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001143 next_plane = primary;
1144 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001145 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001146 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001147 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001148 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001149 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001150 if (next_plane == NULL)
1151 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001152
Jason Ekstranda7af7042013-10-12 22:38:11 -05001153 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001154
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001155 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001156 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001157 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001158
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001159 if (next_plane == primary ||
1160 next_plane == &output->cursor_plane) {
1161 /* cursor plane involves a copy */
1162 ev->psf_flags = 0;
1163 } else {
1164 /* All other planes are a direct scanout of a
1165 * single client buffer.
1166 */
1167 ev->psf_flags = PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
1168 }
1169
Jesse Barnes58ef3792012-02-23 09:45:49 -05001170 pixman_region32_fini(&surface_overlap);
1171 }
1172 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001173}
1174
Matt Roper361d2ad2011-08-29 13:52:23 -07001175static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001176drm_output_fini_pixman(struct drm_output *output);
1177
1178static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001179drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001180{
1181 struct drm_output *output = (struct drm_output *) output_base;
1182 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001183 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001184 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001185
Xiong Zhangabd5d472013-10-11 14:43:07 +08001186 if (output->page_flip_pending) {
1187 output->destroy_pending = 1;
1188 weston_log("destroy output while page flip pending\n");
1189 return;
1190 }
1191
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001192 if (output->backlight)
1193 backlight_destroy(output->backlight);
1194
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001195 drmModeFreeProperty(output->dpms_prop);
1196
Matt Roper361d2ad2011-08-29 13:52:23 -07001197 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001198 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001199
1200 /* Restore original CRTC state */
1201 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001202 origcrtc->x, origcrtc->y,
1203 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001204 drmModeFreeCrtc(origcrtc);
1205
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001206 c->crtc_allocator &= ~(1 << output->crtc_id);
1207 c->connector_allocator &= ~(1 << output->connector_id);
1208
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001209 if (c->use_pixman) {
1210 drm_output_fini_pixman(output);
1211 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001212 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001213 gbm_surface_destroy(output->surface);
1214 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001215
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001216 weston_plane_release(&output->fb_plane);
1217 weston_plane_release(&output->cursor_plane);
1218
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001219 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001220
Matt Roper361d2ad2011-08-29 13:52:23 -07001221 free(output);
1222}
1223
Alex Wub7b8bda2012-04-17 17:20:48 +08001224static struct drm_mode *
1225choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1226{
1227 struct drm_mode *tmp_mode = NULL, *mode;
1228
Hardeningff39efa2013-09-18 23:56:35 +02001229 if (output->base.current_mode->width == target_mode->width &&
1230 output->base.current_mode->height == target_mode->height &&
1231 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001232 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001233 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001234
1235 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1236 if (mode->mode_info.hdisplay == target_mode->width &&
1237 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02001238 if (mode->base.refresh == target_mode->refresh ||
1239 target_mode->refresh == 0) {
Alex Wub7b8bda2012-04-17 17:20:48 +08001240 return mode;
Daniel Stonef556ebe2015-05-21 08:28:58 +01001241 } else if (!tmp_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001242 tmp_mode = mode;
1243 }
1244 }
1245
1246 return tmp_mode;
1247}
1248
1249static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001250drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001251static int
1252drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001253
1254static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001255drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1256{
1257 struct drm_output *output;
1258 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001259 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001260
1261 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001262 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001263 return -1;
1264 }
1265
1266 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001267 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001268 return -1;
1269 }
1270
1271 ec = (struct drm_compositor *)output_base->compositor;
1272 output = (struct drm_output *)output_base;
1273 drm_mode = choose_mode (output, mode);
1274
1275 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001276 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001277 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001278 }
1279
Hardeningff39efa2013-09-18 23:56:35 +02001280 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001281 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001282
Hardeningff39efa2013-09-18 23:56:35 +02001283 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001284
Hardeningff39efa2013-09-18 23:56:35 +02001285 output->base.current_mode = &drm_mode->base;
1286 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001287 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1288
Alex Wub7b8bda2012-04-17 17:20:48 +08001289 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001290 drm_output_release_fb(output, output->current);
1291 drm_output_release_fb(output, output->next);
1292 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001293
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001294 if (ec->use_pixman) {
1295 drm_output_fini_pixman(output);
1296 if (drm_output_init_pixman(output, ec) < 0) {
1297 weston_log("failed to init output pixman state with "
1298 "new mode\n");
1299 return -1;
1300 }
1301 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001302 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001303 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001304
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001305 if (drm_output_init_egl(output, ec) < 0) {
1306 weston_log("failed to init output egl state with "
1307 "new mode");
1308 return -1;
1309 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001310 }
1311
Alex Wub7b8bda2012-04-17 17:20:48 +08001312 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001313}
1314
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001315static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001316on_drm_input(int fd, uint32_t mask, void *data)
1317{
1318 drmEventContext evctx;
1319
1320 memset(&evctx, 0, sizeof evctx);
1321 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1322 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001323 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001324 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001325
1326 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001327}
1328
1329static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001330init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001331{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001332 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001333 uint64_t cap;
1334 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001335 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001336
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001337 sysnum = udev_device_get_sysnum(device);
1338 if (sysnum)
1339 ec->drm.id = atoi(sysnum);
1340 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001341 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001342 return -1;
1343 }
1344
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001345 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001346 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001347 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001348 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001349 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001350 udev_device_get_devnode(device));
1351 return -1;
1352 }
1353
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001354 weston_log("using %s\n", filename);
1355
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001356 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001357 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001358
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001359 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1360 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001361 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001362 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001363 clk_id = CLOCK_REALTIME;
1364
1365 if (weston_compositor_set_presentation_clock(&ec->base, clk_id) < 0) {
1366 weston_log("Error: failed to set presentation clock %d.\n",
1367 clk_id);
1368 return -1;
1369 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001370
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001371 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1372 if (ret == 0)
1373 ec->cursor_width = cap;
1374 else
1375 ec->cursor_width = 64;
1376
1377 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1378 if (ret == 0)
1379 ec->cursor_height = cap;
1380 else
1381 ec->cursor_height = 64;
1382
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001383 return 0;
1384}
1385
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001386static struct gbm_device *
1387create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001388{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001389 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001390
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001391 gl_renderer = weston_load_module("gl-renderer.so",
1392 "gl_renderer_interface");
1393 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001394 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001395
1396 /* GBM will load a dri driver, but even though they need symbols from
1397 * libglapi, in some version of Mesa they are not linked to it. Since
1398 * only the gl-renderer module links to it, the call above won't make
1399 * these symbols globally available, and loading the DRI driver fails.
1400 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1401 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1402
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001403 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001404
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001405 return gbm;
1406}
1407
Bryce Harringtonc056a982015-05-19 15:25:18 -07001408/* When initializing EGL, if the preferred buffer format isn't available
Derek Foremanc4cfe852015-05-15 12:12:40 -05001409 * we may be able to susbstitute an ARGB format for an XRGB one.
1410 *
1411 * This returns 0 if substitution isn't possible, but 0 might be a
1412 * legitimate format for other EGL platforms, so the caller is
1413 * responsible for checking for 0 before calling gl_renderer->create().
1414 *
1415 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
1416 * but it's entirely possible we'll see this again on other implementations.
1417 */
1418static int
1419fallback_format_for(uint32_t format)
1420{
1421 switch (format) {
1422 case GBM_FORMAT_XRGB8888:
1423 return GBM_FORMAT_ARGB8888;
1424 case GBM_FORMAT_XRGB2101010:
1425 return GBM_FORMAT_ARGB2101010;
1426 default:
1427 return 0;
1428 }
1429}
1430
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001431static int
1432drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1433{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001434 EGLint format[2] = {
1435 ec->format,
1436 fallback_format_for(ec->format),
1437 };
1438 int n_formats = 1;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001439
Derek Foremanc4cfe852015-05-15 12:12:40 -05001440 if (format[1])
1441 n_formats = 2;
1442 if (gl_renderer->create(&ec->base,
1443 EGL_PLATFORM_GBM_KHR,
1444 (void *)ec->gbm,
1445 gl_renderer->opaque_attribs,
1446 format,
1447 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001448 return -1;
1449 }
1450
1451 return 0;
1452}
1453
1454static int
1455init_egl(struct drm_compositor *ec)
1456{
1457 ec->gbm = create_gbm_device(ec->drm.fd);
1458
1459 if (!ec->gbm)
1460 return -1;
1461
1462 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001463 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001464 return -1;
1465 }
1466
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001467 return 0;
1468}
1469
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001470static int
1471init_pixman(struct drm_compositor *ec)
1472{
1473 return pixman_renderer_init(&ec->base);
1474}
1475
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001476static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001477drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001478{
1479 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001480 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001481
1482 mode = malloc(sizeof *mode);
1483 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001484 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001485
1486 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001487 mode->base.width = info->hdisplay;
1488 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001489
1490 /* Calculate higher precision (mHz) refresh rate */
1491 refresh = (info->clock * 1000000LL / info->htotal +
1492 info->vtotal / 2) / info->vtotal;
1493
1494 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1495 refresh *= 2;
1496 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1497 refresh /= 2;
1498 if (info->vscan > 1)
1499 refresh /= info->vscan;
1500
1501 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001502 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001503
1504 if (info->type & DRM_MODE_TYPE_PREFERRED)
1505 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1506
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001507 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1508
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001509 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001510}
1511
1512static int
1513drm_subpixel_to_wayland(int drm_value)
1514{
1515 switch (drm_value) {
1516 default:
1517 case DRM_MODE_SUBPIXEL_UNKNOWN:
1518 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1519 case DRM_MODE_SUBPIXEL_NONE:
1520 return WL_OUTPUT_SUBPIXEL_NONE;
1521 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1522 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1523 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1524 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1525 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1526 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1527 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1528 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1529 }
1530}
1531
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001532/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001533static uint32_t
1534drm_get_backlight(struct drm_output *output)
1535{
1536 long brightness, max_brightness, norm;
1537
1538 brightness = backlight_get_brightness(output->backlight);
1539 max_brightness = backlight_get_max_brightness(output->backlight);
1540
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001541 /* convert it on a scale of 0 to 255 */
1542 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001543
1544 return (uint32_t) norm;
1545}
1546
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001547/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001548static void
1549drm_set_backlight(struct weston_output *output_base, uint32_t value)
1550{
1551 struct drm_output *output = (struct drm_output *) output_base;
1552 long max_brightness, new_brightness;
1553
1554 if (!output->backlight)
1555 return;
1556
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001557 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001558 return;
1559
1560 max_brightness = backlight_get_max_brightness(output->backlight);
1561
1562 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001563 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001564
1565 backlight_set_brightness(output->backlight, new_brightness);
1566}
1567
1568static drmModePropertyPtr
1569drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1570{
1571 drmModePropertyPtr props;
1572 int i;
1573
1574 for (i = 0; i < connector->count_props; i++) {
1575 props = drmModeGetProperty(fd, connector->props[i]);
1576 if (!props)
1577 continue;
1578
1579 if (!strcmp(props->name, name))
1580 return props;
1581
1582 drmModeFreeProperty(props);
1583 }
1584
1585 return NULL;
1586}
1587
1588static void
1589drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1590{
1591 struct drm_output *output = (struct drm_output *) output_base;
1592 struct weston_compositor *ec = output_base->compositor;
1593 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001594
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001595 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001596 return;
1597
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001598 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1599 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001600}
1601
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001602static const char *connector_type_names[] = {
1603 "None",
1604 "VGA",
1605 "DVI",
1606 "DVI",
1607 "DVI",
1608 "Composite",
1609 "TV",
1610 "LVDS",
1611 "CTV",
1612 "DIN",
1613 "DP",
1614 "HDMI",
1615 "HDMI",
1616 "TV",
1617 "eDP",
1618};
1619
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001620static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001621find_crtc_for_connector(struct drm_compositor *ec,
1622 drmModeRes *resources, drmModeConnector *connector)
1623{
1624 drmModeEncoder *encoder;
1625 uint32_t possible_crtcs;
1626 int i, j;
1627
1628 for (j = 0; j < connector->count_encoders; j++) {
1629 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1630 if (encoder == NULL) {
1631 weston_log("Failed to get encoder.\n");
1632 return -1;
1633 }
1634 possible_crtcs = encoder->possible_crtcs;
1635 drmModeFreeEncoder(encoder);
1636
1637 for (i = 0; i < resources->count_crtcs; i++) {
1638 if (possible_crtcs & (1 << i) &&
1639 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1640 return i;
1641 }
1642 }
1643
1644 return -1;
1645}
1646
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001647/* Init output state that depends on gl or gbm */
1648static int
1649drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1650{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001651 EGLint format[2] = {
1652 output->format,
1653 fallback_format_for(output->format),
1654 };
1655 int i, flags, n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001656
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001657 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001658 output->base.current_mode->width,
1659 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001660 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001661 GBM_BO_USE_SCANOUT |
1662 GBM_BO_USE_RENDERING);
1663 if (!output->surface) {
1664 weston_log("failed to create gbm surface\n");
1665 return -1;
1666 }
1667
Derek Foremanc4cfe852015-05-15 12:12:40 -05001668 if (format[1])
1669 n_formats = 2;
Jonny Lamb671148f2015-03-20 15:26:52 +01001670 if (gl_renderer->output_create(&output->base,
Jonny Lamb445fb692015-03-24 13:12:01 +01001671 (EGLNativeDisplayType)output->surface,
1672 output->surface,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001673 gl_renderer->opaque_attribs,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001674 format,
1675 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001676 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001677 gbm_surface_destroy(output->surface);
1678 return -1;
1679 }
1680
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001681 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001682
1683 for (i = 0; i < 2; i++) {
1684 if (output->cursor_bo[i])
1685 continue;
1686
1687 output->cursor_bo[i] =
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001688 gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
1689 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001690 }
1691
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001692 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1693 weston_log("cursor buffers unavailable, using gl cursors\n");
1694 ec->cursors_are_broken = 1;
1695 }
1696
1697 return 0;
1698}
1699
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001700static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001701drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1702{
Hardeningff39efa2013-09-18 23:56:35 +02001703 int w = output->base.current_mode->width;
1704 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001705 unsigned int i;
1706
1707 /* FIXME error checking */
1708
1709 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001710 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001711 if (!output->dumb[i])
1712 goto err;
1713
1714 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001715 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001716 output->dumb[i]->map,
1717 output->dumb[i]->stride);
1718 if (!output->image[i])
1719 goto err;
1720 }
1721
1722 if (pixman_renderer_output_create(&output->base) < 0)
1723 goto err;
1724
1725 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001726 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001727
1728 return 0;
1729
1730err:
1731 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1732 if (output->dumb[i])
1733 drm_fb_destroy_dumb(output->dumb[i]);
1734 if (output->image[i])
1735 pixman_image_unref(output->image[i]);
1736
1737 output->dumb[i] = NULL;
1738 output->image[i] = NULL;
1739 }
1740
1741 return -1;
1742}
1743
1744static void
1745drm_output_fini_pixman(struct drm_output *output)
1746{
1747 unsigned int i;
1748
1749 pixman_renderer_output_destroy(&output->base);
1750 pixman_region32_fini(&output->previous_damage);
1751
1752 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1753 drm_fb_destroy_dumb(output->dumb[i]);
1754 pixman_image_unref(output->image[i]);
1755 output->dumb[i] = NULL;
1756 output->image[i] = NULL;
1757 }
1758}
1759
Richard Hughes2b2092a2013-04-24 14:58:02 +01001760static void
1761edid_parse_string(const uint8_t *data, char text[])
1762{
1763 int i;
1764 int replaced = 0;
1765
1766 /* this is always 12 bytes, but we can't guarantee it's null
1767 * terminated or not junk. */
1768 strncpy(text, (const char *) data, 12);
1769
1770 /* remove insane chars */
1771 for (i = 0; text[i] != '\0'; i++) {
1772 if (text[i] == '\n' ||
1773 text[i] == '\r') {
1774 text[i] = '\0';
1775 break;
1776 }
1777 }
1778
1779 /* ensure string is printable */
1780 for (i = 0; text[i] != '\0'; i++) {
1781 if (!isprint(text[i])) {
1782 text[i] = '-';
1783 replaced++;
1784 }
1785 }
1786
1787 /* if the string is random junk, ignore the string */
1788 if (replaced > 4)
1789 text[0] = '\0';
1790}
1791
1792#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1793#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1794#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1795#define EDID_OFFSET_DATA_BLOCKS 0x36
1796#define EDID_OFFSET_LAST_BLOCK 0x6c
1797#define EDID_OFFSET_PNPID 0x08
1798#define EDID_OFFSET_SERIAL 0x0c
1799
1800static int
1801edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1802{
1803 int i;
1804 uint32_t serial_number;
1805
1806 /* check header */
1807 if (length < 128)
1808 return -1;
1809 if (data[0] != 0x00 || data[1] != 0xff)
1810 return -1;
1811
1812 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1813 * /--08--\/--09--\
1814 * 7654321076543210
1815 * |\---/\---/\---/
1816 * R C1 C2 C3 */
1817 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1818 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1819 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1820 edid->pnp_id[3] = '\0';
1821
1822 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1823 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1824 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1825 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1826 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1827 if (serial_number > 0)
1828 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1829
1830 /* parse EDID data */
1831 for (i = EDID_OFFSET_DATA_BLOCKS;
1832 i <= EDID_OFFSET_LAST_BLOCK;
1833 i += 18) {
1834 /* ignore pixel clock data */
1835 if (data[i] != 0)
1836 continue;
1837 if (data[i+2] != 0)
1838 continue;
1839
1840 /* any useful blocks? */
1841 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1842 edid_parse_string(&data[i+5],
1843 edid->monitor_name);
1844 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1845 edid_parse_string(&data[i+5],
1846 edid->serial_number);
1847 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1848 edid_parse_string(&data[i+5],
1849 edid->eisa_id);
1850 }
1851 }
1852 return 0;
1853}
1854
1855static void
1856find_and_parse_output_edid(struct drm_compositor *ec,
1857 struct drm_output *output,
1858 drmModeConnector *connector)
1859{
1860 drmModePropertyBlobPtr edid_blob = NULL;
1861 drmModePropertyPtr property;
1862 int i;
1863 int rc;
1864
1865 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1866 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1867 if (!property)
1868 continue;
1869 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1870 !strcmp(property->name, "EDID")) {
1871 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1872 connector->prop_values[i]);
1873 }
1874 drmModeFreeProperty(property);
1875 }
1876 if (!edid_blob)
1877 return;
1878
1879 rc = edid_parse(&output->edid,
1880 edid_blob->data,
1881 edid_blob->length);
1882 if (!rc) {
1883 weston_log("EDID data '%s', '%s', '%s'\n",
1884 output->edid.pnp_id,
1885 output->edid.monitor_name,
1886 output->edid.serial_number);
1887 if (output->edid.pnp_id[0] != '\0')
1888 output->base.make = output->edid.pnp_id;
1889 if (output->edid.monitor_name[0] != '\0')
1890 output->base.model = output->edid.monitor_name;
1891 if (output->edid.serial_number[0] != '\0')
1892 output->base.serial_number = output->edid.serial_number;
1893 }
1894 drmModeFreePropertyBlob(edid_blob);
1895}
1896
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001897
1898
1899static int
1900parse_modeline(const char *s, drmModeModeInfo *mode)
1901{
1902 char hsync[16];
1903 char vsync[16];
1904 float fclock;
1905
1906 mode->type = DRM_MODE_TYPE_USERDEF;
1907 mode->hskew = 0;
1908 mode->vscan = 0;
1909 mode->vrefresh = 0;
1910 mode->flags = 0;
1911
Rob Bradford307e09e2013-07-26 16:29:40 +01001912 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001913 &fclock,
1914 &mode->hdisplay,
1915 &mode->hsync_start,
1916 &mode->hsync_end,
1917 &mode->htotal,
1918 &mode->vdisplay,
1919 &mode->vsync_start,
1920 &mode->vsync_end,
1921 &mode->vtotal, hsync, vsync) != 11)
1922 return -1;
1923
1924 mode->clock = fclock * 1000;
1925 if (strcmp(hsync, "+hsync") == 0)
1926 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1927 else if (strcmp(hsync, "-hsync") == 0)
1928 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1929 else
1930 return -1;
1931
1932 if (strcmp(vsync, "+vsync") == 0)
1933 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1934 else if (strcmp(vsync, "-vsync") == 0)
1935 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1936 else
1937 return -1;
1938
1939 return 0;
1940}
1941
Rob Bradford66bd9f52013-06-25 18:56:42 +01001942static void
1943setup_output_seat_constraint(struct drm_compositor *ec,
1944 struct weston_output *output,
1945 const char *s)
1946{
1947 if (strcmp(s, "") != 0) {
1948 struct udev_seat *seat;
1949
Jonas Ådahl58e15862014-03-12 22:08:40 +01001950 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001951 if (seat)
1952 seat->base.output = output;
1953
1954 if (seat && seat->base.pointer)
1955 weston_pointer_clamp(seat->base.pointer,
1956 &seat->base.pointer->x,
1957 &seat->base.pointer->y);
1958 }
1959}
1960
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001961static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001962get_gbm_format_from_section(struct weston_config_section *section,
1963 uint32_t default_value,
1964 uint32_t *format)
1965{
1966 char *s;
1967 int ret = 0;
1968
1969 weston_config_section_get_string(section,
1970 "gbm-format", &s, NULL);
1971
1972 if (s == NULL)
1973 *format = default_value;
1974 else if (strcmp(s, "xrgb8888") == 0)
1975 *format = GBM_FORMAT_XRGB8888;
1976 else if (strcmp(s, "rgb565") == 0)
1977 *format = GBM_FORMAT_RGB565;
1978 else if (strcmp(s, "xrgb2101010") == 0)
1979 *format = GBM_FORMAT_XRGB2101010;
1980 else {
1981 weston_log("fatal: unrecognized pixel format: %s\n", s);
1982 ret = -1;
1983 }
1984
1985 free(s);
1986
1987 return ret;
1988}
1989
1990static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001991create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001992 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001993 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001994 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001995{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001996 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001997 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001998 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001999 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002000 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002001 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002002 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002003 int i, width, height, scale;
2004 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002005 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002006 enum output_config config;
2007 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002008
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002009 i = find_crtc_for_connector(ec, resources, connector);
2010 if (i < 0) {
2011 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002012 return -1;
2013 }
2014
Peter Huttererf3d62272013-08-08 11:57:05 +10002015 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002016 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002017 return -1;
2018
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002019 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
2020 output->base.make = "unknown";
2021 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01002022 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002023 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002024
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002025 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
2026 type_name = connector_type_names[connector->connector_type];
2027 else
2028 type_name = "UNKNOWN";
2029 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01002030 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002031
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002032 section = weston_config_get_section(ec->base.config, "output", "name",
2033 output->base.name);
2034 weston_config_section_get_string(section, "mode", &s, "preferred");
2035 if (strcmp(s, "off") == 0)
2036 config = OUTPUT_CONFIG_OFF;
2037 else if (strcmp(s, "preferred") == 0)
2038 config = OUTPUT_CONFIG_PREFERRED;
2039 else if (strcmp(s, "current") == 0)
2040 config = OUTPUT_CONFIG_CURRENT;
2041 else if (sscanf(s, "%dx%d", &width, &height) == 2)
2042 config = OUTPUT_CONFIG_MODE;
2043 else if (parse_modeline(s, &modeline) == 0)
2044 config = OUTPUT_CONFIG_MODELINE;
2045 else {
2046 weston_log("Invalid mode \"%s\" for output %s\n",
2047 s, output->base.name);
2048 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002049 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002050 free(s);
2051
2052 weston_config_section_get_int(section, "scale", &scale, 1);
2053 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05002054 if (weston_parse_transform(s, &transform) < 0)
2055 weston_log("Invalid transform \"%s\" for output %s\n",
2056 s, output->base.name);
2057
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002058 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002059
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002060 if (get_gbm_format_from_section(section,
2061 ec->format,
2062 &output->format) == -1)
2063 output->format = ec->format;
2064
Rob Bradford66bd9f52013-06-25 18:56:42 +01002065 weston_config_section_get_string(section, "seat", &s, "");
2066 setup_output_seat_constraint(ec, &output->base, s);
2067 free(s);
2068
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002069 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002070 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002071 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002072 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002073 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002074
Matt Roper361d2ad2011-08-29 13:52:23 -07002075 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03002076 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002077
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002078 /* Get the current mode on the crtc that's currently driving
2079 * this connector. */
2080 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002081 memset(&crtc_mode, 0, sizeof crtc_mode);
2082 if (encoder != NULL) {
2083 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
2084 drmModeFreeEncoder(encoder);
2085 if (crtc == NULL)
2086 goto err_free;
2087 if (crtc->mode_valid)
2088 crtc_mode = crtc->mode;
2089 drmModeFreeCrtc(crtc);
2090 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002091
David Herrmann0f0d54e2011-12-08 17:05:45 +01002092 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002093 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002094 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002095 goto err_free;
2096 }
2097
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002098 if (config == OUTPUT_CONFIG_OFF) {
2099 weston_log("Disabling output %s\n", output->base.name);
2100 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
2101 0, 0, 0, 0, 0, NULL);
2102 goto err_free;
2103 }
2104
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002105 preferred = NULL;
2106 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002107 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002108 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002109
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002110 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002111 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002112 width == drm_mode->base.width &&
2113 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002114 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002115 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002116 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002117 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002118 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002119 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002120 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002121
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002122 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002123 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002124 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002125 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002126 }
2127
Wang Quanxianacb805a2012-07-30 18:09:46 -04002128 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002129 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002130 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002131 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002132 }
2133
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002134 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002135 configured = current;
2136
Wang Quanxianacb805a2012-07-30 18:09:46 -04002137 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002138 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002139 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002140 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002141 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002142 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002143 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002144 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002145 else if (best)
2146 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002147
Hardeningff39efa2013-09-18 23:56:35 +02002148 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002149 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002150 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002151 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002152
Hardeningff39efa2013-09-18 23:56:35 +02002153 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002154
John Kåre Alsaker94659272012-11-13 19:10:18 +01002155 weston_output_init(&output->base, &ec->base, x, y,
2156 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002157 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002158
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002159 if (ec->use_pixman) {
2160 if (drm_output_init_pixman(output, ec) < 0) {
2161 weston_log("Failed to init output pixman state\n");
2162 goto err_output;
2163 }
2164 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002165 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002166 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002167 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002168
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002169 output->backlight = backlight_init(drm_device,
2170 connector->connector_type);
2171 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002172 weston_log("Initialized backlight, device %s\n",
2173 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002174 output->base.set_backlight = drm_set_backlight;
2175 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002176 } else {
2177 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002178 }
2179
Giulio Camuffob1147152015-05-06 21:41:57 +03002180 weston_compositor_add_output(&ec->base, &output->base);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002181
Richard Hughes2b2092a2013-04-24 14:58:02 +01002182 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002183 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2184 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002185
Jonas Ådahle5a12252013-04-05 23:07:11 +02002186 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002187 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002188 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002189 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002190 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002191 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002192
Richard Hughese7299962013-05-01 21:52:12 +01002193 output->base.gamma_size = output->original_crtc->gamma_size;
2194 output->base.set_gamma = drm_output_set_gamma;
2195
Xiong Zhang97116532013-10-23 13:58:31 +08002196 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2197 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002198
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002199 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2200 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2201 &ec->base.primary_plane);
2202
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002203 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002204 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002205 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002206 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002207 m->width, m->height, m->refresh / 1000.0,
2208 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2209 ", preferred" : "",
2210 m->flags & WL_OUTPUT_MODE_CURRENT ?
2211 ", current" : "",
2212 connector->count_modes == 0 ?
2213 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002214
Mario Kleiner80817042015-06-21 21:25:11 +02002215 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
2216 output->base.native_mode = output->base.current_mode;
2217 output->base.native_scale = output->base.current_scale;
2218
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002219 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002220
John Kåre Alsaker94659272012-11-13 19:10:18 +01002221err_output:
2222 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002223err_free:
2224 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2225 base.link) {
2226 wl_list_remove(&drm_mode->base.link);
2227 free(drm_mode);
2228 }
2229
2230 drmModeFreeCrtc(output->original_crtc);
2231 ec->crtc_allocator &= ~(1 << output->crtc_id);
2232 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002233 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002234
David Herrmann0f0d54e2011-12-08 17:05:45 +01002235 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002236}
2237
Jesse Barnes58ef3792012-02-23 09:45:49 -05002238static void
2239create_sprites(struct drm_compositor *ec)
2240{
2241 struct drm_sprite *sprite;
2242 drmModePlaneRes *plane_res;
2243 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002244 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002245
2246 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2247 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002248 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002249 strerror(errno));
2250 return;
2251 }
2252
2253 for (i = 0; i < plane_res->count_planes; i++) {
2254 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2255 if (!plane)
2256 continue;
2257
Peter Huttererf3d62272013-08-08 11:57:05 +10002258 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002259 plane->count_formats));
2260 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002261 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002262 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002263 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002264 continue;
2265 }
2266
Jesse Barnes58ef3792012-02-23 09:45:49 -05002267 sprite->possible_crtcs = plane->possible_crtcs;
2268 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002269 sprite->current = NULL;
2270 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002271 sprite->compositor = ec;
2272 sprite->count_formats = plane->count_formats;
2273 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002274 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002275 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002276 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002277 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2278 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002279
2280 wl_list_insert(&ec->sprite_list, &sprite->link);
2281 }
2282
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002283 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002284}
2285
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002286static void
2287destroy_sprites(struct drm_compositor *compositor)
2288{
2289 struct drm_sprite *sprite, *next;
2290 struct drm_output *output;
2291
2292 output = container_of(compositor->base.output_list.next,
2293 struct drm_output, base.link);
2294
2295 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2296 drmModeSetPlane(compositor->drm.fd,
2297 sprite->plane_id,
2298 output->crtc_id, 0, 0,
2299 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002300 drm_output_release_fb(output, sprite->current);
2301 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002302 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002303 free(sprite);
2304 }
2305}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002306
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002307static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002308create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002309 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002310{
2311 drmModeConnector *connector;
2312 drmModeRes *resources;
2313 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002314 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002315
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002316 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002317 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002318 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002319 return -1;
2320 }
2321
Jesse Barnes58ef3792012-02-23 09:45:49 -05002322 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002323 if (!ec->crtcs) {
2324 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002325 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002326 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002327
Rob Clark4339add2012-08-09 14:18:28 -05002328 ec->min_width = resources->min_width;
2329 ec->max_width = resources->max_width;
2330 ec->min_height = resources->min_height;
2331 ec->max_height = resources->max_height;
2332
Jesse Barnes58ef3792012-02-23 09:45:49 -05002333 ec->num_crtcs = resources->count_crtcs;
2334 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2335
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002336 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002337 connector = drmModeGetConnector(ec->drm.fd,
2338 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002339 if (connector == NULL)
2340 continue;
2341
2342 if (connector->connection == DRM_MODE_CONNECTED &&
2343 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002344 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002345 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002346 connector, x, y,
2347 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002348 drmModeFreeConnector(connector);
2349 continue;
2350 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002351
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002352 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002353 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002354 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002355 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002356
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002357 drmModeFreeConnector(connector);
2358 }
2359
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002360 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002361 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002362 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002363 return -1;
2364 }
2365
2366 drmModeFreeResources(resources);
2367
2368 return 0;
2369}
2370
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002371static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002372update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002373{
2374 drmModeConnector *connector;
2375 drmModeRes *resources;
2376 struct drm_output *output, *next;
2377 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002378 uint32_t connected = 0, disconnects = 0;
2379 int i;
2380
2381 resources = drmModeGetResources(ec->drm.fd);
2382 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002383 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002384 return;
2385 }
2386
2387 /* collect new connects */
2388 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002389 int connector_id = resources->connectors[i];
2390
2391 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002392 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002393 continue;
2394
David Herrmann7551cff2011-12-08 17:05:43 +01002395 if (connector->connection != DRM_MODE_CONNECTED) {
2396 drmModeFreeConnector(connector);
2397 continue;
2398 }
2399
Benjamin Franzke117483d2011-08-30 11:38:26 +02002400 connected |= (1 << connector_id);
2401
2402 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002403 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002404 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002405 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002406
2407 /* XXX: not yet needed, we die with 0 outputs */
2408 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002409 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002410 else
2411 x = 0;
2412 y = 0;
2413 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002414 connector, x, y,
2415 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002416 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002417
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002418 }
2419 drmModeFreeConnector(connector);
2420 }
2421 drmModeFreeResources(resources);
2422
2423 disconnects = ec->connector_allocator & ~connected;
2424 if (disconnects) {
2425 wl_list_for_each_safe(output, next, &ec->base.output_list,
2426 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002427 if (disconnects & (1 << output->connector_id)) {
2428 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002429 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002430 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002431 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002432 }
2433 }
2434 }
2435
Daniel Stonef556ebe2015-05-21 08:28:58 +01002436 /* FIXME: handle zero outputs, without terminating */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002437 if (ec->connector_allocator == 0)
2438 wl_display_terminate(ec->base.wl_display);
2439}
2440
2441static int
David Herrmannd7488c22012-03-11 20:05:21 +01002442udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002443{
David Herrmannd7488c22012-03-11 20:05:21 +01002444 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002445 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002446
2447 sysnum = udev_device_get_sysnum(device);
2448 if (!sysnum || atoi(sysnum) != ec->drm.id)
2449 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002450
David Herrmann6ac52db2012-03-11 20:05:22 +01002451 val = udev_device_get_property_value(device, "HOTPLUG");
2452 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002453 return 0;
2454
David Herrmann6ac52db2012-03-11 20:05:22 +01002455 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002456}
2457
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002458static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002459udev_drm_event(int fd, uint32_t mask, void *data)
2460{
2461 struct drm_compositor *ec = data;
2462 struct udev_device *event;
2463
2464 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002465
David Herrmannd7488c22012-03-11 20:05:21 +01002466 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002467 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002468
2469 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002470
2471 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002472}
2473
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002474static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002475drm_restore(struct weston_compositor *ec)
2476{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002477 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002478}
2479
2480static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002481drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002482{
2483 struct drm_compositor *d = (struct drm_compositor *) ec;
2484
Rob Bradfordd355b802013-05-31 18:09:55 +01002485 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002486
2487 wl_event_source_remove(d->udev_drm_source);
2488 wl_event_source_remove(d->drm_source);
2489
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002490 destroy_sprites(d);
2491
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002492 weston_compositor_shutdown(ec);
2493
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002494 if (d->gbm)
2495 gbm_device_destroy(d->gbm);
2496
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002497 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002498
Rob Bradford45c15b82013-07-26 16:29:35 +01002499 close(d->drm.fd);
2500
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002501 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002502}
2503
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002504static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002505drm_compositor_set_modes(struct drm_compositor *compositor)
2506{
2507 struct drm_output *output;
2508 struct drm_mode *drm_mode;
2509 int ret;
2510
2511 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002512 if (!output->current) {
2513 /* If something that would cause the output to
2514 * switch mode happened while in another vt, we
2515 * might not have a current drm_fb. In that case,
2516 * schedule a repaint and let drm_output_repaint
2517 * handle setting the mode. */
2518 weston_output_schedule_repaint(&output->base);
2519 continue;
2520 }
2521
Hardeningff39efa2013-09-18 23:56:35 +02002522 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002523 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002524 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002525 &output->connector_id, 1,
2526 &drm_mode->mode_info);
2527 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002528 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002529 "failed to set mode %dx%d for output at %d,%d: %m\n",
Daniel Stonef556ebe2015-05-21 08:28:58 +01002530 drm_mode->base.width, drm_mode->base.height,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002531 output->base.x, output->base.y);
2532 }
2533 }
2534}
2535
2536static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002537session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002538{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002539 struct weston_compositor *compositor = data;
2540 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002541 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002542 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002543
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002544 if (ec->base.session_active) {
2545 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002546 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002547 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002548 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002549 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002550 } else {
2551 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002552 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002553
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002554 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002555 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002556
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002557 /* If we have a repaint scheduled (either from a
2558 * pending pageflip or the idle handler), make sure we
2559 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002560 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002561 * further attemps at repainting. When we switch
2562 * back, we schedule a repaint, which will process
2563 * pending frame callbacks. */
2564
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002565 wl_list_for_each(output, &ec->base.output_list, base.link) {
2566 output->base.repaint_needed = 0;
2567 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002568 }
2569
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002570 output = container_of(ec->base.output_list.next,
2571 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002572
2573 wl_list_for_each(sprite, &ec->sprite_list, link)
2574 drmModeSetPlane(ec->drm.fd,
2575 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002576 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002577 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002578 };
2579}
2580
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002581static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002582switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002583{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002584 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002585
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002586 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002587}
2588
David Herrmann0af066f2012-10-29 19:21:16 +01002589/*
2590 * Find primary GPU
2591 * Some systems may have multiple DRM devices attached to a single seat. This
2592 * function loops over all devices and tries to find a PCI device with the
2593 * boot_vga sysfs attribute set to 1.
2594 * If no such device is found, the first DRM device reported by udev is used.
2595 */
2596static struct udev_device*
2597find_primary_gpu(struct drm_compositor *ec, const char *seat)
2598{
2599 struct udev_enumerate *e;
2600 struct udev_list_entry *entry;
2601 const char *path, *device_seat, *id;
2602 struct udev_device *device, *drm_device, *pci;
2603
2604 e = udev_enumerate_new(ec->udev);
2605 udev_enumerate_add_match_subsystem(e, "drm");
2606 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2607
2608 udev_enumerate_scan_devices(e);
2609 drm_device = NULL;
2610 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2611 path = udev_list_entry_get_name(entry);
2612 device = udev_device_new_from_syspath(ec->udev, path);
2613 if (!device)
2614 continue;
2615 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2616 if (!device_seat)
2617 device_seat = default_seat;
2618 if (strcmp(device_seat, seat)) {
2619 udev_device_unref(device);
2620 continue;
2621 }
2622
2623 pci = udev_device_get_parent_with_subsystem_devtype(device,
2624 "pci", NULL);
2625 if (pci) {
2626 id = udev_device_get_sysattr_value(pci, "boot_vga");
2627 if (id && !strcmp(id, "1")) {
2628 if (drm_device)
2629 udev_device_unref(drm_device);
2630 drm_device = device;
2631 break;
2632 }
2633 }
2634
2635 if (!drm_device)
2636 drm_device = device;
2637 else
2638 udev_device_unref(device);
2639 }
2640
2641 udev_enumerate_unref(e);
2642 return drm_device;
2643}
2644
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002645static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002646planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002647{
2648 struct drm_compositor *c = data;
2649
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002650 switch (key) {
2651 case KEY_C:
2652 c->cursors_are_broken ^= 1;
2653 break;
2654 case KEY_V:
2655 c->sprites_are_broken ^= 1;
2656 break;
2657 case KEY_O:
2658 c->sprites_hidden ^= 1;
2659 break;
2660 default:
2661 break;
2662 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002663}
2664
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002665#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002666static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002667recorder_destroy(struct drm_output *output)
2668{
2669 vaapi_recorder_destroy(output->recorder);
2670 output->recorder = NULL;
2671
2672 output->base.disable_planes--;
2673
2674 wl_list_remove(&output->recorder_frame_listener.link);
2675 weston_log("[libva recorder] done\n");
2676}
2677
2678static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002679recorder_frame_notify(struct wl_listener *listener, void *data)
2680{
2681 struct drm_output *output;
2682 struct drm_compositor *c;
2683 int fd, ret;
2684
2685 output = container_of(listener, struct drm_output,
2686 recorder_frame_listener);
2687 c = (struct drm_compositor *) output->base.compositor;
2688
2689 if (!output->recorder)
2690 return;
2691
2692 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2693 DRM_CLOEXEC, &fd);
2694 if (ret) {
2695 weston_log("[libva recorder] "
2696 "failed to create prime fd for front buffer\n");
2697 return;
2698 }
2699
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002700 ret = vaapi_recorder_frame(output->recorder, fd,
2701 output->current->stride);
2702 if (ret < 0) {
2703 weston_log("[libva recorder] aborted: %m\n");
2704 recorder_destroy(output);
2705 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002706}
2707
2708static void *
2709create_recorder(struct drm_compositor *c, int width, int height,
2710 const char *filename)
2711{
2712 int fd;
2713 drm_magic_t magic;
2714
2715 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2716 if (fd < 0)
2717 return NULL;
2718
2719 drmGetMagic(fd, &magic);
2720 drmAuthMagic(c->drm.fd, magic);
2721
2722 return vaapi_recorder_create(fd, width, height, filename);
2723}
2724
2725static void
2726recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2727 void *data)
2728{
2729 struct drm_compositor *c = data;
2730 struct drm_output *output;
2731 int width, height;
2732
2733 output = container_of(c->base.output_list.next,
2734 struct drm_output, base.link);
2735
2736 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002737 if (output->format != GBM_FORMAT_XRGB8888) {
2738 weston_log("failed to start vaapi recorder: "
2739 "output format not supported\n");
2740 return;
2741 }
2742
Hardeningff39efa2013-09-18 23:56:35 +02002743 width = output->base.current_mode->width;
2744 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002745
2746 output->recorder =
2747 create_recorder(c, width, height, "capture.h264");
2748 if (!output->recorder) {
2749 weston_log("failed to create vaapi recorder\n");
2750 return;
2751 }
2752
2753 output->base.disable_planes++;
2754
2755 output->recorder_frame_listener.notify = recorder_frame_notify;
2756 wl_signal_add(&output->base.frame_signal,
2757 &output->recorder_frame_listener);
2758
2759 weston_output_schedule_repaint(&output->base);
2760
2761 weston_log("[libva recorder] initialized\n");
2762 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002763 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002764 }
2765}
2766#else
2767static void
2768recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2769 void *data)
2770{
2771 weston_log("Compiled without libva support\n");
2772}
2773#endif
2774
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002775static void
2776switch_to_gl_renderer(struct drm_compositor *c)
2777{
2778 struct drm_output *output;
2779
2780 if (!c->use_pixman)
2781 return;
2782
2783 weston_log("Switching to GL renderer\n");
2784
2785 c->gbm = create_gbm_device(c->drm.fd);
2786 if (!c->gbm) {
2787 weston_log("Failed to create gbm device. "
2788 "Aborting renderer switch\n");
2789 return;
2790 }
2791
2792 wl_list_for_each(output, &c->base.output_list, base.link)
2793 pixman_renderer_output_destroy(&output->base);
2794
2795 c->base.renderer->destroy(&c->base);
2796
2797 if (drm_compositor_create_gl_renderer(c) < 0) {
2798 gbm_device_destroy(c->gbm);
2799 weston_log("Failed to create GL renderer. Quitting.\n");
2800 /* FIXME: we need a function to shutdown cleanly */
2801 assert(0);
2802 }
2803
2804 wl_list_for_each(output, &c->base.output_list, base.link)
2805 drm_output_init_egl(output, c);
2806
2807 c->use_pixman = 0;
2808}
2809
2810static void
2811renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2812 void *data)
2813{
2814 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2815
2816 switch_to_gl_renderer(c);
2817}
2818
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002819static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002820drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002821 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002822 int *argc, char *argv[],
2823 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002824{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002825 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002826 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002827 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002828 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002829 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002830 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002831
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002832 weston_log("initializing drm backend\n");
2833
Peter Huttererf3d62272013-08-08 11:57:05 +10002834 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002835 if (ec == NULL)
2836 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002837
Pekka Paalanen68583832015-05-19 09:53:16 +03002838 /*
2839 * KMS support for hardware planes cannot properly synchronize
2840 * without nuclear page flip. Without nuclear/atomic, hw plane
2841 * and cursor plane updates would either tear or cause extra
2842 * waits for vblanks which means dropping the compositor framerate
2843 * to a fraction.
2844 *
2845 * These can be enabled again when nuclear/atomic support lands.
2846 */
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002847 ec->sprites_are_broken = 1;
Pekka Paalanen68583832015-05-19 09:53:16 +03002848 ec->cursors_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002849
2850 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002851 if (get_gbm_format_from_section(section,
2852 GBM_FORMAT_XRGB8888,
2853 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002854 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002855
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002856 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002857
Daniel Stone725c2c32012-06-22 14:04:36 +01002858 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002859 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002860 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002861 goto err_base;
2862 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002863
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002864 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002865 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
David Herrmann2ecb84a2014-12-30 14:33:22 +01002866 param->seat_id, true);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002867 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002868 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002869 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002870 goto err_compositor;
2871 }
2872
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002873 ec->udev = udev_new();
2874 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002875 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002876 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002877 }
2878
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002879 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002880 ec->session_listener.notify = session_notify;
2881 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002882
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002883 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002884 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002885 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002886 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002887 }
David Herrmann0af066f2012-10-29 19:21:16 +01002888 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002889
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002890 if (init_drm(ec, drm_device) < 0) {
2891 weston_log("failed to initialize kms\n");
2892 goto err_udev_dev;
2893 }
2894
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002895 if (ec->use_pixman) {
2896 if (init_pixman(ec) < 0) {
2897 weston_log("failed to initialize pixman renderer\n");
2898 goto err_udev_dev;
2899 }
2900 } else {
2901 if (init_egl(ec) < 0) {
2902 weston_log("failed to initialize egl\n");
2903 goto err_udev_dev;
2904 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002905 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002906
2907 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002908 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002909
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002910 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002911
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002912 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002913 weston_compositor_add_key_binding(&ec->base, key,
2914 MODIFIER_CTRL | MODIFIER_ALT,
2915 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002916
Jesse Barnes58ef3792012-02-23 09:45:49 -05002917 wl_list_init(&ec->sprite_list);
2918 create_sprites(ec);
2919
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002920 if (udev_input_init(&ec->input,
2921 &ec->base, ec->udev, param->seat_id) < 0) {
2922 weston_log("failed to create input devices\n");
2923 goto err_sprite;
2924 }
2925
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002926 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002927 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002928 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002929 }
2930
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002931 /* A this point we have some idea of whether or not we have a working
2932 * cursor plane. */
2933 if (!ec->cursors_are_broken)
2934 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2935
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002936 path = NULL;
2937
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002938 loop = wl_display_get_event_loop(ec->base.wl_display);
2939 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002940 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002941 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002942
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002943 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2944 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002945 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002946 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002947 }
2948 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2949 "drm", NULL);
2950 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002951 wl_event_loop_add_fd(loop,
2952 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002953 WL_EVENT_READABLE, udev_drm_event, ec);
2954
2955 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002956 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002957 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002958 }
2959
Daniel Stonea96b93c2012-06-22 14:04:37 +01002960 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002961
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002962 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002963 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002964 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002965 planes_binding, ec);
2966 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2967 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002968 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2969 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002970 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2971 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002972
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002973 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002974
2975err_udev_monitor:
2976 wl_event_source_remove(ec->udev_drm_source);
2977 udev_monitor_unref(ec->udev_monitor);
2978err_drm_source:
2979 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002980err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002981 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002982err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002983 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002984 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002985 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002986err_udev_dev:
2987 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002988err_launcher:
2989 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002990err_udev:
2991 udev_unref(ec->udev);
2992err_compositor:
2993 weston_compositor_shutdown(&ec->base);
2994err_base:
2995 free(ec);
2996 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002997}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002998
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002999WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05003000backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04003001 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003002{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003003 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003004
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003005 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003006 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
3007 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
3008 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04003009 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003010 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003011 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02003012
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003013 param.seat_id = default_seat;
3014
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003015 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003016
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003017 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003018}