blob: 916fd5f2267b71f201c18eee57dc37e1d00a7b6f [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Daniel Stonec228e232013-05-22 18:03:19 +030024#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040025
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010028#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040029#include <string.h>
30#include <fcntl.h>
31#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040032#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070033#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030034#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020035#include <sys/mman.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030036#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040037
Benjamin Franzkec649a922011-03-02 11:56:04 +010038#include <xf86drm.h>
39#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050040#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010041
Benjamin Franzke060cf802011-04-30 09:32:11 +020042#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020043#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040044#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020045
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040046#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010047#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020048#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050049#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010050#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030051#include "vaapi-recorder.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040052
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030053#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
54#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
55#endif
56
Kristian Høgsberg061c4252012-06-28 11:28:15 -040057static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060058
59enum output_config {
60 OUTPUT_CONFIG_INVALID = 0,
61 OUTPUT_CONFIG_OFF,
62 OUTPUT_CONFIG_PREFERRED,
63 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060064 OUTPUT_CONFIG_MODE,
65 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060066};
67
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040068struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050069 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040070
71 struct udev *udev;
72 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040073
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010074 struct udev_monitor *udev_monitor;
75 struct wl_event_source *udev_drm_source;
76
Benjamin Franzke2af7f102011-03-02 11:14:59 +010077 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010078 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010079 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030080 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010081 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020082 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050083 uint32_t *crtcs;
84 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050085 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010086 uint32_t connector_allocator;
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 ||
Hardeningff39efa2013-09-18 23:56:35 +0200453 buffer->width != output->base.current_mode->width ||
454 buffer->height != output->base.current_mode->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
Hardeningff39efa2013-09-18 23:56:35 +0200584 mode = container_of(output->base.current_mode, 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
Hardeningff39efa2013-09-18 23:56:35 +0200790 if (es->buffer_scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200791 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,
Hardeningff39efa2013-09-18 23:56:35 +0200862 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200863 *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
Hardeningff39efa2013-09-18 23:56:35 +0200981 x = (es->geometry.x - output->base.x) * output->base.current_scale;
982 y = (es->geometry.y - output->base.y) * output->base.current_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
Hardeningff39efa2013-09-18 23:56:35 +02001103 if (output->base.current_mode->width == target_mode->width &&
1104 output->base.current_mode->height == target_mode->height &&
1105 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001106 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001107 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001108
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
Hardeningff39efa2013-09-18 23:56:35 +02001154 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001155 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001156
Hardeningff39efa2013-09-18 23:56:35 +02001157 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001158
Hardeningff39efa2013-09-18 23:56:35 +02001159 output->base.current_mode = &drm_mode->base;
1160 output->base.current_mode->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,
Hardeningff39efa2013-09-18 23:56:35 +02001442 output->base.current_mode->width,
1443 output->base.current_mode->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{
Hardeningff39efa2013-09-18 23:56:35 +02001480 int w = output->base.current_mode->width;
1481 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001482 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)
Hardeningff39efa2013-09-18 23:56:35 +02001901 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001902 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02001903 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001904 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02001905 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001906 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02001907 output->base.current_mode = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001908
Hardeningff39efa2013-09-18 23:56:35 +02001909 if (output->base.current_mode == 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
Hardeningff39efa2013-09-18 23:56:35 +02001914 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001915
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
Hardeningff39efa2013-09-18 23:56:35 +02001947 output->base.original_mode = output->base.current_mode;
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{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002243 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002244}
2245
2246static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002247drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002248{
2249 struct drm_compositor *d = (struct drm_compositor *) ec;
2250
Rob Bradfordd355b802013-05-31 18:09:55 +01002251 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002252
2253 wl_event_source_remove(d->udev_drm_source);
2254 wl_event_source_remove(d->drm_source);
2255
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002256 destroy_sprites(d);
2257
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002258 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002259
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002260 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002261
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002262 if (d->gbm)
2263 gbm_device_destroy(d->gbm);
2264
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002265 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002266
Rob Bradford45c15b82013-07-26 16:29:35 +01002267 close(d->drm.fd);
2268
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002269 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002270}
2271
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002272static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002273drm_compositor_set_modes(struct drm_compositor *compositor)
2274{
2275 struct drm_output *output;
2276 struct drm_mode *drm_mode;
2277 int ret;
2278
2279 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002280 if (!output->current) {
2281 /* If something that would cause the output to
2282 * switch mode happened while in another vt, we
2283 * might not have a current drm_fb. In that case,
2284 * schedule a repaint and let drm_output_repaint
2285 * handle setting the mode. */
2286 weston_output_schedule_repaint(&output->base);
2287 continue;
2288 }
2289
Hardeningff39efa2013-09-18 23:56:35 +02002290 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002291 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002292 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002293 &output->connector_id, 1,
2294 &drm_mode->mode_info);
2295 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002296 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002297 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002298 drm_mode->base.width, drm_mode->base.height,
2299 output->base.x, output->base.y);
2300 }
2301 }
2302}
2303
2304static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002305session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002306{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002307 struct weston_compositor *compositor = data;
2308 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002309 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002310 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002311
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002312 if (ec->base.session_active) {
2313 weston_log("activating session\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002314 compositor->focus = 1;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -07002315 if (ec->base.launcher == NULL && drmSetMaster(ec->drm.fd)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002316 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002317 wl_display_terminate(compositor->wl_display);
2318 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002319 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002320 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002321 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002322 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002323 } else {
2324 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002325 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002326
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002327 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002328 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002329 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002330
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002331 /* If we have a repaint scheduled (either from a
2332 * pending pageflip or the idle handler), make sure we
2333 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002334 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002335 * further attemps at repainting. When we switch
2336 * back, we schedule a repaint, which will process
2337 * pending frame callbacks. */
2338
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002339 wl_list_for_each(output, &ec->base.output_list, base.link) {
2340 output->base.repaint_needed = 0;
2341 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002342 }
2343
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002344 output = container_of(ec->base.output_list.next,
2345 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002346
2347 wl_list_for_each(sprite, &ec->sprite_list, link)
2348 drmModeSetPlane(ec->drm.fd,
2349 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002350 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002351 0, 0, 0, 0, 0, 0, 0, 0);
2352
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -07002353 if (ec->base.launcher == NULL && drmDropMaster(ec->drm.fd) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002354 weston_log("failed to drop master: %m\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002355 };
2356}
2357
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002358static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002359switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002360{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002361 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002362
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002363 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002364}
2365
David Herrmann0af066f2012-10-29 19:21:16 +01002366/*
2367 * Find primary GPU
2368 * Some systems may have multiple DRM devices attached to a single seat. This
2369 * function loops over all devices and tries to find a PCI device with the
2370 * boot_vga sysfs attribute set to 1.
2371 * If no such device is found, the first DRM device reported by udev is used.
2372 */
2373static struct udev_device*
2374find_primary_gpu(struct drm_compositor *ec, const char *seat)
2375{
2376 struct udev_enumerate *e;
2377 struct udev_list_entry *entry;
2378 const char *path, *device_seat, *id;
2379 struct udev_device *device, *drm_device, *pci;
2380
2381 e = udev_enumerate_new(ec->udev);
2382 udev_enumerate_add_match_subsystem(e, "drm");
2383 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2384
2385 udev_enumerate_scan_devices(e);
2386 drm_device = NULL;
2387 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2388 path = udev_list_entry_get_name(entry);
2389 device = udev_device_new_from_syspath(ec->udev, path);
2390 if (!device)
2391 continue;
2392 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2393 if (!device_seat)
2394 device_seat = default_seat;
2395 if (strcmp(device_seat, seat)) {
2396 udev_device_unref(device);
2397 continue;
2398 }
2399
2400 pci = udev_device_get_parent_with_subsystem_devtype(device,
2401 "pci", NULL);
2402 if (pci) {
2403 id = udev_device_get_sysattr_value(pci, "boot_vga");
2404 if (id && !strcmp(id, "1")) {
2405 if (drm_device)
2406 udev_device_unref(drm_device);
2407 drm_device = device;
2408 break;
2409 }
2410 }
2411
2412 if (!drm_device)
2413 drm_device = device;
2414 else
2415 udev_device_unref(device);
2416 }
2417
2418 udev_enumerate_unref(e);
2419 return drm_device;
2420}
2421
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002422static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002423planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002424{
2425 struct drm_compositor *c = data;
2426
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002427 switch (key) {
2428 case KEY_C:
2429 c->cursors_are_broken ^= 1;
2430 break;
2431 case KEY_V:
2432 c->sprites_are_broken ^= 1;
2433 break;
2434 case KEY_O:
2435 c->sprites_hidden ^= 1;
2436 break;
2437 default:
2438 break;
2439 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002440}
2441
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002442#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002443static void
2444recorder_frame_notify(struct wl_listener *listener, void *data)
2445{
2446 struct drm_output *output;
2447 struct drm_compositor *c;
2448 int fd, ret;
2449
2450 output = container_of(listener, struct drm_output,
2451 recorder_frame_listener);
2452 c = (struct drm_compositor *) output->base.compositor;
2453
2454 if (!output->recorder)
2455 return;
2456
2457 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2458 DRM_CLOEXEC, &fd);
2459 if (ret) {
2460 weston_log("[libva recorder] "
2461 "failed to create prime fd for front buffer\n");
2462 return;
2463 }
2464
2465 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002466}
2467
2468static void *
2469create_recorder(struct drm_compositor *c, int width, int height,
2470 const char *filename)
2471{
2472 int fd;
2473 drm_magic_t magic;
2474
2475 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2476 if (fd < 0)
2477 return NULL;
2478
2479 drmGetMagic(fd, &magic);
2480 drmAuthMagic(c->drm.fd, magic);
2481
2482 return vaapi_recorder_create(fd, width, height, filename);
2483}
2484
2485static void
2486recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2487 void *data)
2488{
2489 struct drm_compositor *c = data;
2490 struct drm_output *output;
2491 int width, height;
2492
2493 output = container_of(c->base.output_list.next,
2494 struct drm_output, base.link);
2495
2496 if (!output->recorder) {
Hardeningff39efa2013-09-18 23:56:35 +02002497 width = output->base.current_mode->width;
2498 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002499
2500 output->recorder =
2501 create_recorder(c, width, height, "capture.h264");
2502 if (!output->recorder) {
2503 weston_log("failed to create vaapi recorder\n");
2504 return;
2505 }
2506
2507 output->base.disable_planes++;
2508
2509 output->recorder_frame_listener.notify = recorder_frame_notify;
2510 wl_signal_add(&output->base.frame_signal,
2511 &output->recorder_frame_listener);
2512
2513 weston_output_schedule_repaint(&output->base);
2514
2515 weston_log("[libva recorder] initialized\n");
2516 } else {
2517 vaapi_recorder_destroy(output->recorder);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002518 output->recorder = NULL;
2519
2520 output->base.disable_planes--;
2521
2522 wl_list_remove(&output->recorder_frame_listener.link);
2523 weston_log("[libva recorder] done\n");
2524 }
2525}
2526#else
2527static void
2528recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2529 void *data)
2530{
2531 weston_log("Compiled without libva support\n");
2532}
2533#endif
2534
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002535static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002536drm_compositor_create(struct wl_display *display,
Rob Bradford643641d2013-05-31 18:09:53 +01002537 int connector, const char *seat_id, int tty, int pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002538 int *argc, char *argv[],
2539 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002540{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002541 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002542 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002543 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002544 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002545 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002546
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002547 weston_log("initializing drm backend\n");
2548
Peter Huttererf3d62272013-08-08 11:57:05 +10002549 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002550 if (ec == NULL)
2551 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002552
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002553 /* KMS support for sprites is not complete yet, so disable the
2554 * functionality for now. */
2555 ec->sprites_are_broken = 1;
2556
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002557 ec->use_pixman = pixman;
2558
Daniel Stone725c2c32012-06-22 14:04:36 +01002559 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002560 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002561 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002562 goto err_base;
2563 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002564
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002565 /* Check if we run drm-backend using weston-launch */
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07002566 ec->base.launcher = weston_launcher_connect(&ec->base);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002567 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002568 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002569 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002570 goto err_compositor;
2571 }
2572
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002573 ec->udev = udev_new();
2574 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002575 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002576 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002577 }
2578
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002579 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002580 ec->session_listener.notify = session_notify;
2581 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002582
Rob Bradford643641d2013-05-31 18:09:53 +01002583 drm_device = find_primary_gpu(ec, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002584 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002585 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002586 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002587 }
David Herrmann0af066f2012-10-29 19:21:16 +01002588 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002589
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002590 if (init_drm(ec, drm_device) < 0) {
2591 weston_log("failed to initialize kms\n");
2592 goto err_udev_dev;
2593 }
2594
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002595 if (ec->use_pixman) {
2596 if (init_pixman(ec) < 0) {
2597 weston_log("failed to initialize pixman renderer\n");
2598 goto err_udev_dev;
2599 }
2600 } else {
2601 if (init_egl(ec) < 0) {
2602 weston_log("failed to initialize egl\n");
2603 goto err_udev_dev;
2604 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002605 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002606
2607 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002608 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002609
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002610 ec->base.focus = 1;
2611
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002612 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002613
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002614 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002615 weston_compositor_add_key_binding(&ec->base, key,
2616 MODIFIER_CTRL | MODIFIER_ALT,
2617 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002618
Jesse Barnes58ef3792012-02-23 09:45:49 -05002619 wl_list_init(&ec->sprite_list);
2620 create_sprites(ec);
2621
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002622 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002623 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002624 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002625 }
2626
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002627 path = NULL;
2628
Rob Bradfordd355b802013-05-31 18:09:55 +01002629 if (udev_input_init(&ec->input, &ec->base, ec->udev, seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002630 weston_log("failed to create input devices\n");
2631 goto err_sprite;
2632 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002633
2634 loop = wl_display_get_event_loop(ec->base.wl_display);
2635 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002636 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002637 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002638
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002639 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2640 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002641 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002642 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002643 }
2644 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2645 "drm", NULL);
2646 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002647 wl_event_loop_add_fd(loop,
2648 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002649 WL_EVENT_READABLE, udev_drm_event, ec);
2650
2651 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002652 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002653 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002654 }
2655
Daniel Stonea96b93c2012-06-22 14:04:37 +01002656 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002657
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002658 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002659 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002660 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002661 planes_binding, ec);
2662 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2663 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002664 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2665 recorder_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002666
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002667 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002668
2669err_udev_monitor:
2670 wl_event_source_remove(ec->udev_drm_source);
2671 udev_monitor_unref(ec->udev_monitor);
2672err_drm_source:
2673 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002674 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002675err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002676 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002677 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002678 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002679err_udev_dev:
2680 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002681err_launcher:
2682 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002683err_udev:
2684 udev_unref(ec->udev);
2685err_compositor:
2686 weston_compositor_shutdown(&ec->base);
2687err_base:
2688 free(ec);
2689 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002690}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002691
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002692WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002693backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002694 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002695{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002696 int connector = 0, tty = 0, use_pixman = 0;
Rob Bradford643641d2013-05-31 18:09:53 +01002697 const char *seat_id = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002698
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002699 const struct weston_option drm_options[] = {
2700 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
Rob Bradford643641d2013-05-31 18:09:53 +01002701 { WESTON_OPTION_STRING, "seat", 0, &seat_id },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002702 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002703 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002704 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002705 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002706
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002707 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002708
Rob Bradford643641d2013-05-31 18:09:53 +01002709 return drm_compositor_create(display, connector, seat_id, tty, use_pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002710 argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002711}