blob: 8471a3588d10f3aaa54c48d90c4134cd0dcc11cb [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 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Daniel Stonec228e232013-05-22 18:03:19 +030024#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040025
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010028#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040029#include <string.h>
30#include <fcntl.h>
31#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040032#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070033#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030034#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020035#include <sys/mman.h>
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030036#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030037#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040038
Benjamin Franzkec649a922011-03-02 11:56:04 +010039#include <xf86drm.h>
40#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050041#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010042
Benjamin Franzke060cf802011-04-30 09:32:11 +020043#include <gbm.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040044#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020045
Kristian Høgsberg36d5fac2014-01-27 23:02:35 -080046#include "libbacklight.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040047#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010048#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020049#include "pixman-renderer.h"
Peter Hutterer823ad332014-11-26 07:06:31 +100050#include "libinput-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010051#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030052#include "vaapi-recorder.h"
Pekka Paalanen363aa7b2014-12-17 16:20:40 +020053#include "presentation_timing-server-protocol.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040054
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030055#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
56#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
57#endif
58
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -030059#ifndef DRM_CAP_CURSOR_WIDTH
60#define DRM_CAP_CURSOR_WIDTH 0x8
61#endif
62
63#ifndef DRM_CAP_CURSOR_HEIGHT
64#define DRM_CAP_CURSOR_HEIGHT 0x9
65#endif
66
67#ifndef GBM_BO_USE_CURSOR
68#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
69#endif
70
Jonny Lamb70eba3f2015-03-20 15:26:50 +010071#ifndef EGL_PLATFORM_GBM_KHR
72#define EGL_PLATFORM_GBM_KHR 0x31D7
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) {
1228 if (mode->mode_info.vrefresh == target_mode->refresh ||
1229 target_mode->refresh == 0) {
1230 return mode;
1231 } else if (!tmp_mode)
1232 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
1398static int
1399drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1400{
1401 EGLint format;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001402
Jonny Lamb70eba3f2015-03-20 15:26:50 +01001403 if (!gl_renderer->supports ||
1404 gl_renderer->supports(&ec->base, "gbm") < 0) {
1405 return -1;
1406 }
1407
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001408 format = ec->format;
Jonny Lamb70eba3f2015-03-20 15:26:50 +01001409 if (gl_renderer->create(&ec->base, EGL_PLATFORM_GBM_KHR, (void *) ec->gbm,
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001410 gl_renderer->opaque_attribs, &format) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001411 return -1;
1412 }
1413
1414 return 0;
1415}
1416
1417static int
1418init_egl(struct drm_compositor *ec)
1419{
1420 ec->gbm = create_gbm_device(ec->drm.fd);
1421
1422 if (!ec->gbm)
1423 return -1;
1424
1425 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001426 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001427 return -1;
1428 }
1429
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001430 return 0;
1431}
1432
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001433static int
1434init_pixman(struct drm_compositor *ec)
1435{
1436 return pixman_renderer_init(&ec->base);
1437}
1438
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001439static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001440drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001441{
1442 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001443 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001444
1445 mode = malloc(sizeof *mode);
1446 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001447 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001448
1449 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001450 mode->base.width = info->hdisplay;
1451 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001452
1453 /* Calculate higher precision (mHz) refresh rate */
1454 refresh = (info->clock * 1000000LL / info->htotal +
1455 info->vtotal / 2) / info->vtotal;
1456
1457 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1458 refresh *= 2;
1459 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1460 refresh /= 2;
1461 if (info->vscan > 1)
1462 refresh /= info->vscan;
1463
1464 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001465 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001466
1467 if (info->type & DRM_MODE_TYPE_PREFERRED)
1468 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1469
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001470 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1471
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001472 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001473}
1474
1475static int
1476drm_subpixel_to_wayland(int drm_value)
1477{
1478 switch (drm_value) {
1479 default:
1480 case DRM_MODE_SUBPIXEL_UNKNOWN:
1481 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1482 case DRM_MODE_SUBPIXEL_NONE:
1483 return WL_OUTPUT_SUBPIXEL_NONE;
1484 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1485 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1486 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1487 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1488 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1489 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1490 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1491 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1492 }
1493}
1494
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001495/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001496static uint32_t
1497drm_get_backlight(struct drm_output *output)
1498{
1499 long brightness, max_brightness, norm;
1500
1501 brightness = backlight_get_brightness(output->backlight);
1502 max_brightness = backlight_get_max_brightness(output->backlight);
1503
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001504 /* convert it on a scale of 0 to 255 */
1505 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001506
1507 return (uint32_t) norm;
1508}
1509
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001510/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001511static void
1512drm_set_backlight(struct weston_output *output_base, uint32_t value)
1513{
1514 struct drm_output *output = (struct drm_output *) output_base;
1515 long max_brightness, new_brightness;
1516
1517 if (!output->backlight)
1518 return;
1519
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001520 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001521 return;
1522
1523 max_brightness = backlight_get_max_brightness(output->backlight);
1524
1525 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001526 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001527
1528 backlight_set_brightness(output->backlight, new_brightness);
1529}
1530
1531static drmModePropertyPtr
1532drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1533{
1534 drmModePropertyPtr props;
1535 int i;
1536
1537 for (i = 0; i < connector->count_props; i++) {
1538 props = drmModeGetProperty(fd, connector->props[i]);
1539 if (!props)
1540 continue;
1541
1542 if (!strcmp(props->name, name))
1543 return props;
1544
1545 drmModeFreeProperty(props);
1546 }
1547
1548 return NULL;
1549}
1550
1551static void
1552drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1553{
1554 struct drm_output *output = (struct drm_output *) output_base;
1555 struct weston_compositor *ec = output_base->compositor;
1556 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001557
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001558 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001559 return;
1560
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001561 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1562 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001563}
1564
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001565static const char *connector_type_names[] = {
1566 "None",
1567 "VGA",
1568 "DVI",
1569 "DVI",
1570 "DVI",
1571 "Composite",
1572 "TV",
1573 "LVDS",
1574 "CTV",
1575 "DIN",
1576 "DP",
1577 "HDMI",
1578 "HDMI",
1579 "TV",
1580 "eDP",
1581};
1582
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001583static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001584find_crtc_for_connector(struct drm_compositor *ec,
1585 drmModeRes *resources, drmModeConnector *connector)
1586{
1587 drmModeEncoder *encoder;
1588 uint32_t possible_crtcs;
1589 int i, j;
1590
1591 for (j = 0; j < connector->count_encoders; j++) {
1592 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1593 if (encoder == NULL) {
1594 weston_log("Failed to get encoder.\n");
1595 return -1;
1596 }
1597 possible_crtcs = encoder->possible_crtcs;
1598 drmModeFreeEncoder(encoder);
1599
1600 for (i = 0; i < resources->count_crtcs; i++) {
1601 if (possible_crtcs & (1 << i) &&
1602 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1603 return i;
1604 }
1605 }
1606
1607 return -1;
1608}
1609
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001610/* Init output state that depends on gl or gbm */
1611static int
1612drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1613{
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001614 EGLint format = output->format;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001615 int i, flags;
1616
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001617 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001618 output->base.current_mode->width,
1619 output->base.current_mode->height,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001620 format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001621 GBM_BO_USE_SCANOUT |
1622 GBM_BO_USE_RENDERING);
1623 if (!output->surface) {
1624 weston_log("failed to create gbm surface\n");
1625 return -1;
1626 }
1627
Jonny Lamb671148f2015-03-20 15:26:52 +01001628 if (gl_renderer->output_create(&output->base,
Jonny Lamb445fb692015-03-24 13:12:01 +01001629 (EGLNativeDisplayType)output->surface,
1630 output->surface,
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001631 gl_renderer->opaque_attribs,
1632 &format) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001633 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001634 gbm_surface_destroy(output->surface);
1635 return -1;
1636 }
1637
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001638 flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001639
1640 for (i = 0; i < 2; i++) {
1641 if (output->cursor_bo[i])
1642 continue;
1643
1644 output->cursor_bo[i] =
Alvaro Fernando Garcíadce7c6e2014-07-28 18:30:17 -03001645 gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
1646 GBM_FORMAT_ARGB8888, flags);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001647 }
1648
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001649 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1650 weston_log("cursor buffers unavailable, using gl cursors\n");
1651 ec->cursors_are_broken = 1;
1652 }
1653
1654 return 0;
1655}
1656
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001657static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001658drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1659{
Hardeningff39efa2013-09-18 23:56:35 +02001660 int w = output->base.current_mode->width;
1661 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001662 unsigned int i;
1663
1664 /* FIXME error checking */
1665
1666 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001667 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001668 if (!output->dumb[i])
1669 goto err;
1670
1671 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001672 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001673 output->dumb[i]->map,
1674 output->dumb[i]->stride);
1675 if (!output->image[i])
1676 goto err;
1677 }
1678
1679 if (pixman_renderer_output_create(&output->base) < 0)
1680 goto err;
1681
1682 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001683 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001684
1685 return 0;
1686
1687err:
1688 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1689 if (output->dumb[i])
1690 drm_fb_destroy_dumb(output->dumb[i]);
1691 if (output->image[i])
1692 pixman_image_unref(output->image[i]);
1693
1694 output->dumb[i] = NULL;
1695 output->image[i] = NULL;
1696 }
1697
1698 return -1;
1699}
1700
1701static void
1702drm_output_fini_pixman(struct drm_output *output)
1703{
1704 unsigned int i;
1705
1706 pixman_renderer_output_destroy(&output->base);
1707 pixman_region32_fini(&output->previous_damage);
1708
1709 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1710 drm_fb_destroy_dumb(output->dumb[i]);
1711 pixman_image_unref(output->image[i]);
1712 output->dumb[i] = NULL;
1713 output->image[i] = NULL;
1714 }
1715}
1716
Richard Hughes2b2092a2013-04-24 14:58:02 +01001717static void
1718edid_parse_string(const uint8_t *data, char text[])
1719{
1720 int i;
1721 int replaced = 0;
1722
1723 /* this is always 12 bytes, but we can't guarantee it's null
1724 * terminated or not junk. */
1725 strncpy(text, (const char *) data, 12);
1726
1727 /* remove insane chars */
1728 for (i = 0; text[i] != '\0'; i++) {
1729 if (text[i] == '\n' ||
1730 text[i] == '\r') {
1731 text[i] = '\0';
1732 break;
1733 }
1734 }
1735
1736 /* ensure string is printable */
1737 for (i = 0; text[i] != '\0'; i++) {
1738 if (!isprint(text[i])) {
1739 text[i] = '-';
1740 replaced++;
1741 }
1742 }
1743
1744 /* if the string is random junk, ignore the string */
1745 if (replaced > 4)
1746 text[0] = '\0';
1747}
1748
1749#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1750#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1751#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1752#define EDID_OFFSET_DATA_BLOCKS 0x36
1753#define EDID_OFFSET_LAST_BLOCK 0x6c
1754#define EDID_OFFSET_PNPID 0x08
1755#define EDID_OFFSET_SERIAL 0x0c
1756
1757static int
1758edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1759{
1760 int i;
1761 uint32_t serial_number;
1762
1763 /* check header */
1764 if (length < 128)
1765 return -1;
1766 if (data[0] != 0x00 || data[1] != 0xff)
1767 return -1;
1768
1769 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1770 * /--08--\/--09--\
1771 * 7654321076543210
1772 * |\---/\---/\---/
1773 * R C1 C2 C3 */
1774 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1775 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1776 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1777 edid->pnp_id[3] = '\0';
1778
1779 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1780 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1781 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1782 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1783 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1784 if (serial_number > 0)
1785 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1786
1787 /* parse EDID data */
1788 for (i = EDID_OFFSET_DATA_BLOCKS;
1789 i <= EDID_OFFSET_LAST_BLOCK;
1790 i += 18) {
1791 /* ignore pixel clock data */
1792 if (data[i] != 0)
1793 continue;
1794 if (data[i+2] != 0)
1795 continue;
1796
1797 /* any useful blocks? */
1798 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1799 edid_parse_string(&data[i+5],
1800 edid->monitor_name);
1801 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1802 edid_parse_string(&data[i+5],
1803 edid->serial_number);
1804 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1805 edid_parse_string(&data[i+5],
1806 edid->eisa_id);
1807 }
1808 }
1809 return 0;
1810}
1811
1812static void
1813find_and_parse_output_edid(struct drm_compositor *ec,
1814 struct drm_output *output,
1815 drmModeConnector *connector)
1816{
1817 drmModePropertyBlobPtr edid_blob = NULL;
1818 drmModePropertyPtr property;
1819 int i;
1820 int rc;
1821
1822 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1823 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1824 if (!property)
1825 continue;
1826 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1827 !strcmp(property->name, "EDID")) {
1828 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1829 connector->prop_values[i]);
1830 }
1831 drmModeFreeProperty(property);
1832 }
1833 if (!edid_blob)
1834 return;
1835
1836 rc = edid_parse(&output->edid,
1837 edid_blob->data,
1838 edid_blob->length);
1839 if (!rc) {
1840 weston_log("EDID data '%s', '%s', '%s'\n",
1841 output->edid.pnp_id,
1842 output->edid.monitor_name,
1843 output->edid.serial_number);
1844 if (output->edid.pnp_id[0] != '\0')
1845 output->base.make = output->edid.pnp_id;
1846 if (output->edid.monitor_name[0] != '\0')
1847 output->base.model = output->edid.monitor_name;
1848 if (output->edid.serial_number[0] != '\0')
1849 output->base.serial_number = output->edid.serial_number;
1850 }
1851 drmModeFreePropertyBlob(edid_blob);
1852}
1853
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001854
1855
1856static int
1857parse_modeline(const char *s, drmModeModeInfo *mode)
1858{
1859 char hsync[16];
1860 char vsync[16];
1861 float fclock;
1862
1863 mode->type = DRM_MODE_TYPE_USERDEF;
1864 mode->hskew = 0;
1865 mode->vscan = 0;
1866 mode->vrefresh = 0;
1867 mode->flags = 0;
1868
Rob Bradford307e09e2013-07-26 16:29:40 +01001869 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001870 &fclock,
1871 &mode->hdisplay,
1872 &mode->hsync_start,
1873 &mode->hsync_end,
1874 &mode->htotal,
1875 &mode->vdisplay,
1876 &mode->vsync_start,
1877 &mode->vsync_end,
1878 &mode->vtotal, hsync, vsync) != 11)
1879 return -1;
1880
1881 mode->clock = fclock * 1000;
1882 if (strcmp(hsync, "+hsync") == 0)
1883 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1884 else if (strcmp(hsync, "-hsync") == 0)
1885 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1886 else
1887 return -1;
1888
1889 if (strcmp(vsync, "+vsync") == 0)
1890 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1891 else if (strcmp(vsync, "-vsync") == 0)
1892 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1893 else
1894 return -1;
1895
1896 return 0;
1897}
1898
Rob Bradford66bd9f52013-06-25 18:56:42 +01001899static void
1900setup_output_seat_constraint(struct drm_compositor *ec,
1901 struct weston_output *output,
1902 const char *s)
1903{
1904 if (strcmp(s, "") != 0) {
1905 struct udev_seat *seat;
1906
Jonas Ådahl58e15862014-03-12 22:08:40 +01001907 seat = udev_seat_get_named(&ec->input, s);
Rob Bradford66bd9f52013-06-25 18:56:42 +01001908 if (seat)
1909 seat->base.output = output;
1910
1911 if (seat && seat->base.pointer)
1912 weston_pointer_clamp(seat->base.pointer,
1913 &seat->base.pointer->x,
1914 &seat->base.pointer->y);
1915 }
1916}
1917
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001918static int
Neil Roberts77c1a5b2014-03-07 18:05:50 +00001919get_gbm_format_from_section(struct weston_config_section *section,
1920 uint32_t default_value,
1921 uint32_t *format)
1922{
1923 char *s;
1924 int ret = 0;
1925
1926 weston_config_section_get_string(section,
1927 "gbm-format", &s, NULL);
1928
1929 if (s == NULL)
1930 *format = default_value;
1931 else if (strcmp(s, "xrgb8888") == 0)
1932 *format = GBM_FORMAT_XRGB8888;
1933 else if (strcmp(s, "rgb565") == 0)
1934 *format = GBM_FORMAT_RGB565;
1935 else if (strcmp(s, "xrgb2101010") == 0)
1936 *format = GBM_FORMAT_XRGB2101010;
1937 else {
1938 weston_log("fatal: unrecognized pixel format: %s\n", s);
1939 ret = -1;
1940 }
1941
1942 free(s);
1943
1944 return ret;
1945}
1946
1947static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001948create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001949 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001950 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001951 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001952{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001953 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001954 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001955 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001956 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001957 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001958 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001959 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001960 int i, width, height, scale;
1961 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001962 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001963 enum output_config config;
1964 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001965
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001966 i = find_crtc_for_connector(ec, resources, connector);
1967 if (i < 0) {
1968 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001969 return -1;
1970 }
1971
Peter Huttererf3d62272013-08-08 11:57:05 +10001972 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001973 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001974 return -1;
1975
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001976 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1977 output->base.make = "unknown";
1978 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001979 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001980 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001981
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001982 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1983 type_name = connector_type_names[connector->connector_type];
1984 else
1985 type_name = "UNKNOWN";
1986 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001987 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001988
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001989 section = weston_config_get_section(ec->base.config, "output", "name",
1990 output->base.name);
1991 weston_config_section_get_string(section, "mode", &s, "preferred");
1992 if (strcmp(s, "off") == 0)
1993 config = OUTPUT_CONFIG_OFF;
1994 else if (strcmp(s, "preferred") == 0)
1995 config = OUTPUT_CONFIG_PREFERRED;
1996 else if (strcmp(s, "current") == 0)
1997 config = OUTPUT_CONFIG_CURRENT;
1998 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1999 config = OUTPUT_CONFIG_MODE;
2000 else if (parse_modeline(s, &modeline) == 0)
2001 config = OUTPUT_CONFIG_MODELINE;
2002 else {
2003 weston_log("Invalid mode \"%s\" for output %s\n",
2004 s, output->base.name);
2005 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002006 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002007 free(s);
2008
2009 weston_config_section_get_int(section, "scale", &scale, 1);
2010 weston_config_section_get_string(section, "transform", &s, "normal");
Derek Foreman64a3df02014-10-23 12:24:18 -05002011 if (weston_parse_transform(s, &transform) < 0)
2012 weston_log("Invalid transform \"%s\" for output %s\n",
2013 s, output->base.name);
2014
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002015 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002016
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002017 if (get_gbm_format_from_section(section,
2018 ec->format,
2019 &output->format) == -1)
2020 output->format = ec->format;
2021
Rob Bradford66bd9f52013-06-25 18:56:42 +01002022 weston_config_section_get_string(section, "seat", &s, "");
2023 setup_output_seat_constraint(ec, &output->base, s);
2024 free(s);
2025
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002026 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05002027 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002028 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002029 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002030 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002031
Matt Roper361d2ad2011-08-29 13:52:23 -07002032 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03002033 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07002034
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002035 /* Get the current mode on the crtc that's currently driving
2036 * this connector. */
2037 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002038 memset(&crtc_mode, 0, sizeof crtc_mode);
2039 if (encoder != NULL) {
2040 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
2041 drmModeFreeEncoder(encoder);
2042 if (crtc == NULL)
2043 goto err_free;
2044 if (crtc->mode_valid)
2045 crtc_mode = crtc->mode;
2046 drmModeFreeCrtc(crtc);
2047 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002048
David Herrmann0f0d54e2011-12-08 17:05:45 +01002049 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002050 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002051 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01002052 goto err_free;
2053 }
2054
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002055 if (config == OUTPUT_CONFIG_OFF) {
2056 weston_log("Disabling output %s\n", output->base.name);
2057 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
2058 0, 0, 0, 0, 0, NULL);
2059 goto err_free;
2060 }
2061
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002062 preferred = NULL;
2063 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002064 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002065 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002066
Giulio Camuffoc0b94872013-06-19 15:19:19 +02002067 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002068 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02002069 width == drm_mode->base.width &&
2070 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002071 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002072 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002073 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002074 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002075 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002076 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002077 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002078
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002079 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002080 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002081 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002082 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002083 }
2084
Wang Quanxianacb805a2012-07-30 18:09:46 -04002085 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02002086 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03002087 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002088 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002089 }
2090
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002091 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06002092 configured = current;
2093
Wang Quanxianacb805a2012-07-30 18:09:46 -04002094 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02002095 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002096 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02002097 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002098 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02002099 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002100 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002101 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002102 else if (best)
2103 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002104
Hardeningff39efa2013-09-18 23:56:35 +02002105 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002106 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002107 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002108 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002109
Hardeningff39efa2013-09-18 23:56:35 +02002110 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002111
John Kåre Alsaker94659272012-11-13 19:10:18 +01002112 weston_output_init(&output->base, &ec->base, x, y,
2113 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002114 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002115
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002116 if (ec->use_pixman) {
2117 if (drm_output_init_pixman(output, ec) < 0) {
2118 weston_log("Failed to init output pixman state\n");
2119 goto err_output;
2120 }
2121 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002122 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002123 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002124 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002125
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002126 output->backlight = backlight_init(drm_device,
2127 connector->connector_type);
2128 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002129 weston_log("Initialized backlight, device %s\n",
2130 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002131 output->base.set_backlight = drm_set_backlight;
2132 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002133 } else {
2134 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002135 }
2136
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002137 wl_list_insert(ec->base.output_list.prev, &output->base.link);
2138
Richard Hughes2b2092a2013-04-24 14:58:02 +01002139 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002140 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2141 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002142
Jonas Ådahle5a12252013-04-05 23:07:11 +02002143 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002144 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002145 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002146 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002147 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002148 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002149
Richard Hughese7299962013-05-01 21:52:12 +01002150 output->base.gamma_size = output->original_crtc->gamma_size;
2151 output->base.set_gamma = drm_output_set_gamma;
2152
Xiong Zhang97116532013-10-23 13:58:31 +08002153 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2154 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002155
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002156 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2157 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2158 &ec->base.primary_plane);
2159
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002160 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002161 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002162 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002163 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002164 m->width, m->height, m->refresh / 1000.0,
2165 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2166 ", preferred" : "",
2167 m->flags & WL_OUTPUT_MODE_CURRENT ?
2168 ", current" : "",
2169 connector->count_modes == 0 ?
2170 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002171
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002172 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002173
John Kåre Alsaker94659272012-11-13 19:10:18 +01002174err_output:
2175 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002176err_free:
2177 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2178 base.link) {
2179 wl_list_remove(&drm_mode->base.link);
2180 free(drm_mode);
2181 }
2182
2183 drmModeFreeCrtc(output->original_crtc);
2184 ec->crtc_allocator &= ~(1 << output->crtc_id);
2185 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002186 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002187
David Herrmann0f0d54e2011-12-08 17:05:45 +01002188 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002189}
2190
Jesse Barnes58ef3792012-02-23 09:45:49 -05002191static void
2192create_sprites(struct drm_compositor *ec)
2193{
2194 struct drm_sprite *sprite;
2195 drmModePlaneRes *plane_res;
2196 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002197 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002198
2199 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2200 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002201 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002202 strerror(errno));
2203 return;
2204 }
2205
2206 for (i = 0; i < plane_res->count_planes; i++) {
2207 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2208 if (!plane)
2209 continue;
2210
Peter Huttererf3d62272013-08-08 11:57:05 +10002211 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002212 plane->count_formats));
2213 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002214 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002215 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002216 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002217 continue;
2218 }
2219
Jesse Barnes58ef3792012-02-23 09:45:49 -05002220 sprite->possible_crtcs = plane->possible_crtcs;
2221 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002222 sprite->current = NULL;
2223 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002224 sprite->compositor = ec;
2225 sprite->count_formats = plane->count_formats;
2226 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002227 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002228 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002229 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002230 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2231 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002232
2233 wl_list_insert(&ec->sprite_list, &sprite->link);
2234 }
2235
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002236 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002237}
2238
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002239static void
2240destroy_sprites(struct drm_compositor *compositor)
2241{
2242 struct drm_sprite *sprite, *next;
2243 struct drm_output *output;
2244
2245 output = container_of(compositor->base.output_list.next,
2246 struct drm_output, base.link);
2247
2248 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2249 drmModeSetPlane(compositor->drm.fd,
2250 sprite->plane_id,
2251 output->crtc_id, 0, 0,
2252 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002253 drm_output_release_fb(output, sprite->current);
2254 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002255 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002256 free(sprite);
2257 }
2258}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002259
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002260static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002261create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002262 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002263{
2264 drmModeConnector *connector;
2265 drmModeRes *resources;
2266 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002267 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002268
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002269 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002270 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002271 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002272 return -1;
2273 }
2274
Jesse Barnes58ef3792012-02-23 09:45:49 -05002275 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002276 if (!ec->crtcs) {
2277 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002278 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002279 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002280
Rob Clark4339add2012-08-09 14:18:28 -05002281 ec->min_width = resources->min_width;
2282 ec->max_width = resources->max_width;
2283 ec->min_height = resources->min_height;
2284 ec->max_height = resources->max_height;
2285
Jesse Barnes58ef3792012-02-23 09:45:49 -05002286 ec->num_crtcs = resources->count_crtcs;
2287 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2288
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002289 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002290 connector = drmModeGetConnector(ec->drm.fd,
2291 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002292 if (connector == NULL)
2293 continue;
2294
2295 if (connector->connection == DRM_MODE_CONNECTED &&
2296 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002297 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002298 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002299 connector, x, y,
2300 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002301 drmModeFreeConnector(connector);
2302 continue;
2303 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002304
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002305 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002306 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002307 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002308 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002309
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002310 drmModeFreeConnector(connector);
2311 }
2312
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002313 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002314 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002315 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002316 return -1;
2317 }
2318
2319 drmModeFreeResources(resources);
2320
2321 return 0;
2322}
2323
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002324static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002325update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002326{
2327 drmModeConnector *connector;
2328 drmModeRes *resources;
2329 struct drm_output *output, *next;
2330 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002331 uint32_t connected = 0, disconnects = 0;
2332 int i;
2333
2334 resources = drmModeGetResources(ec->drm.fd);
2335 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002336 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002337 return;
2338 }
2339
2340 /* collect new connects */
2341 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002342 int connector_id = resources->connectors[i];
2343
2344 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002345 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002346 continue;
2347
David Herrmann7551cff2011-12-08 17:05:43 +01002348 if (connector->connection != DRM_MODE_CONNECTED) {
2349 drmModeFreeConnector(connector);
2350 continue;
2351 }
2352
Benjamin Franzke117483d2011-08-30 11:38:26 +02002353 connected |= (1 << connector_id);
2354
2355 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002356 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002357 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002358 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002359
2360 /* XXX: not yet needed, we die with 0 outputs */
2361 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002362 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002363 else
2364 x = 0;
2365 y = 0;
2366 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002367 connector, x, y,
2368 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002369 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002370
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002371 }
2372 drmModeFreeConnector(connector);
2373 }
2374 drmModeFreeResources(resources);
2375
2376 disconnects = ec->connector_allocator & ~connected;
2377 if (disconnects) {
2378 wl_list_for_each_safe(output, next, &ec->base.output_list,
2379 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002380 if (disconnects & (1 << output->connector_id)) {
2381 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002382 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002383 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002384 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002385 }
2386 }
2387 }
2388
2389 /* FIXME: handle zero outputs, without terminating */
2390 if (ec->connector_allocator == 0)
2391 wl_display_terminate(ec->base.wl_display);
2392}
2393
2394static int
David Herrmannd7488c22012-03-11 20:05:21 +01002395udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002396{
David Herrmannd7488c22012-03-11 20:05:21 +01002397 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002398 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002399
2400 sysnum = udev_device_get_sysnum(device);
2401 if (!sysnum || atoi(sysnum) != ec->drm.id)
2402 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002403
David Herrmann6ac52db2012-03-11 20:05:22 +01002404 val = udev_device_get_property_value(device, "HOTPLUG");
2405 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002406 return 0;
2407
David Herrmann6ac52db2012-03-11 20:05:22 +01002408 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002409}
2410
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002411static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002412udev_drm_event(int fd, uint32_t mask, void *data)
2413{
2414 struct drm_compositor *ec = data;
2415 struct udev_device *event;
2416
2417 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002418
David Herrmannd7488c22012-03-11 20:05:21 +01002419 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002420 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002421
2422 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002423
2424 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002425}
2426
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002427static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002428drm_restore(struct weston_compositor *ec)
2429{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002430 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002431}
2432
2433static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002434drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002435{
2436 struct drm_compositor *d = (struct drm_compositor *) ec;
2437
Rob Bradfordd355b802013-05-31 18:09:55 +01002438 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002439
2440 wl_event_source_remove(d->udev_drm_source);
2441 wl_event_source_remove(d->drm_source);
2442
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002443 destroy_sprites(d);
2444
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002445 weston_compositor_shutdown(ec);
2446
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002447 if (d->gbm)
2448 gbm_device_destroy(d->gbm);
2449
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002450 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002451
Rob Bradford45c15b82013-07-26 16:29:35 +01002452 close(d->drm.fd);
2453
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002454 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002455}
2456
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002457static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002458drm_compositor_set_modes(struct drm_compositor *compositor)
2459{
2460 struct drm_output *output;
2461 struct drm_mode *drm_mode;
2462 int ret;
2463
2464 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002465 if (!output->current) {
2466 /* If something that would cause the output to
2467 * switch mode happened while in another vt, we
2468 * might not have a current drm_fb. In that case,
2469 * schedule a repaint and let drm_output_repaint
2470 * handle setting the mode. */
2471 weston_output_schedule_repaint(&output->base);
2472 continue;
2473 }
2474
Hardeningff39efa2013-09-18 23:56:35 +02002475 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002476 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002477 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002478 &output->connector_id, 1,
2479 &drm_mode->mode_info);
2480 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002481 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002482 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002483 drm_mode->base.width, drm_mode->base.height,
2484 output->base.x, output->base.y);
2485 }
2486 }
2487}
2488
2489static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002490session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002491{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002492 struct weston_compositor *compositor = data;
2493 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002494 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002495 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002496
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002497 if (ec->base.session_active) {
2498 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002499 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002500 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002501 weston_compositor_damage_all(compositor);
Jonas Ådahl0feb32e2014-03-12 22:08:41 +01002502 udev_input_enable(&ec->input);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002503 } else {
2504 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002505 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002506
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002507 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002508 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002509
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002510 /* If we have a repaint scheduled (either from a
2511 * pending pageflip or the idle handler), make sure we
2512 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002513 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002514 * further attemps at repainting. When we switch
2515 * back, we schedule a repaint, which will process
2516 * pending frame callbacks. */
2517
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002518 wl_list_for_each(output, &ec->base.output_list, base.link) {
2519 output->base.repaint_needed = 0;
2520 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002521 }
2522
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002523 output = container_of(ec->base.output_list.next,
2524 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002525
2526 wl_list_for_each(sprite, &ec->sprite_list, link)
2527 drmModeSetPlane(ec->drm.fd,
2528 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002529 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002530 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002531 };
2532}
2533
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002534static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002535switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002536{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002537 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002538
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002539 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002540}
2541
David Herrmann0af066f2012-10-29 19:21:16 +01002542/*
2543 * Find primary GPU
2544 * Some systems may have multiple DRM devices attached to a single seat. This
2545 * function loops over all devices and tries to find a PCI device with the
2546 * boot_vga sysfs attribute set to 1.
2547 * If no such device is found, the first DRM device reported by udev is used.
2548 */
2549static struct udev_device*
2550find_primary_gpu(struct drm_compositor *ec, const char *seat)
2551{
2552 struct udev_enumerate *e;
2553 struct udev_list_entry *entry;
2554 const char *path, *device_seat, *id;
2555 struct udev_device *device, *drm_device, *pci;
2556
2557 e = udev_enumerate_new(ec->udev);
2558 udev_enumerate_add_match_subsystem(e, "drm");
2559 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2560
2561 udev_enumerate_scan_devices(e);
2562 drm_device = NULL;
2563 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2564 path = udev_list_entry_get_name(entry);
2565 device = udev_device_new_from_syspath(ec->udev, path);
2566 if (!device)
2567 continue;
2568 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2569 if (!device_seat)
2570 device_seat = default_seat;
2571 if (strcmp(device_seat, seat)) {
2572 udev_device_unref(device);
2573 continue;
2574 }
2575
2576 pci = udev_device_get_parent_with_subsystem_devtype(device,
2577 "pci", NULL);
2578 if (pci) {
2579 id = udev_device_get_sysattr_value(pci, "boot_vga");
2580 if (id && !strcmp(id, "1")) {
2581 if (drm_device)
2582 udev_device_unref(drm_device);
2583 drm_device = device;
2584 break;
2585 }
2586 }
2587
2588 if (!drm_device)
2589 drm_device = device;
2590 else
2591 udev_device_unref(device);
2592 }
2593
2594 udev_enumerate_unref(e);
2595 return drm_device;
2596}
2597
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002598static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002599planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002600{
2601 struct drm_compositor *c = data;
2602
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002603 switch (key) {
2604 case KEY_C:
2605 c->cursors_are_broken ^= 1;
2606 break;
2607 case KEY_V:
2608 c->sprites_are_broken ^= 1;
2609 break;
2610 case KEY_O:
2611 c->sprites_hidden ^= 1;
2612 break;
2613 default:
2614 break;
2615 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002616}
2617
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002618#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002619static void
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002620recorder_destroy(struct drm_output *output)
2621{
2622 vaapi_recorder_destroy(output->recorder);
2623 output->recorder = NULL;
2624
2625 output->base.disable_planes--;
2626
2627 wl_list_remove(&output->recorder_frame_listener.link);
2628 weston_log("[libva recorder] done\n");
2629}
2630
2631static void
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002632recorder_frame_notify(struct wl_listener *listener, void *data)
2633{
2634 struct drm_output *output;
2635 struct drm_compositor *c;
2636 int fd, ret;
2637
2638 output = container_of(listener, struct drm_output,
2639 recorder_frame_listener);
2640 c = (struct drm_compositor *) output->base.compositor;
2641
2642 if (!output->recorder)
2643 return;
2644
2645 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2646 DRM_CLOEXEC, &fd);
2647 if (ret) {
2648 weston_log("[libva recorder] "
2649 "failed to create prime fd for front buffer\n");
2650 return;
2651 }
2652
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002653 ret = vaapi_recorder_frame(output->recorder, fd,
2654 output->current->stride);
2655 if (ret < 0) {
2656 weston_log("[libva recorder] aborted: %m\n");
2657 recorder_destroy(output);
2658 }
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002659}
2660
2661static void *
2662create_recorder(struct drm_compositor *c, int width, int height,
2663 const char *filename)
2664{
2665 int fd;
2666 drm_magic_t magic;
2667
2668 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2669 if (fd < 0)
2670 return NULL;
2671
2672 drmGetMagic(fd, &magic);
2673 drmAuthMagic(c->drm.fd, magic);
2674
2675 return vaapi_recorder_create(fd, width, height, filename);
2676}
2677
2678static void
2679recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2680 void *data)
2681{
2682 struct drm_compositor *c = data;
2683 struct drm_output *output;
2684 int width, height;
2685
2686 output = container_of(c->base.output_list.next,
2687 struct drm_output, base.link);
2688
2689 if (!output->recorder) {
Ander Conselvan de Oliveira2ef1cd12014-05-06 16:49:06 +03002690 if (output->format != GBM_FORMAT_XRGB8888) {
2691 weston_log("failed to start vaapi recorder: "
2692 "output format not supported\n");
2693 return;
2694 }
2695
Hardeningff39efa2013-09-18 23:56:35 +02002696 width = output->base.current_mode->width;
2697 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002698
2699 output->recorder =
2700 create_recorder(c, width, height, "capture.h264");
2701 if (!output->recorder) {
2702 weston_log("failed to create vaapi recorder\n");
2703 return;
2704 }
2705
2706 output->base.disable_planes++;
2707
2708 output->recorder_frame_listener.notify = recorder_frame_notify;
2709 wl_signal_add(&output->base.frame_signal,
2710 &output->recorder_frame_listener);
2711
2712 weston_output_schedule_repaint(&output->base);
2713
2714 weston_log("[libva recorder] initialized\n");
2715 } else {
Ander Conselvan de Oliveira2d13fde2014-05-09 15:57:38 +03002716 recorder_destroy(output);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002717 }
2718}
2719#else
2720static void
2721recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2722 void *data)
2723{
2724 weston_log("Compiled without libva support\n");
2725}
2726#endif
2727
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002728static void
2729switch_to_gl_renderer(struct drm_compositor *c)
2730{
2731 struct drm_output *output;
2732
2733 if (!c->use_pixman)
2734 return;
2735
2736 weston_log("Switching to GL renderer\n");
2737
2738 c->gbm = create_gbm_device(c->drm.fd);
2739 if (!c->gbm) {
2740 weston_log("Failed to create gbm device. "
2741 "Aborting renderer switch\n");
2742 return;
2743 }
2744
2745 wl_list_for_each(output, &c->base.output_list, base.link)
2746 pixman_renderer_output_destroy(&output->base);
2747
2748 c->base.renderer->destroy(&c->base);
2749
2750 if (drm_compositor_create_gl_renderer(c) < 0) {
2751 gbm_device_destroy(c->gbm);
2752 weston_log("Failed to create GL renderer. Quitting.\n");
2753 /* FIXME: we need a function to shutdown cleanly */
2754 assert(0);
2755 }
2756
2757 wl_list_for_each(output, &c->base.output_list, base.link)
2758 drm_output_init_egl(output, c);
2759
2760 c->use_pixman = 0;
2761}
2762
2763static void
2764renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2765 void *data)
2766{
2767 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2768
2769 switch_to_gl_renderer(c);
2770}
2771
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002772static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002773drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002774 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002775 int *argc, char *argv[],
2776 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002777{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002778 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002779 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002780 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002781 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002782 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002783 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002784
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002785 weston_log("initializing drm backend\n");
2786
Peter Huttererf3d62272013-08-08 11:57:05 +10002787 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002788 if (ec == NULL)
2789 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002790
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002791 /* KMS support for sprites is not complete yet, so disable the
2792 * functionality for now. */
2793 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002794
2795 section = weston_config_get_section(config, "core", NULL, NULL);
Neil Roberts77c1a5b2014-03-07 18:05:50 +00002796 if (get_gbm_format_from_section(section,
2797 GBM_FORMAT_XRGB8888,
2798 &ec->format) == -1)
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002799 goto err_base;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002800
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002801 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002802
Daniel Stone725c2c32012-06-22 14:04:36 +01002803 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002804 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002805 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002806 goto err_base;
2807 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002808
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002809 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002810 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
David Herrmann2ecb84a2014-12-30 14:33:22 +01002811 param->seat_id, true);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002812 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002813 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002814 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002815 goto err_compositor;
2816 }
2817
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002818 ec->udev = udev_new();
2819 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002820 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002821 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002822 }
2823
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002824 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002825 ec->session_listener.notify = session_notify;
2826 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002827
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002828 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002829 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002830 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002831 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002832 }
David Herrmann0af066f2012-10-29 19:21:16 +01002833 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002834
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002835 if (init_drm(ec, drm_device) < 0) {
2836 weston_log("failed to initialize kms\n");
2837 goto err_udev_dev;
2838 }
2839
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002840 if (ec->use_pixman) {
2841 if (init_pixman(ec) < 0) {
2842 weston_log("failed to initialize pixman renderer\n");
2843 goto err_udev_dev;
2844 }
2845 } else {
2846 if (init_egl(ec) < 0) {
2847 weston_log("failed to initialize egl\n");
2848 goto err_udev_dev;
2849 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002850 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002851
2852 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002853 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002854
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002855 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002856
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002857 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002858 weston_compositor_add_key_binding(&ec->base, key,
2859 MODIFIER_CTRL | MODIFIER_ALT,
2860 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002861
Jesse Barnes58ef3792012-02-23 09:45:49 -05002862 wl_list_init(&ec->sprite_list);
2863 create_sprites(ec);
2864
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002865 if (udev_input_init(&ec->input,
2866 &ec->base, ec->udev, param->seat_id) < 0) {
2867 weston_log("failed to create input devices\n");
2868 goto err_sprite;
2869 }
2870
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002871 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002872 weston_log("failed to create output for %s\n", path);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002873 goto err_udev_input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002874 }
2875
Jason Ekstrand9fc71512014-04-02 19:53:46 -05002876 /* A this point we have some idea of whether or not we have a working
2877 * cursor plane. */
2878 if (!ec->cursors_are_broken)
2879 ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
2880
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002881 path = NULL;
2882
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002883 loop = wl_display_get_event_loop(ec->base.wl_display);
2884 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002885 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002886 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002887
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002888 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2889 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002890 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002891 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002892 }
2893 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2894 "drm", NULL);
2895 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002896 wl_event_loop_add_fd(loop,
2897 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002898 WL_EVENT_READABLE, udev_drm_event, ec);
2899
2900 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002901 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002902 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002903 }
2904
Daniel Stonea96b93c2012-06-22 14:04:37 +01002905 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002906
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002907 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002908 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002909 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002910 planes_binding, ec);
2911 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2912 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002913 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2914 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002915 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2916 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002917
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002918 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002919
2920err_udev_monitor:
2921 wl_event_source_remove(ec->udev_drm_source);
2922 udev_monitor_unref(ec->udev_monitor);
2923err_drm_source:
2924 wl_event_source_remove(ec->drm_source);
Ander Conselvan de Oliveira4ade0e42014-04-17 13:08:45 +03002925err_udev_input:
Rob Bradfordd355b802013-05-31 18:09:55 +01002926 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002927err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002928 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002929 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002930 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002931err_udev_dev:
2932 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002933err_launcher:
2934 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002935err_udev:
2936 udev_unref(ec->udev);
2937err_compositor:
2938 weston_compositor_shutdown(&ec->base);
2939err_base:
2940 free(ec);
2941 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002942}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002943
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002944WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002945backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002946 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002947{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002948 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002949
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002950 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002951 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2952 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2953 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002954 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002955 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002956 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002957
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002958 param.seat_id = default_seat;
2959
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002960 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002961
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002962 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002963}