blob: 8a70674b4588ca3b963de4ab1c150ba9b1bc293c [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Daniel Stonec228e232013-05-22 18:03:19 +030024#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040025
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010028#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040029#include <string.h>
30#include <fcntl.h>
31#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040032#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070033#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030034#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020035#include <sys/mman.h>
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030036#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030037#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040038
Benjamin Franzkec649a922011-03-02 11:56:04 +010039#include <xf86drm.h>
40#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050041#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010042
Benjamin Franzke060cf802011-04-30 09:32:11 +020043#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020044#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040045#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020046
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040047#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010048#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020049#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050050#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010051#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030052#include "vaapi-recorder.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040053
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030054#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
55#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
56#endif
57
Kristian Høgsberg061c4252012-06-28 11:28:15 -040058static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060059
60enum output_config {
61 OUTPUT_CONFIG_INVALID = 0,
62 OUTPUT_CONFIG_OFF,
63 OUTPUT_CONFIG_PREFERRED,
64 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060065 OUTPUT_CONFIG_MODE,
66 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060067};
68
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040069struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050070 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040071
72 struct udev *udev;
73 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010075 struct udev_monitor *udev_monitor;
76 struct wl_event_source *udev_drm_source;
77
Benjamin Franzke2af7f102011-03-02 11:14:59 +010078 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010079 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010080 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030081 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010082 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020083 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050084 uint32_t *crtcs;
85 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050086 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010087 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -070088 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -070089 uint32_t format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020090
Rob Clark4339add2012-08-09 14:18:28 -050091 /* we need these parameters in order to not fail drmModeAddFB2()
92 * due to out of bounds dimensions, and then mistakenly set
93 * sprites_are_broken:
94 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020095 uint32_t min_width, max_width;
96 uint32_t min_height, max_height;
97 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050098
Jesse Barnes58ef3792012-02-23 09:45:49 -050099 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500100 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200101 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500102
Rob Clarkab5b1e32012-08-09 13:24:45 -0500103 int cursors_are_broken;
104
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200105 int use_pixman;
106
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200107 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300108
109 clockid_t clock;
Rob Bradfordd355b802013-05-31 18:09:55 +0100110 struct udev_input input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400111};
112
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400113struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500114 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400115 drmModeModeInfo mode_info;
116};
117
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300118struct drm_output;
119
120struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300121 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200122 uint32_t fb_id, stride, handle, size;
123 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300124 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200125 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200126
127 /* Used by gbm fbs */
128 struct gbm_bo *bo;
129
130 /* Used by dumb fbs */
131 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300132};
133
Richard Hughes2b2092a2013-04-24 14:58:02 +0100134struct drm_edid {
135 char eisa_id[13];
136 char monitor_name[13];
137 char pnp_id[5];
138 char serial_number[13];
139};
140
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400141struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500142 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400143
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400144 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500145 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400146 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700147 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100148 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300149 drmModePropertyPtr dpms_prop;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200150
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300151 int vblank_pending;
152 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800153 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300154
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400155 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400156 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400157 struct weston_plane cursor_plane;
158 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400159 struct weston_surface *cursor_surface;
160 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300161 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200162 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200163
164 struct drm_fb *dumb[2];
165 pixman_image_t *image[2];
166 int current_image;
167 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300168
169 struct vaapi_recorder *recorder;
170 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400171};
172
Jesse Barnes58ef3792012-02-23 09:45:49 -0500173/*
174 * An output has a primary display plane plus zero or more sprites for
175 * blending display contents.
176 */
177struct drm_sprite {
178 struct wl_list link;
179
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400180 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500181
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200182 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300183 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500184 struct drm_compositor *compositor;
185
Jesse Barnes58ef3792012-02-23 09:45:49 -0500186 uint32_t possible_crtcs;
187 uint32_t plane_id;
188 uint32_t count_formats;
189
190 int32_t src_x, src_y;
191 uint32_t src_w, src_h;
192 uint32_t dest_x, dest_y;
193 uint32_t dest_w, dest_h;
194
195 uint32_t formats[];
196};
197
Kristian Høgsbergd8e98332013-10-16 16:15:11 -0700198struct drm_parameters {
199 int connector;
200 int tty;
201 int use_pixman;
202 const char *seat_id;
203};
204
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300205static struct gl_renderer_interface *gl_renderer;
206
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500207static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400208
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400209static void
210drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400211
Jesse Barnes58ef3792012-02-23 09:45:49 -0500212static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500213drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
214{
215 struct weston_compositor *ec = output_base->compositor;
216 struct drm_compositor *c =(struct drm_compositor *) ec;
217 struct drm_output *output = (struct drm_output *) output_base;
218 int crtc;
219
220 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
221 if (c->crtcs[crtc] != output->crtc_id)
222 continue;
223
224 if (supported & (1 << crtc))
225 return -1;
226 }
227
228 return 0;
229}
230
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300231static void
232drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
233{
234 struct drm_fb *fb = data;
235 struct gbm_device *gbm = gbm_bo_get_device(bo);
236
237 if (fb->fb_id)
238 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
239
Pekka Paalanende685b82012-12-04 15:58:12 +0200240 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300241
242 free(data);
243}
244
245static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200246drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
247{
248 struct drm_fb *fb;
249 int ret;
250
251 struct drm_mode_create_dumb create_arg;
252 struct drm_mode_destroy_dumb destroy_arg;
253 struct drm_mode_map_dumb map_arg;
254
Peter Huttererf3d62272013-08-08 11:57:05 +1000255 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200256 if (!fb)
257 return NULL;
258
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700259 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200260 create_arg.bpp = 32;
261 create_arg.width = width;
262 create_arg.height = height;
263
264 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
265 if (ret)
266 goto err_fb;
267
268 fb->handle = create_arg.handle;
269 fb->stride = create_arg.pitch;
270 fb->size = create_arg.size;
271 fb->fd = ec->drm.fd;
272
273 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
274 fb->stride, fb->handle, &fb->fb_id);
275 if (ret)
276 goto err_bo;
277
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700278 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200279 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400280 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200281 if (ret)
282 goto err_add_fb;
283
284 fb->map = mmap(0, fb->size, PROT_WRITE,
285 MAP_SHARED, ec->drm.fd, map_arg.offset);
286 if (fb->map == MAP_FAILED)
287 goto err_add_fb;
288
289 return fb;
290
291err_add_fb:
292 drmModeRmFB(ec->drm.fd, fb->fb_id);
293err_bo:
294 memset(&destroy_arg, 0, sizeof(destroy_arg));
295 destroy_arg.handle = create_arg.handle;
296 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
297err_fb:
298 free(fb);
299 return NULL;
300}
301
302static void
303drm_fb_destroy_dumb(struct drm_fb *fb)
304{
305 struct drm_mode_destroy_dumb destroy_arg;
306
307 if (!fb->map)
308 return;
309
310 if (fb->fb_id)
311 drmModeRmFB(fb->fd, fb->fb_id);
312
313 weston_buffer_reference(&fb->buffer_ref, NULL);
314
315 munmap(fb->map, fb->size);
316
317 memset(&destroy_arg, 0, sizeof(destroy_arg));
318 destroy_arg.handle = fb->handle;
319 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
320
321 free(fb);
322}
323
324static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500325drm_fb_get_from_bo(struct gbm_bo *bo,
326 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300327{
328 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200329 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200330 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300331 int ret;
332
333 if (fb)
334 return fb;
335
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200336 fb = calloc(1, sizeof *fb);
337 if (!fb)
338 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300339
340 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300341
342 width = gbm_bo_get_width(bo);
343 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200344 fb->stride = gbm_bo_get_stride(bo);
345 fb->handle = gbm_bo_get_handle(bo).u32;
346 fb->size = fb->stride * height;
347 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300348
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200349 if (compositor->min_width > width || width > compositor->max_width ||
350 compositor->min_height > height ||
351 height > compositor->max_height) {
352 weston_log("bo geometry out of bounds\n");
353 goto err_free;
354 }
355
356 ret = -1;
357
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200358 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200359 handles[0] = fb->handle;
360 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200361 offsets[0] = 0;
362
363 ret = drmModeAddFB2(compositor->drm.fd, width, height,
364 format, handles, pitches, offsets,
365 &fb->fb_id, 0);
366 if (ret) {
367 weston_log("addfb2 failed: %m\n");
368 compositor->no_addfb2 = 1;
369 compositor->sprites_are_broken = 1;
370 }
371 }
372
373 if (ret)
374 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200375 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300377 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200378 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200379 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300380 }
381
382 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
383
384 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200385
386err_free:
387 free(fb);
388 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300389}
390
391static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500392drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200393{
Pekka Paalanende685b82012-12-04 15:58:12 +0200394 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200395
396 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200397
Pekka Paalanende685b82012-12-04 15:58:12 +0200398 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200399}
400
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200401static void
402drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
403{
404 if (!fb)
405 return;
406
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200407 if (fb->map &&
408 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200409 drm_fb_destroy_dumb(fb);
410 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200411 if (fb->is_client_buffer)
412 gbm_bo_destroy(fb->bo);
413 else
414 gbm_surface_release_buffer(output->surface,
415 output->current->bo);
416 }
417}
418
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500419static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200420drm_output_check_scanout_format(struct drm_output *output,
421 struct weston_surface *es, struct gbm_bo *bo)
422{
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700423 struct drm_compositor *c =
424 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200425 uint32_t format;
426 pixman_region32_t r;
427
428 format = gbm_bo_get_format(bo);
429
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700430 if (format == GBM_FORMAT_ARGB8888) {
431 /* We can scanout an ARGB buffer if the surface's
432 * opaque region covers the whole output, but we have
433 * to use XRGB as the KMS format code. */
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200434 pixman_region32_init(&r);
435 pixman_region32_subtract(&r, &output->base.region,
436 &es->opaque);
437
438 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500439 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200440
441 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500442 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700443
444 if (c->format == format)
445 return format;
446
447 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200448}
449
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400450static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400451drm_output_prepare_scanout_surface(struct weston_output *_output,
452 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500453{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400454 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500455 struct drm_compositor *c =
456 (struct drm_compositor *) output->base.compositor;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500457 struct weston_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300458 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500459 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500460
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500461 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200462 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200463 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200464 buffer->width != output->base.current_mode->width ||
465 buffer->height != output->base.current_mode->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200466 output->base.transform != es->buffer_transform ||
467 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400468 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500469
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400470 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700471 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500472
Rob Bradford9b101872012-09-14 23:25:41 +0100473 /* Unable to use the buffer for scanout */
474 if (!bo)
475 return NULL;
476
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500477 format = drm_output_check_scanout_format(output, es, bo);
478 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300479 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400480 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300481 }
482
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500483 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300484 if (!output->next) {
485 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400486 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300487 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500488
Pekka Paalanende685b82012-12-04 15:58:12 +0200489 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500490
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400491 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500492}
493
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500494static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200495drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400496{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200497 struct drm_compositor *c =
498 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300499 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400500
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200501 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400502
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300503 bo = gbm_surface_lock_front_buffer(output->surface);
504 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200505 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400506 return;
507 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300508
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700509 output->next = drm_fb_get_from_bo(bo, c, c->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300510 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200511 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300512 gbm_surface_release_buffer(output->surface, bo);
513 return;
514 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400515}
516
517static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200518drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
519{
520 struct weston_compositor *ec = output->base.compositor;
521 pixman_region32_t total_damage, previous_damage;
522
523 pixman_region32_init(&total_damage);
524 pixman_region32_init(&previous_damage);
525
526 pixman_region32_copy(&previous_damage, damage);
527
528 pixman_region32_union(&total_damage, damage, &output->previous_damage);
529 pixman_region32_copy(&output->previous_damage, &previous_damage);
530
531 output->current_image ^= 1;
532
533 output->next = output->dumb[output->current_image];
534 pixman_renderer_output_set_buffer(&output->base,
535 output->image[output->current_image]);
536
537 ec->renderer->repaint_output(&output->base, &total_damage);
538
539 pixman_region32_fini(&total_damage);
540 pixman_region32_fini(&previous_damage);
541}
542
543static void
544drm_output_render(struct drm_output *output, pixman_region32_t *damage)
545{
546 struct drm_compositor *c =
547 (struct drm_compositor *) output->base.compositor;
548
549 if (c->use_pixman)
550 drm_output_render_pixman(output, damage);
551 else
552 drm_output_render_gl(output, damage);
553
554 pixman_region32_subtract(&c->base.primary_plane.damage,
555 &c->base.primary_plane.damage, damage);
556}
557
558static void
Richard Hughese7299962013-05-01 21:52:12 +0100559drm_output_set_gamma(struct weston_output *output_base,
560 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
561{
562 int rc;
563 struct drm_output *output = (struct drm_output *) output_base;
564 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
565
566 /* check */
567 if (output_base->gamma_size != size)
568 return;
569 if (!output->original_crtc)
570 return;
571
572 rc = drmModeCrtcSetGamma(compositor->drm.fd,
573 output->crtc_id,
574 size, r, g, b);
575 if (rc)
576 weston_log("set gamma failed: %m\n");
577}
578
579static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500580drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400581 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100582{
583 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500584 struct drm_compositor *compositor =
585 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500586 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400587 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500588 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100589
Xiong Zhangabd5d472013-10-11 14:43:07 +0800590 if (output->destroy_pending)
591 return;
592
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300593 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400594 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300595 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400596 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100597
Hardeningff39efa2013-09-18 23:56:35 +0200598 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300599 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400600 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300601 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400602 &output->connector_id, 1,
603 &mode->mode_info);
604 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200605 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400606 return;
607 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300608 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200609 }
610
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500611 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300612 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500613 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200614 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500615 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500616 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100617
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300618 output->page_flip_pending = 1;
619
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400620 drm_output_set_cursor(output);
621
Jesse Barnes58ef3792012-02-23 09:45:49 -0500622 /*
623 * Now, update all the sprite surfaces
624 */
625 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200626 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500627 drmVBlank vbl = {
628 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
629 .request.sequence = 1,
630 };
631
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200632 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200633 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634 continue;
635
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200636 if (s->next && !compositor->sprites_hidden)
637 fb_id = s->next->fb_id;
638
Jesse Barnes58ef3792012-02-23 09:45:49 -0500639 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200640 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500641 s->dest_x, s->dest_y,
642 s->dest_w, s->dest_h,
643 s->src_x, s->src_y,
644 s->src_w, s->src_h);
645 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200646 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500647 ret, strerror(errno));
648
Rob Clark5ca1a472012-08-08 20:27:37 -0500649 if (output->pipe > 0)
650 vbl.request.type |= DRM_VBLANK_SECONDARY;
651
Jesse Barnes58ef3792012-02-23 09:45:49 -0500652 /*
653 * Queue a vblank signal so we know when the surface
654 * becomes active on the display or has been replaced.
655 */
656 vbl.request.signal = (unsigned long)s;
657 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
658 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200659 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500660 ret, strerror(errno));
661 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300662
663 s->output = output;
664 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500665 }
666
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500667 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400668}
669
670static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200671drm_output_start_repaint_loop(struct weston_output *output_base)
672{
673 struct drm_output *output = (struct drm_output *) output_base;
674 struct drm_compositor *compositor = (struct drm_compositor *)
675 output_base->compositor;
676 uint32_t fb_id;
David Herrmann3c688c52013-10-22 17:11:25 +0200677 uint32_t msec;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300678 struct timespec ts;
679
Xiong Zhangabd5d472013-10-11 14:43:07 +0800680 if (output->destroy_pending)
681 return;
682
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300683 if (!output->current) {
684 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200685 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300686 }
687
688 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200689
690 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
691 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
692 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200693 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200694 }
David Herrmann3c688c52013-10-22 17:11:25 +0200695
696 return;
697
698finish_frame:
699 /* if we cannot page-flip, immediately finish frame */
700 clock_gettime(compositor->clock, &ts);
701 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
702 weston_output_finish_frame(output_base, msec);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200703}
704
705static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500706vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
707 void *data)
708{
709 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300710 struct drm_output *output = s->output;
711 uint32_t msecs;
712
713 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500714
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200715 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200716 s->current = s->next;
717 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300718
719 if (!output->page_flip_pending) {
720 msecs = sec * 1000 + usec / 1000;
721 weston_output_finish_frame(&output->base, msecs);
722 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500723}
724
725static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800726drm_output_destroy(struct weston_output *output_base);
727
728static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400729page_flip_handler(int fd, unsigned int frame,
730 unsigned int sec, unsigned int usec, void *data)
731{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200732 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400733 uint32_t msecs;
734
Jonas Ådahle5a12252013-04-05 23:07:11 +0200735 /* We don't set page_flip_pending on start_repaint_loop, in that case
736 * we just want to page flip to the current buffer to get an accurate
737 * timestamp */
738 if (output->page_flip_pending) {
739 drm_output_release_fb(output, output->current);
740 output->current = output->next;
741 output->next = NULL;
742 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300743
Jonas Ådahle5a12252013-04-05 23:07:11 +0200744 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400745
Xiong Zhangabd5d472013-10-11 14:43:07 +0800746 if (output->destroy_pending)
747 drm_output_destroy(&output->base);
748 else if (!output->vblank_pending) {
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300749 msecs = sec * 1000 + usec / 1000;
750 weston_output_finish_frame(&output->base, msecs);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300751
752 /* We can't call this from frame_notify, because the output's
753 * repaint needed flag is cleared just after that */
754 if (output->recorder)
755 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300756 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200757}
758
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500759static uint32_t
760drm_output_check_sprite_format(struct drm_sprite *s,
761 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500762{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500763 uint32_t i, format;
764
765 format = gbm_bo_get_format(bo);
766
767 if (format == GBM_FORMAT_ARGB8888) {
768 pixman_region32_t r;
769
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500770 pixman_region32_init_rect(&r, 0, 0,
771 es->geometry.width,
772 es->geometry.height);
773 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500774
775 if (!pixman_region32_not_empty(&r))
776 format = GBM_FORMAT_XRGB8888;
777
778 pixman_region32_fini(&r);
779 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500780
781 for (i = 0; i < s->count_formats; i++)
782 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500783 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500784
785 return 0;
786}
787
788static int
789drm_surface_transform_supported(struct weston_surface *es)
790{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500791 return !es->transform.enabled ||
792 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500793}
794
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400795static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500796drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400797 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500798{
799 struct weston_compositor *ec = output_base->compositor;
800 struct drm_compositor *c =(struct drm_compositor *) ec;
801 struct drm_sprite *s;
802 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500803 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500804 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200805 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500806 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400807 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500808
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200809 if (c->gbm == NULL)
810 return NULL;
811
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200812 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200813 return NULL;
814
Hardeningff39efa2013-09-18 23:56:35 +0200815 if (es->buffer_scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200816 return NULL;
817
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500818 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400819 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500820
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300821 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400822 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300823
Pekka Paalanende685b82012-12-04 15:58:12 +0200824 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400825 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500826
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200827 if (es->alpha != 1.0f)
828 return NULL;
829
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500830 if (wl_shm_buffer_get(es->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500831 return NULL;
832
Jesse Barnes58ef3792012-02-23 09:45:49 -0500833 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400834 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500835
Jesse Barnes58ef3792012-02-23 09:45:49 -0500836 wl_list_for_each(s, &c->sprite_list, link) {
837 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
838 continue;
839
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200840 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500841 found = 1;
842 break;
843 }
844 }
845
846 /* No sprites available */
847 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400848 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500849
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400850 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700851 es->buffer_ref.buffer->resource,
852 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400853 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400854 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400855
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500856 format = drm_output_check_sprite_format(s, es, bo);
857 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200858 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400859 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500860 }
861
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200862 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200863 if (!s->next) {
864 gbm_bo_destroy(bo);
865 return NULL;
866 }
867
Pekka Paalanende685b82012-12-04 15:58:12 +0200868 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500869
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400870 box = pixman_region32_extents(&es->transform.boundingbox);
871 s->plane.x = box->x1;
872 s->plane.y = box->y1;
873
Jesse Barnes58ef3792012-02-23 09:45:49 -0500874 /*
875 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200876 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500877 * for us already).
878 */
879 pixman_region32_init(&dest_rect);
880 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
881 &output_base->region);
882 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
883 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200884 tbox = weston_transformed_rect(output_base->width,
885 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200886 output_base->transform,
Hardeningff39efa2013-09-18 23:56:35 +0200887 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200888 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200889 s->dest_x = tbox.x1;
890 s->dest_y = tbox.y1;
891 s->dest_w = tbox.x2 - tbox.x1;
892 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500893 pixman_region32_fini(&dest_rect);
894
895 pixman_region32_init(&src_rect);
896 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
897 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500898 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400899
900 weston_surface_from_global_fixed(es,
901 wl_fixed_from_int(box->x1),
902 wl_fixed_from_int(box->y1),
903 &sx1, &sy1);
904 weston_surface_from_global_fixed(es,
905 wl_fixed_from_int(box->x2),
906 wl_fixed_from_int(box->y2),
907 &sx2, &sy2);
908
909 if (sx1 < 0)
910 sx1 = 0;
911 if (sy1 < 0)
912 sy1 = 0;
913 if (sx2 > wl_fixed_from_int(es->geometry.width))
914 sx2 = wl_fixed_from_int(es->geometry.width);
915 if (sy2 > wl_fixed_from_int(es->geometry.height))
916 sy2 = wl_fixed_from_int(es->geometry.height);
917
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200918 tbox.x1 = sx1;
919 tbox.y1 = sy1;
920 tbox.x2 = sx2;
921 tbox.y2 = sy2;
922
923 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
924 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200925 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200926
927 s->src_x = tbox.x1 << 8;
928 s->src_y = tbox.y1 << 8;
929 s->src_w = (tbox.x2 - tbox.x1) << 8;
930 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500931 pixman_region32_fini(&src_rect);
932
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400933 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500934}
935
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400936static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400937drm_output_prepare_cursor_surface(struct weston_output *output_base,
938 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500939{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400940 struct drm_compositor *c =
941 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400942 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400943
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200944 if (c->gbm == NULL)
945 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200946 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
947 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400948 if (output->cursor_surface)
949 return NULL;
950 if (es->output_mask != (1u << output_base->id))
951 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500952 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400953 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200954 if (es->buffer_ref.buffer == NULL ||
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500955 !wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400956 es->geometry.width > 64 || es->geometry.height > 64)
957 return NULL;
958
959 output->cursor_surface = es;
960
961 return &output->cursor_plane;
962}
963
964static void
965drm_output_set_cursor(struct drm_output *output)
966{
967 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400968 struct drm_compositor *c =
969 (struct drm_compositor *) output->base.compositor;
970 EGLint handle, stride;
971 struct gbm_bo *bo;
972 uint32_t buf[64 * 64];
973 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400974 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500975
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400976 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400977 if (es == NULL) {
978 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
979 return;
980 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500981
Pekka Paalanende685b82012-12-04 15:58:12 +0200982 if (es->buffer_ref.buffer &&
983 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400984 pixman_region32_fini(&output->cursor_plane.damage);
985 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400986 output->current_cursor ^= 1;
987 bo = output->cursor_bo[output->current_cursor];
988 memset(buf, 0, sizeof buf);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500989 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
990 s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400991 for (i = 0; i < es->geometry.height; i++)
992 memcpy(buf + i * 64, s + i * stride,
993 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500994
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400995 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300996 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400997
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400998 handle = gbm_bo_get_handle(bo).s32;
999 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -05001000 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001001 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001002 c->cursors_are_broken = 1;
1003 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001004 }
1005
Hardeningff39efa2013-09-18 23:56:35 +02001006 x = (es->geometry.x - output->base.x) * output->base.current_scale;
1007 y = (es->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001008 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001009 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001010 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001011 c->cursors_are_broken = 1;
1012 }
1013
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001014 output->cursor_plane.x = x;
1015 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001016 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001017}
1018
Jesse Barnes58ef3792012-02-23 09:45:49 -05001019static void
1020drm_assign_planes(struct weston_output *output)
1021{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001022 struct drm_compositor *c =
1023 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001024 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001025 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001026 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001027
1028 /*
1029 * Find a surface for each sprite in the output using some heuristics:
1030 * 1) size
1031 * 2) frequency of update
1032 * 3) opacity (though some hw might support alpha blending)
1033 * 4) clipping (this can be fixed with color keys)
1034 *
1035 * The idea is to save on blitting since this should save power.
1036 * If we can get a large video surface on the sprite for example,
1037 * the main display surface may not need to update at all, and
1038 * the client buffer can be used directly for the sprite surface
1039 * as we do for flipping full screen surfaces.
1040 */
1041 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001042 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001043 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001044 /* test whether this buffer can ever go into a plane:
1045 * non-shm, or small enough to be a cursor
1046 */
1047 if ((es->buffer_ref.buffer &&
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001048 !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) ||
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001049 (es->geometry.width <= 64 && es->geometry.height <= 64))
1050 es->keep_buffer = 1;
1051 else
1052 es->keep_buffer = 0;
1053
Jesse Barnes58ef3792012-02-23 09:45:49 -05001054 pixman_region32_init(&surface_overlap);
1055 pixman_region32_intersect(&surface_overlap, &overlap,
1056 &es->transform.boundingbox);
1057
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001058 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001059 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001060 next_plane = primary;
1061 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001062 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001063 if (next_plane == NULL)
1064 next_plane = drm_output_prepare_scanout_surface(output, es);
1065 if (next_plane == NULL)
1066 next_plane = drm_output_prepare_overlay_surface(output, es);
1067 if (next_plane == NULL)
1068 next_plane = primary;
1069 weston_surface_move_to_plane(es, next_plane);
1070 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001071 pixman_region32_union(&overlap, &overlap,
1072 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001073
Jesse Barnes58ef3792012-02-23 09:45:49 -05001074 pixman_region32_fini(&surface_overlap);
1075 }
1076 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001077}
1078
Matt Roper361d2ad2011-08-29 13:52:23 -07001079static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001080drm_output_fini_pixman(struct drm_output *output);
1081
1082static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001083drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001084{
1085 struct drm_output *output = (struct drm_output *) output_base;
1086 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001087 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001088 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001089
Xiong Zhangabd5d472013-10-11 14:43:07 +08001090 if (output->page_flip_pending) {
1091 output->destroy_pending = 1;
1092 weston_log("destroy output while page flip pending\n");
1093 return;
1094 }
1095
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001096 if (output->backlight)
1097 backlight_destroy(output->backlight);
1098
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001099 drmModeFreeProperty(output->dpms_prop);
1100
Matt Roper361d2ad2011-08-29 13:52:23 -07001101 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001102 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001103
1104 /* Restore original CRTC state */
1105 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001106 origcrtc->x, origcrtc->y,
1107 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001108 drmModeFreeCrtc(origcrtc);
1109
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001110 c->crtc_allocator &= ~(1 << output->crtc_id);
1111 c->connector_allocator &= ~(1 << output->connector_id);
1112
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001113 if (c->use_pixman) {
1114 drm_output_fini_pixman(output);
1115 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001116 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001117 gbm_surface_destroy(output->surface);
1118 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001119
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001120 weston_plane_release(&output->fb_plane);
1121 weston_plane_release(&output->cursor_plane);
1122
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001123 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001124 wl_list_remove(&output->base.link);
1125
Matt Roper361d2ad2011-08-29 13:52:23 -07001126 free(output);
1127}
1128
Alex Wub7b8bda2012-04-17 17:20:48 +08001129static struct drm_mode *
1130choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1131{
1132 struct drm_mode *tmp_mode = NULL, *mode;
1133
Hardeningff39efa2013-09-18 23:56:35 +02001134 if (output->base.current_mode->width == target_mode->width &&
1135 output->base.current_mode->height == target_mode->height &&
1136 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001137 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001138 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001139
1140 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1141 if (mode->mode_info.hdisplay == target_mode->width &&
1142 mode->mode_info.vdisplay == target_mode->height) {
1143 if (mode->mode_info.vrefresh == target_mode->refresh ||
1144 target_mode->refresh == 0) {
1145 return mode;
1146 } else if (!tmp_mode)
1147 tmp_mode = mode;
1148 }
1149 }
1150
1151 return tmp_mode;
1152}
1153
1154static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001155drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001156static int
1157drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001158
1159static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001160drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1161{
1162 struct drm_output *output;
1163 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001164 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001165
1166 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001167 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001168 return -1;
1169 }
1170
1171 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001172 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001173 return -1;
1174 }
1175
1176 ec = (struct drm_compositor *)output_base->compositor;
1177 output = (struct drm_output *)output_base;
1178 drm_mode = choose_mode (output, mode);
1179
1180 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001181 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001182 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001183 }
1184
Hardeningff39efa2013-09-18 23:56:35 +02001185 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001186 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001187
Hardeningff39efa2013-09-18 23:56:35 +02001188 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001189
Hardeningff39efa2013-09-18 23:56:35 +02001190 output->base.current_mode = &drm_mode->base;
1191 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001192 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1193
Alex Wub7b8bda2012-04-17 17:20:48 +08001194 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001195 drm_output_release_fb(output, output->current);
1196 drm_output_release_fb(output, output->next);
1197 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001198
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001199 if (ec->use_pixman) {
1200 drm_output_fini_pixman(output);
1201 if (drm_output_init_pixman(output, ec) < 0) {
1202 weston_log("failed to init output pixman state with "
1203 "new mode\n");
1204 return -1;
1205 }
1206 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001207 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001208 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001209
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001210 if (drm_output_init_egl(output, ec) < 0) {
1211 weston_log("failed to init output egl state with "
1212 "new mode");
1213 return -1;
1214 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001215 }
1216
Alex Wub7b8bda2012-04-17 17:20:48 +08001217 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001218}
1219
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001220static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001221on_drm_input(int fd, uint32_t mask, void *data)
1222{
1223 drmEventContext evctx;
1224
1225 memset(&evctx, 0, sizeof evctx);
1226 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1227 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001228 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001229 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001230
1231 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001232}
1233
1234static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001235init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001236{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001237 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001238 uint64_t cap;
1239 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001240
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001241 sysnum = udev_device_get_sysnum(device);
1242 if (sysnum)
1243 ec->drm.id = atoi(sysnum);
1244 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001245 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001246 return -1;
1247 }
1248
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001249 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001250 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001251 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001252 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001253 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001254 udev_device_get_devnode(device));
1255 return -1;
1256 }
1257
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001258 weston_log("using %s\n", filename);
1259
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001260 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001261 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001262
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001263 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1264 if (ret == 0 && cap == 1)
1265 ec->clock = CLOCK_MONOTONIC;
1266 else
1267 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001268
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001269 return 0;
1270}
1271
1272static int
1273init_egl(struct drm_compositor *ec)
1274{
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001275 EGLint format;
1276
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001277 gl_renderer = weston_load_module("gl-renderer.so",
1278 "gl_renderer_interface");
1279 if (!gl_renderer)
1280 return -1;
1281
1282 /* GBM will load a dri driver, but even though they need symbols from
1283 * libglapi, in some version of Mesa they are not linked to it. Since
1284 * only the gl-renderer module links to it, the call above won't make
1285 * these symbols globally available, and loading the DRI driver fails.
1286 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1287 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1288
Benjamin Franzke060cf802011-04-30 09:32:11 +02001289 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001290
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001291 if (!ec->gbm)
1292 return -1;
1293
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001294 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001295 if (gl_renderer->create(&ec->base, ec->gbm,
1296 gl_renderer->opaque_attribs, &format) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001297 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001298 return -1;
1299 }
1300
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001301 return 0;
1302}
1303
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001304static int
1305init_pixman(struct drm_compositor *ec)
1306{
1307 return pixman_renderer_init(&ec->base);
1308}
1309
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001310static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001311drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001312{
1313 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001314 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001315
1316 mode = malloc(sizeof *mode);
1317 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001318 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001319
1320 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001321 mode->base.width = info->hdisplay;
1322 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001323
1324 /* Calculate higher precision (mHz) refresh rate */
1325 refresh = (info->clock * 1000000LL / info->htotal +
1326 info->vtotal / 2) / info->vtotal;
1327
1328 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1329 refresh *= 2;
1330 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1331 refresh /= 2;
1332 if (info->vscan > 1)
1333 refresh /= info->vscan;
1334
1335 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001336 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001337
1338 if (info->type & DRM_MODE_TYPE_PREFERRED)
1339 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1340
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001341 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1342
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001343 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001344}
1345
1346static int
1347drm_subpixel_to_wayland(int drm_value)
1348{
1349 switch (drm_value) {
1350 default:
1351 case DRM_MODE_SUBPIXEL_UNKNOWN:
1352 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1353 case DRM_MODE_SUBPIXEL_NONE:
1354 return WL_OUTPUT_SUBPIXEL_NONE;
1355 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1356 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1357 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1358 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1359 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1360 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1361 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1362 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1363 }
1364}
1365
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001366/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001367static uint32_t
1368drm_get_backlight(struct drm_output *output)
1369{
1370 long brightness, max_brightness, norm;
1371
1372 brightness = backlight_get_brightness(output->backlight);
1373 max_brightness = backlight_get_max_brightness(output->backlight);
1374
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001375 /* convert it on a scale of 0 to 255 */
1376 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001377
1378 return (uint32_t) norm;
1379}
1380
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001381/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001382static void
1383drm_set_backlight(struct weston_output *output_base, uint32_t value)
1384{
1385 struct drm_output *output = (struct drm_output *) output_base;
1386 long max_brightness, new_brightness;
1387
1388 if (!output->backlight)
1389 return;
1390
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001391 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001392 return;
1393
1394 max_brightness = backlight_get_max_brightness(output->backlight);
1395
1396 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001397 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001398
1399 backlight_set_brightness(output->backlight, new_brightness);
1400}
1401
1402static drmModePropertyPtr
1403drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1404{
1405 drmModePropertyPtr props;
1406 int i;
1407
1408 for (i = 0; i < connector->count_props; i++) {
1409 props = drmModeGetProperty(fd, connector->props[i]);
1410 if (!props)
1411 continue;
1412
1413 if (!strcmp(props->name, name))
1414 return props;
1415
1416 drmModeFreeProperty(props);
1417 }
1418
1419 return NULL;
1420}
1421
1422static void
1423drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1424{
1425 struct drm_output *output = (struct drm_output *) output_base;
1426 struct weston_compositor *ec = output_base->compositor;
1427 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001428
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001429 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001430 return;
1431
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001432 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1433 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001434}
1435
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001436static const char *connector_type_names[] = {
1437 "None",
1438 "VGA",
1439 "DVI",
1440 "DVI",
1441 "DVI",
1442 "Composite",
1443 "TV",
1444 "LVDS",
1445 "CTV",
1446 "DIN",
1447 "DP",
1448 "HDMI",
1449 "HDMI",
1450 "TV",
1451 "eDP",
1452};
1453
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001454static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001455find_crtc_for_connector(struct drm_compositor *ec,
1456 drmModeRes *resources, drmModeConnector *connector)
1457{
1458 drmModeEncoder *encoder;
1459 uint32_t possible_crtcs;
1460 int i, j;
1461
1462 for (j = 0; j < connector->count_encoders; j++) {
1463 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1464 if (encoder == NULL) {
1465 weston_log("Failed to get encoder.\n");
1466 return -1;
1467 }
1468 possible_crtcs = encoder->possible_crtcs;
1469 drmModeFreeEncoder(encoder);
1470
1471 for (i = 0; i < resources->count_crtcs; i++) {
1472 if (possible_crtcs & (1 << i) &&
1473 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1474 return i;
1475 }
1476 }
1477
1478 return -1;
1479}
1480
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001481/* Init output state that depends on gl or gbm */
1482static int
1483drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1484{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001485 int i, flags;
1486
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001487 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001488 output->base.current_mode->width,
1489 output->base.current_mode->height,
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07001490 ec->format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001491 GBM_BO_USE_SCANOUT |
1492 GBM_BO_USE_RENDERING);
1493 if (!output->surface) {
1494 weston_log("failed to create gbm surface\n");
1495 return -1;
1496 }
1497
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001498 if (gl_renderer->output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001499 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001500 gbm_surface_destroy(output->surface);
1501 return -1;
1502 }
1503
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001504 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1505
1506 for (i = 0; i < 2; i++) {
1507 if (output->cursor_bo[i])
1508 continue;
1509
1510 output->cursor_bo[i] =
1511 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1512 flags);
1513 }
1514
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001515 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1516 weston_log("cursor buffers unavailable, using gl cursors\n");
1517 ec->cursors_are_broken = 1;
1518 }
1519
1520 return 0;
1521}
1522
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001523static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001524drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1525{
Hardeningff39efa2013-09-18 23:56:35 +02001526 int w = output->base.current_mode->width;
1527 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001528 unsigned int i;
1529
1530 /* FIXME error checking */
1531
1532 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001533 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001534 if (!output->dumb[i])
1535 goto err;
1536
1537 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001538 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001539 output->dumb[i]->map,
1540 output->dumb[i]->stride);
1541 if (!output->image[i])
1542 goto err;
1543 }
1544
1545 if (pixman_renderer_output_create(&output->base) < 0)
1546 goto err;
1547
1548 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001549 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001550
1551 return 0;
1552
1553err:
1554 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1555 if (output->dumb[i])
1556 drm_fb_destroy_dumb(output->dumb[i]);
1557 if (output->image[i])
1558 pixman_image_unref(output->image[i]);
1559
1560 output->dumb[i] = NULL;
1561 output->image[i] = NULL;
1562 }
1563
1564 return -1;
1565}
1566
1567static void
1568drm_output_fini_pixman(struct drm_output *output)
1569{
1570 unsigned int i;
1571
1572 pixman_renderer_output_destroy(&output->base);
1573 pixman_region32_fini(&output->previous_damage);
1574
1575 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1576 drm_fb_destroy_dumb(output->dumb[i]);
1577 pixman_image_unref(output->image[i]);
1578 output->dumb[i] = NULL;
1579 output->image[i] = NULL;
1580 }
1581}
1582
Richard Hughes2b2092a2013-04-24 14:58:02 +01001583static void
1584edid_parse_string(const uint8_t *data, char text[])
1585{
1586 int i;
1587 int replaced = 0;
1588
1589 /* this is always 12 bytes, but we can't guarantee it's null
1590 * terminated or not junk. */
1591 strncpy(text, (const char *) data, 12);
1592
1593 /* remove insane chars */
1594 for (i = 0; text[i] != '\0'; i++) {
1595 if (text[i] == '\n' ||
1596 text[i] == '\r') {
1597 text[i] = '\0';
1598 break;
1599 }
1600 }
1601
1602 /* ensure string is printable */
1603 for (i = 0; text[i] != '\0'; i++) {
1604 if (!isprint(text[i])) {
1605 text[i] = '-';
1606 replaced++;
1607 }
1608 }
1609
1610 /* if the string is random junk, ignore the string */
1611 if (replaced > 4)
1612 text[0] = '\0';
1613}
1614
1615#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1616#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1617#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1618#define EDID_OFFSET_DATA_BLOCKS 0x36
1619#define EDID_OFFSET_LAST_BLOCK 0x6c
1620#define EDID_OFFSET_PNPID 0x08
1621#define EDID_OFFSET_SERIAL 0x0c
1622
1623static int
1624edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1625{
1626 int i;
1627 uint32_t serial_number;
1628
1629 /* check header */
1630 if (length < 128)
1631 return -1;
1632 if (data[0] != 0x00 || data[1] != 0xff)
1633 return -1;
1634
1635 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1636 * /--08--\/--09--\
1637 * 7654321076543210
1638 * |\---/\---/\---/
1639 * R C1 C2 C3 */
1640 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1641 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1642 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1643 edid->pnp_id[3] = '\0';
1644
1645 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1646 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1647 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1648 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1649 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1650 if (serial_number > 0)
1651 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1652
1653 /* parse EDID data */
1654 for (i = EDID_OFFSET_DATA_BLOCKS;
1655 i <= EDID_OFFSET_LAST_BLOCK;
1656 i += 18) {
1657 /* ignore pixel clock data */
1658 if (data[i] != 0)
1659 continue;
1660 if (data[i+2] != 0)
1661 continue;
1662
1663 /* any useful blocks? */
1664 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1665 edid_parse_string(&data[i+5],
1666 edid->monitor_name);
1667 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1668 edid_parse_string(&data[i+5],
1669 edid->serial_number);
1670 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1671 edid_parse_string(&data[i+5],
1672 edid->eisa_id);
1673 }
1674 }
1675 return 0;
1676}
1677
1678static void
1679find_and_parse_output_edid(struct drm_compositor *ec,
1680 struct drm_output *output,
1681 drmModeConnector *connector)
1682{
1683 drmModePropertyBlobPtr edid_blob = NULL;
1684 drmModePropertyPtr property;
1685 int i;
1686 int rc;
1687
1688 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1689 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1690 if (!property)
1691 continue;
1692 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1693 !strcmp(property->name, "EDID")) {
1694 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1695 connector->prop_values[i]);
1696 }
1697 drmModeFreeProperty(property);
1698 }
1699 if (!edid_blob)
1700 return;
1701
1702 rc = edid_parse(&output->edid,
1703 edid_blob->data,
1704 edid_blob->length);
1705 if (!rc) {
1706 weston_log("EDID data '%s', '%s', '%s'\n",
1707 output->edid.pnp_id,
1708 output->edid.monitor_name,
1709 output->edid.serial_number);
1710 if (output->edid.pnp_id[0] != '\0')
1711 output->base.make = output->edid.pnp_id;
1712 if (output->edid.monitor_name[0] != '\0')
1713 output->base.model = output->edid.monitor_name;
1714 if (output->edid.serial_number[0] != '\0')
1715 output->base.serial_number = output->edid.serial_number;
1716 }
1717 drmModeFreePropertyBlob(edid_blob);
1718}
1719
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001720
1721
1722static int
1723parse_modeline(const char *s, drmModeModeInfo *mode)
1724{
1725 char hsync[16];
1726 char vsync[16];
1727 float fclock;
1728
1729 mode->type = DRM_MODE_TYPE_USERDEF;
1730 mode->hskew = 0;
1731 mode->vscan = 0;
1732 mode->vrefresh = 0;
1733 mode->flags = 0;
1734
Rob Bradford307e09e2013-07-26 16:29:40 +01001735 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001736 &fclock,
1737 &mode->hdisplay,
1738 &mode->hsync_start,
1739 &mode->hsync_end,
1740 &mode->htotal,
1741 &mode->vdisplay,
1742 &mode->vsync_start,
1743 &mode->vsync_end,
1744 &mode->vtotal, hsync, vsync) != 11)
1745 return -1;
1746
1747 mode->clock = fclock * 1000;
1748 if (strcmp(hsync, "+hsync") == 0)
1749 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1750 else if (strcmp(hsync, "-hsync") == 0)
1751 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1752 else
1753 return -1;
1754
1755 if (strcmp(vsync, "+vsync") == 0)
1756 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1757 else if (strcmp(vsync, "-vsync") == 0)
1758 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1759 else
1760 return -1;
1761
1762 return 0;
1763}
1764
1765static uint32_t
1766parse_transform(const char *transform, const char *output_name)
1767{
1768 static const struct { const char *name; uint32_t token; } names[] = {
1769 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1770 { "90", WL_OUTPUT_TRANSFORM_90 },
1771 { "180", WL_OUTPUT_TRANSFORM_180 },
1772 { "270", WL_OUTPUT_TRANSFORM_270 },
1773 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1774 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1775 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1776 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1777 };
1778 unsigned int i;
1779
1780 for (i = 0; i < ARRAY_LENGTH(names); i++)
1781 if (strcmp(names[i].name, transform) == 0)
1782 return names[i].token;
1783
1784 weston_log("Invalid transform \"%s\" for output %s\n",
1785 transform, output_name);
1786
1787 return WL_OUTPUT_TRANSFORM_NORMAL;
1788}
1789
Rob Bradford66bd9f52013-06-25 18:56:42 +01001790static void
1791setup_output_seat_constraint(struct drm_compositor *ec,
1792 struct weston_output *output,
1793 const char *s)
1794{
1795 if (strcmp(s, "") != 0) {
1796 struct udev_seat *seat;
1797
1798 seat = udev_seat_get_named(&ec->base, s);
1799 if (seat)
1800 seat->base.output = output;
1801
1802 if (seat && seat->base.pointer)
1803 weston_pointer_clamp(seat->base.pointer,
1804 &seat->base.pointer->x,
1805 &seat->base.pointer->y);
1806 }
1807}
1808
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001809static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001810create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001811 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001812 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001813 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001814{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001815 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001816 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1817 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001818 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001819 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001820 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001821 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001822 int i, width, height, scale;
1823 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001824 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001825 enum output_config config;
1826 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001827
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001828 i = find_crtc_for_connector(ec, resources, connector);
1829 if (i < 0) {
1830 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001831 return -1;
1832 }
1833
Peter Huttererf3d62272013-08-08 11:57:05 +10001834 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001835 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001836 return -1;
1837
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001838 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1839 output->base.make = "unknown";
1840 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001841 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001842 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001843
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001844 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1845 type_name = connector_type_names[connector->connector_type];
1846 else
1847 type_name = "UNKNOWN";
1848 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001849 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001850
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001851 section = weston_config_get_section(ec->base.config, "output", "name",
1852 output->base.name);
1853 weston_config_section_get_string(section, "mode", &s, "preferred");
1854 if (strcmp(s, "off") == 0)
1855 config = OUTPUT_CONFIG_OFF;
1856 else if (strcmp(s, "preferred") == 0)
1857 config = OUTPUT_CONFIG_PREFERRED;
1858 else if (strcmp(s, "current") == 0)
1859 config = OUTPUT_CONFIG_CURRENT;
1860 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1861 config = OUTPUT_CONFIG_MODE;
1862 else if (parse_modeline(s, &modeline) == 0)
1863 config = OUTPUT_CONFIG_MODELINE;
1864 else {
1865 weston_log("Invalid mode \"%s\" for output %s\n",
1866 s, output->base.name);
1867 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001868 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001869 free(s);
1870
1871 weston_config_section_get_int(section, "scale", &scale, 1);
1872 weston_config_section_get_string(section, "transform", &s, "normal");
1873 transform = parse_transform(s, output->base.name);
1874 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001875
Rob Bradford66bd9f52013-06-25 18:56:42 +01001876 weston_config_section_get_string(section, "seat", &s, "");
1877 setup_output_seat_constraint(ec, &output->base, s);
1878 free(s);
1879
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001880 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001881 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001882 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001883 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001884 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001885
Matt Roper361d2ad2011-08-29 13:52:23 -07001886 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001887 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001888
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001889 /* Get the current mode on the crtc that's currently driving
1890 * this connector. */
1891 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001892 memset(&crtc_mode, 0, sizeof crtc_mode);
1893 if (encoder != NULL) {
1894 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1895 drmModeFreeEncoder(encoder);
1896 if (crtc == NULL)
1897 goto err_free;
1898 if (crtc->mode_valid)
1899 crtc_mode = crtc->mode;
1900 drmModeFreeCrtc(crtc);
1901 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001902
David Herrmann0f0d54e2011-12-08 17:05:45 +01001903 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001904 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001905 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001906 goto err_free;
1907 }
1908
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001909 if (config == OUTPUT_CONFIG_OFF) {
1910 weston_log("Disabling output %s\n", output->base.name);
1911 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1912 0, 0, 0, 0, 0, NULL);
1913 goto err_free;
1914 }
1915
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001916 preferred = NULL;
1917 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001918 configured = NULL;
1919
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001920 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001921 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001922 width == drm_mode->base.width &&
1923 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001924 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001925 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001926 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001927 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001928 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001929 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001930
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001931 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001932 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001933 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001934 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001935 }
1936
Wang Quanxianacb805a2012-07-30 18:09:46 -04001937 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001938 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001939 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001940 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001941 }
1942
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001943 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001944 configured = current;
1945
Wang Quanxianacb805a2012-07-30 18:09:46 -04001946 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02001947 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001948 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02001949 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001950 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02001951 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001952 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02001953 output->base.current_mode = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001954
Hardeningff39efa2013-09-18 23:56:35 +02001955 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001956 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001957 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001958 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001959
Hardeningff39efa2013-09-18 23:56:35 +02001960 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001961
John Kåre Alsaker94659272012-11-13 19:10:18 +01001962 weston_output_init(&output->base, &ec->base, x, y,
1963 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001964 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001965
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001966 if (ec->use_pixman) {
1967 if (drm_output_init_pixman(output, ec) < 0) {
1968 weston_log("Failed to init output pixman state\n");
1969 goto err_output;
1970 }
1971 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001972 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001973 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001974 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001975
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001976 output->backlight = backlight_init(drm_device,
1977 connector->connector_type);
1978 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001979 weston_log("Initialized backlight, device %s\n",
1980 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001981 output->base.set_backlight = drm_set_backlight;
1982 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001983 } else {
1984 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001985 }
1986
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001987 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1988
Richard Hughes2b2092a2013-04-24 14:58:02 +01001989 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001990 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1991 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001992
Jonas Ådahle5a12252013-04-05 23:07:11 +02001993 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001994 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001995 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001996 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001997 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001998 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001999
Richard Hughese7299962013-05-01 21:52:12 +01002000 output->base.gamma_size = output->original_crtc->gamma_size;
2001 output->base.set_gamma = drm_output_set_gamma;
2002
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002003 weston_plane_init(&output->cursor_plane, 0, 0);
2004 weston_plane_init(&output->fb_plane, 0, 0);
2005
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002006 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2007 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2008 &ec->base.primary_plane);
2009
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002010 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002011 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002012 wl_list_for_each(m, &output->base.mode_list, link)
2013 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
2014 m->width, m->height, m->refresh / 1000.0,
2015 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2016 ", preferred" : "",
2017 m->flags & WL_OUTPUT_MODE_CURRENT ?
2018 ", current" : "",
2019 connector->count_modes == 0 ?
2020 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002021
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002022 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002023
John Kåre Alsaker94659272012-11-13 19:10:18 +01002024err_output:
2025 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002026err_free:
2027 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2028 base.link) {
2029 wl_list_remove(&drm_mode->base.link);
2030 free(drm_mode);
2031 }
2032
2033 drmModeFreeCrtc(output->original_crtc);
2034 ec->crtc_allocator &= ~(1 << output->crtc_id);
2035 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002036 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002037
David Herrmann0f0d54e2011-12-08 17:05:45 +01002038 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002039}
2040
Jesse Barnes58ef3792012-02-23 09:45:49 -05002041static void
2042create_sprites(struct drm_compositor *ec)
2043{
2044 struct drm_sprite *sprite;
2045 drmModePlaneRes *plane_res;
2046 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002047 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002048
2049 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2050 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002051 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002052 strerror(errno));
2053 return;
2054 }
2055
2056 for (i = 0; i < plane_res->count_planes; i++) {
2057 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2058 if (!plane)
2059 continue;
2060
Peter Huttererf3d62272013-08-08 11:57:05 +10002061 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002062 plane->count_formats));
2063 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002064 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002065 __func__);
2066 free(plane);
2067 continue;
2068 }
2069
Jesse Barnes58ef3792012-02-23 09:45:49 -05002070 sprite->possible_crtcs = plane->possible_crtcs;
2071 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002072 sprite->current = NULL;
2073 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002074 sprite->compositor = ec;
2075 sprite->count_formats = plane->count_formats;
2076 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002077 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002078 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002079 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002080 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2081 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002082
2083 wl_list_insert(&ec->sprite_list, &sprite->link);
2084 }
2085
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002086 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002087}
2088
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002089static void
2090destroy_sprites(struct drm_compositor *compositor)
2091{
2092 struct drm_sprite *sprite, *next;
2093 struct drm_output *output;
2094
2095 output = container_of(compositor->base.output_list.next,
2096 struct drm_output, base.link);
2097
2098 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2099 drmModeSetPlane(compositor->drm.fd,
2100 sprite->plane_id,
2101 output->crtc_id, 0, 0,
2102 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002103 drm_output_release_fb(output, sprite->current);
2104 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002105 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002106 free(sprite);
2107 }
2108}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002109
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002110static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002111create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002112 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002113{
2114 drmModeConnector *connector;
2115 drmModeRes *resources;
2116 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002117 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002118
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002119 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002120 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002121 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002122 return -1;
2123 }
2124
Jesse Barnes58ef3792012-02-23 09:45:49 -05002125 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002126 if (!ec->crtcs) {
2127 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002128 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002129 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002130
Rob Clark4339add2012-08-09 14:18:28 -05002131 ec->min_width = resources->min_width;
2132 ec->max_width = resources->max_width;
2133 ec->min_height = resources->min_height;
2134 ec->max_height = resources->max_height;
2135
Jesse Barnes58ef3792012-02-23 09:45:49 -05002136 ec->num_crtcs = resources->count_crtcs;
2137 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2138
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002139 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002140 connector = drmModeGetConnector(ec->drm.fd,
2141 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002142 if (connector == NULL)
2143 continue;
2144
2145 if (connector->connection == DRM_MODE_CONNECTED &&
2146 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002147 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002148 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002149 connector, x, y,
2150 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002151 drmModeFreeConnector(connector);
2152 continue;
2153 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002154
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002155 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002156 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002157 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002158 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002159
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002160 drmModeFreeConnector(connector);
2161 }
2162
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002163 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002164 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002165 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002166 return -1;
2167 }
2168
2169 drmModeFreeResources(resources);
2170
2171 return 0;
2172}
2173
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002174static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002175update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002176{
2177 drmModeConnector *connector;
2178 drmModeRes *resources;
2179 struct drm_output *output, *next;
2180 int x = 0, y = 0;
2181 int x_offset = 0, y_offset = 0;
2182 uint32_t connected = 0, disconnects = 0;
2183 int i;
2184
2185 resources = drmModeGetResources(ec->drm.fd);
2186 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002187 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002188 return;
2189 }
2190
2191 /* collect new connects */
2192 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002193 int connector_id = resources->connectors[i];
2194
2195 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002196 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002197 continue;
2198
David Herrmann7551cff2011-12-08 17:05:43 +01002199 if (connector->connection != DRM_MODE_CONNECTED) {
2200 drmModeFreeConnector(connector);
2201 continue;
2202 }
2203
Benjamin Franzke117483d2011-08-30 11:38:26 +02002204 connected |= (1 << connector_id);
2205
2206 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002207 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002208 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002209 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002210
2211 /* XXX: not yet needed, we die with 0 outputs */
2212 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002213 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002214 else
2215 x = 0;
2216 y = 0;
2217 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002218 connector, x, y,
2219 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002220 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002221
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002222 }
2223 drmModeFreeConnector(connector);
2224 }
2225 drmModeFreeResources(resources);
2226
2227 disconnects = ec->connector_allocator & ~connected;
2228 if (disconnects) {
2229 wl_list_for_each_safe(output, next, &ec->base.output_list,
2230 base.link) {
2231 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002232 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002233 output->base.x - x_offset,
2234 output->base.y - y_offset);
2235 }
2236
2237 if (disconnects & (1 << output->connector_id)) {
2238 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002239 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002240 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002241 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002242 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002243 }
2244 }
2245 }
2246
2247 /* FIXME: handle zero outputs, without terminating */
2248 if (ec->connector_allocator == 0)
2249 wl_display_terminate(ec->base.wl_display);
2250}
2251
2252static int
David Herrmannd7488c22012-03-11 20:05:21 +01002253udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002254{
David Herrmannd7488c22012-03-11 20:05:21 +01002255 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002256 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002257
2258 sysnum = udev_device_get_sysnum(device);
2259 if (!sysnum || atoi(sysnum) != ec->drm.id)
2260 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002261
David Herrmann6ac52db2012-03-11 20:05:22 +01002262 val = udev_device_get_property_value(device, "HOTPLUG");
2263 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002264 return 0;
2265
David Herrmann6ac52db2012-03-11 20:05:22 +01002266 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002267}
2268
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002269static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002270udev_drm_event(int fd, uint32_t mask, void *data)
2271{
2272 struct drm_compositor *ec = data;
2273 struct udev_device *event;
2274
2275 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002276
David Herrmannd7488c22012-03-11 20:05:21 +01002277 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002278 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002279
2280 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002281
2282 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002283}
2284
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002285static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002286drm_restore(struct weston_compositor *ec)
2287{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002288 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002289}
2290
2291static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002292drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002293{
2294 struct drm_compositor *d = (struct drm_compositor *) ec;
2295
Rob Bradfordd355b802013-05-31 18:09:55 +01002296 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002297
2298 wl_event_source_remove(d->udev_drm_source);
2299 wl_event_source_remove(d->drm_source);
2300
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002301 destroy_sprites(d);
2302
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002303 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002304
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002305 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002306
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002307 if (d->gbm)
2308 gbm_device_destroy(d->gbm);
2309
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002310 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002311
Rob Bradford45c15b82013-07-26 16:29:35 +01002312 close(d->drm.fd);
2313
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002314 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002315}
2316
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002317static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002318drm_compositor_set_modes(struct drm_compositor *compositor)
2319{
2320 struct drm_output *output;
2321 struct drm_mode *drm_mode;
2322 int ret;
2323
2324 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002325 if (!output->current) {
2326 /* If something that would cause the output to
2327 * switch mode happened while in another vt, we
2328 * might not have a current drm_fb. In that case,
2329 * schedule a repaint and let drm_output_repaint
2330 * handle setting the mode. */
2331 weston_output_schedule_repaint(&output->base);
2332 continue;
2333 }
2334
Hardeningff39efa2013-09-18 23:56:35 +02002335 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002336 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002337 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002338 &output->connector_id, 1,
2339 &drm_mode->mode_info);
2340 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002341 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002342 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002343 drm_mode->base.width, drm_mode->base.height,
2344 output->base.x, output->base.y);
2345 }
2346 }
2347}
2348
2349static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002350session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002351{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002352 struct weston_compositor *compositor = data;
2353 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002354 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002355 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002356
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002357 if (ec->base.session_active) {
2358 weston_log("activating session\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002359 compositor->focus = 1;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -07002360 if (ec->base.launcher == NULL && drmSetMaster(ec->drm.fd)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002361 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002362 wl_display_terminate(compositor->wl_display);
2363 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002364 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002365 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002366 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002367 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002368 } else {
2369 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002370 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002371
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002372 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002373 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002374 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002375
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002376 /* If we have a repaint scheduled (either from a
2377 * pending pageflip or the idle handler), make sure we
2378 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002379 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002380 * further attemps at repainting. When we switch
2381 * back, we schedule a repaint, which will process
2382 * pending frame callbacks. */
2383
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002384 wl_list_for_each(output, &ec->base.output_list, base.link) {
2385 output->base.repaint_needed = 0;
2386 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002387 }
2388
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002389 output = container_of(ec->base.output_list.next,
2390 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002391
2392 wl_list_for_each(sprite, &ec->sprite_list, link)
2393 drmModeSetPlane(ec->drm.fd,
2394 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002395 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002396 0, 0, 0, 0, 0, 0, 0, 0);
2397
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -07002398 if (ec->base.launcher == NULL && drmDropMaster(ec->drm.fd) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002399 weston_log("failed to drop master: %m\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002400 };
2401}
2402
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002403static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002404switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002405{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002406 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002407
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002408 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002409}
2410
David Herrmann0af066f2012-10-29 19:21:16 +01002411/*
2412 * Find primary GPU
2413 * Some systems may have multiple DRM devices attached to a single seat. This
2414 * function loops over all devices and tries to find a PCI device with the
2415 * boot_vga sysfs attribute set to 1.
2416 * If no such device is found, the first DRM device reported by udev is used.
2417 */
2418static struct udev_device*
2419find_primary_gpu(struct drm_compositor *ec, const char *seat)
2420{
2421 struct udev_enumerate *e;
2422 struct udev_list_entry *entry;
2423 const char *path, *device_seat, *id;
2424 struct udev_device *device, *drm_device, *pci;
2425
2426 e = udev_enumerate_new(ec->udev);
2427 udev_enumerate_add_match_subsystem(e, "drm");
2428 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2429
2430 udev_enumerate_scan_devices(e);
2431 drm_device = NULL;
2432 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2433 path = udev_list_entry_get_name(entry);
2434 device = udev_device_new_from_syspath(ec->udev, path);
2435 if (!device)
2436 continue;
2437 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2438 if (!device_seat)
2439 device_seat = default_seat;
2440 if (strcmp(device_seat, seat)) {
2441 udev_device_unref(device);
2442 continue;
2443 }
2444
2445 pci = udev_device_get_parent_with_subsystem_devtype(device,
2446 "pci", NULL);
2447 if (pci) {
2448 id = udev_device_get_sysattr_value(pci, "boot_vga");
2449 if (id && !strcmp(id, "1")) {
2450 if (drm_device)
2451 udev_device_unref(drm_device);
2452 drm_device = device;
2453 break;
2454 }
2455 }
2456
2457 if (!drm_device)
2458 drm_device = device;
2459 else
2460 udev_device_unref(device);
2461 }
2462
2463 udev_enumerate_unref(e);
2464 return drm_device;
2465}
2466
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002467static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002468planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002469{
2470 struct drm_compositor *c = data;
2471
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002472 switch (key) {
2473 case KEY_C:
2474 c->cursors_are_broken ^= 1;
2475 break;
2476 case KEY_V:
2477 c->sprites_are_broken ^= 1;
2478 break;
2479 case KEY_O:
2480 c->sprites_hidden ^= 1;
2481 break;
2482 default:
2483 break;
2484 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002485}
2486
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002487#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002488static void
2489recorder_frame_notify(struct wl_listener *listener, void *data)
2490{
2491 struct drm_output *output;
2492 struct drm_compositor *c;
2493 int fd, ret;
2494
2495 output = container_of(listener, struct drm_output,
2496 recorder_frame_listener);
2497 c = (struct drm_compositor *) output->base.compositor;
2498
2499 if (!output->recorder)
2500 return;
2501
2502 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2503 DRM_CLOEXEC, &fd);
2504 if (ret) {
2505 weston_log("[libva recorder] "
2506 "failed to create prime fd for front buffer\n");
2507 return;
2508 }
2509
2510 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002511}
2512
2513static void *
2514create_recorder(struct drm_compositor *c, int width, int height,
2515 const char *filename)
2516{
2517 int fd;
2518 drm_magic_t magic;
2519
2520 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2521 if (fd < 0)
2522 return NULL;
2523
2524 drmGetMagic(fd, &magic);
2525 drmAuthMagic(c->drm.fd, magic);
2526
2527 return vaapi_recorder_create(fd, width, height, filename);
2528}
2529
2530static void
2531recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2532 void *data)
2533{
2534 struct drm_compositor *c = data;
2535 struct drm_output *output;
2536 int width, height;
2537
2538 output = container_of(c->base.output_list.next,
2539 struct drm_output, base.link);
2540
2541 if (!output->recorder) {
Hardeningff39efa2013-09-18 23:56:35 +02002542 width = output->base.current_mode->width;
2543 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002544
2545 output->recorder =
2546 create_recorder(c, width, height, "capture.h264");
2547 if (!output->recorder) {
2548 weston_log("failed to create vaapi recorder\n");
2549 return;
2550 }
2551
2552 output->base.disable_planes++;
2553
2554 output->recorder_frame_listener.notify = recorder_frame_notify;
2555 wl_signal_add(&output->base.frame_signal,
2556 &output->recorder_frame_listener);
2557
2558 weston_output_schedule_repaint(&output->base);
2559
2560 weston_log("[libva recorder] initialized\n");
2561 } else {
2562 vaapi_recorder_destroy(output->recorder);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002563 output->recorder = NULL;
2564
2565 output->base.disable_planes--;
2566
2567 wl_list_remove(&output->recorder_frame_listener.link);
2568 weston_log("[libva recorder] done\n");
2569 }
2570}
2571#else
2572static void
2573recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2574 void *data)
2575{
2576 weston_log("Compiled without libva support\n");
2577}
2578#endif
2579
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002580static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002581drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002582 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002583 int *argc, char *argv[],
2584 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002585{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002586 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002587 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002588 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002589 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002590 const char *path;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002591 char *s;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002592 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002593
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002594 weston_log("initializing drm backend\n");
2595
Peter Huttererf3d62272013-08-08 11:57:05 +10002596 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002597 if (ec == NULL)
2598 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002599
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002600 /* KMS support for sprites is not complete yet, so disable the
2601 * functionality for now. */
2602 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002603
2604 section = weston_config_get_section(config, "core", NULL, NULL);
2605 weston_config_section_get_string(section,
2606 "gbm-format", &s, "xrgb8888");
2607 if (strcmp(s, "xrgb8888") == 0)
2608 ec->format = GBM_FORMAT_XRGB8888;
2609 else if (strcmp(s, "rgb565") == 0)
2610 ec->format = GBM_FORMAT_RGB565;
2611 else if (strcmp(s, "xrgb2101010") == 0)
2612 ec->format = GBM_FORMAT_XRGB2101010;
2613 else {
2614 weston_log("fatal: unrecognized pixel format: %s\n", s);
2615 free(s);
2616 goto err_base;
2617 }
2618 free(s);
2619
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002620 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002621
Daniel Stone725c2c32012-06-22 14:04:36 +01002622 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002623 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002624 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002625 goto err_base;
2626 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002627
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002628 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002629 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
2630 param->seat_id);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002631 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002632 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002633 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002634 goto err_compositor;
2635 }
2636
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002637 ec->udev = udev_new();
2638 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002639 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002640 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002641 }
2642
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002643 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002644 ec->session_listener.notify = session_notify;
2645 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002646
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002647 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002648 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002649 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002650 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002651 }
David Herrmann0af066f2012-10-29 19:21:16 +01002652 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002653
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002654 if (init_drm(ec, drm_device) < 0) {
2655 weston_log("failed to initialize kms\n");
2656 goto err_udev_dev;
2657 }
2658
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002659 if (ec->use_pixman) {
2660 if (init_pixman(ec) < 0) {
2661 weston_log("failed to initialize pixman renderer\n");
2662 goto err_udev_dev;
2663 }
2664 } else {
2665 if (init_egl(ec) < 0) {
2666 weston_log("failed to initialize egl\n");
2667 goto err_udev_dev;
2668 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002669 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002670
2671 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002672 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002673
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002674 ec->base.focus = 1;
2675
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002676 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002677
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002678 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002679 weston_compositor_add_key_binding(&ec->base, key,
2680 MODIFIER_CTRL | MODIFIER_ALT,
2681 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002682
Jesse Barnes58ef3792012-02-23 09:45:49 -05002683 wl_list_init(&ec->sprite_list);
2684 create_sprites(ec);
2685
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002686 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002687 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002688 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002689 }
2690
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002691 path = NULL;
2692
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002693 if (udev_input_init(&ec->input,
2694 &ec->base, ec->udev, param->seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002695 weston_log("failed to create input devices\n");
2696 goto err_sprite;
2697 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002698
2699 loop = wl_display_get_event_loop(ec->base.wl_display);
2700 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002701 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002702 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002703
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002704 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2705 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002706 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002707 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002708 }
2709 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2710 "drm", NULL);
2711 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002712 wl_event_loop_add_fd(loop,
2713 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002714 WL_EVENT_READABLE, udev_drm_event, ec);
2715
2716 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002717 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002718 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002719 }
2720
Daniel Stonea96b93c2012-06-22 14:04:37 +01002721 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002722
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002723 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002724 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002725 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002726 planes_binding, ec);
2727 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2728 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002729 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2730 recorder_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002731
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002732 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002733
2734err_udev_monitor:
2735 wl_event_source_remove(ec->udev_drm_source);
2736 udev_monitor_unref(ec->udev_monitor);
2737err_drm_source:
2738 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002739 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002740err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002741 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002742 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002743 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002744err_udev_dev:
2745 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002746err_launcher:
2747 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002748err_udev:
2749 udev_unref(ec->udev);
2750err_compositor:
2751 weston_compositor_shutdown(&ec->base);
2752err_base:
2753 free(ec);
2754 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002755}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002756
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002757WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002758backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002759 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002760{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002761 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002762
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002763 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002764 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2765 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2766 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002767 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002768 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002769 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002770
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002771 param.seat_id = default_seat;
2772
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002773 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002774
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002775 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002776}