blob: 83ff1c86f0a2121eeef53564633f3fb0c0edaf78 [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>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030033#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020034#include <sys/mman.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030035#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040036
Benjamin Franzkec649a922011-03-02 11:56:04 +010037#include <xf86drm.h>
38#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050039#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010040
Benjamin Franzke060cf802011-04-30 09:32:11 +020041#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020042#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040043#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020044
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040045#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010046#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020047#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050048#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010049#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030050#include "vaapi-recorder.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040051
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030052#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
53#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
54#endif
55
Kristian Høgsberg061c4252012-06-28 11:28:15 -040056static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060057
58enum output_config {
59 OUTPUT_CONFIG_INVALID = 0,
60 OUTPUT_CONFIG_OFF,
61 OUTPUT_CONFIG_PREFERRED,
62 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060063 OUTPUT_CONFIG_MODE,
64 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060065};
66
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040067struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050068 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040069
70 struct udev *udev;
71 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040072
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010073 struct udev_monitor *udev_monitor;
74 struct wl_event_source *udev_drm_source;
75
Benjamin Franzke2af7f102011-03-02 11:14:59 +010076 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010077 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010078 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030079 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010080 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020081 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050082 uint32_t *crtcs;
83 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050084 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010085 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050086 struct tty *tty;
Kristian Høgsberg61741a22013-09-17 16:02:57 -070087 struct wl_listener session_listener;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020088
Rob Clark4339add2012-08-09 14:18:28 -050089 /* we need these parameters in order to not fail drmModeAddFB2()
90 * due to out of bounds dimensions, and then mistakenly set
91 * sprites_are_broken:
92 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020093 uint32_t min_width, max_width;
94 uint32_t min_height, max_height;
95 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050096
Jesse Barnes58ef3792012-02-23 09:45:49 -050097 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -050098 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +020099 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500100
Rob Clarkab5b1e32012-08-09 13:24:45 -0500101 int cursors_are_broken;
102
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200103 int use_pixman;
104
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200105 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300106
107 clockid_t clock;
Rob Bradfordd355b802013-05-31 18:09:55 +0100108 struct udev_input input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400109};
110
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400111struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500112 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400113 drmModeModeInfo mode_info;
114};
115
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300116struct drm_output;
117
118struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300119 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200120 uint32_t fb_id, stride, handle, size;
121 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300122 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200123 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200124
125 /* Used by gbm fbs */
126 struct gbm_bo *bo;
127
128 /* Used by dumb fbs */
129 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300130};
131
Richard Hughes2b2092a2013-04-24 14:58:02 +0100132struct drm_edid {
133 char eisa_id[13];
134 char monitor_name[13];
135 char pnp_id[5];
136 char serial_number[13];
137};
138
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400139struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500140 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400141
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400142 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500143 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400144 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700145 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100146 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300147 drmModePropertyPtr dpms_prop;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200148
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300149 int vblank_pending;
150 int page_flip_pending;
151
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400152 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400153 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400154 struct weston_plane cursor_plane;
155 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400156 struct weston_surface *cursor_surface;
157 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300158 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200159 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200160
161 struct drm_fb *dumb[2];
162 pixman_image_t *image[2];
163 int current_image;
164 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300165
166 struct vaapi_recorder *recorder;
167 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400168};
169
Jesse Barnes58ef3792012-02-23 09:45:49 -0500170/*
171 * An output has a primary display plane plus zero or more sprites for
172 * blending display contents.
173 */
174struct drm_sprite {
175 struct wl_list link;
176
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400177 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500178
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200179 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300180 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500181 struct drm_compositor *compositor;
182
Jesse Barnes58ef3792012-02-23 09:45:49 -0500183 uint32_t possible_crtcs;
184 uint32_t plane_id;
185 uint32_t count_formats;
186
187 int32_t src_x, src_y;
188 uint32_t src_w, src_h;
189 uint32_t dest_x, dest_y;
190 uint32_t dest_w, dest_h;
191
192 uint32_t formats[];
193};
194
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500195static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400196
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400197static void
198drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400199
Jesse Barnes58ef3792012-02-23 09:45:49 -0500200static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500201drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
202{
203 struct weston_compositor *ec = output_base->compositor;
204 struct drm_compositor *c =(struct drm_compositor *) ec;
205 struct drm_output *output = (struct drm_output *) output_base;
206 int crtc;
207
208 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
209 if (c->crtcs[crtc] != output->crtc_id)
210 continue;
211
212 if (supported & (1 << crtc))
213 return -1;
214 }
215
216 return 0;
217}
218
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300219static void
220drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
221{
222 struct drm_fb *fb = data;
223 struct gbm_device *gbm = gbm_bo_get_device(bo);
224
225 if (fb->fb_id)
226 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
227
Pekka Paalanende685b82012-12-04 15:58:12 +0200228 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300229
230 free(data);
231}
232
233static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200234drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
235{
236 struct drm_fb *fb;
237 int ret;
238
239 struct drm_mode_create_dumb create_arg;
240 struct drm_mode_destroy_dumb destroy_arg;
241 struct drm_mode_map_dumb map_arg;
242
Peter Huttererf3d62272013-08-08 11:57:05 +1000243 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200244 if (!fb)
245 return NULL;
246
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700247 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200248 create_arg.bpp = 32;
249 create_arg.width = width;
250 create_arg.height = height;
251
252 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
253 if (ret)
254 goto err_fb;
255
256 fb->handle = create_arg.handle;
257 fb->stride = create_arg.pitch;
258 fb->size = create_arg.size;
259 fb->fd = ec->drm.fd;
260
261 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
262 fb->stride, fb->handle, &fb->fb_id);
263 if (ret)
264 goto err_bo;
265
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700266 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200267 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400268 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200269 if (ret)
270 goto err_add_fb;
271
272 fb->map = mmap(0, fb->size, PROT_WRITE,
273 MAP_SHARED, ec->drm.fd, map_arg.offset);
274 if (fb->map == MAP_FAILED)
275 goto err_add_fb;
276
277 return fb;
278
279err_add_fb:
280 drmModeRmFB(ec->drm.fd, fb->fb_id);
281err_bo:
282 memset(&destroy_arg, 0, sizeof(destroy_arg));
283 destroy_arg.handle = create_arg.handle;
284 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
285err_fb:
286 free(fb);
287 return NULL;
288}
289
290static void
291drm_fb_destroy_dumb(struct drm_fb *fb)
292{
293 struct drm_mode_destroy_dumb destroy_arg;
294
295 if (!fb->map)
296 return;
297
298 if (fb->fb_id)
299 drmModeRmFB(fb->fd, fb->fb_id);
300
301 weston_buffer_reference(&fb->buffer_ref, NULL);
302
303 munmap(fb->map, fb->size);
304
305 memset(&destroy_arg, 0, sizeof(destroy_arg));
306 destroy_arg.handle = fb->handle;
307 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
308
309 free(fb);
310}
311
312static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500313drm_fb_get_from_bo(struct gbm_bo *bo,
314 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300315{
316 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200317 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200318 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300319 int ret;
320
321 if (fb)
322 return fb;
323
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200324 fb = calloc(1, sizeof *fb);
325 if (!fb)
326 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300327
328 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300329
330 width = gbm_bo_get_width(bo);
331 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200332 fb->stride = gbm_bo_get_stride(bo);
333 fb->handle = gbm_bo_get_handle(bo).u32;
334 fb->size = fb->stride * height;
335 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300336
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200337 if (compositor->min_width > width || width > compositor->max_width ||
338 compositor->min_height > height ||
339 height > compositor->max_height) {
340 weston_log("bo geometry out of bounds\n");
341 goto err_free;
342 }
343
344 ret = -1;
345
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200346 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200347 handles[0] = fb->handle;
348 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200349 offsets[0] = 0;
350
351 ret = drmModeAddFB2(compositor->drm.fd, width, height,
352 format, handles, pitches, offsets,
353 &fb->fb_id, 0);
354 if (ret) {
355 weston_log("addfb2 failed: %m\n");
356 compositor->no_addfb2 = 1;
357 compositor->sprites_are_broken = 1;
358 }
359 }
360
361 if (ret)
362 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200363 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200364
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300365 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200366 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200367 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300368 }
369
370 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
371
372 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200373
374err_free:
375 free(fb);
376 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300377}
378
379static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500380drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200381{
Pekka Paalanende685b82012-12-04 15:58:12 +0200382 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200383
384 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200385
Pekka Paalanende685b82012-12-04 15:58:12 +0200386 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200387}
388
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200389static void
390drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
391{
392 if (!fb)
393 return;
394
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200395 if (fb->map &&
396 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200397 drm_fb_destroy_dumb(fb);
398 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200399 if (fb->is_client_buffer)
400 gbm_bo_destroy(fb->bo);
401 else
402 gbm_surface_release_buffer(output->surface,
403 output->current->bo);
404 }
405}
406
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500407static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200408drm_output_check_scanout_format(struct drm_output *output,
409 struct weston_surface *es, struct gbm_bo *bo)
410{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200411 uint32_t format;
412 pixman_region32_t r;
413
414 format = gbm_bo_get_format(bo);
415
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500416 switch (format) {
417 case GBM_FORMAT_XRGB8888:
418 return format;
419 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200420 /* We can only scanout an ARGB buffer if the surface's
421 * opaque region covers the whole output */
422 pixman_region32_init(&r);
423 pixman_region32_subtract(&r, &output->base.region,
424 &es->opaque);
425
426 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500427 format = GBM_FORMAT_XRGB8888;
428 else
429 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200430
431 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200432
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500433 return format;
434 default:
435 return 0;
436 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200437}
438
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400439static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400440drm_output_prepare_scanout_surface(struct weston_output *_output,
441 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500442{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400443 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500444 struct drm_compositor *c =
445 (struct drm_compositor *) output->base.compositor;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500446 struct weston_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300447 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500448 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500449
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500450 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200451 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200452 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200453 buffer->width != output->base.current->width ||
454 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200455 output->base.transform != es->buffer_transform ||
456 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400457 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500458
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400459 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700460 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500461
Rob Bradford9b101872012-09-14 23:25:41 +0100462 /* Unable to use the buffer for scanout */
463 if (!bo)
464 return NULL;
465
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500466 format = drm_output_check_scanout_format(output, es, bo);
467 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300468 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400469 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300470 }
471
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500472 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300473 if (!output->next) {
474 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400475 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300476 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500477
Pekka Paalanende685b82012-12-04 15:58:12 +0200478 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500479
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400480 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500481}
482
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500483static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200484drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400485{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200486 struct drm_compositor *c =
487 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300488 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400489
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200490 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400491
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300492 bo = gbm_surface_lock_front_buffer(output->surface);
493 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200494 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400495 return;
496 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300497
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500498 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300499 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200500 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300501 gbm_surface_release_buffer(output->surface, bo);
502 return;
503 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400504}
505
506static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200507drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
508{
509 struct weston_compositor *ec = output->base.compositor;
510 pixman_region32_t total_damage, previous_damage;
511
512 pixman_region32_init(&total_damage);
513 pixman_region32_init(&previous_damage);
514
515 pixman_region32_copy(&previous_damage, damage);
516
517 pixman_region32_union(&total_damage, damage, &output->previous_damage);
518 pixman_region32_copy(&output->previous_damage, &previous_damage);
519
520 output->current_image ^= 1;
521
522 output->next = output->dumb[output->current_image];
523 pixman_renderer_output_set_buffer(&output->base,
524 output->image[output->current_image]);
525
526 ec->renderer->repaint_output(&output->base, &total_damage);
527
528 pixman_region32_fini(&total_damage);
529 pixman_region32_fini(&previous_damage);
530}
531
532static void
533drm_output_render(struct drm_output *output, pixman_region32_t *damage)
534{
535 struct drm_compositor *c =
536 (struct drm_compositor *) output->base.compositor;
537
538 if (c->use_pixman)
539 drm_output_render_pixman(output, damage);
540 else
541 drm_output_render_gl(output, damage);
542
543 pixman_region32_subtract(&c->base.primary_plane.damage,
544 &c->base.primary_plane.damage, damage);
545}
546
547static void
Richard Hughese7299962013-05-01 21:52:12 +0100548drm_output_set_gamma(struct weston_output *output_base,
549 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
550{
551 int rc;
552 struct drm_output *output = (struct drm_output *) output_base;
553 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
554
555 /* check */
556 if (output_base->gamma_size != size)
557 return;
558 if (!output->original_crtc)
559 return;
560
561 rc = drmModeCrtcSetGamma(compositor->drm.fd,
562 output->crtc_id,
563 size, r, g, b);
564 if (rc)
565 weston_log("set gamma failed: %m\n");
566}
567
568static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500569drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400570 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100571{
572 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500573 struct drm_compositor *compositor =
574 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500575 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400576 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500577 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100578
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300579 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400580 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300581 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400582 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100583
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400584 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300585 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400586 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300587 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400588 &output->connector_id, 1,
589 &mode->mode_info);
590 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200591 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400592 return;
593 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300594 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200595 }
596
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500597 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300598 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500599 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200600 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500601 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500602 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100603
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300604 output->page_flip_pending = 1;
605
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400606 drm_output_set_cursor(output);
607
Jesse Barnes58ef3792012-02-23 09:45:49 -0500608 /*
609 * Now, update all the sprite surfaces
610 */
611 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200612 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500613 drmVBlank vbl = {
614 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
615 .request.sequence = 1,
616 };
617
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200618 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200619 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500620 continue;
621
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200622 if (s->next && !compositor->sprites_hidden)
623 fb_id = s->next->fb_id;
624
Jesse Barnes58ef3792012-02-23 09:45:49 -0500625 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200626 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500627 s->dest_x, s->dest_y,
628 s->dest_w, s->dest_h,
629 s->src_x, s->src_y,
630 s->src_w, s->src_h);
631 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200632 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500633 ret, strerror(errno));
634
Rob Clark5ca1a472012-08-08 20:27:37 -0500635 if (output->pipe > 0)
636 vbl.request.type |= DRM_VBLANK_SECONDARY;
637
Jesse Barnes58ef3792012-02-23 09:45:49 -0500638 /*
639 * Queue a vblank signal so we know when the surface
640 * becomes active on the display or has been replaced.
641 */
642 vbl.request.signal = (unsigned long)s;
643 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
644 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200645 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500646 ret, strerror(errno));
647 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300648
649 s->output = output;
650 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500651 }
652
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500653 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400654}
655
656static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200657drm_output_start_repaint_loop(struct weston_output *output_base)
658{
659 struct drm_output *output = (struct drm_output *) output_base;
660 struct drm_compositor *compositor = (struct drm_compositor *)
661 output_base->compositor;
662 uint32_t fb_id;
663
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300664 struct timespec ts;
665
666 if (!output->current) {
667 /* We can't page flip if there's no mode set */
668 uint32_t msec;
669
670 clock_gettime(compositor->clock, &ts);
671 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
672 weston_output_finish_frame(output_base, msec);
673 return;
674 }
675
676 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200677
678 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
679 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
680 weston_log("queueing pageflip failed: %m\n");
681 return;
682 }
683}
684
685static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500686vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
687 void *data)
688{
689 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300690 struct drm_output *output = s->output;
691 uint32_t msecs;
692
693 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500694
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200695 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200696 s->current = s->next;
697 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300698
699 if (!output->page_flip_pending) {
700 msecs = sec * 1000 + usec / 1000;
701 weston_output_finish_frame(&output->base, msecs);
702 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500703}
704
705static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400706page_flip_handler(int fd, unsigned int frame,
707 unsigned int sec, unsigned int usec, void *data)
708{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200709 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400710 uint32_t msecs;
711
Jonas Ådahle5a12252013-04-05 23:07:11 +0200712 /* We don't set page_flip_pending on start_repaint_loop, in that case
713 * we just want to page flip to the current buffer to get an accurate
714 * timestamp */
715 if (output->page_flip_pending) {
716 drm_output_release_fb(output, output->current);
717 output->current = output->next;
718 output->next = NULL;
719 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300720
Jonas Ådahle5a12252013-04-05 23:07:11 +0200721 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400722
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300723 if (!output->vblank_pending) {
724 msecs = sec * 1000 + usec / 1000;
725 weston_output_finish_frame(&output->base, msecs);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300726
727 /* We can't call this from frame_notify, because the output's
728 * repaint needed flag is cleared just after that */
729 if (output->recorder)
730 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300731 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200732}
733
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500734static uint32_t
735drm_output_check_sprite_format(struct drm_sprite *s,
736 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500737{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500738 uint32_t i, format;
739
740 format = gbm_bo_get_format(bo);
741
742 if (format == GBM_FORMAT_ARGB8888) {
743 pixman_region32_t r;
744
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500745 pixman_region32_init_rect(&r, 0, 0,
746 es->geometry.width,
747 es->geometry.height);
748 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500749
750 if (!pixman_region32_not_empty(&r))
751 format = GBM_FORMAT_XRGB8888;
752
753 pixman_region32_fini(&r);
754 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500755
756 for (i = 0; i < s->count_formats; i++)
757 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500758 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500759
760 return 0;
761}
762
763static int
764drm_surface_transform_supported(struct weston_surface *es)
765{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500766 return !es->transform.enabled ||
767 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500768}
769
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400770static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500771drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400772 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500773{
774 struct weston_compositor *ec = output_base->compositor;
775 struct drm_compositor *c =(struct drm_compositor *) ec;
776 struct drm_sprite *s;
777 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500778 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500779 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200780 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500781 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400782 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500783
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200784 if (c->gbm == NULL)
785 return NULL;
786
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200787 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200788 return NULL;
789
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200790 if (es->buffer_scale != output_base->scale)
791 return NULL;
792
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500793 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400794 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500795
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300796 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400797 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300798
Pekka Paalanende685b82012-12-04 15:58:12 +0200799 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400800 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200802 if (es->alpha != 1.0f)
803 return NULL;
804
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500805 if (wl_shm_buffer_get(es->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500806 return NULL;
807
Jesse Barnes58ef3792012-02-23 09:45:49 -0500808 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400809 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500810
Jesse Barnes58ef3792012-02-23 09:45:49 -0500811 wl_list_for_each(s, &c->sprite_list, link) {
812 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
813 continue;
814
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200815 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500816 found = 1;
817 break;
818 }
819 }
820
821 /* No sprites available */
822 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400823 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500824
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400825 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700826 es->buffer_ref.buffer->resource,
827 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400828 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400829 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400830
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500831 format = drm_output_check_sprite_format(s, es, bo);
832 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200833 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400834 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500835 }
836
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200837 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200838 if (!s->next) {
839 gbm_bo_destroy(bo);
840 return NULL;
841 }
842
Pekka Paalanende685b82012-12-04 15:58:12 +0200843 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500844
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400845 box = pixman_region32_extents(&es->transform.boundingbox);
846 s->plane.x = box->x1;
847 s->plane.y = box->y1;
848
Jesse Barnes58ef3792012-02-23 09:45:49 -0500849 /*
850 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200851 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500852 * for us already).
853 */
854 pixman_region32_init(&dest_rect);
855 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
856 &output_base->region);
857 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
858 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200859 tbox = weston_transformed_rect(output_base->width,
860 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200861 output_base->transform,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200862 output_base->scale,
863 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200864 s->dest_x = tbox.x1;
865 s->dest_y = tbox.y1;
866 s->dest_w = tbox.x2 - tbox.x1;
867 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500868 pixman_region32_fini(&dest_rect);
869
870 pixman_region32_init(&src_rect);
871 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
872 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500873 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400874
875 weston_surface_from_global_fixed(es,
876 wl_fixed_from_int(box->x1),
877 wl_fixed_from_int(box->y1),
878 &sx1, &sy1);
879 weston_surface_from_global_fixed(es,
880 wl_fixed_from_int(box->x2),
881 wl_fixed_from_int(box->y2),
882 &sx2, &sy2);
883
884 if (sx1 < 0)
885 sx1 = 0;
886 if (sy1 < 0)
887 sy1 = 0;
888 if (sx2 > wl_fixed_from_int(es->geometry.width))
889 sx2 = wl_fixed_from_int(es->geometry.width);
890 if (sy2 > wl_fixed_from_int(es->geometry.height))
891 sy2 = wl_fixed_from_int(es->geometry.height);
892
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200893 tbox.x1 = sx1;
894 tbox.y1 = sy1;
895 tbox.x2 = sx2;
896 tbox.y2 = sy2;
897
898 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
899 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200900 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200901
902 s->src_x = tbox.x1 << 8;
903 s->src_y = tbox.y1 << 8;
904 s->src_w = (tbox.x2 - tbox.x1) << 8;
905 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500906 pixman_region32_fini(&src_rect);
907
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400908 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500909}
910
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400911static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400912drm_output_prepare_cursor_surface(struct weston_output *output_base,
913 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500914{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400915 struct drm_compositor *c =
916 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400917 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400918
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200919 if (c->gbm == NULL)
920 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200921 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
922 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400923 if (output->cursor_surface)
924 return NULL;
925 if (es->output_mask != (1u << output_base->id))
926 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500927 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400928 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200929 if (es->buffer_ref.buffer == NULL ||
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500930 !wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400931 es->geometry.width > 64 || es->geometry.height > 64)
932 return NULL;
933
934 output->cursor_surface = es;
935
936 return &output->cursor_plane;
937}
938
939static void
940drm_output_set_cursor(struct drm_output *output)
941{
942 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400943 struct drm_compositor *c =
944 (struct drm_compositor *) output->base.compositor;
945 EGLint handle, stride;
946 struct gbm_bo *bo;
947 uint32_t buf[64 * 64];
948 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400949 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500950
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400951 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400952 if (es == NULL) {
953 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
954 return;
955 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500956
Pekka Paalanende685b82012-12-04 15:58:12 +0200957 if (es->buffer_ref.buffer &&
958 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400959 pixman_region32_fini(&output->cursor_plane.damage);
960 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400961 output->current_cursor ^= 1;
962 bo = output->cursor_bo[output->current_cursor];
963 memset(buf, 0, sizeof buf);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500964 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
965 s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400966 for (i = 0; i < es->geometry.height; i++)
967 memcpy(buf + i * 64, s + i * stride,
968 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500969
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400970 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300971 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400972
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400973 handle = gbm_bo_get_handle(bo).s32;
974 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500975 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300976 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500977 c->cursors_are_broken = 1;
978 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400979 }
980
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200981 x = (es->geometry.x - output->base.x) * output->base.scale;
982 y = (es->geometry.y - output->base.y) * output->base.scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400983 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500984 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400985 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500986 c->cursors_are_broken = 1;
987 }
988
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400989 output->cursor_plane.x = x;
990 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400991 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500992}
993
Jesse Barnes58ef3792012-02-23 09:45:49 -0500994static void
995drm_assign_planes(struct weston_output *output)
996{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400997 struct drm_compositor *c =
998 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400999 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001000 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001001 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001002
1003 /*
1004 * Find a surface for each sprite in the output using some heuristics:
1005 * 1) size
1006 * 2) frequency of update
1007 * 3) opacity (though some hw might support alpha blending)
1008 * 4) clipping (this can be fixed with color keys)
1009 *
1010 * The idea is to save on blitting since this should save power.
1011 * If we can get a large video surface on the sprite for example,
1012 * the main display surface may not need to update at all, and
1013 * the client buffer can be used directly for the sprite surface
1014 * as we do for flipping full screen surfaces.
1015 */
1016 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001017 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001018 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001019 /* test whether this buffer can ever go into a plane:
1020 * non-shm, or small enough to be a cursor
1021 */
1022 if ((es->buffer_ref.buffer &&
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001023 !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) ||
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001024 (es->geometry.width <= 64 && es->geometry.height <= 64))
1025 es->keep_buffer = 1;
1026 else
1027 es->keep_buffer = 0;
1028
Jesse Barnes58ef3792012-02-23 09:45:49 -05001029 pixman_region32_init(&surface_overlap);
1030 pixman_region32_intersect(&surface_overlap, &overlap,
1031 &es->transform.boundingbox);
1032
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001033 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001034 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001035 next_plane = primary;
1036 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001037 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001038 if (next_plane == NULL)
1039 next_plane = drm_output_prepare_scanout_surface(output, es);
1040 if (next_plane == NULL)
1041 next_plane = drm_output_prepare_overlay_surface(output, es);
1042 if (next_plane == NULL)
1043 next_plane = primary;
1044 weston_surface_move_to_plane(es, next_plane);
1045 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001046 pixman_region32_union(&overlap, &overlap,
1047 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001048
Jesse Barnes58ef3792012-02-23 09:45:49 -05001049 pixman_region32_fini(&surface_overlap);
1050 }
1051 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001052}
1053
Matt Roper361d2ad2011-08-29 13:52:23 -07001054static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001055drm_output_fini_pixman(struct drm_output *output);
1056
1057static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001058drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001059{
1060 struct drm_output *output = (struct drm_output *) output_base;
1061 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001062 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001063 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001064
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001065 if (output->backlight)
1066 backlight_destroy(output->backlight);
1067
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001068 drmModeFreeProperty(output->dpms_prop);
1069
Matt Roper361d2ad2011-08-29 13:52:23 -07001070 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001071 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001072
1073 /* Restore original CRTC state */
1074 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001075 origcrtc->x, origcrtc->y,
1076 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001077 drmModeFreeCrtc(origcrtc);
1078
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001079 c->crtc_allocator &= ~(1 << output->crtc_id);
1080 c->connector_allocator &= ~(1 << output->connector_id);
1081
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001082 if (c->use_pixman) {
1083 drm_output_fini_pixman(output);
1084 } else {
1085 gl_renderer_output_destroy(output_base);
1086 gbm_surface_destroy(output->surface);
1087 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001088
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001089 weston_plane_release(&output->fb_plane);
1090 weston_plane_release(&output->cursor_plane);
1091
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001092 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001093 wl_list_remove(&output->base.link);
1094
Matt Roper361d2ad2011-08-29 13:52:23 -07001095 free(output);
1096}
1097
Alex Wub7b8bda2012-04-17 17:20:48 +08001098static struct drm_mode *
1099choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1100{
1101 struct drm_mode *tmp_mode = NULL, *mode;
1102
1103 if (output->base.current->width == target_mode->width &&
1104 output->base.current->height == target_mode->height &&
1105 (output->base.current->refresh == target_mode->refresh ||
1106 target_mode->refresh == 0))
1107 return (struct drm_mode *)output->base.current;
1108
1109 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1110 if (mode->mode_info.hdisplay == target_mode->width &&
1111 mode->mode_info.vdisplay == target_mode->height) {
1112 if (mode->mode_info.vrefresh == target_mode->refresh ||
1113 target_mode->refresh == 0) {
1114 return mode;
1115 } else if (!tmp_mode)
1116 tmp_mode = mode;
1117 }
1118 }
1119
1120 return tmp_mode;
1121}
1122
1123static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001124drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001125static int
1126drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001127
1128static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001129drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1130{
1131 struct drm_output *output;
1132 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001133 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001134
1135 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001136 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001137 return -1;
1138 }
1139
1140 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001141 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001142 return -1;
1143 }
1144
1145 ec = (struct drm_compositor *)output_base->compositor;
1146 output = (struct drm_output *)output_base;
1147 drm_mode = choose_mode (output, mode);
1148
1149 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001150 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001151 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001152 }
1153
1154 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001155 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001156
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001157 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001158
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001159 output->base.current = &drm_mode->base;
1160 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001161 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1162
Alex Wub7b8bda2012-04-17 17:20:48 +08001163 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001164 drm_output_release_fb(output, output->current);
1165 drm_output_release_fb(output, output->next);
1166 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001167
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001168 if (ec->use_pixman) {
1169 drm_output_fini_pixman(output);
1170 if (drm_output_init_pixman(output, ec) < 0) {
1171 weston_log("failed to init output pixman state with "
1172 "new mode\n");
1173 return -1;
1174 }
1175 } else {
1176 gl_renderer_output_destroy(&output->base);
1177 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001178
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001179 if (drm_output_init_egl(output, ec) < 0) {
1180 weston_log("failed to init output egl state with "
1181 "new mode");
1182 return -1;
1183 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001184 }
1185
Alex Wub7b8bda2012-04-17 17:20:48 +08001186 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001187}
1188
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001189static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001190on_drm_input(int fd, uint32_t mask, void *data)
1191{
1192 drmEventContext evctx;
1193
1194 memset(&evctx, 0, sizeof evctx);
1195 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1196 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001197 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001198 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001199
1200 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001201}
1202
1203static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001204init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001205{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001206 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001207 uint64_t cap;
1208 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001209
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001210 sysnum = udev_device_get_sysnum(device);
1211 if (sysnum)
1212 ec->drm.id = atoi(sysnum);
1213 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001214 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001215 return -1;
1216 }
1217
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001218 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001219 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001220 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001221 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001222 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001223 udev_device_get_devnode(device));
1224 return -1;
1225 }
1226
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001227 weston_log("using %s\n", filename);
1228
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001229 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001230 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001231
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001232 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1233 if (ret == 0 && cap == 1)
1234 ec->clock = CLOCK_MONOTONIC;
1235 else
1236 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001237
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001238 return 0;
1239}
1240
1241static int
1242init_egl(struct drm_compositor *ec)
1243{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001244 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001245
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001246 if (!ec->gbm)
1247 return -1;
1248
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001249 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001250 NULL) < 0) {
1251 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001252 return -1;
1253 }
1254
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001255 return 0;
1256}
1257
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001258static int
1259init_pixman(struct drm_compositor *ec)
1260{
1261 return pixman_renderer_init(&ec->base);
1262}
1263
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001264static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001265drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001266{
1267 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001268 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001269
1270 mode = malloc(sizeof *mode);
1271 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001272 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001273
1274 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001275 mode->base.width = info->hdisplay;
1276 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001277
1278 /* Calculate higher precision (mHz) refresh rate */
1279 refresh = (info->clock * 1000000LL / info->htotal +
1280 info->vtotal / 2) / info->vtotal;
1281
1282 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1283 refresh *= 2;
1284 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1285 refresh /= 2;
1286 if (info->vscan > 1)
1287 refresh /= info->vscan;
1288
1289 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001290 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001291
1292 if (info->type & DRM_MODE_TYPE_PREFERRED)
1293 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1294
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001295 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1296
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001297 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001298}
1299
1300static int
1301drm_subpixel_to_wayland(int drm_value)
1302{
1303 switch (drm_value) {
1304 default:
1305 case DRM_MODE_SUBPIXEL_UNKNOWN:
1306 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1307 case DRM_MODE_SUBPIXEL_NONE:
1308 return WL_OUTPUT_SUBPIXEL_NONE;
1309 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1310 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1311 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1312 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1313 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1314 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1315 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1316 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1317 }
1318}
1319
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001320/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001321static uint32_t
1322drm_get_backlight(struct drm_output *output)
1323{
1324 long brightness, max_brightness, norm;
1325
1326 brightness = backlight_get_brightness(output->backlight);
1327 max_brightness = backlight_get_max_brightness(output->backlight);
1328
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001329 /* convert it on a scale of 0 to 255 */
1330 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001331
1332 return (uint32_t) norm;
1333}
1334
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001335/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001336static void
1337drm_set_backlight(struct weston_output *output_base, uint32_t value)
1338{
1339 struct drm_output *output = (struct drm_output *) output_base;
1340 long max_brightness, new_brightness;
1341
1342 if (!output->backlight)
1343 return;
1344
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001345 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001346 return;
1347
1348 max_brightness = backlight_get_max_brightness(output->backlight);
1349
1350 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001351 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001352
1353 backlight_set_brightness(output->backlight, new_brightness);
1354}
1355
1356static drmModePropertyPtr
1357drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1358{
1359 drmModePropertyPtr props;
1360 int i;
1361
1362 for (i = 0; i < connector->count_props; i++) {
1363 props = drmModeGetProperty(fd, connector->props[i]);
1364 if (!props)
1365 continue;
1366
1367 if (!strcmp(props->name, name))
1368 return props;
1369
1370 drmModeFreeProperty(props);
1371 }
1372
1373 return NULL;
1374}
1375
1376static void
1377drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1378{
1379 struct drm_output *output = (struct drm_output *) output_base;
1380 struct weston_compositor *ec = output_base->compositor;
1381 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001382
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001383 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001384 return;
1385
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001386 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1387 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001388}
1389
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001390static const char *connector_type_names[] = {
1391 "None",
1392 "VGA",
1393 "DVI",
1394 "DVI",
1395 "DVI",
1396 "Composite",
1397 "TV",
1398 "LVDS",
1399 "CTV",
1400 "DIN",
1401 "DP",
1402 "HDMI",
1403 "HDMI",
1404 "TV",
1405 "eDP",
1406};
1407
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001408static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001409find_crtc_for_connector(struct drm_compositor *ec,
1410 drmModeRes *resources, drmModeConnector *connector)
1411{
1412 drmModeEncoder *encoder;
1413 uint32_t possible_crtcs;
1414 int i, j;
1415
1416 for (j = 0; j < connector->count_encoders; j++) {
1417 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1418 if (encoder == NULL) {
1419 weston_log("Failed to get encoder.\n");
1420 return -1;
1421 }
1422 possible_crtcs = encoder->possible_crtcs;
1423 drmModeFreeEncoder(encoder);
1424
1425 for (i = 0; i < resources->count_crtcs; i++) {
1426 if (possible_crtcs & (1 << i) &&
1427 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1428 return i;
1429 }
1430 }
1431
1432 return -1;
1433}
1434
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001435/* Init output state that depends on gl or gbm */
1436static int
1437drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1438{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001439 int i, flags;
1440
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001441 output->surface = gbm_surface_create(ec->gbm,
Alexander Larsson0b135062013-05-28 16:23:36 +02001442 output->base.current->width,
1443 output->base.current->height,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001444 GBM_FORMAT_XRGB8888,
1445 GBM_BO_USE_SCANOUT |
1446 GBM_BO_USE_RENDERING);
1447 if (!output->surface) {
1448 weston_log("failed to create gbm surface\n");
1449 return -1;
1450 }
1451
1452 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001453 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001454 gbm_surface_destroy(output->surface);
1455 return -1;
1456 }
1457
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001458 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1459
1460 for (i = 0; i < 2; i++) {
1461 if (output->cursor_bo[i])
1462 continue;
1463
1464 output->cursor_bo[i] =
1465 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1466 flags);
1467 }
1468
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001469 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1470 weston_log("cursor buffers unavailable, using gl cursors\n");
1471 ec->cursors_are_broken = 1;
1472 }
1473
1474 return 0;
1475}
1476
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001477static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001478drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1479{
1480 int w = output->base.current->width;
1481 int h = output->base.current->height;
1482 unsigned int i;
1483
1484 /* FIXME error checking */
1485
1486 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001487 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001488 if (!output->dumb[i])
1489 goto err;
1490
1491 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001492 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001493 output->dumb[i]->map,
1494 output->dumb[i]->stride);
1495 if (!output->image[i])
1496 goto err;
1497 }
1498
1499 if (pixman_renderer_output_create(&output->base) < 0)
1500 goto err;
1501
1502 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001503 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001504
1505 return 0;
1506
1507err:
1508 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1509 if (output->dumb[i])
1510 drm_fb_destroy_dumb(output->dumb[i]);
1511 if (output->image[i])
1512 pixman_image_unref(output->image[i]);
1513
1514 output->dumb[i] = NULL;
1515 output->image[i] = NULL;
1516 }
1517
1518 return -1;
1519}
1520
1521static void
1522drm_output_fini_pixman(struct drm_output *output)
1523{
1524 unsigned int i;
1525
1526 pixman_renderer_output_destroy(&output->base);
1527 pixman_region32_fini(&output->previous_damage);
1528
1529 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1530 drm_fb_destroy_dumb(output->dumb[i]);
1531 pixman_image_unref(output->image[i]);
1532 output->dumb[i] = NULL;
1533 output->image[i] = NULL;
1534 }
1535}
1536
Richard Hughes2b2092a2013-04-24 14:58:02 +01001537static void
1538edid_parse_string(const uint8_t *data, char text[])
1539{
1540 int i;
1541 int replaced = 0;
1542
1543 /* this is always 12 bytes, but we can't guarantee it's null
1544 * terminated or not junk. */
1545 strncpy(text, (const char *) data, 12);
1546
1547 /* remove insane chars */
1548 for (i = 0; text[i] != '\0'; i++) {
1549 if (text[i] == '\n' ||
1550 text[i] == '\r') {
1551 text[i] = '\0';
1552 break;
1553 }
1554 }
1555
1556 /* ensure string is printable */
1557 for (i = 0; text[i] != '\0'; i++) {
1558 if (!isprint(text[i])) {
1559 text[i] = '-';
1560 replaced++;
1561 }
1562 }
1563
1564 /* if the string is random junk, ignore the string */
1565 if (replaced > 4)
1566 text[0] = '\0';
1567}
1568
1569#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1570#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1571#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1572#define EDID_OFFSET_DATA_BLOCKS 0x36
1573#define EDID_OFFSET_LAST_BLOCK 0x6c
1574#define EDID_OFFSET_PNPID 0x08
1575#define EDID_OFFSET_SERIAL 0x0c
1576
1577static int
1578edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1579{
1580 int i;
1581 uint32_t serial_number;
1582
1583 /* check header */
1584 if (length < 128)
1585 return -1;
1586 if (data[0] != 0x00 || data[1] != 0xff)
1587 return -1;
1588
1589 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1590 * /--08--\/--09--\
1591 * 7654321076543210
1592 * |\---/\---/\---/
1593 * R C1 C2 C3 */
1594 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1595 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1596 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1597 edid->pnp_id[3] = '\0';
1598
1599 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1600 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1601 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1602 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1603 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1604 if (serial_number > 0)
1605 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1606
1607 /* parse EDID data */
1608 for (i = EDID_OFFSET_DATA_BLOCKS;
1609 i <= EDID_OFFSET_LAST_BLOCK;
1610 i += 18) {
1611 /* ignore pixel clock data */
1612 if (data[i] != 0)
1613 continue;
1614 if (data[i+2] != 0)
1615 continue;
1616
1617 /* any useful blocks? */
1618 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1619 edid_parse_string(&data[i+5],
1620 edid->monitor_name);
1621 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1622 edid_parse_string(&data[i+5],
1623 edid->serial_number);
1624 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1625 edid_parse_string(&data[i+5],
1626 edid->eisa_id);
1627 }
1628 }
1629 return 0;
1630}
1631
1632static void
1633find_and_parse_output_edid(struct drm_compositor *ec,
1634 struct drm_output *output,
1635 drmModeConnector *connector)
1636{
1637 drmModePropertyBlobPtr edid_blob = NULL;
1638 drmModePropertyPtr property;
1639 int i;
1640 int rc;
1641
1642 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1643 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1644 if (!property)
1645 continue;
1646 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1647 !strcmp(property->name, "EDID")) {
1648 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1649 connector->prop_values[i]);
1650 }
1651 drmModeFreeProperty(property);
1652 }
1653 if (!edid_blob)
1654 return;
1655
1656 rc = edid_parse(&output->edid,
1657 edid_blob->data,
1658 edid_blob->length);
1659 if (!rc) {
1660 weston_log("EDID data '%s', '%s', '%s'\n",
1661 output->edid.pnp_id,
1662 output->edid.monitor_name,
1663 output->edid.serial_number);
1664 if (output->edid.pnp_id[0] != '\0')
1665 output->base.make = output->edid.pnp_id;
1666 if (output->edid.monitor_name[0] != '\0')
1667 output->base.model = output->edid.monitor_name;
1668 if (output->edid.serial_number[0] != '\0')
1669 output->base.serial_number = output->edid.serial_number;
1670 }
1671 drmModeFreePropertyBlob(edid_blob);
1672}
1673
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001674
1675
1676static int
1677parse_modeline(const char *s, drmModeModeInfo *mode)
1678{
1679 char hsync[16];
1680 char vsync[16];
1681 float fclock;
1682
1683 mode->type = DRM_MODE_TYPE_USERDEF;
1684 mode->hskew = 0;
1685 mode->vscan = 0;
1686 mode->vrefresh = 0;
1687 mode->flags = 0;
1688
Rob Bradford307e09e2013-07-26 16:29:40 +01001689 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001690 &fclock,
1691 &mode->hdisplay,
1692 &mode->hsync_start,
1693 &mode->hsync_end,
1694 &mode->htotal,
1695 &mode->vdisplay,
1696 &mode->vsync_start,
1697 &mode->vsync_end,
1698 &mode->vtotal, hsync, vsync) != 11)
1699 return -1;
1700
1701 mode->clock = fclock * 1000;
1702 if (strcmp(hsync, "+hsync") == 0)
1703 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1704 else if (strcmp(hsync, "-hsync") == 0)
1705 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1706 else
1707 return -1;
1708
1709 if (strcmp(vsync, "+vsync") == 0)
1710 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1711 else if (strcmp(vsync, "-vsync") == 0)
1712 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1713 else
1714 return -1;
1715
1716 return 0;
1717}
1718
1719static uint32_t
1720parse_transform(const char *transform, const char *output_name)
1721{
1722 static const struct { const char *name; uint32_t token; } names[] = {
1723 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1724 { "90", WL_OUTPUT_TRANSFORM_90 },
1725 { "180", WL_OUTPUT_TRANSFORM_180 },
1726 { "270", WL_OUTPUT_TRANSFORM_270 },
1727 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1728 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1729 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1730 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1731 };
1732 unsigned int i;
1733
1734 for (i = 0; i < ARRAY_LENGTH(names); i++)
1735 if (strcmp(names[i].name, transform) == 0)
1736 return names[i].token;
1737
1738 weston_log("Invalid transform \"%s\" for output %s\n",
1739 transform, output_name);
1740
1741 return WL_OUTPUT_TRANSFORM_NORMAL;
1742}
1743
Rob Bradford66bd9f52013-06-25 18:56:42 +01001744static void
1745setup_output_seat_constraint(struct drm_compositor *ec,
1746 struct weston_output *output,
1747 const char *s)
1748{
1749 if (strcmp(s, "") != 0) {
1750 struct udev_seat *seat;
1751
1752 seat = udev_seat_get_named(&ec->base, s);
1753 if (seat)
1754 seat->base.output = output;
1755
1756 if (seat && seat->base.pointer)
1757 weston_pointer_clamp(seat->base.pointer,
1758 &seat->base.pointer->x,
1759 &seat->base.pointer->y);
1760 }
1761}
1762
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001763static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001764create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001765 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001766 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001767 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001768{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001769 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001770 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1771 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001772 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001773 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001774 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001775 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001776 int i, width, height, scale;
1777 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001778 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001779 enum output_config config;
1780 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001781
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001782 i = find_crtc_for_connector(ec, resources, connector);
1783 if (i < 0) {
1784 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001785 return -1;
1786 }
1787
Peter Huttererf3d62272013-08-08 11:57:05 +10001788 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001789 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001790 return -1;
1791
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001792 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1793 output->base.make = "unknown";
1794 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001795 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001796 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001797
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001798 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1799 type_name = connector_type_names[connector->connector_type];
1800 else
1801 type_name = "UNKNOWN";
1802 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001803 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001804
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001805 section = weston_config_get_section(ec->base.config, "output", "name",
1806 output->base.name);
1807 weston_config_section_get_string(section, "mode", &s, "preferred");
1808 if (strcmp(s, "off") == 0)
1809 config = OUTPUT_CONFIG_OFF;
1810 else if (strcmp(s, "preferred") == 0)
1811 config = OUTPUT_CONFIG_PREFERRED;
1812 else if (strcmp(s, "current") == 0)
1813 config = OUTPUT_CONFIG_CURRENT;
1814 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1815 config = OUTPUT_CONFIG_MODE;
1816 else if (parse_modeline(s, &modeline) == 0)
1817 config = OUTPUT_CONFIG_MODELINE;
1818 else {
1819 weston_log("Invalid mode \"%s\" for output %s\n",
1820 s, output->base.name);
1821 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001822 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001823 free(s);
1824
1825 weston_config_section_get_int(section, "scale", &scale, 1);
1826 weston_config_section_get_string(section, "transform", &s, "normal");
1827 transform = parse_transform(s, output->base.name);
1828 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001829
Rob Bradford66bd9f52013-06-25 18:56:42 +01001830 weston_config_section_get_string(section, "seat", &s, "");
1831 setup_output_seat_constraint(ec, &output->base, s);
1832 free(s);
1833
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001834 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001835 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001836 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001837 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001838 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001839
Matt Roper361d2ad2011-08-29 13:52:23 -07001840 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001841 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001842
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001843 /* Get the current mode on the crtc that's currently driving
1844 * this connector. */
1845 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001846 memset(&crtc_mode, 0, sizeof crtc_mode);
1847 if (encoder != NULL) {
1848 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1849 drmModeFreeEncoder(encoder);
1850 if (crtc == NULL)
1851 goto err_free;
1852 if (crtc->mode_valid)
1853 crtc_mode = crtc->mode;
1854 drmModeFreeCrtc(crtc);
1855 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001856
David Herrmann0f0d54e2011-12-08 17:05:45 +01001857 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001858 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001859 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001860 goto err_free;
1861 }
1862
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001863 if (config == OUTPUT_CONFIG_OFF) {
1864 weston_log("Disabling output %s\n", output->base.name);
1865 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1866 0, 0, 0, 0, 0, NULL);
1867 goto err_free;
1868 }
1869
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001870 preferred = NULL;
1871 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001872 configured = NULL;
1873
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001874 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001875 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001876 width == drm_mode->base.width &&
1877 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001878 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001879 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001880 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001881 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001882 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001883 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001884
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001885 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001886 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001887 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001888 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001889 }
1890
Wang Quanxianacb805a2012-07-30 18:09:46 -04001891 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001892 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001893 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001894 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001895 }
1896
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001897 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001898 configured = current;
1899
Wang Quanxianacb805a2012-07-30 18:09:46 -04001900 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001901 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001902 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001903 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001904 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001905 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001906 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001907 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001908
1909 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001910 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001911 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001912 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001913
Wang Quanxianacb805a2012-07-30 18:09:46 -04001914 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1915
John Kåre Alsaker94659272012-11-13 19:10:18 +01001916 weston_output_init(&output->base, &ec->base, x, y,
1917 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001918 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001919
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001920 if (ec->use_pixman) {
1921 if (drm_output_init_pixman(output, ec) < 0) {
1922 weston_log("Failed to init output pixman state\n");
1923 goto err_output;
1924 }
1925 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001926 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001927 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001928 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001929
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001930 output->backlight = backlight_init(drm_device,
1931 connector->connector_type);
1932 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001933 weston_log("Initialized backlight, device %s\n",
1934 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001935 output->base.set_backlight = drm_set_backlight;
1936 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001937 } else {
1938 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001939 }
1940
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001941 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1942
Richard Hughes2b2092a2013-04-24 14:58:02 +01001943 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001944 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1945 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001946
Alex Wubd3354b2012-04-17 17:20:49 +08001947 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001948 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001949 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001950 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001951 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001952 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001953 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001954
Richard Hughese7299962013-05-01 21:52:12 +01001955 output->base.gamma_size = output->original_crtc->gamma_size;
1956 output->base.set_gamma = drm_output_set_gamma;
1957
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001958 weston_plane_init(&output->cursor_plane, 0, 0);
1959 weston_plane_init(&output->fb_plane, 0, 0);
1960
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001961 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1962 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1963 &ec->base.primary_plane);
1964
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001965 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001966 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001967 wl_list_for_each(m, &output->base.mode_list, link)
1968 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1969 m->width, m->height, m->refresh / 1000.0,
1970 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1971 ", preferred" : "",
1972 m->flags & WL_OUTPUT_MODE_CURRENT ?
1973 ", current" : "",
1974 connector->count_modes == 0 ?
1975 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001976
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001977 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001978
John Kåre Alsaker94659272012-11-13 19:10:18 +01001979err_output:
1980 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001981err_free:
1982 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1983 base.link) {
1984 wl_list_remove(&drm_mode->base.link);
1985 free(drm_mode);
1986 }
1987
1988 drmModeFreeCrtc(output->original_crtc);
1989 ec->crtc_allocator &= ~(1 << output->crtc_id);
1990 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001991 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001992
David Herrmann0f0d54e2011-12-08 17:05:45 +01001993 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001994}
1995
Jesse Barnes58ef3792012-02-23 09:45:49 -05001996static void
1997create_sprites(struct drm_compositor *ec)
1998{
1999 struct drm_sprite *sprite;
2000 drmModePlaneRes *plane_res;
2001 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002002 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002003
2004 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2005 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002006 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002007 strerror(errno));
2008 return;
2009 }
2010
2011 for (i = 0; i < plane_res->count_planes; i++) {
2012 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2013 if (!plane)
2014 continue;
2015
Peter Huttererf3d62272013-08-08 11:57:05 +10002016 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002017 plane->count_formats));
2018 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002019 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002020 __func__);
2021 free(plane);
2022 continue;
2023 }
2024
Jesse Barnes58ef3792012-02-23 09:45:49 -05002025 sprite->possible_crtcs = plane->possible_crtcs;
2026 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002027 sprite->current = NULL;
2028 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002029 sprite->compositor = ec;
2030 sprite->count_formats = plane->count_formats;
2031 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002032 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002033 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002034 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002035 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2036 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002037
2038 wl_list_insert(&ec->sprite_list, &sprite->link);
2039 }
2040
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002041 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002042}
2043
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002044static void
2045destroy_sprites(struct drm_compositor *compositor)
2046{
2047 struct drm_sprite *sprite, *next;
2048 struct drm_output *output;
2049
2050 output = container_of(compositor->base.output_list.next,
2051 struct drm_output, base.link);
2052
2053 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2054 drmModeSetPlane(compositor->drm.fd,
2055 sprite->plane_id,
2056 output->crtc_id, 0, 0,
2057 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002058 drm_output_release_fb(output, sprite->current);
2059 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002060 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002061 free(sprite);
2062 }
2063}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002064
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002065static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002066create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002067 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002068{
2069 drmModeConnector *connector;
2070 drmModeRes *resources;
2071 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002072 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002073
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002074 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002075 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002076 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002077 return -1;
2078 }
2079
Jesse Barnes58ef3792012-02-23 09:45:49 -05002080 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002081 if (!ec->crtcs) {
2082 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002083 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002084 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002085
Rob Clark4339add2012-08-09 14:18:28 -05002086 ec->min_width = resources->min_width;
2087 ec->max_width = resources->max_width;
2088 ec->min_height = resources->min_height;
2089 ec->max_height = resources->max_height;
2090
Jesse Barnes58ef3792012-02-23 09:45:49 -05002091 ec->num_crtcs = resources->count_crtcs;
2092 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2093
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002094 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002095 connector = drmModeGetConnector(ec->drm.fd,
2096 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002097 if (connector == NULL)
2098 continue;
2099
2100 if (connector->connection == DRM_MODE_CONNECTED &&
2101 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002102 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002103 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002104 connector, x, y,
2105 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002106 drmModeFreeConnector(connector);
2107 continue;
2108 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002109
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002110 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002111 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002112 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002113 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002114
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002115 drmModeFreeConnector(connector);
2116 }
2117
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002118 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002119 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002120 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002121 return -1;
2122 }
2123
2124 drmModeFreeResources(resources);
2125
2126 return 0;
2127}
2128
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002129static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002130update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002131{
2132 drmModeConnector *connector;
2133 drmModeRes *resources;
2134 struct drm_output *output, *next;
2135 int x = 0, y = 0;
2136 int x_offset = 0, y_offset = 0;
2137 uint32_t connected = 0, disconnects = 0;
2138 int i;
2139
2140 resources = drmModeGetResources(ec->drm.fd);
2141 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002142 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002143 return;
2144 }
2145
2146 /* collect new connects */
2147 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002148 int connector_id = resources->connectors[i];
2149
2150 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002151 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002152 continue;
2153
David Herrmann7551cff2011-12-08 17:05:43 +01002154 if (connector->connection != DRM_MODE_CONNECTED) {
2155 drmModeFreeConnector(connector);
2156 continue;
2157 }
2158
Benjamin Franzke117483d2011-08-30 11:38:26 +02002159 connected |= (1 << connector_id);
2160
2161 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002162 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002163 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002164 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002165
2166 /* XXX: not yet needed, we die with 0 outputs */
2167 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002168 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002169 else
2170 x = 0;
2171 y = 0;
2172 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002173 connector, x, y,
2174 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002175 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002176
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002177 }
2178 drmModeFreeConnector(connector);
2179 }
2180 drmModeFreeResources(resources);
2181
2182 disconnects = ec->connector_allocator & ~connected;
2183 if (disconnects) {
2184 wl_list_for_each_safe(output, next, &ec->base.output_list,
2185 base.link) {
2186 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002187 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002188 output->base.x - x_offset,
2189 output->base.y - y_offset);
2190 }
2191
2192 if (disconnects & (1 << output->connector_id)) {
2193 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002194 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002195 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002196 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002197 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002198 }
2199 }
2200 }
2201
2202 /* FIXME: handle zero outputs, without terminating */
2203 if (ec->connector_allocator == 0)
2204 wl_display_terminate(ec->base.wl_display);
2205}
2206
2207static int
David Herrmannd7488c22012-03-11 20:05:21 +01002208udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002209{
David Herrmannd7488c22012-03-11 20:05:21 +01002210 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002211 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002212
2213 sysnum = udev_device_get_sysnum(device);
2214 if (!sysnum || atoi(sysnum) != ec->drm.id)
2215 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002216
David Herrmann6ac52db2012-03-11 20:05:22 +01002217 val = udev_device_get_property_value(device, "HOTPLUG");
2218 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002219 return 0;
2220
David Herrmann6ac52db2012-03-11 20:05:22 +01002221 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002222}
2223
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002224static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002225udev_drm_event(int fd, uint32_t mask, void *data)
2226{
2227 struct drm_compositor *ec = data;
2228 struct udev_device *event;
2229
2230 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002231
David Herrmannd7488c22012-03-11 20:05:21 +01002232 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002233 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002234
2235 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002236
2237 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002238}
2239
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002240static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002241drm_restore(struct weston_compositor *ec)
2242{
2243 struct drm_compositor *d = (struct drm_compositor *) ec;
2244
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07002245 if (weston_launcher_drm_set_master(d->base.launcher, d->drm.fd, 0) < 0)
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002246 weston_log("failed to drop master: %m\n");
2247 tty_reset(d->tty);
2248}
2249
2250static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002251drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002252{
2253 struct drm_compositor *d = (struct drm_compositor *) ec;
2254
Rob Bradfordd355b802013-05-31 18:09:55 +01002255 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002256
2257 wl_event_source_remove(d->udev_drm_source);
2258 wl_event_source_remove(d->drm_source);
2259
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002260 destroy_sprites(d);
2261
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002262 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002263
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002264 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002265
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002266 if (d->gbm)
2267 gbm_device_destroy(d->gbm);
2268
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07002269 if (weston_launcher_drm_set_master(d->base.launcher, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002270 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002271 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002272
Rob Bradford45c15b82013-07-26 16:29:35 +01002273 close(d->drm.fd);
2274
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002275 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002276}
2277
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002278static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002279drm_compositor_set_modes(struct drm_compositor *compositor)
2280{
2281 struct drm_output *output;
2282 struct drm_mode *drm_mode;
2283 int ret;
2284
2285 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002286 if (!output->current) {
2287 /* If something that would cause the output to
2288 * switch mode happened while in another vt, we
2289 * might not have a current drm_fb. In that case,
2290 * schedule a repaint and let drm_output_repaint
2291 * handle setting the mode. */
2292 weston_output_schedule_repaint(&output->base);
2293 continue;
2294 }
2295
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002296 drm_mode = (struct drm_mode *) output->base.current;
2297 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002298 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002299 &output->connector_id, 1,
2300 &drm_mode->mode_info);
2301 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002302 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002303 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002304 drm_mode->base.width, drm_mode->base.height,
2305 output->base.x, output->base.y);
2306 }
2307 }
2308}
2309
2310static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002311session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002312{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002313 struct weston_compositor *compositor = data;
2314 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002315 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002316 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002317
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002318 if (ec->base.session_active) {
2319 weston_log("activating session\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002320 compositor->focus = 1;
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07002321 if (weston_launcher_drm_set_master(ec->base.launcher,
2322 ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002323 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002324 wl_display_terminate(compositor->wl_display);
2325 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002326 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002327 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002328 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002329 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002330 } else {
2331 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002332 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002333
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002334 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002335 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002336 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002337
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002338 /* If we have a repaint scheduled (either from a
2339 * pending pageflip or the idle handler), make sure we
2340 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002341 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002342 * further attemps at repainting. When we switch
2343 * back, we schedule a repaint, which will process
2344 * pending frame callbacks. */
2345
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002346 wl_list_for_each(output, &ec->base.output_list, base.link) {
2347 output->base.repaint_needed = 0;
2348 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002349 }
2350
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002351 output = container_of(ec->base.output_list.next,
2352 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002353
2354 wl_list_for_each(sprite, &ec->sprite_list, link)
2355 drmModeSetPlane(ec->drm.fd,
2356 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002357 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002358 0, 0, 0, 0, 0, 0, 0, 0);
2359
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07002360 if (weston_launcher_drm_set_master(ec->base.launcher,
2361 ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002362 weston_log("failed to drop master: %m\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002363 };
2364}
2365
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002366static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002367switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002368{
2369 struct drm_compositor *ec = data;
2370
Daniel Stone325fc2d2012-05-30 16:31:58 +01002371 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002372}
2373
David Herrmann0af066f2012-10-29 19:21:16 +01002374/*
2375 * Find primary GPU
2376 * Some systems may have multiple DRM devices attached to a single seat. This
2377 * function loops over all devices and tries to find a PCI device with the
2378 * boot_vga sysfs attribute set to 1.
2379 * If no such device is found, the first DRM device reported by udev is used.
2380 */
2381static struct udev_device*
2382find_primary_gpu(struct drm_compositor *ec, const char *seat)
2383{
2384 struct udev_enumerate *e;
2385 struct udev_list_entry *entry;
2386 const char *path, *device_seat, *id;
2387 struct udev_device *device, *drm_device, *pci;
2388
2389 e = udev_enumerate_new(ec->udev);
2390 udev_enumerate_add_match_subsystem(e, "drm");
2391 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2392
2393 udev_enumerate_scan_devices(e);
2394 drm_device = NULL;
2395 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2396 path = udev_list_entry_get_name(entry);
2397 device = udev_device_new_from_syspath(ec->udev, path);
2398 if (!device)
2399 continue;
2400 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2401 if (!device_seat)
2402 device_seat = default_seat;
2403 if (strcmp(device_seat, seat)) {
2404 udev_device_unref(device);
2405 continue;
2406 }
2407
2408 pci = udev_device_get_parent_with_subsystem_devtype(device,
2409 "pci", NULL);
2410 if (pci) {
2411 id = udev_device_get_sysattr_value(pci, "boot_vga");
2412 if (id && !strcmp(id, "1")) {
2413 if (drm_device)
2414 udev_device_unref(drm_device);
2415 drm_device = device;
2416 break;
2417 }
2418 }
2419
2420 if (!drm_device)
2421 drm_device = device;
2422 else
2423 udev_device_unref(device);
2424 }
2425
2426 udev_enumerate_unref(e);
2427 return drm_device;
2428}
2429
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002430static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002431planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002432{
2433 struct drm_compositor *c = data;
2434
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002435 switch (key) {
2436 case KEY_C:
2437 c->cursors_are_broken ^= 1;
2438 break;
2439 case KEY_V:
2440 c->sprites_are_broken ^= 1;
2441 break;
2442 case KEY_O:
2443 c->sprites_hidden ^= 1;
2444 break;
2445 default:
2446 break;
2447 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002448}
2449
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002450#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002451static void
2452recorder_frame_notify(struct wl_listener *listener, void *data)
2453{
2454 struct drm_output *output;
2455 struct drm_compositor *c;
2456 int fd, ret;
2457
2458 output = container_of(listener, struct drm_output,
2459 recorder_frame_listener);
2460 c = (struct drm_compositor *) output->base.compositor;
2461
2462 if (!output->recorder)
2463 return;
2464
2465 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2466 DRM_CLOEXEC, &fd);
2467 if (ret) {
2468 weston_log("[libva recorder] "
2469 "failed to create prime fd for front buffer\n");
2470 return;
2471 }
2472
2473 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002474}
2475
2476static void *
2477create_recorder(struct drm_compositor *c, int width, int height,
2478 const char *filename)
2479{
2480 int fd;
2481 drm_magic_t magic;
2482
2483 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2484 if (fd < 0)
2485 return NULL;
2486
2487 drmGetMagic(fd, &magic);
2488 drmAuthMagic(c->drm.fd, magic);
2489
2490 return vaapi_recorder_create(fd, width, height, filename);
2491}
2492
2493static void
2494recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2495 void *data)
2496{
2497 struct drm_compositor *c = data;
2498 struct drm_output *output;
2499 int width, height;
2500
2501 output = container_of(c->base.output_list.next,
2502 struct drm_output, base.link);
2503
2504 if (!output->recorder) {
2505 width = output->base.current->width;
2506 height = output->base.current->height;
2507
2508 output->recorder =
2509 create_recorder(c, width, height, "capture.h264");
2510 if (!output->recorder) {
2511 weston_log("failed to create vaapi recorder\n");
2512 return;
2513 }
2514
2515 output->base.disable_planes++;
2516
2517 output->recorder_frame_listener.notify = recorder_frame_notify;
2518 wl_signal_add(&output->base.frame_signal,
2519 &output->recorder_frame_listener);
2520
2521 weston_output_schedule_repaint(&output->base);
2522
2523 weston_log("[libva recorder] initialized\n");
2524 } else {
2525 vaapi_recorder_destroy(output->recorder);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002526 output->recorder = NULL;
2527
2528 output->base.disable_planes--;
2529
2530 wl_list_remove(&output->recorder_frame_listener.link);
2531 weston_log("[libva recorder] done\n");
2532 }
2533}
2534#else
2535static void
2536recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2537 void *data)
2538{
2539 weston_log("Compiled without libva support\n");
2540}
2541#endif
2542
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002543static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002544drm_compositor_create(struct wl_display *display,
Rob Bradford643641d2013-05-31 18:09:53 +01002545 int connector, const char *seat_id, int tty, int pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002546 int *argc, char *argv[],
2547 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002548{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002549 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002550 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002551 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002552 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002553 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002554
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002555 weston_log("initializing drm backend\n");
2556
Peter Huttererf3d62272013-08-08 11:57:05 +10002557 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002558 if (ec == NULL)
2559 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002560
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002561 /* KMS support for sprites is not complete yet, so disable the
2562 * functionality for now. */
2563 ec->sprites_are_broken = 1;
2564
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002565 ec->use_pixman = pixman;
2566
Daniel Stone725c2c32012-06-22 14:04:36 +01002567 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002568 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002569 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002570 goto err_base;
2571 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002572
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002573 /* Check if we run drm-backend using weston-launch */
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07002574 ec->base.launcher = weston_launcher_connect(&ec->base);
2575 if (ec->base.launcher == NULL && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002576 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002577 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002578 goto err_compositor;
2579 }
2580
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002581 ec->udev = udev_new();
2582 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002583 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002584 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002585 }
2586
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002587 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002588 ec->session_listener.notify = session_notify;
2589 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
2590 ec->tty = tty_create(&ec->base, tty);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002591 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002592 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002593 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002594 }
2595
Rob Bradford643641d2013-05-31 18:09:53 +01002596 drm_device = find_primary_gpu(ec, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002597 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002598 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002599 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002600 }
David Herrmann0af066f2012-10-29 19:21:16 +01002601 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002602
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002603 if (init_drm(ec, drm_device) < 0) {
2604 weston_log("failed to initialize kms\n");
2605 goto err_udev_dev;
2606 }
2607
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002608 if (ec->use_pixman) {
2609 if (init_pixman(ec) < 0) {
2610 weston_log("failed to initialize pixman renderer\n");
2611 goto err_udev_dev;
2612 }
2613 } else {
2614 if (init_egl(ec) < 0) {
2615 weston_log("failed to initialize egl\n");
2616 goto err_udev_dev;
2617 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002618 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002619
2620 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002621 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002622
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002623 ec->base.focus = 1;
2624
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002625 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002626
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002627 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002628 weston_compositor_add_key_binding(&ec->base, key,
2629 MODIFIER_CTRL | MODIFIER_ALT,
2630 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002631
Jesse Barnes58ef3792012-02-23 09:45:49 -05002632 wl_list_init(&ec->sprite_list);
2633 create_sprites(ec);
2634
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002635 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002636 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002637 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002638 }
2639
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002640 path = NULL;
2641
Rob Bradfordd355b802013-05-31 18:09:55 +01002642 if (udev_input_init(&ec->input, &ec->base, ec->udev, seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002643 weston_log("failed to create input devices\n");
2644 goto err_sprite;
2645 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002646
2647 loop = wl_display_get_event_loop(ec->base.wl_display);
2648 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002649 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002650 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002651
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002652 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2653 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002654 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002655 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002656 }
2657 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2658 "drm", NULL);
2659 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002660 wl_event_loop_add_fd(loop,
2661 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002662 WL_EVENT_READABLE, udev_drm_event, ec);
2663
2664 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002665 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002666 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002667 }
2668
Daniel Stonea96b93c2012-06-22 14:04:37 +01002669 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002670
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002671 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002672 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002673 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002674 planes_binding, ec);
2675 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2676 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002677 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2678 recorder_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002679
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002680 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002681
2682err_udev_monitor:
2683 wl_event_source_remove(ec->udev_drm_source);
2684 udev_monitor_unref(ec->udev_monitor);
2685err_drm_source:
2686 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002687 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002688err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002689 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002690 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002691 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002692err_udev_dev:
2693 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002694err_tty:
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07002695 if (weston_launcher_drm_set_master(ec->base.launcher,
2696 ec->drm.fd, 0) < 0)
Kristian Høgsberg50623842013-02-18 15:02:27 -05002697 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002698 tty_destroy(ec->tty);
2699err_udev:
2700 udev_unref(ec->udev);
2701err_compositor:
2702 weston_compositor_shutdown(&ec->base);
2703err_base:
2704 free(ec);
2705 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002706}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002707
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002708WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002709backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002710 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002711{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002712 int connector = 0, tty = 0, use_pixman = 0;
Rob Bradford643641d2013-05-31 18:09:53 +01002713 const char *seat_id = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002714
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002715 const struct weston_option drm_options[] = {
2716 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
Rob Bradford643641d2013-05-31 18:09:53 +01002717 { WESTON_OPTION_STRING, "seat", 0, &seat_id },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002718 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002719 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002720 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002721 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002722
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002723 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002724
Rob Bradford643641d2013-05-31 18:09:53 +01002725 return drm_compositor_create(display, connector, seat_id, tty, use_pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002726 argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002727}