blob: 9922708654acafcbd792b918f57813366ffe97e8 [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
David Herrmann1edf44c2013-10-22 17:11:26 +0200579static int
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)
David Herrmann1edf44c2013-10-22 17:11:26 +0200591 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800592
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)
David Herrmann1edf44c2013-10-22 17:11:26 +0200596 return -1;
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");
David Herrmann1edf44c2013-10-22 17:11:26 +0200606 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400607 }
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");
David Herrmann1edf44c2013-10-22 17:11:26 +0200615 goto err_pageflip;
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
David Herrmann1edf44c2013-10-22 17:11:26 +0200667 return 0;
668
669err_pageflip:
670 if (output->next) {
671 drm_output_release_fb(output, output->next);
672 output->next = NULL;
673 }
674
675 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400676}
677
678static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200679drm_output_start_repaint_loop(struct weston_output *output_base)
680{
681 struct drm_output *output = (struct drm_output *) output_base;
682 struct drm_compositor *compositor = (struct drm_compositor *)
683 output_base->compositor;
684 uint32_t fb_id;
David Herrmann3c688c52013-10-22 17:11:25 +0200685 uint32_t msec;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300686 struct timespec ts;
687
Xiong Zhangabd5d472013-10-11 14:43:07 +0800688 if (output->destroy_pending)
689 return;
690
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300691 if (!output->current) {
692 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200693 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300694 }
695
696 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200697
698 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
699 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
700 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200701 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200702 }
David Herrmann3c688c52013-10-22 17:11:25 +0200703
704 return;
705
706finish_frame:
707 /* if we cannot page-flip, immediately finish frame */
708 clock_gettime(compositor->clock, &ts);
709 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
710 weston_output_finish_frame(output_base, msec);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200711}
712
713static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500714vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
715 void *data)
716{
717 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300718 struct drm_output *output = s->output;
719 uint32_t msecs;
720
721 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500722
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200723 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200724 s->current = s->next;
725 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300726
727 if (!output->page_flip_pending) {
728 msecs = sec * 1000 + usec / 1000;
729 weston_output_finish_frame(&output->base, msecs);
730 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500731}
732
733static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800734drm_output_destroy(struct weston_output *output_base);
735
736static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400737page_flip_handler(int fd, unsigned int frame,
738 unsigned int sec, unsigned int usec, void *data)
739{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200740 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400741 uint32_t msecs;
742
Jonas Ådahle5a12252013-04-05 23:07:11 +0200743 /* We don't set page_flip_pending on start_repaint_loop, in that case
744 * we just want to page flip to the current buffer to get an accurate
745 * timestamp */
746 if (output->page_flip_pending) {
747 drm_output_release_fb(output, output->current);
748 output->current = output->next;
749 output->next = NULL;
750 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300751
Jonas Ådahle5a12252013-04-05 23:07:11 +0200752 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400753
Xiong Zhangabd5d472013-10-11 14:43:07 +0800754 if (output->destroy_pending)
755 drm_output_destroy(&output->base);
756 else if (!output->vblank_pending) {
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300757 msecs = sec * 1000 + usec / 1000;
758 weston_output_finish_frame(&output->base, msecs);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300759
760 /* We can't call this from frame_notify, because the output's
761 * repaint needed flag is cleared just after that */
762 if (output->recorder)
763 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300764 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200765}
766
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500767static uint32_t
768drm_output_check_sprite_format(struct drm_sprite *s,
769 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500770{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500771 uint32_t i, format;
772
773 format = gbm_bo_get_format(bo);
774
775 if (format == GBM_FORMAT_ARGB8888) {
776 pixman_region32_t r;
777
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500778 pixman_region32_init_rect(&r, 0, 0,
779 es->geometry.width,
780 es->geometry.height);
781 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500782
783 if (!pixman_region32_not_empty(&r))
784 format = GBM_FORMAT_XRGB8888;
785
786 pixman_region32_fini(&r);
787 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500788
789 for (i = 0; i < s->count_formats; i++)
790 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500791 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500792
793 return 0;
794}
795
796static int
797drm_surface_transform_supported(struct weston_surface *es)
798{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500799 return !es->transform.enabled ||
800 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801}
802
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400803static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500804drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400805 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500806{
807 struct weston_compositor *ec = output_base->compositor;
808 struct drm_compositor *c =(struct drm_compositor *) ec;
809 struct drm_sprite *s;
810 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500811 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500812 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200813 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500814 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400815 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500816
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200817 if (c->gbm == NULL)
818 return NULL;
819
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200820 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200821 return NULL;
822
Hardeningff39efa2013-09-18 23:56:35 +0200823 if (es->buffer_scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200824 return NULL;
825
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500826 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400827 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500828
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300829 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400830 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300831
Pekka Paalanende685b82012-12-04 15:58:12 +0200832 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400833 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500834
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200835 if (es->alpha != 1.0f)
836 return NULL;
837
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500838 if (wl_shm_buffer_get(es->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500839 return NULL;
840
Jesse Barnes58ef3792012-02-23 09:45:49 -0500841 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400842 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500843
Jesse Barnes58ef3792012-02-23 09:45:49 -0500844 wl_list_for_each(s, &c->sprite_list, link) {
845 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
846 continue;
847
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200848 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500849 found = 1;
850 break;
851 }
852 }
853
854 /* No sprites available */
855 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400856 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500857
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400858 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700859 es->buffer_ref.buffer->resource,
860 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400861 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400862 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400863
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500864 format = drm_output_check_sprite_format(s, es, bo);
865 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200866 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400867 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500868 }
869
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200870 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200871 if (!s->next) {
872 gbm_bo_destroy(bo);
873 return NULL;
874 }
875
Pekka Paalanende685b82012-12-04 15:58:12 +0200876 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500877
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400878 box = pixman_region32_extents(&es->transform.boundingbox);
879 s->plane.x = box->x1;
880 s->plane.y = box->y1;
881
Jesse Barnes58ef3792012-02-23 09:45:49 -0500882 /*
883 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200884 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500885 * for us already).
886 */
887 pixman_region32_init(&dest_rect);
888 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
889 &output_base->region);
890 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
891 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200892 tbox = weston_transformed_rect(output_base->width,
893 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200894 output_base->transform,
Hardeningff39efa2013-09-18 23:56:35 +0200895 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200896 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200897 s->dest_x = tbox.x1;
898 s->dest_y = tbox.y1;
899 s->dest_w = tbox.x2 - tbox.x1;
900 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500901 pixman_region32_fini(&dest_rect);
902
903 pixman_region32_init(&src_rect);
904 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
905 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500906 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400907
908 weston_surface_from_global_fixed(es,
909 wl_fixed_from_int(box->x1),
910 wl_fixed_from_int(box->y1),
911 &sx1, &sy1);
912 weston_surface_from_global_fixed(es,
913 wl_fixed_from_int(box->x2),
914 wl_fixed_from_int(box->y2),
915 &sx2, &sy2);
916
917 if (sx1 < 0)
918 sx1 = 0;
919 if (sy1 < 0)
920 sy1 = 0;
921 if (sx2 > wl_fixed_from_int(es->geometry.width))
922 sx2 = wl_fixed_from_int(es->geometry.width);
923 if (sy2 > wl_fixed_from_int(es->geometry.height))
924 sy2 = wl_fixed_from_int(es->geometry.height);
925
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200926 tbox.x1 = sx1;
927 tbox.y1 = sy1;
928 tbox.x2 = sx2;
929 tbox.y2 = sy2;
930
931 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
932 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200933 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200934
935 s->src_x = tbox.x1 << 8;
936 s->src_y = tbox.y1 << 8;
937 s->src_w = (tbox.x2 - tbox.x1) << 8;
938 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500939 pixman_region32_fini(&src_rect);
940
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400941 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500942}
943
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400944static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400945drm_output_prepare_cursor_surface(struct weston_output *output_base,
946 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500947{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400948 struct drm_compositor *c =
949 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400950 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400951
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200952 if (c->gbm == NULL)
953 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200954 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
955 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400956 if (output->cursor_surface)
957 return NULL;
958 if (es->output_mask != (1u << output_base->id))
959 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500960 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400961 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200962 if (es->buffer_ref.buffer == NULL ||
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500963 !wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400964 es->geometry.width > 64 || es->geometry.height > 64)
965 return NULL;
966
967 output->cursor_surface = es;
968
969 return &output->cursor_plane;
970}
971
972static void
973drm_output_set_cursor(struct drm_output *output)
974{
975 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400976 struct drm_compositor *c =
977 (struct drm_compositor *) output->base.compositor;
978 EGLint handle, stride;
979 struct gbm_bo *bo;
980 uint32_t buf[64 * 64];
981 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400982 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500983
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400984 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400985 if (es == NULL) {
986 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
987 return;
988 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500989
Pekka Paalanende685b82012-12-04 15:58:12 +0200990 if (es->buffer_ref.buffer &&
991 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400992 pixman_region32_fini(&output->cursor_plane.damage);
993 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400994 output->current_cursor ^= 1;
995 bo = output->cursor_bo[output->current_cursor];
996 memset(buf, 0, sizeof buf);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500997 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
998 s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400999 for (i = 0; i < es->geometry.height; i++)
1000 memcpy(buf + i * 64, s + i * stride,
1001 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001002
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001003 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001004 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001005
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001006 handle = gbm_bo_get_handle(bo).s32;
1007 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -05001008 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001009 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001010 c->cursors_are_broken = 1;
1011 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001012 }
1013
Hardeningff39efa2013-09-18 23:56:35 +02001014 x = (es->geometry.x - output->base.x) * output->base.current_scale;
1015 y = (es->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001016 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001017 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001018 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001019 c->cursors_are_broken = 1;
1020 }
1021
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001022 output->cursor_plane.x = x;
1023 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001024 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001025}
1026
Jesse Barnes58ef3792012-02-23 09:45:49 -05001027static void
1028drm_assign_planes(struct weston_output *output)
1029{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001030 struct drm_compositor *c =
1031 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001032 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001033 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001034 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001035
1036 /*
1037 * Find a surface for each sprite in the output using some heuristics:
1038 * 1) size
1039 * 2) frequency of update
1040 * 3) opacity (though some hw might support alpha blending)
1041 * 4) clipping (this can be fixed with color keys)
1042 *
1043 * The idea is to save on blitting since this should save power.
1044 * If we can get a large video surface on the sprite for example,
1045 * the main display surface may not need to update at all, and
1046 * the client buffer can be used directly for the sprite surface
1047 * as we do for flipping full screen surfaces.
1048 */
1049 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001050 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001051 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001052 /* test whether this buffer can ever go into a plane:
1053 * non-shm, or small enough to be a cursor
1054 */
1055 if ((es->buffer_ref.buffer &&
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001056 !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) ||
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001057 (es->geometry.width <= 64 && es->geometry.height <= 64))
1058 es->keep_buffer = 1;
1059 else
1060 es->keep_buffer = 0;
1061
Jesse Barnes58ef3792012-02-23 09:45:49 -05001062 pixman_region32_init(&surface_overlap);
1063 pixman_region32_intersect(&surface_overlap, &overlap,
1064 &es->transform.boundingbox);
1065
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001066 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001067 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001068 next_plane = primary;
1069 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001070 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001071 if (next_plane == NULL)
1072 next_plane = drm_output_prepare_scanout_surface(output, es);
1073 if (next_plane == NULL)
1074 next_plane = drm_output_prepare_overlay_surface(output, es);
1075 if (next_plane == NULL)
1076 next_plane = primary;
1077 weston_surface_move_to_plane(es, next_plane);
1078 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001079 pixman_region32_union(&overlap, &overlap,
1080 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001081
Jesse Barnes58ef3792012-02-23 09:45:49 -05001082 pixman_region32_fini(&surface_overlap);
1083 }
1084 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001085}
1086
Matt Roper361d2ad2011-08-29 13:52:23 -07001087static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001088drm_output_fini_pixman(struct drm_output *output);
1089
1090static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001091drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001092{
1093 struct drm_output *output = (struct drm_output *) output_base;
1094 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001095 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001096 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001097
Xiong Zhangabd5d472013-10-11 14:43:07 +08001098 if (output->page_flip_pending) {
1099 output->destroy_pending = 1;
1100 weston_log("destroy output while page flip pending\n");
1101 return;
1102 }
1103
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001104 if (output->backlight)
1105 backlight_destroy(output->backlight);
1106
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001107 drmModeFreeProperty(output->dpms_prop);
1108
Matt Roper361d2ad2011-08-29 13:52:23 -07001109 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001110 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001111
1112 /* Restore original CRTC state */
1113 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001114 origcrtc->x, origcrtc->y,
1115 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001116 drmModeFreeCrtc(origcrtc);
1117
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001118 c->crtc_allocator &= ~(1 << output->crtc_id);
1119 c->connector_allocator &= ~(1 << output->connector_id);
1120
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001121 if (c->use_pixman) {
1122 drm_output_fini_pixman(output);
1123 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001124 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001125 gbm_surface_destroy(output->surface);
1126 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001127
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001128 weston_plane_release(&output->fb_plane);
1129 weston_plane_release(&output->cursor_plane);
1130
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001131 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001132 wl_list_remove(&output->base.link);
1133
Matt Roper361d2ad2011-08-29 13:52:23 -07001134 free(output);
1135}
1136
Alex Wub7b8bda2012-04-17 17:20:48 +08001137static struct drm_mode *
1138choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1139{
1140 struct drm_mode *tmp_mode = NULL, *mode;
1141
Hardeningff39efa2013-09-18 23:56:35 +02001142 if (output->base.current_mode->width == target_mode->width &&
1143 output->base.current_mode->height == target_mode->height &&
1144 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001145 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001146 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001147
1148 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1149 if (mode->mode_info.hdisplay == target_mode->width &&
1150 mode->mode_info.vdisplay == target_mode->height) {
1151 if (mode->mode_info.vrefresh == target_mode->refresh ||
1152 target_mode->refresh == 0) {
1153 return mode;
1154 } else if (!tmp_mode)
1155 tmp_mode = mode;
1156 }
1157 }
1158
1159 return tmp_mode;
1160}
1161
1162static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001163drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001164static int
1165drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001166
1167static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001168drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1169{
1170 struct drm_output *output;
1171 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001172 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001173
1174 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001175 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001176 return -1;
1177 }
1178
1179 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001180 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001181 return -1;
1182 }
1183
1184 ec = (struct drm_compositor *)output_base->compositor;
1185 output = (struct drm_output *)output_base;
1186 drm_mode = choose_mode (output, mode);
1187
1188 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001189 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001190 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001191 }
1192
Hardeningff39efa2013-09-18 23:56:35 +02001193 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001194 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001195
Hardeningff39efa2013-09-18 23:56:35 +02001196 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001197
Hardeningff39efa2013-09-18 23:56:35 +02001198 output->base.current_mode = &drm_mode->base;
1199 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001200 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1201
Alex Wub7b8bda2012-04-17 17:20:48 +08001202 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001203 drm_output_release_fb(output, output->current);
1204 drm_output_release_fb(output, output->next);
1205 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001206
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001207 if (ec->use_pixman) {
1208 drm_output_fini_pixman(output);
1209 if (drm_output_init_pixman(output, ec) < 0) {
1210 weston_log("failed to init output pixman state with "
1211 "new mode\n");
1212 return -1;
1213 }
1214 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001215 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001216 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001217
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001218 if (drm_output_init_egl(output, ec) < 0) {
1219 weston_log("failed to init output egl state with "
1220 "new mode");
1221 return -1;
1222 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001223 }
1224
Alex Wub7b8bda2012-04-17 17:20:48 +08001225 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001226}
1227
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001228static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001229on_drm_input(int fd, uint32_t mask, void *data)
1230{
1231 drmEventContext evctx;
1232
1233 memset(&evctx, 0, sizeof evctx);
1234 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1235 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001236 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001237 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001238
1239 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001240}
1241
1242static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001243init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001244{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001245 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001246 uint64_t cap;
1247 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001248
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001249 sysnum = udev_device_get_sysnum(device);
1250 if (sysnum)
1251 ec->drm.id = atoi(sysnum);
1252 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001253 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001254 return -1;
1255 }
1256
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001257 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001258 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001259 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001260 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001261 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001262 udev_device_get_devnode(device));
1263 return -1;
1264 }
1265
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001266 weston_log("using %s\n", filename);
1267
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001268 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001269 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001270
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001271 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1272 if (ret == 0 && cap == 1)
1273 ec->clock = CLOCK_MONOTONIC;
1274 else
1275 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001276
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001277 return 0;
1278}
1279
1280static int
1281init_egl(struct drm_compositor *ec)
1282{
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001283 EGLint format;
1284
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001285 gl_renderer = weston_load_module("gl-renderer.so",
1286 "gl_renderer_interface");
1287 if (!gl_renderer)
1288 return -1;
1289
1290 /* GBM will load a dri driver, but even though they need symbols from
1291 * libglapi, in some version of Mesa they are not linked to it. Since
1292 * only the gl-renderer module links to it, the call above won't make
1293 * these symbols globally available, and loading the DRI driver fails.
1294 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1295 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1296
Benjamin Franzke060cf802011-04-30 09:32:11 +02001297 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001298
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001299 if (!ec->gbm)
1300 return -1;
1301
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001302 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001303 if (gl_renderer->create(&ec->base, ec->gbm,
1304 gl_renderer->opaque_attribs, &format) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001305 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001306 return -1;
1307 }
1308
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001309 return 0;
1310}
1311
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001312static int
1313init_pixman(struct drm_compositor *ec)
1314{
1315 return pixman_renderer_init(&ec->base);
1316}
1317
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001318static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001319drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001320{
1321 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001322 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001323
1324 mode = malloc(sizeof *mode);
1325 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001326 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001327
1328 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001329 mode->base.width = info->hdisplay;
1330 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001331
1332 /* Calculate higher precision (mHz) refresh rate */
1333 refresh = (info->clock * 1000000LL / info->htotal +
1334 info->vtotal / 2) / info->vtotal;
1335
1336 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1337 refresh *= 2;
1338 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1339 refresh /= 2;
1340 if (info->vscan > 1)
1341 refresh /= info->vscan;
1342
1343 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001344 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001345
1346 if (info->type & DRM_MODE_TYPE_PREFERRED)
1347 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1348
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001349 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1350
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001351 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001352}
1353
1354static int
1355drm_subpixel_to_wayland(int drm_value)
1356{
1357 switch (drm_value) {
1358 default:
1359 case DRM_MODE_SUBPIXEL_UNKNOWN:
1360 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1361 case DRM_MODE_SUBPIXEL_NONE:
1362 return WL_OUTPUT_SUBPIXEL_NONE;
1363 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1364 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1365 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1366 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1367 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1368 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1369 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1370 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1371 }
1372}
1373
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001374/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001375static uint32_t
1376drm_get_backlight(struct drm_output *output)
1377{
1378 long brightness, max_brightness, norm;
1379
1380 brightness = backlight_get_brightness(output->backlight);
1381 max_brightness = backlight_get_max_brightness(output->backlight);
1382
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001383 /* convert it on a scale of 0 to 255 */
1384 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001385
1386 return (uint32_t) norm;
1387}
1388
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001389/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001390static void
1391drm_set_backlight(struct weston_output *output_base, uint32_t value)
1392{
1393 struct drm_output *output = (struct drm_output *) output_base;
1394 long max_brightness, new_brightness;
1395
1396 if (!output->backlight)
1397 return;
1398
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001399 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001400 return;
1401
1402 max_brightness = backlight_get_max_brightness(output->backlight);
1403
1404 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001405 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001406
1407 backlight_set_brightness(output->backlight, new_brightness);
1408}
1409
1410static drmModePropertyPtr
1411drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1412{
1413 drmModePropertyPtr props;
1414 int i;
1415
1416 for (i = 0; i < connector->count_props; i++) {
1417 props = drmModeGetProperty(fd, connector->props[i]);
1418 if (!props)
1419 continue;
1420
1421 if (!strcmp(props->name, name))
1422 return props;
1423
1424 drmModeFreeProperty(props);
1425 }
1426
1427 return NULL;
1428}
1429
1430static void
1431drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1432{
1433 struct drm_output *output = (struct drm_output *) output_base;
1434 struct weston_compositor *ec = output_base->compositor;
1435 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001436
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001437 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001438 return;
1439
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001440 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1441 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001442}
1443
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001444static const char *connector_type_names[] = {
1445 "None",
1446 "VGA",
1447 "DVI",
1448 "DVI",
1449 "DVI",
1450 "Composite",
1451 "TV",
1452 "LVDS",
1453 "CTV",
1454 "DIN",
1455 "DP",
1456 "HDMI",
1457 "HDMI",
1458 "TV",
1459 "eDP",
1460};
1461
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001462static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001463find_crtc_for_connector(struct drm_compositor *ec,
1464 drmModeRes *resources, drmModeConnector *connector)
1465{
1466 drmModeEncoder *encoder;
1467 uint32_t possible_crtcs;
1468 int i, j;
1469
1470 for (j = 0; j < connector->count_encoders; j++) {
1471 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1472 if (encoder == NULL) {
1473 weston_log("Failed to get encoder.\n");
1474 return -1;
1475 }
1476 possible_crtcs = encoder->possible_crtcs;
1477 drmModeFreeEncoder(encoder);
1478
1479 for (i = 0; i < resources->count_crtcs; i++) {
1480 if (possible_crtcs & (1 << i) &&
1481 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1482 return i;
1483 }
1484 }
1485
1486 return -1;
1487}
1488
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001489/* Init output state that depends on gl or gbm */
1490static int
1491drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1492{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001493 int i, flags;
1494
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001495 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001496 output->base.current_mode->width,
1497 output->base.current_mode->height,
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07001498 ec->format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001499 GBM_BO_USE_SCANOUT |
1500 GBM_BO_USE_RENDERING);
1501 if (!output->surface) {
1502 weston_log("failed to create gbm surface\n");
1503 return -1;
1504 }
1505
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001506 if (gl_renderer->output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001507 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001508 gbm_surface_destroy(output->surface);
1509 return -1;
1510 }
1511
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001512 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1513
1514 for (i = 0; i < 2; i++) {
1515 if (output->cursor_bo[i])
1516 continue;
1517
1518 output->cursor_bo[i] =
1519 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1520 flags);
1521 }
1522
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001523 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1524 weston_log("cursor buffers unavailable, using gl cursors\n");
1525 ec->cursors_are_broken = 1;
1526 }
1527
1528 return 0;
1529}
1530
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001531static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001532drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1533{
Hardeningff39efa2013-09-18 23:56:35 +02001534 int w = output->base.current_mode->width;
1535 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001536 unsigned int i;
1537
1538 /* FIXME error checking */
1539
1540 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001541 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001542 if (!output->dumb[i])
1543 goto err;
1544
1545 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001546 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001547 output->dumb[i]->map,
1548 output->dumb[i]->stride);
1549 if (!output->image[i])
1550 goto err;
1551 }
1552
1553 if (pixman_renderer_output_create(&output->base) < 0)
1554 goto err;
1555
1556 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001557 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001558
1559 return 0;
1560
1561err:
1562 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1563 if (output->dumb[i])
1564 drm_fb_destroy_dumb(output->dumb[i]);
1565 if (output->image[i])
1566 pixman_image_unref(output->image[i]);
1567
1568 output->dumb[i] = NULL;
1569 output->image[i] = NULL;
1570 }
1571
1572 return -1;
1573}
1574
1575static void
1576drm_output_fini_pixman(struct drm_output *output)
1577{
1578 unsigned int i;
1579
1580 pixman_renderer_output_destroy(&output->base);
1581 pixman_region32_fini(&output->previous_damage);
1582
1583 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1584 drm_fb_destroy_dumb(output->dumb[i]);
1585 pixman_image_unref(output->image[i]);
1586 output->dumb[i] = NULL;
1587 output->image[i] = NULL;
1588 }
1589}
1590
Richard Hughes2b2092a2013-04-24 14:58:02 +01001591static void
1592edid_parse_string(const uint8_t *data, char text[])
1593{
1594 int i;
1595 int replaced = 0;
1596
1597 /* this is always 12 bytes, but we can't guarantee it's null
1598 * terminated or not junk. */
1599 strncpy(text, (const char *) data, 12);
1600
1601 /* remove insane chars */
1602 for (i = 0; text[i] != '\0'; i++) {
1603 if (text[i] == '\n' ||
1604 text[i] == '\r') {
1605 text[i] = '\0';
1606 break;
1607 }
1608 }
1609
1610 /* ensure string is printable */
1611 for (i = 0; text[i] != '\0'; i++) {
1612 if (!isprint(text[i])) {
1613 text[i] = '-';
1614 replaced++;
1615 }
1616 }
1617
1618 /* if the string is random junk, ignore the string */
1619 if (replaced > 4)
1620 text[0] = '\0';
1621}
1622
1623#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1624#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1625#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1626#define EDID_OFFSET_DATA_BLOCKS 0x36
1627#define EDID_OFFSET_LAST_BLOCK 0x6c
1628#define EDID_OFFSET_PNPID 0x08
1629#define EDID_OFFSET_SERIAL 0x0c
1630
1631static int
1632edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1633{
1634 int i;
1635 uint32_t serial_number;
1636
1637 /* check header */
1638 if (length < 128)
1639 return -1;
1640 if (data[0] != 0x00 || data[1] != 0xff)
1641 return -1;
1642
1643 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1644 * /--08--\/--09--\
1645 * 7654321076543210
1646 * |\---/\---/\---/
1647 * R C1 C2 C3 */
1648 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1649 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1650 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1651 edid->pnp_id[3] = '\0';
1652
1653 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1654 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1655 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1656 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1657 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1658 if (serial_number > 0)
1659 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1660
1661 /* parse EDID data */
1662 for (i = EDID_OFFSET_DATA_BLOCKS;
1663 i <= EDID_OFFSET_LAST_BLOCK;
1664 i += 18) {
1665 /* ignore pixel clock data */
1666 if (data[i] != 0)
1667 continue;
1668 if (data[i+2] != 0)
1669 continue;
1670
1671 /* any useful blocks? */
1672 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1673 edid_parse_string(&data[i+5],
1674 edid->monitor_name);
1675 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1676 edid_parse_string(&data[i+5],
1677 edid->serial_number);
1678 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1679 edid_parse_string(&data[i+5],
1680 edid->eisa_id);
1681 }
1682 }
1683 return 0;
1684}
1685
1686static void
1687find_and_parse_output_edid(struct drm_compositor *ec,
1688 struct drm_output *output,
1689 drmModeConnector *connector)
1690{
1691 drmModePropertyBlobPtr edid_blob = NULL;
1692 drmModePropertyPtr property;
1693 int i;
1694 int rc;
1695
1696 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1697 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1698 if (!property)
1699 continue;
1700 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1701 !strcmp(property->name, "EDID")) {
1702 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1703 connector->prop_values[i]);
1704 }
1705 drmModeFreeProperty(property);
1706 }
1707 if (!edid_blob)
1708 return;
1709
1710 rc = edid_parse(&output->edid,
1711 edid_blob->data,
1712 edid_blob->length);
1713 if (!rc) {
1714 weston_log("EDID data '%s', '%s', '%s'\n",
1715 output->edid.pnp_id,
1716 output->edid.monitor_name,
1717 output->edid.serial_number);
1718 if (output->edid.pnp_id[0] != '\0')
1719 output->base.make = output->edid.pnp_id;
1720 if (output->edid.monitor_name[0] != '\0')
1721 output->base.model = output->edid.monitor_name;
1722 if (output->edid.serial_number[0] != '\0')
1723 output->base.serial_number = output->edid.serial_number;
1724 }
1725 drmModeFreePropertyBlob(edid_blob);
1726}
1727
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001728
1729
1730static int
1731parse_modeline(const char *s, drmModeModeInfo *mode)
1732{
1733 char hsync[16];
1734 char vsync[16];
1735 float fclock;
1736
1737 mode->type = DRM_MODE_TYPE_USERDEF;
1738 mode->hskew = 0;
1739 mode->vscan = 0;
1740 mode->vrefresh = 0;
1741 mode->flags = 0;
1742
Rob Bradford307e09e2013-07-26 16:29:40 +01001743 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001744 &fclock,
1745 &mode->hdisplay,
1746 &mode->hsync_start,
1747 &mode->hsync_end,
1748 &mode->htotal,
1749 &mode->vdisplay,
1750 &mode->vsync_start,
1751 &mode->vsync_end,
1752 &mode->vtotal, hsync, vsync) != 11)
1753 return -1;
1754
1755 mode->clock = fclock * 1000;
1756 if (strcmp(hsync, "+hsync") == 0)
1757 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1758 else if (strcmp(hsync, "-hsync") == 0)
1759 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1760 else
1761 return -1;
1762
1763 if (strcmp(vsync, "+vsync") == 0)
1764 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1765 else if (strcmp(vsync, "-vsync") == 0)
1766 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1767 else
1768 return -1;
1769
1770 return 0;
1771}
1772
1773static uint32_t
1774parse_transform(const char *transform, const char *output_name)
1775{
1776 static const struct { const char *name; uint32_t token; } names[] = {
1777 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1778 { "90", WL_OUTPUT_TRANSFORM_90 },
1779 { "180", WL_OUTPUT_TRANSFORM_180 },
1780 { "270", WL_OUTPUT_TRANSFORM_270 },
1781 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1782 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1783 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1784 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1785 };
1786 unsigned int i;
1787
1788 for (i = 0; i < ARRAY_LENGTH(names); i++)
1789 if (strcmp(names[i].name, transform) == 0)
1790 return names[i].token;
1791
1792 weston_log("Invalid transform \"%s\" for output %s\n",
1793 transform, output_name);
1794
1795 return WL_OUTPUT_TRANSFORM_NORMAL;
1796}
1797
Rob Bradford66bd9f52013-06-25 18:56:42 +01001798static void
1799setup_output_seat_constraint(struct drm_compositor *ec,
1800 struct weston_output *output,
1801 const char *s)
1802{
1803 if (strcmp(s, "") != 0) {
1804 struct udev_seat *seat;
1805
1806 seat = udev_seat_get_named(&ec->base, s);
1807 if (seat)
1808 seat->base.output = output;
1809
1810 if (seat && seat->base.pointer)
1811 weston_pointer_clamp(seat->base.pointer,
1812 &seat->base.pointer->x,
1813 &seat->base.pointer->y);
1814 }
1815}
1816
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001817static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001818create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001819 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001820 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001821 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001822{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001823 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001824 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1825 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001826 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001827 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001828 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001829 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001830 int i, width, height, scale;
1831 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001832 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001833 enum output_config config;
1834 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001835
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001836 i = find_crtc_for_connector(ec, resources, connector);
1837 if (i < 0) {
1838 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001839 return -1;
1840 }
1841
Peter Huttererf3d62272013-08-08 11:57:05 +10001842 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001843 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001844 return -1;
1845
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001846 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1847 output->base.make = "unknown";
1848 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001849 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001850 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001851
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001852 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1853 type_name = connector_type_names[connector->connector_type];
1854 else
1855 type_name = "UNKNOWN";
1856 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001857 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001858
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001859 section = weston_config_get_section(ec->base.config, "output", "name",
1860 output->base.name);
1861 weston_config_section_get_string(section, "mode", &s, "preferred");
1862 if (strcmp(s, "off") == 0)
1863 config = OUTPUT_CONFIG_OFF;
1864 else if (strcmp(s, "preferred") == 0)
1865 config = OUTPUT_CONFIG_PREFERRED;
1866 else if (strcmp(s, "current") == 0)
1867 config = OUTPUT_CONFIG_CURRENT;
1868 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1869 config = OUTPUT_CONFIG_MODE;
1870 else if (parse_modeline(s, &modeline) == 0)
1871 config = OUTPUT_CONFIG_MODELINE;
1872 else {
1873 weston_log("Invalid mode \"%s\" for output %s\n",
1874 s, output->base.name);
1875 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001876 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001877 free(s);
1878
1879 weston_config_section_get_int(section, "scale", &scale, 1);
1880 weston_config_section_get_string(section, "transform", &s, "normal");
1881 transform = parse_transform(s, output->base.name);
1882 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001883
Rob Bradford66bd9f52013-06-25 18:56:42 +01001884 weston_config_section_get_string(section, "seat", &s, "");
1885 setup_output_seat_constraint(ec, &output->base, s);
1886 free(s);
1887
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001888 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001889 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001890 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001891 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001892 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001893
Matt Roper361d2ad2011-08-29 13:52:23 -07001894 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001895 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001896
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001897 /* Get the current mode on the crtc that's currently driving
1898 * this connector. */
1899 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001900 memset(&crtc_mode, 0, sizeof crtc_mode);
1901 if (encoder != NULL) {
1902 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1903 drmModeFreeEncoder(encoder);
1904 if (crtc == NULL)
1905 goto err_free;
1906 if (crtc->mode_valid)
1907 crtc_mode = crtc->mode;
1908 drmModeFreeCrtc(crtc);
1909 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001910
David Herrmann0f0d54e2011-12-08 17:05:45 +01001911 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001912 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001913 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001914 goto err_free;
1915 }
1916
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001917 if (config == OUTPUT_CONFIG_OFF) {
1918 weston_log("Disabling output %s\n", output->base.name);
1919 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1920 0, 0, 0, 0, 0, NULL);
1921 goto err_free;
1922 }
1923
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001924 preferred = NULL;
1925 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001926 configured = NULL;
1927
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001928 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001929 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001930 width == drm_mode->base.width &&
1931 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001932 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001933 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001934 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001935 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001936 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001937 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001938
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001939 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001940 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001941 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001942 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001943 }
1944
Wang Quanxianacb805a2012-07-30 18:09:46 -04001945 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001946 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001947 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001948 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001949 }
1950
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001951 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001952 configured = current;
1953
Wang Quanxianacb805a2012-07-30 18:09:46 -04001954 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02001955 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001956 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02001957 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001958 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02001959 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001960 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02001961 output->base.current_mode = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001962
Hardeningff39efa2013-09-18 23:56:35 +02001963 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001964 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001965 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001966 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001967
Hardeningff39efa2013-09-18 23:56:35 +02001968 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001969
John Kåre Alsaker94659272012-11-13 19:10:18 +01001970 weston_output_init(&output->base, &ec->base, x, y,
1971 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001972 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001973
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001974 if (ec->use_pixman) {
1975 if (drm_output_init_pixman(output, ec) < 0) {
1976 weston_log("Failed to init output pixman state\n");
1977 goto err_output;
1978 }
1979 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001980 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001981 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001982 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001983
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001984 output->backlight = backlight_init(drm_device,
1985 connector->connector_type);
1986 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001987 weston_log("Initialized backlight, device %s\n",
1988 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001989 output->base.set_backlight = drm_set_backlight;
1990 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001991 } else {
1992 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001993 }
1994
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001995 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1996
Richard Hughes2b2092a2013-04-24 14:58:02 +01001997 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001998 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1999 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002000
Jonas Ådahle5a12252013-04-05 23:07:11 +02002001 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002002 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002003 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002004 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002005 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002006 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002007
Richard Hughese7299962013-05-01 21:52:12 +01002008 output->base.gamma_size = output->original_crtc->gamma_size;
2009 output->base.set_gamma = drm_output_set_gamma;
2010
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002011 weston_plane_init(&output->cursor_plane, 0, 0);
2012 weston_plane_init(&output->fb_plane, 0, 0);
2013
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002014 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2015 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2016 &ec->base.primary_plane);
2017
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002018 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002019 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002020 wl_list_for_each(m, &output->base.mode_list, link)
2021 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
2022 m->width, m->height, m->refresh / 1000.0,
2023 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2024 ", preferred" : "",
2025 m->flags & WL_OUTPUT_MODE_CURRENT ?
2026 ", current" : "",
2027 connector->count_modes == 0 ?
2028 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002029
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002030 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002031
John Kåre Alsaker94659272012-11-13 19:10:18 +01002032err_output:
2033 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002034err_free:
2035 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2036 base.link) {
2037 wl_list_remove(&drm_mode->base.link);
2038 free(drm_mode);
2039 }
2040
2041 drmModeFreeCrtc(output->original_crtc);
2042 ec->crtc_allocator &= ~(1 << output->crtc_id);
2043 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002044 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002045
David Herrmann0f0d54e2011-12-08 17:05:45 +01002046 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002047}
2048
Jesse Barnes58ef3792012-02-23 09:45:49 -05002049static void
2050create_sprites(struct drm_compositor *ec)
2051{
2052 struct drm_sprite *sprite;
2053 drmModePlaneRes *plane_res;
2054 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002055 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002056
2057 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2058 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002059 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002060 strerror(errno));
2061 return;
2062 }
2063
2064 for (i = 0; i < plane_res->count_planes; i++) {
2065 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2066 if (!plane)
2067 continue;
2068
Peter Huttererf3d62272013-08-08 11:57:05 +10002069 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002070 plane->count_formats));
2071 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002072 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002073 __func__);
2074 free(plane);
2075 continue;
2076 }
2077
Jesse Barnes58ef3792012-02-23 09:45:49 -05002078 sprite->possible_crtcs = plane->possible_crtcs;
2079 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002080 sprite->current = NULL;
2081 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002082 sprite->compositor = ec;
2083 sprite->count_formats = plane->count_formats;
2084 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002085 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002086 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002087 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002088 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2089 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002090
2091 wl_list_insert(&ec->sprite_list, &sprite->link);
2092 }
2093
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002094 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002095}
2096
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002097static void
2098destroy_sprites(struct drm_compositor *compositor)
2099{
2100 struct drm_sprite *sprite, *next;
2101 struct drm_output *output;
2102
2103 output = container_of(compositor->base.output_list.next,
2104 struct drm_output, base.link);
2105
2106 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2107 drmModeSetPlane(compositor->drm.fd,
2108 sprite->plane_id,
2109 output->crtc_id, 0, 0,
2110 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002111 drm_output_release_fb(output, sprite->current);
2112 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002113 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002114 free(sprite);
2115 }
2116}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002117
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002118static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002119create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002120 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002121{
2122 drmModeConnector *connector;
2123 drmModeRes *resources;
2124 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002125 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002126
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002127 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002128 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002129 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002130 return -1;
2131 }
2132
Jesse Barnes58ef3792012-02-23 09:45:49 -05002133 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002134 if (!ec->crtcs) {
2135 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002136 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002137 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002138
Rob Clark4339add2012-08-09 14:18:28 -05002139 ec->min_width = resources->min_width;
2140 ec->max_width = resources->max_width;
2141 ec->min_height = resources->min_height;
2142 ec->max_height = resources->max_height;
2143
Jesse Barnes58ef3792012-02-23 09:45:49 -05002144 ec->num_crtcs = resources->count_crtcs;
2145 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2146
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002147 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002148 connector = drmModeGetConnector(ec->drm.fd,
2149 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002150 if (connector == NULL)
2151 continue;
2152
2153 if (connector->connection == DRM_MODE_CONNECTED &&
2154 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002155 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002156 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002157 connector, x, y,
2158 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002159 drmModeFreeConnector(connector);
2160 continue;
2161 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002162
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002163 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002164 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002165 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002166 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002167
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002168 drmModeFreeConnector(connector);
2169 }
2170
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002171 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002172 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002173 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002174 return -1;
2175 }
2176
2177 drmModeFreeResources(resources);
2178
2179 return 0;
2180}
2181
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002182static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002183update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002184{
2185 drmModeConnector *connector;
2186 drmModeRes *resources;
2187 struct drm_output *output, *next;
2188 int x = 0, y = 0;
2189 int x_offset = 0, y_offset = 0;
2190 uint32_t connected = 0, disconnects = 0;
2191 int i;
2192
2193 resources = drmModeGetResources(ec->drm.fd);
2194 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002195 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002196 return;
2197 }
2198
2199 /* collect new connects */
2200 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002201 int connector_id = resources->connectors[i];
2202
2203 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002204 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002205 continue;
2206
David Herrmann7551cff2011-12-08 17:05:43 +01002207 if (connector->connection != DRM_MODE_CONNECTED) {
2208 drmModeFreeConnector(connector);
2209 continue;
2210 }
2211
Benjamin Franzke117483d2011-08-30 11:38:26 +02002212 connected |= (1 << connector_id);
2213
2214 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002215 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002216 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002217 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002218
2219 /* XXX: not yet needed, we die with 0 outputs */
2220 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002221 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002222 else
2223 x = 0;
2224 y = 0;
2225 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002226 connector, x, y,
2227 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002228 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002229
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002230 }
2231 drmModeFreeConnector(connector);
2232 }
2233 drmModeFreeResources(resources);
2234
2235 disconnects = ec->connector_allocator & ~connected;
2236 if (disconnects) {
2237 wl_list_for_each_safe(output, next, &ec->base.output_list,
2238 base.link) {
2239 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002240 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002241 output->base.x - x_offset,
2242 output->base.y - y_offset);
2243 }
2244
2245 if (disconnects & (1 << output->connector_id)) {
2246 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002247 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002248 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002249 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002250 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002251 }
2252 }
2253 }
2254
2255 /* FIXME: handle zero outputs, without terminating */
2256 if (ec->connector_allocator == 0)
2257 wl_display_terminate(ec->base.wl_display);
2258}
2259
2260static int
David Herrmannd7488c22012-03-11 20:05:21 +01002261udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002262{
David Herrmannd7488c22012-03-11 20:05:21 +01002263 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002264 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002265
2266 sysnum = udev_device_get_sysnum(device);
2267 if (!sysnum || atoi(sysnum) != ec->drm.id)
2268 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002269
David Herrmann6ac52db2012-03-11 20:05:22 +01002270 val = udev_device_get_property_value(device, "HOTPLUG");
2271 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002272 return 0;
2273
David Herrmann6ac52db2012-03-11 20:05:22 +01002274 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002275}
2276
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002277static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002278udev_drm_event(int fd, uint32_t mask, void *data)
2279{
2280 struct drm_compositor *ec = data;
2281 struct udev_device *event;
2282
2283 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002284
David Herrmannd7488c22012-03-11 20:05:21 +01002285 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002286 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002287
2288 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002289
2290 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002291}
2292
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002293static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002294drm_restore(struct weston_compositor *ec)
2295{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002296 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002297}
2298
2299static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002300drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002301{
2302 struct drm_compositor *d = (struct drm_compositor *) ec;
2303
Rob Bradfordd355b802013-05-31 18:09:55 +01002304 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002305
2306 wl_event_source_remove(d->udev_drm_source);
2307 wl_event_source_remove(d->drm_source);
2308
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002309 destroy_sprites(d);
2310
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002311 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002312
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002313 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002314
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002315 if (d->gbm)
2316 gbm_device_destroy(d->gbm);
2317
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002318 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002319
Rob Bradford45c15b82013-07-26 16:29:35 +01002320 close(d->drm.fd);
2321
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002322 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002323}
2324
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002325static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002326drm_compositor_set_modes(struct drm_compositor *compositor)
2327{
2328 struct drm_output *output;
2329 struct drm_mode *drm_mode;
2330 int ret;
2331
2332 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002333 if (!output->current) {
2334 /* If something that would cause the output to
2335 * switch mode happened while in another vt, we
2336 * might not have a current drm_fb. In that case,
2337 * schedule a repaint and let drm_output_repaint
2338 * handle setting the mode. */
2339 weston_output_schedule_repaint(&output->base);
2340 continue;
2341 }
2342
Hardeningff39efa2013-09-18 23:56:35 +02002343 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002344 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002345 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002346 &output->connector_id, 1,
2347 &drm_mode->mode_info);
2348 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002349 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002350 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002351 drm_mode->base.width, drm_mode->base.height,
2352 output->base.x, output->base.y);
2353 }
2354 }
2355}
2356
2357static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002358session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002359{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002360 struct weston_compositor *compositor = data;
2361 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002362 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002363 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002364
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002365 if (ec->base.session_active) {
2366 weston_log("activating session\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002367 compositor->focus = 1;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -07002368 if (ec->base.launcher == NULL && drmSetMaster(ec->drm.fd)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002369 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002370 wl_display_terminate(compositor->wl_display);
2371 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002372 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002373 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002374 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002375 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002376 } else {
2377 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002378 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002379
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002380 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002381 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002382 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002383
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002384 /* If we have a repaint scheduled (either from a
2385 * pending pageflip or the idle handler), make sure we
2386 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002387 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002388 * further attemps at repainting. When we switch
2389 * back, we schedule a repaint, which will process
2390 * pending frame callbacks. */
2391
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002392 wl_list_for_each(output, &ec->base.output_list, base.link) {
2393 output->base.repaint_needed = 0;
2394 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002395 }
2396
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002397 output = container_of(ec->base.output_list.next,
2398 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002399
2400 wl_list_for_each(sprite, &ec->sprite_list, link)
2401 drmModeSetPlane(ec->drm.fd,
2402 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002403 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002404 0, 0, 0, 0, 0, 0, 0, 0);
2405
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -07002406 if (ec->base.launcher == NULL && drmDropMaster(ec->drm.fd) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002407 weston_log("failed to drop master: %m\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002408 };
2409}
2410
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002411static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002412switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002413{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002414 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002415
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002416 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002417}
2418
David Herrmann0af066f2012-10-29 19:21:16 +01002419/*
2420 * Find primary GPU
2421 * Some systems may have multiple DRM devices attached to a single seat. This
2422 * function loops over all devices and tries to find a PCI device with the
2423 * boot_vga sysfs attribute set to 1.
2424 * If no such device is found, the first DRM device reported by udev is used.
2425 */
2426static struct udev_device*
2427find_primary_gpu(struct drm_compositor *ec, const char *seat)
2428{
2429 struct udev_enumerate *e;
2430 struct udev_list_entry *entry;
2431 const char *path, *device_seat, *id;
2432 struct udev_device *device, *drm_device, *pci;
2433
2434 e = udev_enumerate_new(ec->udev);
2435 udev_enumerate_add_match_subsystem(e, "drm");
2436 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2437
2438 udev_enumerate_scan_devices(e);
2439 drm_device = NULL;
2440 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2441 path = udev_list_entry_get_name(entry);
2442 device = udev_device_new_from_syspath(ec->udev, path);
2443 if (!device)
2444 continue;
2445 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2446 if (!device_seat)
2447 device_seat = default_seat;
2448 if (strcmp(device_seat, seat)) {
2449 udev_device_unref(device);
2450 continue;
2451 }
2452
2453 pci = udev_device_get_parent_with_subsystem_devtype(device,
2454 "pci", NULL);
2455 if (pci) {
2456 id = udev_device_get_sysattr_value(pci, "boot_vga");
2457 if (id && !strcmp(id, "1")) {
2458 if (drm_device)
2459 udev_device_unref(drm_device);
2460 drm_device = device;
2461 break;
2462 }
2463 }
2464
2465 if (!drm_device)
2466 drm_device = device;
2467 else
2468 udev_device_unref(device);
2469 }
2470
2471 udev_enumerate_unref(e);
2472 return drm_device;
2473}
2474
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002475static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002476planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002477{
2478 struct drm_compositor *c = data;
2479
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002480 switch (key) {
2481 case KEY_C:
2482 c->cursors_are_broken ^= 1;
2483 break;
2484 case KEY_V:
2485 c->sprites_are_broken ^= 1;
2486 break;
2487 case KEY_O:
2488 c->sprites_hidden ^= 1;
2489 break;
2490 default:
2491 break;
2492 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002493}
2494
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002495#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002496static void
2497recorder_frame_notify(struct wl_listener *listener, void *data)
2498{
2499 struct drm_output *output;
2500 struct drm_compositor *c;
2501 int fd, ret;
2502
2503 output = container_of(listener, struct drm_output,
2504 recorder_frame_listener);
2505 c = (struct drm_compositor *) output->base.compositor;
2506
2507 if (!output->recorder)
2508 return;
2509
2510 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2511 DRM_CLOEXEC, &fd);
2512 if (ret) {
2513 weston_log("[libva recorder] "
2514 "failed to create prime fd for front buffer\n");
2515 return;
2516 }
2517
2518 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002519}
2520
2521static void *
2522create_recorder(struct drm_compositor *c, int width, int height,
2523 const char *filename)
2524{
2525 int fd;
2526 drm_magic_t magic;
2527
2528 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2529 if (fd < 0)
2530 return NULL;
2531
2532 drmGetMagic(fd, &magic);
2533 drmAuthMagic(c->drm.fd, magic);
2534
2535 return vaapi_recorder_create(fd, width, height, filename);
2536}
2537
2538static void
2539recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2540 void *data)
2541{
2542 struct drm_compositor *c = data;
2543 struct drm_output *output;
2544 int width, height;
2545
2546 output = container_of(c->base.output_list.next,
2547 struct drm_output, base.link);
2548
2549 if (!output->recorder) {
Hardeningff39efa2013-09-18 23:56:35 +02002550 width = output->base.current_mode->width;
2551 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002552
2553 output->recorder =
2554 create_recorder(c, width, height, "capture.h264");
2555 if (!output->recorder) {
2556 weston_log("failed to create vaapi recorder\n");
2557 return;
2558 }
2559
2560 output->base.disable_planes++;
2561
2562 output->recorder_frame_listener.notify = recorder_frame_notify;
2563 wl_signal_add(&output->base.frame_signal,
2564 &output->recorder_frame_listener);
2565
2566 weston_output_schedule_repaint(&output->base);
2567
2568 weston_log("[libva recorder] initialized\n");
2569 } else {
2570 vaapi_recorder_destroy(output->recorder);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002571 output->recorder = NULL;
2572
2573 output->base.disable_planes--;
2574
2575 wl_list_remove(&output->recorder_frame_listener.link);
2576 weston_log("[libva recorder] done\n");
2577 }
2578}
2579#else
2580static void
2581recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2582 void *data)
2583{
2584 weston_log("Compiled without libva support\n");
2585}
2586#endif
2587
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002588static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002589drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002590 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002591 int *argc, char *argv[],
2592 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002593{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002594 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002595 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002596 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002597 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002598 const char *path;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002599 char *s;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002600 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002601
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002602 weston_log("initializing drm backend\n");
2603
Peter Huttererf3d62272013-08-08 11:57:05 +10002604 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002605 if (ec == NULL)
2606 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002607
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002608 /* KMS support for sprites is not complete yet, so disable the
2609 * functionality for now. */
2610 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002611
2612 section = weston_config_get_section(config, "core", NULL, NULL);
2613 weston_config_section_get_string(section,
2614 "gbm-format", &s, "xrgb8888");
2615 if (strcmp(s, "xrgb8888") == 0)
2616 ec->format = GBM_FORMAT_XRGB8888;
2617 else if (strcmp(s, "rgb565") == 0)
2618 ec->format = GBM_FORMAT_RGB565;
2619 else if (strcmp(s, "xrgb2101010") == 0)
2620 ec->format = GBM_FORMAT_XRGB2101010;
2621 else {
2622 weston_log("fatal: unrecognized pixel format: %s\n", s);
2623 free(s);
2624 goto err_base;
2625 }
2626 free(s);
2627
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002628 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002629
Daniel Stone725c2c32012-06-22 14:04:36 +01002630 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002631 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002632 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002633 goto err_base;
2634 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002635
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002636 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002637 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
2638 param->seat_id);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002639 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002640 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002641 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002642 goto err_compositor;
2643 }
2644
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002645 ec->udev = udev_new();
2646 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002647 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002648 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002649 }
2650
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002651 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002652 ec->session_listener.notify = session_notify;
2653 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002654
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002655 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002656 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002657 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002658 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002659 }
David Herrmann0af066f2012-10-29 19:21:16 +01002660 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002661
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002662 if (init_drm(ec, drm_device) < 0) {
2663 weston_log("failed to initialize kms\n");
2664 goto err_udev_dev;
2665 }
2666
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002667 if (ec->use_pixman) {
2668 if (init_pixman(ec) < 0) {
2669 weston_log("failed to initialize pixman renderer\n");
2670 goto err_udev_dev;
2671 }
2672 } else {
2673 if (init_egl(ec) < 0) {
2674 weston_log("failed to initialize egl\n");
2675 goto err_udev_dev;
2676 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002677 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002678
2679 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002680 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002681
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002682 ec->base.focus = 1;
2683
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002684 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002685
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002686 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002687 weston_compositor_add_key_binding(&ec->base, key,
2688 MODIFIER_CTRL | MODIFIER_ALT,
2689 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002690
Jesse Barnes58ef3792012-02-23 09:45:49 -05002691 wl_list_init(&ec->sprite_list);
2692 create_sprites(ec);
2693
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002694 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002695 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002696 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002697 }
2698
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002699 path = NULL;
2700
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002701 if (udev_input_init(&ec->input,
2702 &ec->base, ec->udev, param->seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002703 weston_log("failed to create input devices\n");
2704 goto err_sprite;
2705 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002706
2707 loop = wl_display_get_event_loop(ec->base.wl_display);
2708 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002709 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002710 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002711
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002712 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2713 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002714 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002715 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002716 }
2717 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2718 "drm", NULL);
2719 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002720 wl_event_loop_add_fd(loop,
2721 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002722 WL_EVENT_READABLE, udev_drm_event, ec);
2723
2724 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002725 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002726 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002727 }
2728
Daniel Stonea96b93c2012-06-22 14:04:37 +01002729 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002730
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002731 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002732 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002733 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002734 planes_binding, ec);
2735 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2736 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002737 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2738 recorder_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002739
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002740 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002741
2742err_udev_monitor:
2743 wl_event_source_remove(ec->udev_drm_source);
2744 udev_monitor_unref(ec->udev_monitor);
2745err_drm_source:
2746 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002747 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002748err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002749 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002750 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002751 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002752err_udev_dev:
2753 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002754err_launcher:
2755 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002756err_udev:
2757 udev_unref(ec->udev);
2758err_compositor:
2759 weston_compositor_shutdown(&ec->base);
2760err_base:
2761 free(ec);
2762 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002763}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002764
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002765WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002766backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002767 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002768{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002769 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002770
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002771 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002772 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2773 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2774 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002775 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002776 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002777 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002778
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002779 param.seat_id = default_seat;
2780
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002781 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002782
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002783 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002784}