blob: ad708079bf2ffa99ddda16d36d965ff939bdaa08 [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
David Herrmann1edf44c2013-10-22 17:11:26 +0200600static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500601drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400602 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100603{
604 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500605 struct drm_compositor *compositor =
606 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500607 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400608 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500609 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100610
Xiong Zhangabd5d472013-10-11 14:43:07 +0800611 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200612 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800613
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300614 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400615 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300616 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200617 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100618
Hardeningff39efa2013-09-18 23:56:35 +0200619 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200620 if (!output->current ||
621 output->current->stride != output->next->stride) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400622 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300623 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400624 &output->connector_id, 1,
625 &mode->mode_info);
626 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200627 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200628 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400629 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300630 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200631 }
632
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500633 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300634 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500635 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200636 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200637 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500638 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100639
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300640 output->page_flip_pending = 1;
641
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400642 drm_output_set_cursor(output);
643
Jesse Barnes58ef3792012-02-23 09:45:49 -0500644 /*
645 * Now, update all the sprite surfaces
646 */
647 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200648 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500649 drmVBlank vbl = {
650 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
651 .request.sequence = 1,
652 };
653
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200654 if ((!s->current && !s->next) ||
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200655 !drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500656 continue;
657
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200658 if (s->next && !compositor->sprites_hidden)
659 fb_id = s->next->fb_id;
660
Jesse Barnes58ef3792012-02-23 09:45:49 -0500661 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200662 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500663 s->dest_x, s->dest_y,
664 s->dest_w, s->dest_h,
665 s->src_x, s->src_y,
666 s->src_w, s->src_h);
667 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200668 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500669 ret, strerror(errno));
670
Rob Clark5ca1a472012-08-08 20:27:37 -0500671 if (output->pipe > 0)
672 vbl.request.type |= DRM_VBLANK_SECONDARY;
673
Jesse Barnes58ef3792012-02-23 09:45:49 -0500674 /*
675 * Queue a vblank signal so we know when the surface
676 * becomes active on the display or has been replaced.
677 */
678 vbl.request.signal = (unsigned long)s;
679 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
680 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200681 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500682 ret, strerror(errno));
683 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300684
685 s->output = output;
686 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500687 }
688
David Herrmann1edf44c2013-10-22 17:11:26 +0200689 return 0;
690
691err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800692 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200693 if (output->next) {
694 drm_output_release_fb(output, output->next);
695 output->next = NULL;
696 }
697
698 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400699}
700
701static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200702drm_output_start_repaint_loop(struct weston_output *output_base)
703{
704 struct drm_output *output = (struct drm_output *) output_base;
705 struct drm_compositor *compositor = (struct drm_compositor *)
706 output_base->compositor;
707 uint32_t fb_id;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300708 struct timespec ts;
709
Xiong Zhangabd5d472013-10-11 14:43:07 +0800710 if (output->destroy_pending)
711 return;
712
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300713 if (!output->current) {
714 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200715 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300716 }
717
718 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200719
720 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
721 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
722 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200723 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200724 }
David Herrmann3c688c52013-10-22 17:11:25 +0200725
726 return;
727
728finish_frame:
729 /* if we cannot page-flip, immediately finish frame */
Pekka Paalanen662f3842015-03-18 12:17:26 +0200730 weston_compositor_read_presentation_clock(&compositor->base, &ts);
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200731 weston_output_finish_frame(output_base, &ts,
732 PRESENTATION_FEEDBACK_INVALID);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200733}
734
735static void
Pekka Paalanen641307c2014-09-23 22:08:47 -0400736drm_output_update_msc(struct drm_output *output, unsigned int seq)
737{
738 uint64_t msc_hi = output->base.msc >> 32;
739
740 if (seq < (output->base.msc & 0xffffffff))
741 msc_hi++;
742
743 output->base.msc = (msc_hi << 32) + seq;
744}
745
746static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500747vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
748 void *data)
749{
750 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300751 struct drm_output *output = s->output;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400752 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200753 uint32_t flags = PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
754 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300755
Pekka Paalanen641307c2014-09-23 22:08:47 -0400756 drm_output_update_msc(output, frame);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300757 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500758
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200759 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200760 s->current = s->next;
761 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300762
763 if (!output->page_flip_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400764 ts.tv_sec = sec;
765 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200766 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300767 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500768}
769
770static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800771drm_output_destroy(struct weston_output *output_base);
772
773static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400774page_flip_handler(int fd, unsigned int frame,
775 unsigned int sec, unsigned int usec, void *data)
776{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200777 struct drm_output *output = (struct drm_output *) data;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400778 struct timespec ts;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200779 uint32_t flags = PRESENTATION_FEEDBACK_KIND_VSYNC |
780 PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
781 PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400782
Pekka Paalanen641307c2014-09-23 22:08:47 -0400783 drm_output_update_msc(output, frame);
784
Jonas Ådahle5a12252013-04-05 23:07:11 +0200785 /* We don't set page_flip_pending on start_repaint_loop, in that case
786 * we just want to page flip to the current buffer to get an accurate
787 * timestamp */
788 if (output->page_flip_pending) {
789 drm_output_release_fb(output, output->current);
790 output->current = output->next;
791 output->next = NULL;
792 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300793
Jonas Ådahle5a12252013-04-05 23:07:11 +0200794 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400795
Xiong Zhangabd5d472013-10-11 14:43:07 +0800796 if (output->destroy_pending)
797 drm_output_destroy(&output->base);
798 else if (!output->vblank_pending) {
Pekka Paalanenb5eedad2014-09-23 22:08:45 -0400799 ts.tv_sec = sec;
800 ts.tv_nsec = usec * 1000;
Pekka Paalanen363aa7b2014-12-17 16:20:40 +0200801 weston_output_finish_frame(&output->base, &ts, flags);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300802
803 /* We can't call this from frame_notify, because the output's
804 * repaint needed flag is cleared just after that */
805 if (output->recorder)
806 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300807 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200808}
809
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500810static uint32_t
811drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500812 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500813{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500814 uint32_t i, format;
815
816 format = gbm_bo_get_format(bo);
817
818 if (format == GBM_FORMAT_ARGB8888) {
819 pixman_region32_t r;
820
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500821 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600822 ev->surface->width,
823 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500824 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500825
826 if (!pixman_region32_not_empty(&r))
827 format = GBM_FORMAT_XRGB8888;
828
829 pixman_region32_fini(&r);
830 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500831
832 for (i = 0; i < s->count_formats; i++)
833 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500834 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500835
836 return 0;
837}
838
839static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500840drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500841{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500842 return !ev->transform.enabled ||
843 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500844}
845
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400846static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200847drm_output_prepare_overlay_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500848 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500849{
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200850 struct weston_compositor *ec = output->base.compositor;
851 struct drm_compositor *c = (struct drm_compositor *)ec;
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200852 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500853 struct drm_sprite *s;
854 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500855 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500856 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200857 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500858 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400859 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500860
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200861 if (c->gbm == NULL)
862 return NULL;
863
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200864 if (viewport->buffer.transform != output->base.transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200865 return NULL;
866
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200867 if (viewport->buffer.scale != output->base.current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200868 return NULL;
869
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500870 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400871 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500872
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200873 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400874 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300875
Jason Ekstranda7af7042013-10-12 22:38:11 -0500876 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400877 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500878
Jason Ekstranda7af7042013-10-12 22:38:11 -0500879 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200880 return NULL;
881
Jason Ekstranda7af7042013-10-12 22:38:11 -0500882 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500883 return NULL;
884
Jason Ekstranda7af7042013-10-12 22:38:11 -0500885 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400886 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500887
Jesse Barnes58ef3792012-02-23 09:45:49 -0500888 wl_list_for_each(s, &c->sprite_list, link) {
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200889 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500890 continue;
891
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200892 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500893 found = 1;
894 break;
895 }
896 }
897
898 /* No sprites available */
899 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400900 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500901
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400902 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500903 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700904 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400905 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400906 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400907
Jason Ekstranda7af7042013-10-12 22:38:11 -0500908 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500909 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200910 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400911 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500912 }
913
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200914 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200915 if (!s->next) {
916 gbm_bo_destroy(bo);
917 return NULL;
918 }
919
Jason Ekstranda7af7042013-10-12 22:38:11 -0500920 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500921
Jason Ekstranda7af7042013-10-12 22:38:11 -0500922 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400923 s->plane.x = box->x1;
924 s->plane.y = box->y1;
925
Jesse Barnes58ef3792012-02-23 09:45:49 -0500926 /*
927 * Calculate the source & dest rects properly based on actual
Derek Foreman4b1a0a12014-09-10 15:37:33 -0500928 * position (note the caller has called weston_view_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500929 * for us already).
930 */
931 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500932 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200933 &output->base.region);
934 pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500935 box = pixman_region32_extents(&dest_rect);
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200936 tbox = weston_transformed_rect(output->base.width,
937 output->base.height,
938 output->base.transform,
939 output->base.current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200940 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200941 s->dest_x = tbox.x1;
942 s->dest_y = tbox.y1;
943 s->dest_w = tbox.x2 - tbox.x1;
944 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500945 pixman_region32_fini(&dest_rect);
946
947 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500948 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200949 &output->base.region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500950 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400951
Jason Ekstranda7af7042013-10-12 22:38:11 -0500952 weston_view_from_global_fixed(ev,
953 wl_fixed_from_int(box->x1),
954 wl_fixed_from_int(box->y1),
955 &sx1, &sy1);
956 weston_view_from_global_fixed(ev,
957 wl_fixed_from_int(box->x2),
958 wl_fixed_from_int(box->y2),
959 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400960
961 if (sx1 < 0)
962 sx1 = 0;
963 if (sy1 < 0)
964 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600965 if (sx2 > wl_fixed_from_int(ev->surface->width))
966 sx2 = wl_fixed_from_int(ev->surface->width);
967 if (sy2 > wl_fixed_from_int(ev->surface->height))
968 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400969
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200970 tbox.x1 = sx1;
971 tbox.y1 = sy1;
972 tbox.x2 = sx2;
973 tbox.y2 = sy2;
974
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600975 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
976 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen952b6c82014-03-14 14:38:15 +0200977 viewport->buffer.transform,
978 viewport->buffer.scale,
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100979 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200980
981 s->src_x = tbox.x1 << 8;
982 s->src_y = tbox.y1 << 8;
983 s->src_w = (tbox.x2 - tbox.x1) << 8;
984 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500985 pixman_region32_fini(&src_rect);
986
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400987 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500988}
989
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400990static struct weston_plane *
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200991drm_output_prepare_cursor_view(struct drm_output *output,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500992 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500993{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400994 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +0200995 (struct drm_compositor *)output->base.compositor;
Neil Robertsf37f82c2014-05-01 18:00:41 +0100996 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400997
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200998 if (c->gbm == NULL)
999 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +02001000 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
1001 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001002 if (viewport->buffer.scale != output->base.current_scale)
Neil Robertsf37f82c2014-05-01 18:00:41 +01001003 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001004 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001005 return NULL;
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001006 if (ev->output_mask != (1u << output->base.id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001007 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -05001008 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -04001009 return NULL;
Pekka Paalanen5580f222015-02-17 16:33:18 +02001010 if (ev->geometry.scissor_enabled)
1011 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001012 if (ev->surface->buffer_ref.buffer == NULL ||
1013 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001014 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001015 return NULL;
1016
Jason Ekstranda7af7042013-10-12 22:38:11 -05001017 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001018
1019 return &output->cursor_plane;
1020}
1021
1022static void
1023drm_output_set_cursor(struct drm_output *output)
1024{
Jason Ekstranda7af7042013-10-12 22:38:11 -05001025 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +00001026 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001027 struct drm_compositor *c =
1028 (struct drm_compositor *) output->base.compositor;
1029 EGLint handle, stride;
1030 struct gbm_bo *bo;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001031 uint32_t buf[c->cursor_width * c->cursor_height];
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001032 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001033 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001034
Jason Ekstranda7af7042013-10-12 22:38:11 -05001035 output->cursor_view = NULL;
1036 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001037 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
1038 return;
1039 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001040
Neil Robertse5051712013-11-13 15:44:06 +00001041 buffer = ev->surface->buffer_ref.buffer;
1042
1043 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +02001044 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001045 pixman_region32_fini(&output->cursor_plane.damage);
1046 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001047 output->current_cursor ^= 1;
1048 bo = output->cursor_bo[output->current_cursor];
1049 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001050 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1051 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1052 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001053 for (i = 0; i < ev->surface->height; i++)
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001054 memcpy(buf + i * c->cursor_width, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001055 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001056 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001057
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001058 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001059 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001060
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001061 handle = gbm_bo_get_handle(bo).s32;
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001062 if (drmModeSetCursor(c->drm.fd, output->crtc_id, handle,
1063 c->cursor_width, c->cursor_height)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001064 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001065 c->cursors_are_broken = 1;
1066 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001067 }
1068
Jason Ekstranda7af7042013-10-12 22:38:11 -05001069 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1070 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001071 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001072 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001073 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001074 c->cursors_are_broken = 1;
1075 }
1076
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001077 output->cursor_plane.x = x;
1078 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001079 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001080}
1081
Jesse Barnes58ef3792012-02-23 09:45:49 -05001082static void
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001083drm_assign_planes(struct weston_output *output_base)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001084{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001085 struct drm_compositor *c =
Pekka Paalanen050c1ba2014-12-17 16:20:38 +02001086 (struct drm_compositor *)output_base->compositor;
1087 struct drm_output *output = (struct drm_output *)output_base;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001088 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001089 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001090 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001091
1092 /*
1093 * Find a surface for each sprite in the output using some heuristics:
1094 * 1) size
1095 * 2) frequency of update
1096 * 3) opacity (though some hw might support alpha blending)
1097 * 4) clipping (this can be fixed with color keys)
1098 *
1099 * The idea is to save on blitting since this should save power.
1100 * If we can get a large video surface on the sprite for example,
1101 * the main display surface may not need to update at all, and
1102 * the client buffer can be used directly for the sprite surface
1103 * as we do for flipping full screen surfaces.
1104 */
1105 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001106 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001107
Jason Ekstranda7af7042013-10-12 22:38:11 -05001108 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001109 struct weston_surface *es = ev->surface;
1110
1111 /* Test whether this buffer can ever go into a plane:
1112 * non-shm, or small enough to be a cursor.
1113 *
1114 * Also, keep a reference when using the pixman renderer.
1115 * That makes it possible to do a seamless switch to the GL
1116 * renderer and since the pixman renderer keeps a reference
1117 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001118 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001119 if (c->use_pixman ||
1120 (es->buffer_ref.buffer &&
1121 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001122 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001123 es->keep_buffer = true;
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001124 else
Derek Foreman0fd6d4e2014-10-10 09:36:45 -05001125 es->keep_buffer = false;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001126
Jesse Barnes58ef3792012-02-23 09:45:49 -05001127 pixman_region32_init(&surface_overlap);
1128 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001129 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001130
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001131 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001132 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001133 next_plane = primary;
1134 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001135 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001136 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001137 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001138 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001139 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001140 if (next_plane == NULL)
1141 next_plane = primary;
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001142
Jason Ekstranda7af7042013-10-12 22:38:11 -05001143 weston_view_move_to_plane(ev, next_plane);
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001144
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001145 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001146 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001147 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001148
Pekka Paalanenbf0e0312014-12-17 16:20:41 +02001149 if (next_plane == primary ||
1150 next_plane == &output->cursor_plane) {
1151 /* cursor plane involves a copy */
1152 ev->psf_flags = 0;
1153 } else {
1154 /* All other planes are a direct scanout of a
1155 * single client buffer.
1156 */
1157 ev->psf_flags = PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
1158 }
1159
Jesse Barnes58ef3792012-02-23 09:45:49 -05001160 pixman_region32_fini(&surface_overlap);
1161 }
1162 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001163}
1164
Matt Roper361d2ad2011-08-29 13:52:23 -07001165static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001166drm_output_fini_pixman(struct drm_output *output);
1167
1168static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001169drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001170{
1171 struct drm_output *output = (struct drm_output *) output_base;
1172 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001173 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001174 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001175
Xiong Zhangabd5d472013-10-11 14:43:07 +08001176 if (output->page_flip_pending) {
1177 output->destroy_pending = 1;
1178 weston_log("destroy output while page flip pending\n");
1179 return;
1180 }
1181
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001182 if (output->backlight)
1183 backlight_destroy(output->backlight);
1184
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001185 drmModeFreeProperty(output->dpms_prop);
1186
Matt Roper361d2ad2011-08-29 13:52:23 -07001187 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001188 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001189
1190 /* Restore original CRTC state */
1191 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001192 origcrtc->x, origcrtc->y,
1193 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001194 drmModeFreeCrtc(origcrtc);
1195
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001196 c->crtc_allocator &= ~(1 << output->crtc_id);
1197 c->connector_allocator &= ~(1 << output->connector_id);
1198
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001199 if (c->use_pixman) {
1200 drm_output_fini_pixman(output);
1201 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001202 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001203 gbm_surface_destroy(output->surface);
1204 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001205
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001206 weston_plane_release(&output->fb_plane);
1207 weston_plane_release(&output->cursor_plane);
1208
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001209 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001210
Matt Roper361d2ad2011-08-29 13:52:23 -07001211 free(output);
1212}
1213
Alex Wub7b8bda2012-04-17 17:20:48 +08001214static struct drm_mode *
1215choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1216{
1217 struct drm_mode *tmp_mode = NULL, *mode;
1218
Hardeningff39efa2013-09-18 23:56:35 +02001219 if (output->base.current_mode->width == target_mode->width &&
1220 output->base.current_mode->height == target_mode->height &&
1221 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001222 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001223 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001224
1225 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1226 if (mode->mode_info.hdisplay == target_mode->width &&
1227 mode->mode_info.vdisplay == target_mode->height) {
Mario Kleiner872797c2015-06-21 21:25:09 +02001228 if (mode->base.refresh == target_mode->refresh ||
1229 target_mode->refresh == 0) {
Alex Wub7b8bda2012-04-17 17:20:48 +08001230 return mode;
Daniel Stonef556ebe2015-05-21 08:28:58 +01001231 } else if (!tmp_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001232 tmp_mode = mode;
1233 }
1234 }
1235
1236 return tmp_mode;
1237}
1238
1239static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001240drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001241static int
1242drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001243
1244static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001245drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1246{
1247 struct drm_output *output;
1248 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001249 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001250
1251 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001252 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001253 return -1;
1254 }
1255
1256 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001257 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001258 return -1;
1259 }
1260
1261 ec = (struct drm_compositor *)output_base->compositor;
1262 output = (struct drm_output *)output_base;
1263 drm_mode = choose_mode (output, mode);
1264
1265 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001266 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001267 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001268 }
1269
Hardeningff39efa2013-09-18 23:56:35 +02001270 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001271 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001272
Hardeningff39efa2013-09-18 23:56:35 +02001273 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001274
Hardeningff39efa2013-09-18 23:56:35 +02001275 output->base.current_mode = &drm_mode->base;
1276 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001277 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1278
Alex Wub7b8bda2012-04-17 17:20:48 +08001279 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001280 drm_output_release_fb(output, output->current);
1281 drm_output_release_fb(output, output->next);
1282 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001283
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001284 if (ec->use_pixman) {
1285 drm_output_fini_pixman(output);
1286 if (drm_output_init_pixman(output, ec) < 0) {
1287 weston_log("failed to init output pixman state with "
1288 "new mode\n");
1289 return -1;
1290 }
1291 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001292 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001293 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001294
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001295 if (drm_output_init_egl(output, ec) < 0) {
1296 weston_log("failed to init output egl state with "
1297 "new mode");
1298 return -1;
1299 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001300 }
1301
Alex Wub7b8bda2012-04-17 17:20:48 +08001302 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001303}
1304
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001305static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001306on_drm_input(int fd, uint32_t mask, void *data)
1307{
1308 drmEventContext evctx;
1309
1310 memset(&evctx, 0, sizeof evctx);
1311 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1312 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001313 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001314 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001315
1316 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001317}
1318
1319static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001320init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001321{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001322 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001323 uint64_t cap;
1324 int fd, ret;
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001325 clockid_t clk_id;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001326
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001327 sysnum = udev_device_get_sysnum(device);
1328 if (sysnum)
1329 ec->drm.id = atoi(sysnum);
1330 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001331 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001332 return -1;
1333 }
1334
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001335 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001336 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001337 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001338 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001339 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001340 udev_device_get_devnode(device));
1341 return -1;
1342 }
1343
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001344 weston_log("using %s\n", filename);
1345
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001346 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001347 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001348
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001349 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1350 if (ret == 0 && cap == 1)
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001351 clk_id = CLOCK_MONOTONIC;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001352 else
Pekka Paalanenb5eedad2014-09-23 22:08:45 -04001353 clk_id = CLOCK_REALTIME;
1354
1355 if (weston_compositor_set_presentation_clock(&ec->base, clk_id) < 0) {
1356 weston_log("Error: failed to set presentation clock %d.\n",
1357 clk_id);
1358 return -1;
1359 }
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001360
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001361 ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
1362 if (ret == 0)
1363 ec->cursor_width = cap;
1364 else
1365 ec->cursor_width = 64;
1366
1367 ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
1368 if (ret == 0)
1369 ec->cursor_height = cap;
1370 else
1371 ec->cursor_height = 64;
1372
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001373 return 0;
1374}
1375
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001376static struct gbm_device *
1377create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001378{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001379 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001380
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001381 gl_renderer = weston_load_module("gl-renderer.so",
1382 "gl_renderer_interface");
1383 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001384 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001385
1386 /* GBM will load a dri driver, but even though they need symbols from
1387 * libglapi, in some version of Mesa they are not linked to it. Since
1388 * only the gl-renderer module links to it, the call above won't make
1389 * these symbols globally available, and loading the DRI driver fails.
1390 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1391 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1392
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001393 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001394
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001395 return gbm;
1396}
1397
Bryce Harringtonc056a982015-05-19 15:25:18 -07001398/* When initializing EGL, if the preferred buffer format isn't available
Derek Foremanc4cfe852015-05-15 12:12:40 -05001399 * we may be able to susbstitute an ARGB format for an XRGB one.
1400 *
1401 * This returns 0 if substitution isn't possible, but 0 might be a
1402 * legitimate format for other EGL platforms, so the caller is
1403 * responsible for checking for 0 before calling gl_renderer->create().
1404 *
1405 * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
1406 * but it's entirely possible we'll see this again on other implementations.
1407 */
1408static int
1409fallback_format_for(uint32_t format)
1410{
1411 switch (format) {
1412 case GBM_FORMAT_XRGB8888:
1413 return GBM_FORMAT_ARGB8888;
1414 case GBM_FORMAT_XRGB2101010:
1415 return GBM_FORMAT_ARGB2101010;
1416 default:
1417 return 0;
1418 }
1419}
1420
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001421static int
1422drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1423{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001424 EGLint format[2] = {
1425 ec->format,
1426 fallback_format_for(ec->format),
1427 };
1428 int n_formats = 1;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001429
Derek Foremanc4cfe852015-05-15 12:12:40 -05001430 if (format[1])
1431 n_formats = 2;
1432 if (gl_renderer->create(&ec->base,
1433 EGL_PLATFORM_GBM_KHR,
1434 (void *)ec->gbm,
1435 gl_renderer->opaque_attribs,
1436 format,
1437 n_formats) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001438 return -1;
1439 }
1440
1441 return 0;
1442}
1443
1444static int
1445init_egl(struct drm_compositor *ec)
1446{
1447 ec->gbm = create_gbm_device(ec->drm.fd);
1448
1449 if (!ec->gbm)
1450 return -1;
1451
1452 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001453 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001454 return -1;
1455 }
1456
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001457 return 0;
1458}
1459
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001460static int
1461init_pixman(struct drm_compositor *ec)
1462{
1463 return pixman_renderer_init(&ec->base);
1464}
1465
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001466static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001467drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001468{
1469 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001470 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001471
1472 mode = malloc(sizeof *mode);
1473 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001474 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001475
1476 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001477 mode->base.width = info->hdisplay;
1478 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001479
1480 /* Calculate higher precision (mHz) refresh rate */
1481 refresh = (info->clock * 1000000LL / info->htotal +
1482 info->vtotal / 2) / info->vtotal;
1483
1484 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1485 refresh *= 2;
1486 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1487 refresh /= 2;
1488 if (info->vscan > 1)
1489 refresh /= info->vscan;
1490
1491 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001492 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001493
1494 if (info->type & DRM_MODE_TYPE_PREFERRED)
1495 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1496
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001497 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1498
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001499 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001500}
1501
1502static int
1503drm_subpixel_to_wayland(int drm_value)
1504{
1505 switch (drm_value) {
1506 default:
1507 case DRM_MODE_SUBPIXEL_UNKNOWN:
1508 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1509 case DRM_MODE_SUBPIXEL_NONE:
1510 return WL_OUTPUT_SUBPIXEL_NONE;
1511 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1512 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1513 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1514 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1515 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1516 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1517 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1518 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1519 }
1520}
1521
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001522/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001523static uint32_t
1524drm_get_backlight(struct drm_output *output)
1525{
1526 long brightness, max_brightness, norm;
1527
1528 brightness = backlight_get_brightness(output->backlight);
1529 max_brightness = backlight_get_max_brightness(output->backlight);
1530
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001531 /* convert it on a scale of 0 to 255 */
1532 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001533
1534 return (uint32_t) norm;
1535}
1536
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001537/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001538static void
1539drm_set_backlight(struct weston_output *output_base, uint32_t value)
1540{
1541 struct drm_output *output = (struct drm_output *) output_base;
1542 long max_brightness, new_brightness;
1543
1544 if (!output->backlight)
1545 return;
1546
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001547 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001548 return;
1549
1550 max_brightness = backlight_get_max_brightness(output->backlight);
1551
1552 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001553 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001554
1555 backlight_set_brightness(output->backlight, new_brightness);
1556}
1557
1558static drmModePropertyPtr
1559drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1560{
1561 drmModePropertyPtr props;
1562 int i;
1563
1564 for (i = 0; i < connector->count_props; i++) {
1565 props = drmModeGetProperty(fd, connector->props[i]);
1566 if (!props)
1567 continue;
1568
1569 if (!strcmp(props->name, name))
1570 return props;
1571
1572 drmModeFreeProperty(props);
1573 }
1574
1575 return NULL;
1576}
1577
1578static void
1579drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1580{
1581 struct drm_output *output = (struct drm_output *) output_base;
1582 struct weston_compositor *ec = output_base->compositor;
1583 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001584
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001585 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001586 return;
1587
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001588 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1589 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001590}
1591
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001592static const char *connector_type_names[] = {
1593 "None",
1594 "VGA",
1595 "DVI",
1596 "DVI",
1597 "DVI",
1598 "Composite",
1599 "TV",
1600 "LVDS",
1601 "CTV",
1602 "DIN",
1603 "DP",
1604 "HDMI",
1605 "HDMI",
1606 "TV",
1607 "eDP",
1608};
1609
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001610static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001611find_crtc_for_connector(struct drm_compositor *ec,
1612 drmModeRes *resources, drmModeConnector *connector)
1613{
1614 drmModeEncoder *encoder;
1615 uint32_t possible_crtcs;
1616 int i, j;
1617
1618 for (j = 0; j < connector->count_encoders; j++) {
1619 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1620 if (encoder == NULL) {
1621 weston_log("Failed to get encoder.\n");
1622 return -1;
1623 }
1624 possible_crtcs = encoder->possible_crtcs;
1625 drmModeFreeEncoder(encoder);
1626
1627 for (i = 0; i < resources->count_crtcs; i++) {
1628 if (possible_crtcs & (1 << i) &&
1629 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1630 return i;
1631 }
1632 }
1633
1634 return -1;
1635}
1636
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001637/* Init output state that depends on gl or gbm */
1638static int
1639drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1640{
Derek Foremanc4cfe852015-05-15 12:12:40 -05001641 EGLint format[2] = {
1642 output->format,
1643 fallback_format_for(output->format),
1644 };
1645 int i, flags, n_formats = 1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001646
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001647 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001648 output->base.current_mode->width,
1649 output->base.current_mode->height,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001650 format[0],
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001651 GBM_BO_USE_SCANOUT |
1652 GBM_BO_USE_RENDERING);
1653 if (!output->surface) {
1654 weston_log("failed to create gbm surface\n");
1655 return -1;
1656 }
1657
Derek Foremanc4cfe852015-05-15 12:12:40 -05001658 if (format[1])
1659 n_formats = 2;
Jonny Lamb671148f2015-03-20 15:26:52 +01001660 if (gl_renderer->output_create(&output->base,
Jonny Lamb445fb692015-03-24 13:12:01 +01001661 (EGLNativeDisplayType)output->surface,
1662 output->surface,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001663 gl_renderer->opaque_attribs,
Derek Foremanc4cfe852015-05-15 12:12:40 -05001664 format,
1665 n_formats) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001666 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001667 gbm_surface_destroy(output->surface);
1668 return -1;
1669 }
1670
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001671 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001672
1673 for (i = 0; i < 2; i++) {
1674 if (output->cursor_bo[i])
1675 continue;
1676
1677 output->cursor_bo[i] =
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001678 gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
1679 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001680 }
1681
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001682 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1683 weston_log("cursor buffers unavailable, using gl cursors\n");
1684 ec->cursors_are_broken = 1;
1685 }
1686
1687 return 0;
1688}
1689
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001690static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001691drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1692{
Hardeningff39efa2013-09-18 23:56:35 +02001693 int w = output->base.current_mode->width;
1694 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001695 unsigned int i;
1696
1697 /* FIXME error checking */
1698
1699 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001700 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001701 if (!output->dumb[i])
1702 goto err;
1703
1704 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001705 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001706 output->dumb[i]->map,
1707 output->dumb[i]->stride);
1708 if (!output->image[i])
1709 goto err;
1710 }
1711
1712 if (pixman_renderer_output_create(&output->base) < 0)
1713 goto err;
1714
1715 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001716 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001717
1718 return 0;
1719
1720err:
1721 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1722 if (output->dumb[i])
1723 drm_fb_destroy_dumb(output->dumb[i]);
1724 if (output->image[i])
1725 pixman_image_unref(output->image[i]);
1726
1727 output->dumb[i] = NULL;
1728 output->image[i] = NULL;
1729 }
1730
1731 return -1;
1732}
1733
1734static void
1735drm_output_fini_pixman(struct drm_output *output)
1736{
1737 unsigned int i;
1738
1739 pixman_renderer_output_destroy(&output->base);
1740 pixman_region32_fini(&output->previous_damage);
1741
1742 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1743 drm_fb_destroy_dumb(output->dumb[i]);
1744 pixman_image_unref(output->image[i]);
1745 output->dumb[i] = NULL;
1746 output->image[i] = NULL;
1747 }
1748}
1749
Richard Hughes2b2092a2013-04-24 14:58:02 +01001750static void
1751edid_parse_string(const uint8_t *data, char text[])
1752{
1753 int i;
1754 int replaced = 0;
1755
1756 /* this is always 12 bytes, but we can't guarantee it's null
1757 * terminated or not junk. */
1758 strncpy(text, (const char *) data, 12);
1759
1760 /* remove insane chars */
1761 for (i = 0; text[i] != '\0'; i++) {
1762 if (text[i] == '\n' ||
1763 text[i] == '\r') {
1764 text[i] = '\0';
1765 break;
1766 }
1767 }
1768
1769 /* ensure string is printable */
1770 for (i = 0; text[i] != '\0'; i++) {
1771 if (!isprint(text[i])) {
1772 text[i] = '-';
1773 replaced++;
1774 }
1775 }
1776
1777 /* if the string is random junk, ignore the string */
1778 if (replaced > 4)
1779 text[0] = '\0';
1780}
1781
1782#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1783#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1784#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1785#define EDID_OFFSET_DATA_BLOCKS 0x36
1786#define EDID_OFFSET_LAST_BLOCK 0x6c
1787#define EDID_OFFSET_PNPID 0x08
1788#define EDID_OFFSET_SERIAL 0x0c
1789
1790static int
1791edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1792{
1793 int i;
1794 uint32_t serial_number;
1795
1796 /* check header */
1797 if (length < 128)
1798 return -1;
1799 if (data[0] != 0x00 || data[1] != 0xff)
1800 return -1;
1801
1802 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1803 * /--08--\/--09--\
1804 * 7654321076543210
1805 * |\---/\---/\---/
1806 * R C1 C2 C3 */
1807 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1808 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1809 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1810 edid->pnp_id[3] = '\0';
1811
1812 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1813 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1814 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1815 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1816 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1817 if (serial_number > 0)
1818 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1819
1820 /* parse EDID data */
1821 for (i = EDID_OFFSET_DATA_BLOCKS;
1822 i <= EDID_OFFSET_LAST_BLOCK;
1823 i += 18) {
1824 /* ignore pixel clock data */
1825 if (data[i] != 0)
1826 continue;
1827 if (data[i+2] != 0)
1828 continue;
1829
1830 /* any useful blocks? */
1831 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1832 edid_parse_string(&data[i+5],
1833 edid->monitor_name);
1834 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1835 edid_parse_string(&data[i+5],
1836 edid->serial_number);
1837 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1838 edid_parse_string(&data[i+5],
1839 edid->eisa_id);
1840 }
1841 }
1842 return 0;
1843}
1844
1845static void
1846find_and_parse_output_edid(struct drm_compositor *ec,
1847 struct drm_output *output,
1848 drmModeConnector *connector)
1849{
1850 drmModePropertyBlobPtr edid_blob = NULL;
1851 drmModePropertyPtr property;
1852 int i;
1853 int rc;
1854
1855 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1856 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1857 if (!property)
1858 continue;
1859 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1860 !strcmp(property->name, "EDID")) {
1861 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1862 connector->prop_values[i]);
1863 }
1864 drmModeFreeProperty(property);
1865 }
1866 if (!edid_blob)
1867 return;
1868
1869 rc = edid_parse(&output->edid,
1870 edid_blob->data,
1871 edid_blob->length);
1872 if (!rc) {
1873 weston_log("EDID data '%s', '%s', '%s'\n",
1874 output->edid.pnp_id,
1875 output->edid.monitor_name,
1876 output->edid.serial_number);
1877 if (output->edid.pnp_id[0] != '\0')
1878 output->base.make = output->edid.pnp_id;
1879 if (output->edid.monitor_name[0] != '\0')
1880 output->base.model = output->edid.monitor_name;
1881 if (output->edid.serial_number[0] != '\0')
1882 output->base.serial_number = output->edid.serial_number;
1883 }
1884 drmModeFreePropertyBlob(edid_blob);
1885}
1886
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001887
1888
1889static int
1890parse_modeline(const char *s, drmModeModeInfo *mode)
1891{
1892 char hsync[16];
1893 char vsync[16];
1894 float fclock;
1895
1896 mode->type = DRM_MODE_TYPE_USERDEF;
1897 mode->hskew = 0;
1898 mode->vscan = 0;
1899 mode->vrefresh = 0;
1900 mode->flags = 0;
1901
Rob Bradford307e09e2013-07-26 16:29:40 +01001902 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001903 &fclock,
1904 &mode->hdisplay,
1905 &mode->hsync_start,
1906 &mode->hsync_end,
1907 &mode->htotal,
1908 &mode->vdisplay,
1909 &mode->vsync_start,
1910 &mode->vsync_end,
1911 &mode->vtotal, hsync, vsync) != 11)
1912 return -1;
1913
1914 mode->clock = fclock * 1000;
1915 if (strcmp(hsync, "+hsync") == 0)
1916 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1917 else if (strcmp(hsync, "-hsync") == 0)
1918 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1919 else
1920 return -1;
1921
1922 if (strcmp(vsync, "+vsync") == 0)
1923 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1924 else if (strcmp(vsync, "-vsync") == 0)
1925 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1926 else
1927 return -1;
1928
1929 return 0;
1930}
1931
Rob Bradford66bd9f52013-06-25 18:56:42 +01001932static void
1933setup_output_seat_constraint(struct drm_compositor *ec,
1934 struct weston_output *output,
1935 const char *s)
1936{
1937 if (strcmp(s, "") != 0) {
1938 struct udev_seat *seat;
1939
Jonas Ådahl58e15862014-03-12 22:08:40 +01001940 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001941 if (seat)
1942 seat->base.output = output;
1943
1944 if (seat && seat->base.pointer)
1945 weston_pointer_clamp(seat->base.pointer,
1946 &seat->base.pointer->x,
1947 &seat->base.pointer->y);
1948 }
1949}
1950
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001951static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001952get_gbm_format_from_section(struct weston_config_section *section,
1953 uint32_t default_value,
1954 uint32_t *format)
1955{
1956 char *s;
1957 int ret = 0;
1958
1959 weston_config_section_get_string(section,
1960 "gbm-format", &s, NULL);
1961
1962 if (s == NULL)
1963 *format = default_value;
1964 else if (strcmp(s, "xrgb8888") == 0)
1965 *format = GBM_FORMAT_XRGB8888;
1966 else if (strcmp(s, "rgb565") == 0)
1967 *format = GBM_FORMAT_RGB565;
1968 else if (strcmp(s, "xrgb2101010") == 0)
1969 *format = GBM_FORMAT_XRGB2101010;
1970 else {
1971 weston_log("fatal: unrecognized pixel format: %s\n", s);
1972 ret = -1;
1973 }
1974
1975 free(s);
1976
1977 return ret;
1978}
1979
1980static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001981create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001982 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001983 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001984 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001985{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001986 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001987 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001988 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001989 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001990 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001991 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001992 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001993 int i, width, height, scale;
1994 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001995 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001996 enum output_config config;
1997 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001998
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001999 i = find_crtc_for_connector(ec, resources, connector);
2000 if (i < 0) {
2001 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002002 return -1;
2003 }
2004
Peter Huttererf3d62272013-08-08 11:57:05 +10002005 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04002006 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002007 return -1;
2008
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002009 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
2010 output->base.make = "unknown";
2011 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01002012 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002013 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002014
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002015 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
2016 type_name = connector_type_names[connector->connector_type];
2017 else
2018 type_name = "UNKNOWN";
2019 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01002020 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002021
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002022 section = weston_config_get_section(ec->base.config, "output", "name",
2023 output->base.name);
2024 weston_config_section_get_string(section, "mode", &s, "preferred");
2025 if (strcmp(s, "off") == 0)
2026 config = OUTPUT_CONFIG_OFF;
2027 else if (strcmp(s, "preferred") == 0)
2028 config = OUTPUT_CONFIG_PREFERRED;
2029 else if (strcmp(s, "current") == 0)
2030 config = OUTPUT_CONFIG_CURRENT;
2031 else if (sscanf(s, "%dx%d", &width, &height) == 2)
2032 config = OUTPUT_CONFIG_MODE;
2033 else if (parse_modeline(s, &modeline) == 0)
2034 config = OUTPUT_CONFIG_MODELINE;
2035 else {
2036 weston_log("Invalid mode \"%s\" for output %s\n",
2037 s, output->base.name);
2038 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002039 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002040 free(s);
2041
2042 weston_config_section_get_int(section, "scale", &scale, 1);
2043 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05002044 if (weston_parse_transform(s, &transform) < 0)
2045 weston_log("Invalid transform \"%s\" for output %s\n",
2046 s, output->base.name);
2047
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002048 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002049
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002050 if (get_gbm_format_from_section(section,
2051 ec->format,
2052 &output->format) == -1)
2053 output->format = ec->format;
2054
Rob Bradford66bd9f52013-06-25 18:56:42 +01002055 weston_config_section_get_string(section, "seat", &s, "");
2056 setup_output_seat_constraint(ec, &output->base, s);
2057 free(s);
2058
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002059 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002060 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002061 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002062 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002063 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002064
Matt Roper361d2ad2011-08-29 13:52:23 -07002065 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03002066 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002067
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002068 /* Get the current mode on the crtc that's currently driving
2069 * this connector. */
2070 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002071 memset(&crtc_mode, 0, sizeof crtc_mode);
2072 if (encoder != NULL) {
2073 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
2074 drmModeFreeEncoder(encoder);
2075 if (crtc == NULL)
2076 goto err_free;
2077 if (crtc->mode_valid)
2078 crtc_mode = crtc->mode;
2079 drmModeFreeCrtc(crtc);
2080 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002081
David Herrmann0f0d54e2011-12-08 17:05:45 +01002082 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002083 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002084 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002085 goto err_free;
2086 }
2087
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002088 if (config == OUTPUT_CONFIG_OFF) {
2089 weston_log("Disabling output %s\n", output->base.name);
2090 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
2091 0, 0, 0, 0, 0, NULL);
2092 goto err_free;
2093 }
2094
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002095 preferred = NULL;
2096 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002097 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002098 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002099
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002100 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002101 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002102 width == drm_mode->base.width &&
2103 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002104 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002105 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002106 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002107 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002108 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002109 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002110 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002111
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002112 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002113 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002114 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002115 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002116 }
2117
Wang Quanxianacb805a2012-07-30 18:09:46 -04002118 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002119 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002120 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002121 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002122 }
2123
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002124 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002125 configured = current;
2126
Wang Quanxianacb805a2012-07-30 18:09:46 -04002127 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002128 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002129 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002130 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002131 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002132 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002133 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002134 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002135 else if (best)
2136 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002137
Hardeningff39efa2013-09-18 23:56:35 +02002138 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002139 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002140 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002141 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002142
Hardeningff39efa2013-09-18 23:56:35 +02002143 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002144
John Kåre Alsaker94659272012-11-13 19:10:18 +01002145 weston_output_init(&output->base, &ec->base, x, y,
2146 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002147 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002148
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002149 if (ec->use_pixman) {
2150 if (drm_output_init_pixman(output, ec) < 0) {
2151 weston_log("Failed to init output pixman state\n");
2152 goto err_output;
2153 }
2154 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002155 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002156 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002157 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002158
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002159 output->backlight = backlight_init(drm_device,
2160 connector->connector_type);
2161 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002162 weston_log("Initialized backlight, device %s\n",
2163 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002164 output->base.set_backlight = drm_set_backlight;
2165 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002166 } else {
2167 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002168 }
2169
Giulio Camuffob1147152015-05-06 21:41:57 +03002170 weston_compositor_add_output(&ec->base, &output->base);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002171
Richard Hughes2b2092a2013-04-24 14:58:02 +01002172 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002173 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2174 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002175
Jonas Ådahle5a12252013-04-05 23:07:11 +02002176 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002177 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002178 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002179 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002180 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002181 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002182
Richard Hughese7299962013-05-01 21:52:12 +01002183 output->base.gamma_size = output->original_crtc->gamma_size;
2184 output->base.set_gamma = drm_output_set_gamma;
2185
Xiong Zhang97116532013-10-23 13:58:31 +08002186 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2187 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002188
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002189 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2190 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2191 &ec->base.primary_plane);
2192
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002193 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002194 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002195 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002196 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002197 m->width, m->height, m->refresh / 1000.0,
2198 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2199 ", preferred" : "",
2200 m->flags & WL_OUTPUT_MODE_CURRENT ?
2201 ", current" : "",
2202 connector->count_modes == 0 ?
2203 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002204
Mario Kleiner80817042015-06-21 21:25:11 +02002205 /* Set native_ fields, so weston_output_mode_switch_to_native() works */
2206 output->base.native_mode = output->base.current_mode;
2207 output->base.native_scale = output->base.current_scale;
2208
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002209 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002210
John Kåre Alsaker94659272012-11-13 19:10:18 +01002211err_output:
2212 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002213err_free:
2214 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2215 base.link) {
2216 wl_list_remove(&drm_mode->base.link);
2217 free(drm_mode);
2218 }
2219
2220 drmModeFreeCrtc(output->original_crtc);
2221 ec->crtc_allocator &= ~(1 << output->crtc_id);
2222 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002223 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002224
David Herrmann0f0d54e2011-12-08 17:05:45 +01002225 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002226}
2227
Jesse Barnes58ef3792012-02-23 09:45:49 -05002228static void
2229create_sprites(struct drm_compositor *ec)
2230{
2231 struct drm_sprite *sprite;
2232 drmModePlaneRes *plane_res;
2233 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002234 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002235
2236 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2237 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002238 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002239 strerror(errno));
2240 return;
2241 }
2242
2243 for (i = 0; i < plane_res->count_planes; i++) {
2244 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2245 if (!plane)
2246 continue;
2247
Peter Huttererf3d62272013-08-08 11:57:05 +10002248 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002249 plane->count_formats));
2250 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002251 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002252 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002253 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002254 continue;
2255 }
2256
Jesse Barnes58ef3792012-02-23 09:45:49 -05002257 sprite->possible_crtcs = plane->possible_crtcs;
2258 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002259 sprite->current = NULL;
2260 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002261 sprite->compositor = ec;
2262 sprite->count_formats = plane->count_formats;
2263 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002264 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002265 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002266 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002267 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2268 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002269
2270 wl_list_insert(&ec->sprite_list, &sprite->link);
2271 }
2272
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002273 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002274}
2275
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002276static void
2277destroy_sprites(struct drm_compositor *compositor)
2278{
2279 struct drm_sprite *sprite, *next;
2280 struct drm_output *output;
2281
2282 output = container_of(compositor->base.output_list.next,
2283 struct drm_output, base.link);
2284
2285 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2286 drmModeSetPlane(compositor->drm.fd,
2287 sprite->plane_id,
2288 output->crtc_id, 0, 0,
2289 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002290 drm_output_release_fb(output, sprite->current);
2291 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002292 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002293 free(sprite);
2294 }
2295}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002296
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002297static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002298create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002299 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002300{
2301 drmModeConnector *connector;
2302 drmModeRes *resources;
2303 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002304 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002305
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002306 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002307 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002308 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002309 return -1;
2310 }
2311
Jesse Barnes58ef3792012-02-23 09:45:49 -05002312 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002313 if (!ec->crtcs) {
2314 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002315 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002316 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002317
Rob Clark4339add2012-08-09 14:18:28 -05002318 ec->min_width = resources->min_width;
2319 ec->max_width = resources->max_width;
2320 ec->min_height = resources->min_height;
2321 ec->max_height = resources->max_height;
2322
Jesse Barnes58ef3792012-02-23 09:45:49 -05002323 ec->num_crtcs = resources->count_crtcs;
2324 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2325
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002326 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002327 connector = drmModeGetConnector(ec->drm.fd,
2328 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002329 if (connector == NULL)
2330 continue;
2331
2332 if (connector->connection == DRM_MODE_CONNECTED &&
2333 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002334 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002335 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002336 connector, x, y,
2337 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002338 drmModeFreeConnector(connector);
2339 continue;
2340 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002341
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002342 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002343 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002344 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002345 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002346
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002347 drmModeFreeConnector(connector);
2348 }
2349
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002350 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002351 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002352 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002353 return -1;
2354 }
2355
2356 drmModeFreeResources(resources);
2357
2358 return 0;
2359}
2360
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002361static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002362update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002363{
2364 drmModeConnector *connector;
2365 drmModeRes *resources;
2366 struct drm_output *output, *next;
2367 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002368 uint32_t connected = 0, disconnects = 0;
2369 int i;
2370
2371 resources = drmModeGetResources(ec->drm.fd);
2372 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002373 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002374 return;
2375 }
2376
2377 /* collect new connects */
2378 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002379 int connector_id = resources->connectors[i];
2380
2381 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002382 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002383 continue;
2384
David Herrmann7551cff2011-12-08 17:05:43 +01002385 if (connector->connection != DRM_MODE_CONNECTED) {
2386 drmModeFreeConnector(connector);
2387 continue;
2388 }
2389
Benjamin Franzke117483d2011-08-30 11:38:26 +02002390 connected |= (1 << connector_id);
2391
2392 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002393 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002394 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002395 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002396
2397 /* XXX: not yet needed, we die with 0 outputs */
2398 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002399 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002400 else
2401 x = 0;
2402 y = 0;
2403 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002404 connector, x, y,
2405 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002406 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002407
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002408 }
2409 drmModeFreeConnector(connector);
2410 }
2411 drmModeFreeResources(resources);
2412
2413 disconnects = ec->connector_allocator & ~connected;
2414 if (disconnects) {
2415 wl_list_for_each_safe(output, next, &ec->base.output_list,
2416 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002417 if (disconnects & (1 << output->connector_id)) {
2418 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002419 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002420 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002421 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002422 }
2423 }
2424 }
2425
Daniel Stonef556ebe2015-05-21 08:28:58 +01002426 /* FIXME: handle zero outputs, without terminating */
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002427 if (ec->connector_allocator == 0)
2428 wl_display_terminate(ec->base.wl_display);
2429}
2430
2431static int
David Herrmannd7488c22012-03-11 20:05:21 +01002432udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002433{
David Herrmannd7488c22012-03-11 20:05:21 +01002434 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002435 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002436
2437 sysnum = udev_device_get_sysnum(device);
2438 if (!sysnum || atoi(sysnum) != ec->drm.id)
2439 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002440
David Herrmann6ac52db2012-03-11 20:05:22 +01002441 val = udev_device_get_property_value(device, "HOTPLUG");
2442 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002443 return 0;
2444
David Herrmann6ac52db2012-03-11 20:05:22 +01002445 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002446}
2447
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002448static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002449udev_drm_event(int fd, uint32_t mask, void *data)
2450{
2451 struct drm_compositor *ec = data;
2452 struct udev_device *event;
2453
2454 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002455
David Herrmannd7488c22012-03-11 20:05:21 +01002456 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002457 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002458
2459 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002460
2461 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002462}
2463
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002464static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002465drm_restore(struct weston_compositor *ec)
2466{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002467 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002468}
2469
2470static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002471drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002472{
2473 struct drm_compositor *d = (struct drm_compositor *) ec;
2474
Rob Bradfordd355b802013-05-31 18:09:55 +01002475 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002476
2477 wl_event_source_remove(d->udev_drm_source);
2478 wl_event_source_remove(d->drm_source);
2479
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002480 destroy_sprites(d);
2481
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002482 weston_compositor_shutdown(ec);
2483
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002484 if (d->gbm)
2485 gbm_device_destroy(d->gbm);
2486
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002487 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002488
Rob Bradford45c15b82013-07-26 16:29:35 +01002489 close(d->drm.fd);
2490
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002491 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002492}
2493
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002494static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002495drm_compositor_set_modes(struct drm_compositor *compositor)
2496{
2497 struct drm_output *output;
2498 struct drm_mode *drm_mode;
2499 int ret;
2500
2501 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002502 if (!output->current) {
2503 /* If something that would cause the output to
2504 * switch mode happened while in another vt, we
2505 * might not have a current drm_fb. In that case,
2506 * schedule a repaint and let drm_output_repaint
2507 * handle setting the mode. */
2508 weston_output_schedule_repaint(&output->base);
2509 continue;
2510 }
2511
Hardeningff39efa2013-09-18 23:56:35 +02002512 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002513 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002514 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002515 &output->connector_id, 1,
2516 &drm_mode->mode_info);
2517 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002518 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002519 "failed to set mode %dx%d for output at %d,%d: %m\n",
Daniel Stonef556ebe2015-05-21 08:28:58 +01002520 drm_mode->base.width, drm_mode->base.height,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002521 output->base.x, output->base.y);
2522 }
2523 }
2524}
2525
2526static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002527session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002528{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002529 struct weston_compositor *compositor = data;
2530 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002531 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002532 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002533
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002534 if (ec->base.session_active) {
2535 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002536 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002537 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002538 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002539 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002540 } else {
2541 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002542 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002543
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002544 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002545 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002546
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002547 /* If we have a repaint scheduled (either from a
2548 * pending pageflip or the idle handler), make sure we
2549 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002550 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002551 * further attemps at repainting. When we switch
2552 * back, we schedule a repaint, which will process
2553 * pending frame callbacks. */
2554
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002555 wl_list_for_each(output, &ec->base.output_list, base.link) {
2556 output->base.repaint_needed = 0;
2557 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002558 }
2559
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002560 output = container_of(ec->base.output_list.next,
2561 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002562
2563 wl_list_for_each(sprite, &ec->sprite_list, link)
2564 drmModeSetPlane(ec->drm.fd,
2565 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002566 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002567 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002568 };
2569}
2570
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002571static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002572switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002573{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002574 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002575
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002576 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002577}
2578
David Herrmann0af066f2012-10-29 19:21:16 +01002579/*
2580 * Find primary GPU
2581 * Some systems may have multiple DRM devices attached to a single seat. This
2582 * function loops over all devices and tries to find a PCI device with the
2583 * boot_vga sysfs attribute set to 1.
2584 * If no such device is found, the first DRM device reported by udev is used.
2585 */
2586static struct udev_device*
2587find_primary_gpu(struct drm_compositor *ec, const char *seat)
2588{
2589 struct udev_enumerate *e;
2590 struct udev_list_entry *entry;
2591 const char *path, *device_seat, *id;
2592 struct udev_device *device, *drm_device, *pci;
2593
2594 e = udev_enumerate_new(ec->udev);
2595 udev_enumerate_add_match_subsystem(e, "drm");
2596 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2597
2598 udev_enumerate_scan_devices(e);
2599 drm_device = NULL;
2600 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2601 path = udev_list_entry_get_name(entry);
2602 device = udev_device_new_from_syspath(ec->udev, path);
2603 if (!device)
2604 continue;
2605 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2606 if (!device_seat)
2607 device_seat = default_seat;
2608 if (strcmp(device_seat, seat)) {
2609 udev_device_unref(device);
2610 continue;
2611 }
2612
2613 pci = udev_device_get_parent_with_subsystem_devtype(device,
2614 "pci", NULL);
2615 if (pci) {
2616 id = udev_device_get_sysattr_value(pci, "boot_vga");
2617 if (id && !strcmp(id, "1")) {
2618 if (drm_device)
2619 udev_device_unref(drm_device);
2620 drm_device = device;
2621 break;
2622 }
2623 }
2624
2625 if (!drm_device)
2626 drm_device = device;
2627 else
2628 udev_device_unref(device);
2629 }
2630
2631 udev_enumerate_unref(e);
2632 return drm_device;
2633}
2634
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002635static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002636planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002637{
2638 struct drm_compositor *c = data;
2639
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002640 switch (key) {
2641 case KEY_C:
2642 c->cursors_are_broken ^= 1;
2643 break;
2644 case KEY_V:
2645 c->sprites_are_broken ^= 1;
2646 break;
2647 case KEY_O:
2648 c->sprites_hidden ^= 1;
2649 break;
2650 default:
2651 break;
2652 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002653}
2654
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002655#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002656static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002657recorder_destroy(struct drm_output *output)
2658{
2659 vaapi_recorder_destroy(output->recorder);
2660 output->recorder = NULL;
2661
2662 output->base.disable_planes--;
2663
2664 wl_list_remove(&output->recorder_frame_listener.link);
2665 weston_log("[libva recorder] done\n");
2666}
2667
2668static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002669recorder_frame_notify(struct wl_listener *listener, void *data)
2670{
2671 struct drm_output *output;
2672 struct drm_compositor *c;
2673 int fd, ret;
2674
2675 output = container_of(listener, struct drm_output,
2676 recorder_frame_listener);
2677 c = (struct drm_compositor *) output->base.compositor;
2678
2679 if (!output->recorder)
2680 return;
2681
2682 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2683 DRM_CLOEXEC, &fd);
2684 if (ret) {
2685 weston_log("[libva recorder] "
2686 "failed to create prime fd for front buffer\n");
2687 return;
2688 }
2689
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002690 ret = vaapi_recorder_frame(output->recorder, fd,
2691 output->current->stride);
2692 if (ret < 0) {
2693 weston_log("[libva recorder] aborted: %m\n");
2694 recorder_destroy(output);
2695 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002696}
2697
2698static void *
2699create_recorder(struct drm_compositor *c, int width, int height,
2700 const char *filename)
2701{
2702 int fd;
2703 drm_magic_t magic;
2704
2705 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2706 if (fd < 0)
2707 return NULL;
2708
2709 drmGetMagic(fd, &magic);
2710 drmAuthMagic(c->drm.fd, magic);
2711
2712 return vaapi_recorder_create(fd, width, height, filename);
2713}
2714
2715static void
2716recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2717 void *data)
2718{
2719 struct drm_compositor *c = data;
2720 struct drm_output *output;
2721 int width, height;
2722
2723 output = container_of(c->base.output_list.next,
2724 struct drm_output, base.link);
2725
2726 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002727 if (output->format != GBM_FORMAT_XRGB8888) {
2728 weston_log("failed to start vaapi recorder: "
2729 "output format not supported\n");
2730 return;
2731 }
2732
Hardeningff39efa2013-09-18 23:56:35 +02002733 width = output->base.current_mode->width;
2734 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002735
2736 output->recorder =
2737 create_recorder(c, width, height, "capture.h264");
2738 if (!output->recorder) {
2739 weston_log("failed to create vaapi recorder\n");
2740 return;
2741 }
2742
2743 output->base.disable_planes++;
2744
2745 output->recorder_frame_listener.notify = recorder_frame_notify;
2746 wl_signal_add(&output->base.frame_signal,
2747 &output->recorder_frame_listener);
2748
2749 weston_output_schedule_repaint(&output->base);
2750
2751 weston_log("[libva recorder] initialized\n");
2752 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002753 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002754 }
2755}
2756#else
2757static void
2758recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2759 void *data)
2760{
2761 weston_log("Compiled without libva support\n");
2762}
2763#endif
2764
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002765static void
2766switch_to_gl_renderer(struct drm_compositor *c)
2767{
2768 struct drm_output *output;
2769
2770 if (!c->use_pixman)
2771 return;
2772
2773 weston_log("Switching to GL renderer\n");
2774
2775 c->gbm = create_gbm_device(c->drm.fd);
2776 if (!c->gbm) {
2777 weston_log("Failed to create gbm device. "
2778 "Aborting renderer switch\n");
2779 return;
2780 }
2781
2782 wl_list_for_each(output, &c->base.output_list, base.link)
2783 pixman_renderer_output_destroy(&output->base);
2784
2785 c->base.renderer->destroy(&c->base);
2786
2787 if (drm_compositor_create_gl_renderer(c) < 0) {
2788 gbm_device_destroy(c->gbm);
2789 weston_log("Failed to create GL renderer. Quitting.\n");
2790 /* FIXME: we need a function to shutdown cleanly */
2791 assert(0);
2792 }
2793
2794 wl_list_for_each(output, &c->base.output_list, base.link)
2795 drm_output_init_egl(output, c);
2796
2797 c->use_pixman = 0;
2798}
2799
2800static void
2801renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2802 void *data)
2803{
2804 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2805
2806 switch_to_gl_renderer(c);
2807}
2808
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002809static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002810drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002811 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002812 int *argc, char *argv[],
2813 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002814{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002815 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002816 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002817 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002818 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002819 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002820 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002821
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002822 weston_log("initializing drm backend\n");
2823
Peter Huttererf3d62272013-08-08 11:57:05 +10002824 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002825 if (ec == NULL)
2826 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002827
Pekka Paalanen68583832015-05-19 09:53:16 +03002828 /*
2829 * KMS support for hardware planes cannot properly synchronize
2830 * without nuclear page flip. Without nuclear/atomic, hw plane
2831 * and cursor plane updates would either tear or cause extra
2832 * waits for vblanks which means dropping the compositor framerate
2833 * to a fraction.
2834 *
2835 * These can be enabled again when nuclear/atomic support lands.
2836 */
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002837 ec->sprites_are_broken = 1;
Pekka Paalanen68583832015-05-19 09:53:16 +03002838 ec->cursors_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002839
2840 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002841 if (get_gbm_format_from_section(section,
2842 GBM_FORMAT_XRGB8888,
2843 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002844 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002845
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002846 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002847
Daniel Stone725c2c32012-06-22 14:04:36 +01002848 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002849 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002850 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002851 goto err_base;
2852 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002853
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002854 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002855 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
David Herrmann2ecb84a2014-12-30 14:33:22 +01002856 param->seat_id, true);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002857 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002858 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002859 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002860 goto err_compositor;
2861 }
2862
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002863 ec->udev = udev_new();
2864 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002865 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002866 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002867 }
2868
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002869 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002870 ec->session_listener.notify = session_notify;
2871 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002872
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002873 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002874 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002875 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002876 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002877 }
David Herrmann0af066f2012-10-29 19:21:16 +01002878 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002879
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002880 if (init_drm(ec, drm_device) < 0) {
2881 weston_log("failed to initialize kms\n");
2882 goto err_udev_dev;
2883 }
2884
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002885 if (ec->use_pixman) {
2886 if (init_pixman(ec) < 0) {
2887 weston_log("failed to initialize pixman renderer\n");
2888 goto err_udev_dev;
2889 }
2890 } else {
2891 if (init_egl(ec) < 0) {
2892 weston_log("failed to initialize egl\n");
2893 goto err_udev_dev;
2894 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002895 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002896
2897 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002898 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002899
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002900 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002901
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002902 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002903 weston_compositor_add_key_binding(&ec->base, key,
2904 MODIFIER_CTRL | MODIFIER_ALT,
2905 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002906
Jesse Barnes58ef3792012-02-23 09:45:49 -05002907 wl_list_init(&ec->sprite_list);
2908 create_sprites(ec);
2909
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002910 if (udev_input_init(&ec->input,
2911 &ec->base, ec->udev, param->seat_id) < 0) {
2912 weston_log("failed to create input devices\n");
2913 goto err_sprite;
2914 }
2915
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002916 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002917 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002918 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002919 }
2920
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002921 /* A this point we have some idea of whether or not we have a working
2922 * cursor plane. */
2923 if (!ec->cursors_are_broken)
2924 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2925
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002926 path = NULL;
2927
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002928 loop = wl_display_get_event_loop(ec->base.wl_display);
2929 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002930 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002931 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002932
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002933 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2934 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002935 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002936 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002937 }
2938 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2939 "drm", NULL);
2940 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002941 wl_event_loop_add_fd(loop,
2942 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002943 WL_EVENT_READABLE, udev_drm_event, ec);
2944
2945 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002946 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002947 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002948 }
2949
Daniel Stonea96b93c2012-06-22 14:04:37 +01002950 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002951
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002952 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002953 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002954 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002955 planes_binding, ec);
2956 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2957 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002958 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2959 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002960 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2961 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002962
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002963 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002964
2965err_udev_monitor:
2966 wl_event_source_remove(ec->udev_drm_source);
2967 udev_monitor_unref(ec->udev_monitor);
2968err_drm_source:
2969 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002970err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002971 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002972err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002973 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002974 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002975 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002976err_udev_dev:
2977 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002978err_launcher:
2979 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002980err_udev:
2981 udev_unref(ec->udev);
2982err_compositor:
2983 weston_compositor_shutdown(&ec->base);
2984err_base:
2985 free(ec);
2986 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002987}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002988
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002989WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002990backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002991 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002992{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002993 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002994
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002995 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002996 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2997 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2998 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002999 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003000 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003001 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02003002
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003003 param.seat_id = default_seat;
3004
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04003005 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003006
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07003007 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04003008}