blob: 71cbcfa44878493a3e89bb4927d6bfdf637bfab2 [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Daniel Stonec228e232013-05-22 18:03:19 +030024#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040025
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010028#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040029#include <string.h>
30#include <fcntl.h>
31#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040032#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070033#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030034#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020035#include <sys/mman.h>
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030036#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030037#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040038
Benjamin Franzkec649a922011-03-02 11:56:04 +010039#include <xf86drm.h>
40#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050041#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010042
Benjamin Franzke060cf802011-04-30 09:32:11 +020043#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020044#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040045#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020046
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040047#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010048#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020049#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050050#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010051#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030052#include "vaapi-recorder.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040053
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030054#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
55#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
56#endif
57
Kristian Høgsberg061c4252012-06-28 11:28:15 -040058static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060059
60enum output_config {
61 OUTPUT_CONFIG_INVALID = 0,
62 OUTPUT_CONFIG_OFF,
63 OUTPUT_CONFIG_PREFERRED,
64 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060065 OUTPUT_CONFIG_MODE,
66 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060067};
68
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040069struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050070 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040071
72 struct udev *udev;
73 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010075 struct udev_monitor *udev_monitor;
76 struct wl_event_source *udev_drm_source;
77
Benjamin Franzke2af7f102011-03-02 11:14:59 +010078 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010079 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010080 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030081 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010082 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020083 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050084 uint32_t *crtcs;
85 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050086 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010087 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -070088 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -070089 uint32_t format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020090
Rob Clark4339add2012-08-09 14:18:28 -050091 /* we need these parameters in order to not fail drmModeAddFB2()
92 * due to out of bounds dimensions, and then mistakenly set
93 * sprites_are_broken:
94 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020095 uint32_t min_width, max_width;
96 uint32_t min_height, max_height;
97 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050098
Jesse Barnes58ef3792012-02-23 09:45:49 -050099 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500100 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200101 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500102
Rob Clarkab5b1e32012-08-09 13:24:45 -0500103 int cursors_are_broken;
104
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200105 int use_pixman;
106
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200107 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300108
109 clockid_t clock;
Rob Bradfordd355b802013-05-31 18:09:55 +0100110 struct udev_input input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400111};
112
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400113struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500114 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400115 drmModeModeInfo mode_info;
116};
117
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300118struct drm_output;
119
120struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300121 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200122 uint32_t fb_id, stride, handle, size;
123 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300124 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200125 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200126
127 /* Used by gbm fbs */
128 struct gbm_bo *bo;
129
130 /* Used by dumb fbs */
131 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300132};
133
Richard Hughes2b2092a2013-04-24 14:58:02 +0100134struct drm_edid {
135 char eisa_id[13];
136 char monitor_name[13];
137 char pnp_id[5];
138 char serial_number[13];
139};
140
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400141struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500142 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400143
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400144 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500145 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400146 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700147 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100148 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300149 drmModePropertyPtr dpms_prop;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200150
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300151 int vblank_pending;
152 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800153 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300154
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400155 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400156 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400157 struct weston_plane cursor_plane;
158 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400159 struct weston_surface *cursor_surface;
160 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300161 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200162 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200163
164 struct drm_fb *dumb[2];
165 pixman_image_t *image[2];
166 int current_image;
167 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300168
169 struct vaapi_recorder *recorder;
170 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400171};
172
Jesse Barnes58ef3792012-02-23 09:45:49 -0500173/*
174 * An output has a primary display plane plus zero or more sprites for
175 * blending display contents.
176 */
177struct drm_sprite {
178 struct wl_list link;
179
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400180 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500181
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200182 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300183 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500184 struct drm_compositor *compositor;
185
Jesse Barnes58ef3792012-02-23 09:45:49 -0500186 uint32_t possible_crtcs;
187 uint32_t plane_id;
188 uint32_t count_formats;
189
190 int32_t src_x, src_y;
191 uint32_t src_w, src_h;
192 uint32_t dest_x, dest_y;
193 uint32_t dest_w, dest_h;
194
195 uint32_t formats[];
196};
197
Kristian Høgsbergd8e98332013-10-16 16:15:11 -0700198struct drm_parameters {
199 int connector;
200 int tty;
201 int use_pixman;
202 const char *seat_id;
203};
204
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300205static struct gl_renderer_interface *gl_renderer;
206
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500207static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400208
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400209static void
210drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400211
Jesse Barnes58ef3792012-02-23 09:45:49 -0500212static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500213drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
214{
215 struct weston_compositor *ec = output_base->compositor;
216 struct drm_compositor *c =(struct drm_compositor *) ec;
217 struct drm_output *output = (struct drm_output *) output_base;
218 int crtc;
219
220 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
221 if (c->crtcs[crtc] != output->crtc_id)
222 continue;
223
224 if (supported & (1 << crtc))
225 return -1;
226 }
227
228 return 0;
229}
230
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300231static void
232drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
233{
234 struct drm_fb *fb = data;
235 struct gbm_device *gbm = gbm_bo_get_device(bo);
236
237 if (fb->fb_id)
238 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
239
Pekka Paalanende685b82012-12-04 15:58:12 +0200240 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300241
242 free(data);
243}
244
245static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200246drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
247{
248 struct drm_fb *fb;
249 int ret;
250
251 struct drm_mode_create_dumb create_arg;
252 struct drm_mode_destroy_dumb destroy_arg;
253 struct drm_mode_map_dumb map_arg;
254
Peter Huttererf3d62272013-08-08 11:57:05 +1000255 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200256 if (!fb)
257 return NULL;
258
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700259 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200260 create_arg.bpp = 32;
261 create_arg.width = width;
262 create_arg.height = height;
263
264 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
265 if (ret)
266 goto err_fb;
267
268 fb->handle = create_arg.handle;
269 fb->stride = create_arg.pitch;
270 fb->size = create_arg.size;
271 fb->fd = ec->drm.fd;
272
273 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
274 fb->stride, fb->handle, &fb->fb_id);
275 if (ret)
276 goto err_bo;
277
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700278 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200279 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400280 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200281 if (ret)
282 goto err_add_fb;
283
284 fb->map = mmap(0, fb->size, PROT_WRITE,
285 MAP_SHARED, ec->drm.fd, map_arg.offset);
286 if (fb->map == MAP_FAILED)
287 goto err_add_fb;
288
289 return fb;
290
291err_add_fb:
292 drmModeRmFB(ec->drm.fd, fb->fb_id);
293err_bo:
294 memset(&destroy_arg, 0, sizeof(destroy_arg));
295 destroy_arg.handle = create_arg.handle;
296 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
297err_fb:
298 free(fb);
299 return NULL;
300}
301
302static void
303drm_fb_destroy_dumb(struct drm_fb *fb)
304{
305 struct drm_mode_destroy_dumb destroy_arg;
306
307 if (!fb->map)
308 return;
309
310 if (fb->fb_id)
311 drmModeRmFB(fb->fd, fb->fb_id);
312
313 weston_buffer_reference(&fb->buffer_ref, NULL);
314
315 munmap(fb->map, fb->size);
316
317 memset(&destroy_arg, 0, sizeof(destroy_arg));
318 destroy_arg.handle = fb->handle;
319 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
320
321 free(fb);
322}
323
324static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500325drm_fb_get_from_bo(struct gbm_bo *bo,
326 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300327{
328 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200329 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200330 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300331 int ret;
332
333 if (fb)
334 return fb;
335
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200336 fb = calloc(1, sizeof *fb);
337 if (!fb)
338 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300339
340 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300341
342 width = gbm_bo_get_width(bo);
343 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200344 fb->stride = gbm_bo_get_stride(bo);
345 fb->handle = gbm_bo_get_handle(bo).u32;
346 fb->size = fb->stride * height;
347 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300348
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200349 if (compositor->min_width > width || width > compositor->max_width ||
350 compositor->min_height > height ||
351 height > compositor->max_height) {
352 weston_log("bo geometry out of bounds\n");
353 goto err_free;
354 }
355
356 ret = -1;
357
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200358 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200359 handles[0] = fb->handle;
360 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200361 offsets[0] = 0;
362
363 ret = drmModeAddFB2(compositor->drm.fd, width, height,
364 format, handles, pitches, offsets,
365 &fb->fb_id, 0);
366 if (ret) {
367 weston_log("addfb2 failed: %m\n");
368 compositor->no_addfb2 = 1;
369 compositor->sprites_are_broken = 1;
370 }
371 }
372
373 if (ret)
374 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200375 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300377 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200378 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200379 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300380 }
381
382 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
383
384 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200385
386err_free:
387 free(fb);
388 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300389}
390
391static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500392drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200393{
Pekka Paalanende685b82012-12-04 15:58:12 +0200394 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200395
396 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200397
Pekka Paalanende685b82012-12-04 15:58:12 +0200398 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200399}
400
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200401static void
402drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
403{
404 if (!fb)
405 return;
406
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200407 if (fb->map &&
408 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200409 drm_fb_destroy_dumb(fb);
410 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200411 if (fb->is_client_buffer)
412 gbm_bo_destroy(fb->bo);
413 else
414 gbm_surface_release_buffer(output->surface,
415 output->current->bo);
416 }
417}
418
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500419static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200420drm_output_check_scanout_format(struct drm_output *output,
421 struct weston_surface *es, struct gbm_bo *bo)
422{
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700423 struct drm_compositor *c =
424 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200425 uint32_t format;
426 pixman_region32_t r;
427
428 format = gbm_bo_get_format(bo);
429
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700430 if (format == GBM_FORMAT_ARGB8888) {
431 /* We can scanout an ARGB buffer if the surface's
432 * opaque region covers the whole output, but we have
433 * to use XRGB as the KMS format code. */
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200434 pixman_region32_init(&r);
435 pixman_region32_subtract(&r, &output->base.region,
436 &es->opaque);
437
438 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500439 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200440
441 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500442 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700443
444 if (c->format == format)
445 return format;
446
447 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200448}
449
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400450static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400451drm_output_prepare_scanout_surface(struct weston_output *_output,
452 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500453{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400454 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500455 struct drm_compositor *c =
456 (struct drm_compositor *) output->base.compositor;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500457 struct weston_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300458 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500459 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500460
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500461 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200462 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200463 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200464 buffer->width != output->base.current_mode->width ||
465 buffer->height != output->base.current_mode->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200466 output->base.transform != es->buffer_transform ||
467 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400468 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500469
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400470 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700471 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500472
Rob Bradford9b101872012-09-14 23:25:41 +0100473 /* Unable to use the buffer for scanout */
474 if (!bo)
475 return NULL;
476
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500477 format = drm_output_check_scanout_format(output, es, bo);
478 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300479 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400480 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300481 }
482
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500483 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300484 if (!output->next) {
485 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400486 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300487 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500488
Pekka Paalanende685b82012-12-04 15:58:12 +0200489 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500490
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400491 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500492}
493
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500494static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200495drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400496{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200497 struct drm_compositor *c =
498 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300499 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400500
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200501 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400502
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300503 bo = gbm_surface_lock_front_buffer(output->surface);
504 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200505 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400506 return;
507 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300508
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700509 output->next = drm_fb_get_from_bo(bo, c, c->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300510 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200511 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300512 gbm_surface_release_buffer(output->surface, bo);
513 return;
514 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400515}
516
517static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200518drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
519{
520 struct weston_compositor *ec = output->base.compositor;
521 pixman_region32_t total_damage, previous_damage;
522
523 pixman_region32_init(&total_damage);
524 pixman_region32_init(&previous_damage);
525
526 pixman_region32_copy(&previous_damage, damage);
527
528 pixman_region32_union(&total_damage, damage, &output->previous_damage);
529 pixman_region32_copy(&output->previous_damage, &previous_damage);
530
531 output->current_image ^= 1;
532
533 output->next = output->dumb[output->current_image];
534 pixman_renderer_output_set_buffer(&output->base,
535 output->image[output->current_image]);
536
537 ec->renderer->repaint_output(&output->base, &total_damage);
538
539 pixman_region32_fini(&total_damage);
540 pixman_region32_fini(&previous_damage);
541}
542
543static void
544drm_output_render(struct drm_output *output, pixman_region32_t *damage)
545{
546 struct drm_compositor *c =
547 (struct drm_compositor *) output->base.compositor;
548
549 if (c->use_pixman)
550 drm_output_render_pixman(output, damage);
551 else
552 drm_output_render_gl(output, damage);
553
554 pixman_region32_subtract(&c->base.primary_plane.damage,
555 &c->base.primary_plane.damage, damage);
556}
557
558static void
Richard Hughese7299962013-05-01 21:52:12 +0100559drm_output_set_gamma(struct weston_output *output_base,
560 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
561{
562 int rc;
563 struct drm_output *output = (struct drm_output *) output_base;
564 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
565
566 /* check */
567 if (output_base->gamma_size != size)
568 return;
569 if (!output->original_crtc)
570 return;
571
572 rc = drmModeCrtcSetGamma(compositor->drm.fd,
573 output->crtc_id,
574 size, r, g, b);
575 if (rc)
576 weston_log("set gamma failed: %m\n");
577}
578
579static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500580drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400581 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100582{
583 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500584 struct drm_compositor *compositor =
585 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500586 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400587 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500588 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100589
Xiong Zhangabd5d472013-10-11 14:43:07 +0800590 if (output->destroy_pending)
591 return;
592
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300593 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400594 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300595 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400596 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100597
Hardeningff39efa2013-09-18 23:56:35 +0200598 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300599 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400600 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300601 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400602 &output->connector_id, 1,
603 &mode->mode_info);
604 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200605 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400606 return;
607 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300608 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200609 }
610
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500611 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300612 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500613 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200614 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500615 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500616 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100617
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300618 output->page_flip_pending = 1;
619
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400620 drm_output_set_cursor(output);
621
Jesse Barnes58ef3792012-02-23 09:45:49 -0500622 /*
623 * Now, update all the sprite surfaces
624 */
625 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200626 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500627 drmVBlank vbl = {
628 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
629 .request.sequence = 1,
630 };
631
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200632 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200633 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634 continue;
635
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200636 if (s->next && !compositor->sprites_hidden)
637 fb_id = s->next->fb_id;
638
Jesse Barnes58ef3792012-02-23 09:45:49 -0500639 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200640 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500641 s->dest_x, s->dest_y,
642 s->dest_w, s->dest_h,
643 s->src_x, s->src_y,
644 s->src_w, s->src_h);
645 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200646 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500647 ret, strerror(errno));
648
Rob Clark5ca1a472012-08-08 20:27:37 -0500649 if (output->pipe > 0)
650 vbl.request.type |= DRM_VBLANK_SECONDARY;
651
Jesse Barnes58ef3792012-02-23 09:45:49 -0500652 /*
653 * Queue a vblank signal so we know when the surface
654 * becomes active on the display or has been replaced.
655 */
656 vbl.request.signal = (unsigned long)s;
657 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
658 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200659 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500660 ret, strerror(errno));
661 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300662
663 s->output = output;
664 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500665 }
666
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500667 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400668}
669
670static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200671drm_output_start_repaint_loop(struct weston_output *output_base)
672{
673 struct drm_output *output = (struct drm_output *) output_base;
674 struct drm_compositor *compositor = (struct drm_compositor *)
675 output_base->compositor;
676 uint32_t fb_id;
677
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300678 struct timespec ts;
679
Xiong Zhangabd5d472013-10-11 14:43:07 +0800680 if (output->destroy_pending)
681 return;
682
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300683 if (!output->current) {
684 /* We can't page flip if there's no mode set */
685 uint32_t msec;
686
687 clock_gettime(compositor->clock, &ts);
688 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
689 weston_output_finish_frame(output_base, msec);
690 return;
691 }
692
693 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200694
695 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
696 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
697 weston_log("queueing pageflip failed: %m\n");
698 return;
699 }
700}
701
702static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500703vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
704 void *data)
705{
706 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300707 struct drm_output *output = s->output;
708 uint32_t msecs;
709
710 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500711
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200712 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200713 s->current = s->next;
714 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300715
716 if (!output->page_flip_pending) {
717 msecs = sec * 1000 + usec / 1000;
718 weston_output_finish_frame(&output->base, msecs);
719 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500720}
721
722static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800723drm_output_destroy(struct weston_output *output_base);
724
725static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400726page_flip_handler(int fd, unsigned int frame,
727 unsigned int sec, unsigned int usec, void *data)
728{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200729 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400730 uint32_t msecs;
731
Jonas Ådahle5a12252013-04-05 23:07:11 +0200732 /* We don't set page_flip_pending on start_repaint_loop, in that case
733 * we just want to page flip to the current buffer to get an accurate
734 * timestamp */
735 if (output->page_flip_pending) {
736 drm_output_release_fb(output, output->current);
737 output->current = output->next;
738 output->next = NULL;
739 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300740
Jonas Ådahle5a12252013-04-05 23:07:11 +0200741 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400742
Xiong Zhangabd5d472013-10-11 14:43:07 +0800743 if (output->destroy_pending)
744 drm_output_destroy(&output->base);
745 else if (!output->vblank_pending) {
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300746 msecs = sec * 1000 + usec / 1000;
747 weston_output_finish_frame(&output->base, msecs);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300748
749 /* We can't call this from frame_notify, because the output's
750 * repaint needed flag is cleared just after that */
751 if (output->recorder)
752 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300753 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200754}
755
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500756static uint32_t
757drm_output_check_sprite_format(struct drm_sprite *s,
758 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500759{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500760 uint32_t i, format;
761
762 format = gbm_bo_get_format(bo);
763
764 if (format == GBM_FORMAT_ARGB8888) {
765 pixman_region32_t r;
766
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500767 pixman_region32_init_rect(&r, 0, 0,
768 es->geometry.width,
769 es->geometry.height);
770 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500771
772 if (!pixman_region32_not_empty(&r))
773 format = GBM_FORMAT_XRGB8888;
774
775 pixman_region32_fini(&r);
776 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500777
778 for (i = 0; i < s->count_formats; i++)
779 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500780 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500781
782 return 0;
783}
784
785static int
786drm_surface_transform_supported(struct weston_surface *es)
787{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500788 return !es->transform.enabled ||
789 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500790}
791
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400792static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500793drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400794 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500795{
796 struct weston_compositor *ec = output_base->compositor;
797 struct drm_compositor *c =(struct drm_compositor *) ec;
798 struct drm_sprite *s;
799 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500800 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200802 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500803 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400804 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500805
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200806 if (c->gbm == NULL)
807 return NULL;
808
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200809 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200810 return NULL;
811
Hardeningff39efa2013-09-18 23:56:35 +0200812 if (es->buffer_scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200813 return NULL;
814
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500815 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400816 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500817
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300818 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400819 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300820
Pekka Paalanende685b82012-12-04 15:58:12 +0200821 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400822 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500823
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200824 if (es->alpha != 1.0f)
825 return NULL;
826
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500827 if (wl_shm_buffer_get(es->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500828 return NULL;
829
Jesse Barnes58ef3792012-02-23 09:45:49 -0500830 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400831 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500832
Jesse Barnes58ef3792012-02-23 09:45:49 -0500833 wl_list_for_each(s, &c->sprite_list, link) {
834 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
835 continue;
836
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200837 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500838 found = 1;
839 break;
840 }
841 }
842
843 /* No sprites available */
844 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400845 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500846
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400847 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700848 es->buffer_ref.buffer->resource,
849 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400850 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400851 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400852
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500853 format = drm_output_check_sprite_format(s, es, bo);
854 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200855 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400856 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500857 }
858
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200859 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200860 if (!s->next) {
861 gbm_bo_destroy(bo);
862 return NULL;
863 }
864
Pekka Paalanende685b82012-12-04 15:58:12 +0200865 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500866
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400867 box = pixman_region32_extents(&es->transform.boundingbox);
868 s->plane.x = box->x1;
869 s->plane.y = box->y1;
870
Jesse Barnes58ef3792012-02-23 09:45:49 -0500871 /*
872 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200873 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500874 * for us already).
875 */
876 pixman_region32_init(&dest_rect);
877 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
878 &output_base->region);
879 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
880 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200881 tbox = weston_transformed_rect(output_base->width,
882 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200883 output_base->transform,
Hardeningff39efa2013-09-18 23:56:35 +0200884 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200885 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200886 s->dest_x = tbox.x1;
887 s->dest_y = tbox.y1;
888 s->dest_w = tbox.x2 - tbox.x1;
889 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500890 pixman_region32_fini(&dest_rect);
891
892 pixman_region32_init(&src_rect);
893 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
894 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500895 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400896
897 weston_surface_from_global_fixed(es,
898 wl_fixed_from_int(box->x1),
899 wl_fixed_from_int(box->y1),
900 &sx1, &sy1);
901 weston_surface_from_global_fixed(es,
902 wl_fixed_from_int(box->x2),
903 wl_fixed_from_int(box->y2),
904 &sx2, &sy2);
905
906 if (sx1 < 0)
907 sx1 = 0;
908 if (sy1 < 0)
909 sy1 = 0;
910 if (sx2 > wl_fixed_from_int(es->geometry.width))
911 sx2 = wl_fixed_from_int(es->geometry.width);
912 if (sy2 > wl_fixed_from_int(es->geometry.height))
913 sy2 = wl_fixed_from_int(es->geometry.height);
914
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200915 tbox.x1 = sx1;
916 tbox.y1 = sy1;
917 tbox.x2 = sx2;
918 tbox.y2 = sy2;
919
920 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
921 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200922 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200923
924 s->src_x = tbox.x1 << 8;
925 s->src_y = tbox.y1 << 8;
926 s->src_w = (tbox.x2 - tbox.x1) << 8;
927 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500928 pixman_region32_fini(&src_rect);
929
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400930 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500931}
932
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400933static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400934drm_output_prepare_cursor_surface(struct weston_output *output_base,
935 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500936{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400937 struct drm_compositor *c =
938 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400939 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400940
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200941 if (c->gbm == NULL)
942 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200943 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
944 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400945 if (output->cursor_surface)
946 return NULL;
947 if (es->output_mask != (1u << output_base->id))
948 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500949 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400950 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200951 if (es->buffer_ref.buffer == NULL ||
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500952 !wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400953 es->geometry.width > 64 || es->geometry.height > 64)
954 return NULL;
955
956 output->cursor_surface = es;
957
958 return &output->cursor_plane;
959}
960
961static void
962drm_output_set_cursor(struct drm_output *output)
963{
964 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400965 struct drm_compositor *c =
966 (struct drm_compositor *) output->base.compositor;
967 EGLint handle, stride;
968 struct gbm_bo *bo;
969 uint32_t buf[64 * 64];
970 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400971 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500972
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400973 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400974 if (es == NULL) {
975 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
976 return;
977 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500978
Pekka Paalanende685b82012-12-04 15:58:12 +0200979 if (es->buffer_ref.buffer &&
980 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400981 pixman_region32_fini(&output->cursor_plane.damage);
982 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400983 output->current_cursor ^= 1;
984 bo = output->cursor_bo[output->current_cursor];
985 memset(buf, 0, sizeof buf);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500986 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
987 s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400988 for (i = 0; i < es->geometry.height; i++)
989 memcpy(buf + i * 64, s + i * stride,
990 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500991
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400992 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300993 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400994
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400995 handle = gbm_bo_get_handle(bo).s32;
996 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500997 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300998 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500999 c->cursors_are_broken = 1;
1000 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001001 }
1002
Hardeningff39efa2013-09-18 23:56:35 +02001003 x = (es->geometry.x - output->base.x) * output->base.current_scale;
1004 y = (es->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001005 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001006 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001007 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001008 c->cursors_are_broken = 1;
1009 }
1010
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001011 output->cursor_plane.x = x;
1012 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001013 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001014}
1015
Jesse Barnes58ef3792012-02-23 09:45:49 -05001016static void
1017drm_assign_planes(struct weston_output *output)
1018{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001019 struct drm_compositor *c =
1020 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001021 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001022 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001023 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001024
1025 /*
1026 * Find a surface for each sprite in the output using some heuristics:
1027 * 1) size
1028 * 2) frequency of update
1029 * 3) opacity (though some hw might support alpha blending)
1030 * 4) clipping (this can be fixed with color keys)
1031 *
1032 * The idea is to save on blitting since this should save power.
1033 * If we can get a large video surface on the sprite for example,
1034 * the main display surface may not need to update at all, and
1035 * the client buffer can be used directly for the sprite surface
1036 * as we do for flipping full screen surfaces.
1037 */
1038 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001039 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001040 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001041 /* test whether this buffer can ever go into a plane:
1042 * non-shm, or small enough to be a cursor
1043 */
1044 if ((es->buffer_ref.buffer &&
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001045 !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) ||
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001046 (es->geometry.width <= 64 && es->geometry.height <= 64))
1047 es->keep_buffer = 1;
1048 else
1049 es->keep_buffer = 0;
1050
Jesse Barnes58ef3792012-02-23 09:45:49 -05001051 pixman_region32_init(&surface_overlap);
1052 pixman_region32_intersect(&surface_overlap, &overlap,
1053 &es->transform.boundingbox);
1054
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001055 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001056 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001057 next_plane = primary;
1058 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001059 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001060 if (next_plane == NULL)
1061 next_plane = drm_output_prepare_scanout_surface(output, es);
1062 if (next_plane == NULL)
1063 next_plane = drm_output_prepare_overlay_surface(output, es);
1064 if (next_plane == NULL)
1065 next_plane = primary;
1066 weston_surface_move_to_plane(es, next_plane);
1067 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001068 pixman_region32_union(&overlap, &overlap,
1069 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001070
Jesse Barnes58ef3792012-02-23 09:45:49 -05001071 pixman_region32_fini(&surface_overlap);
1072 }
1073 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001074}
1075
Matt Roper361d2ad2011-08-29 13:52:23 -07001076static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001077drm_output_fini_pixman(struct drm_output *output);
1078
1079static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001080drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001081{
1082 struct drm_output *output = (struct drm_output *) output_base;
1083 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001084 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001085 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001086
Xiong Zhangabd5d472013-10-11 14:43:07 +08001087 if (output->page_flip_pending) {
1088 output->destroy_pending = 1;
1089 weston_log("destroy output while page flip pending\n");
1090 return;
1091 }
1092
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001093 if (output->backlight)
1094 backlight_destroy(output->backlight);
1095
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001096 drmModeFreeProperty(output->dpms_prop);
1097
Matt Roper361d2ad2011-08-29 13:52:23 -07001098 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001099 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001100
1101 /* Restore original CRTC state */
1102 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001103 origcrtc->x, origcrtc->y,
1104 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001105 drmModeFreeCrtc(origcrtc);
1106
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001107 c->crtc_allocator &= ~(1 << output->crtc_id);
1108 c->connector_allocator &= ~(1 << output->connector_id);
1109
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001110 if (c->use_pixman) {
1111 drm_output_fini_pixman(output);
1112 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001113 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001114 gbm_surface_destroy(output->surface);
1115 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001116
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001117 weston_plane_release(&output->fb_plane);
1118 weston_plane_release(&output->cursor_plane);
1119
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001120 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001121 wl_list_remove(&output->base.link);
1122
Matt Roper361d2ad2011-08-29 13:52:23 -07001123 free(output);
1124}
1125
Alex Wub7b8bda2012-04-17 17:20:48 +08001126static struct drm_mode *
1127choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1128{
1129 struct drm_mode *tmp_mode = NULL, *mode;
1130
Hardeningff39efa2013-09-18 23:56:35 +02001131 if (output->base.current_mode->width == target_mode->width &&
1132 output->base.current_mode->height == target_mode->height &&
1133 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001134 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001135 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001136
1137 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1138 if (mode->mode_info.hdisplay == target_mode->width &&
1139 mode->mode_info.vdisplay == target_mode->height) {
1140 if (mode->mode_info.vrefresh == target_mode->refresh ||
1141 target_mode->refresh == 0) {
1142 return mode;
1143 } else if (!tmp_mode)
1144 tmp_mode = mode;
1145 }
1146 }
1147
1148 return tmp_mode;
1149}
1150
1151static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001152drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001153static int
1154drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001155
1156static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001157drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1158{
1159 struct drm_output *output;
1160 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001161 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001162
1163 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001164 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001165 return -1;
1166 }
1167
1168 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001169 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001170 return -1;
1171 }
1172
1173 ec = (struct drm_compositor *)output_base->compositor;
1174 output = (struct drm_output *)output_base;
1175 drm_mode = choose_mode (output, mode);
1176
1177 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001178 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001179 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001180 }
1181
Hardeningff39efa2013-09-18 23:56:35 +02001182 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001183 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001184
Hardeningff39efa2013-09-18 23:56:35 +02001185 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001186
Hardeningff39efa2013-09-18 23:56:35 +02001187 output->base.current_mode = &drm_mode->base;
1188 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001189 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1190
Alex Wub7b8bda2012-04-17 17:20:48 +08001191 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001192 drm_output_release_fb(output, output->current);
1193 drm_output_release_fb(output, output->next);
1194 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001195
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001196 if (ec->use_pixman) {
1197 drm_output_fini_pixman(output);
1198 if (drm_output_init_pixman(output, ec) < 0) {
1199 weston_log("failed to init output pixman state with "
1200 "new mode\n");
1201 return -1;
1202 }
1203 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001204 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001205 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001206
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001207 if (drm_output_init_egl(output, ec) < 0) {
1208 weston_log("failed to init output egl state with "
1209 "new mode");
1210 return -1;
1211 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001212 }
1213
Alex Wub7b8bda2012-04-17 17:20:48 +08001214 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001215}
1216
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001217static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001218on_drm_input(int fd, uint32_t mask, void *data)
1219{
1220 drmEventContext evctx;
1221
1222 memset(&evctx, 0, sizeof evctx);
1223 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1224 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001225 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001226 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001227
1228 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001229}
1230
1231static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001232init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001233{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001234 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001235 uint64_t cap;
1236 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001237
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001238 sysnum = udev_device_get_sysnum(device);
1239 if (sysnum)
1240 ec->drm.id = atoi(sysnum);
1241 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001242 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001243 return -1;
1244 }
1245
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001246 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001247 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001248 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001249 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001250 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001251 udev_device_get_devnode(device));
1252 return -1;
1253 }
1254
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001255 weston_log("using %s\n", filename);
1256
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001257 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001258 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001259
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001260 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1261 if (ret == 0 && cap == 1)
1262 ec->clock = CLOCK_MONOTONIC;
1263 else
1264 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001265
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001266 return 0;
1267}
1268
1269static int
1270init_egl(struct drm_compositor *ec)
1271{
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001272 EGLint format;
1273
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001274 gl_renderer = weston_load_module("gl-renderer.so",
1275 "gl_renderer_interface");
1276 if (!gl_renderer)
1277 return -1;
1278
1279 /* GBM will load a dri driver, but even though they need symbols from
1280 * libglapi, in some version of Mesa they are not linked to it. Since
1281 * only the gl-renderer module links to it, the call above won't make
1282 * these symbols globally available, and loading the DRI driver fails.
1283 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1284 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1285
Benjamin Franzke060cf802011-04-30 09:32:11 +02001286 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001287
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001288 if (!ec->gbm)
1289 return -1;
1290
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001291 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001292 if (gl_renderer->create(&ec->base, ec->gbm,
1293 gl_renderer->opaque_attribs, &format) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001294 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001295 return -1;
1296 }
1297
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001298 return 0;
1299}
1300
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001301static int
1302init_pixman(struct drm_compositor *ec)
1303{
1304 return pixman_renderer_init(&ec->base);
1305}
1306
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001307static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001308drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001309{
1310 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001311 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001312
1313 mode = malloc(sizeof *mode);
1314 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001315 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001316
1317 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001318 mode->base.width = info->hdisplay;
1319 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001320
1321 /* Calculate higher precision (mHz) refresh rate */
1322 refresh = (info->clock * 1000000LL / info->htotal +
1323 info->vtotal / 2) / info->vtotal;
1324
1325 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1326 refresh *= 2;
1327 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1328 refresh /= 2;
1329 if (info->vscan > 1)
1330 refresh /= info->vscan;
1331
1332 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001333 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001334
1335 if (info->type & DRM_MODE_TYPE_PREFERRED)
1336 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1337
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001338 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1339
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001340 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001341}
1342
1343static int
1344drm_subpixel_to_wayland(int drm_value)
1345{
1346 switch (drm_value) {
1347 default:
1348 case DRM_MODE_SUBPIXEL_UNKNOWN:
1349 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1350 case DRM_MODE_SUBPIXEL_NONE:
1351 return WL_OUTPUT_SUBPIXEL_NONE;
1352 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1353 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1354 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1355 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1356 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1357 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1358 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1359 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1360 }
1361}
1362
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001363/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001364static uint32_t
1365drm_get_backlight(struct drm_output *output)
1366{
1367 long brightness, max_brightness, norm;
1368
1369 brightness = backlight_get_brightness(output->backlight);
1370 max_brightness = backlight_get_max_brightness(output->backlight);
1371
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001372 /* convert it on a scale of 0 to 255 */
1373 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001374
1375 return (uint32_t) norm;
1376}
1377
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001378/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001379static void
1380drm_set_backlight(struct weston_output *output_base, uint32_t value)
1381{
1382 struct drm_output *output = (struct drm_output *) output_base;
1383 long max_brightness, new_brightness;
1384
1385 if (!output->backlight)
1386 return;
1387
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001388 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001389 return;
1390
1391 max_brightness = backlight_get_max_brightness(output->backlight);
1392
1393 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001394 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001395
1396 backlight_set_brightness(output->backlight, new_brightness);
1397}
1398
1399static drmModePropertyPtr
1400drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1401{
1402 drmModePropertyPtr props;
1403 int i;
1404
1405 for (i = 0; i < connector->count_props; i++) {
1406 props = drmModeGetProperty(fd, connector->props[i]);
1407 if (!props)
1408 continue;
1409
1410 if (!strcmp(props->name, name))
1411 return props;
1412
1413 drmModeFreeProperty(props);
1414 }
1415
1416 return NULL;
1417}
1418
1419static void
1420drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1421{
1422 struct drm_output *output = (struct drm_output *) output_base;
1423 struct weston_compositor *ec = output_base->compositor;
1424 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001425
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001426 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001427 return;
1428
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001429 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1430 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001431}
1432
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001433static const char *connector_type_names[] = {
1434 "None",
1435 "VGA",
1436 "DVI",
1437 "DVI",
1438 "DVI",
1439 "Composite",
1440 "TV",
1441 "LVDS",
1442 "CTV",
1443 "DIN",
1444 "DP",
1445 "HDMI",
1446 "HDMI",
1447 "TV",
1448 "eDP",
1449};
1450
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001451static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001452find_crtc_for_connector(struct drm_compositor *ec,
1453 drmModeRes *resources, drmModeConnector *connector)
1454{
1455 drmModeEncoder *encoder;
1456 uint32_t possible_crtcs;
1457 int i, j;
1458
1459 for (j = 0; j < connector->count_encoders; j++) {
1460 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1461 if (encoder == NULL) {
1462 weston_log("Failed to get encoder.\n");
1463 return -1;
1464 }
1465 possible_crtcs = encoder->possible_crtcs;
1466 drmModeFreeEncoder(encoder);
1467
1468 for (i = 0; i < resources->count_crtcs; i++) {
1469 if (possible_crtcs & (1 << i) &&
1470 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1471 return i;
1472 }
1473 }
1474
1475 return -1;
1476}
1477
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001478/* Init output state that depends on gl or gbm */
1479static int
1480drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1481{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001482 int i, flags;
1483
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001484 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001485 output->base.current_mode->width,
1486 output->base.current_mode->height,
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07001487 ec->format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001488 GBM_BO_USE_SCANOUT |
1489 GBM_BO_USE_RENDERING);
1490 if (!output->surface) {
1491 weston_log("failed to create gbm surface\n");
1492 return -1;
1493 }
1494
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001495 if (gl_renderer->output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001496 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001497 gbm_surface_destroy(output->surface);
1498 return -1;
1499 }
1500
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001501 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1502
1503 for (i = 0; i < 2; i++) {
1504 if (output->cursor_bo[i])
1505 continue;
1506
1507 output->cursor_bo[i] =
1508 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1509 flags);
1510 }
1511
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001512 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1513 weston_log("cursor buffers unavailable, using gl cursors\n");
1514 ec->cursors_are_broken = 1;
1515 }
1516
1517 return 0;
1518}
1519
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001520static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001521drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1522{
Hardeningff39efa2013-09-18 23:56:35 +02001523 int w = output->base.current_mode->width;
1524 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001525 unsigned int i;
1526
1527 /* FIXME error checking */
1528
1529 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001530 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001531 if (!output->dumb[i])
1532 goto err;
1533
1534 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001535 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001536 output->dumb[i]->map,
1537 output->dumb[i]->stride);
1538 if (!output->image[i])
1539 goto err;
1540 }
1541
1542 if (pixman_renderer_output_create(&output->base) < 0)
1543 goto err;
1544
1545 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001546 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001547
1548 return 0;
1549
1550err:
1551 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1552 if (output->dumb[i])
1553 drm_fb_destroy_dumb(output->dumb[i]);
1554 if (output->image[i])
1555 pixman_image_unref(output->image[i]);
1556
1557 output->dumb[i] = NULL;
1558 output->image[i] = NULL;
1559 }
1560
1561 return -1;
1562}
1563
1564static void
1565drm_output_fini_pixman(struct drm_output *output)
1566{
1567 unsigned int i;
1568
1569 pixman_renderer_output_destroy(&output->base);
1570 pixman_region32_fini(&output->previous_damage);
1571
1572 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1573 drm_fb_destroy_dumb(output->dumb[i]);
1574 pixman_image_unref(output->image[i]);
1575 output->dumb[i] = NULL;
1576 output->image[i] = NULL;
1577 }
1578}
1579
Richard Hughes2b2092a2013-04-24 14:58:02 +01001580static void
1581edid_parse_string(const uint8_t *data, char text[])
1582{
1583 int i;
1584 int replaced = 0;
1585
1586 /* this is always 12 bytes, but we can't guarantee it's null
1587 * terminated or not junk. */
1588 strncpy(text, (const char *) data, 12);
1589
1590 /* remove insane chars */
1591 for (i = 0; text[i] != '\0'; i++) {
1592 if (text[i] == '\n' ||
1593 text[i] == '\r') {
1594 text[i] = '\0';
1595 break;
1596 }
1597 }
1598
1599 /* ensure string is printable */
1600 for (i = 0; text[i] != '\0'; i++) {
1601 if (!isprint(text[i])) {
1602 text[i] = '-';
1603 replaced++;
1604 }
1605 }
1606
1607 /* if the string is random junk, ignore the string */
1608 if (replaced > 4)
1609 text[0] = '\0';
1610}
1611
1612#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1613#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1614#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1615#define EDID_OFFSET_DATA_BLOCKS 0x36
1616#define EDID_OFFSET_LAST_BLOCK 0x6c
1617#define EDID_OFFSET_PNPID 0x08
1618#define EDID_OFFSET_SERIAL 0x0c
1619
1620static int
1621edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1622{
1623 int i;
1624 uint32_t serial_number;
1625
1626 /* check header */
1627 if (length < 128)
1628 return -1;
1629 if (data[0] != 0x00 || data[1] != 0xff)
1630 return -1;
1631
1632 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1633 * /--08--\/--09--\
1634 * 7654321076543210
1635 * |\---/\---/\---/
1636 * R C1 C2 C3 */
1637 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1638 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1639 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1640 edid->pnp_id[3] = '\0';
1641
1642 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1643 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1644 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1645 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1646 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1647 if (serial_number > 0)
1648 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1649
1650 /* parse EDID data */
1651 for (i = EDID_OFFSET_DATA_BLOCKS;
1652 i <= EDID_OFFSET_LAST_BLOCK;
1653 i += 18) {
1654 /* ignore pixel clock data */
1655 if (data[i] != 0)
1656 continue;
1657 if (data[i+2] != 0)
1658 continue;
1659
1660 /* any useful blocks? */
1661 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1662 edid_parse_string(&data[i+5],
1663 edid->monitor_name);
1664 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1665 edid_parse_string(&data[i+5],
1666 edid->serial_number);
1667 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1668 edid_parse_string(&data[i+5],
1669 edid->eisa_id);
1670 }
1671 }
1672 return 0;
1673}
1674
1675static void
1676find_and_parse_output_edid(struct drm_compositor *ec,
1677 struct drm_output *output,
1678 drmModeConnector *connector)
1679{
1680 drmModePropertyBlobPtr edid_blob = NULL;
1681 drmModePropertyPtr property;
1682 int i;
1683 int rc;
1684
1685 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1686 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1687 if (!property)
1688 continue;
1689 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1690 !strcmp(property->name, "EDID")) {
1691 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1692 connector->prop_values[i]);
1693 }
1694 drmModeFreeProperty(property);
1695 }
1696 if (!edid_blob)
1697 return;
1698
1699 rc = edid_parse(&output->edid,
1700 edid_blob->data,
1701 edid_blob->length);
1702 if (!rc) {
1703 weston_log("EDID data '%s', '%s', '%s'\n",
1704 output->edid.pnp_id,
1705 output->edid.monitor_name,
1706 output->edid.serial_number);
1707 if (output->edid.pnp_id[0] != '\0')
1708 output->base.make = output->edid.pnp_id;
1709 if (output->edid.monitor_name[0] != '\0')
1710 output->base.model = output->edid.monitor_name;
1711 if (output->edid.serial_number[0] != '\0')
1712 output->base.serial_number = output->edid.serial_number;
1713 }
1714 drmModeFreePropertyBlob(edid_blob);
1715}
1716
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001717
1718
1719static int
1720parse_modeline(const char *s, drmModeModeInfo *mode)
1721{
1722 char hsync[16];
1723 char vsync[16];
1724 float fclock;
1725
1726 mode->type = DRM_MODE_TYPE_USERDEF;
1727 mode->hskew = 0;
1728 mode->vscan = 0;
1729 mode->vrefresh = 0;
1730 mode->flags = 0;
1731
Rob Bradford307e09e2013-07-26 16:29:40 +01001732 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001733 &fclock,
1734 &mode->hdisplay,
1735 &mode->hsync_start,
1736 &mode->hsync_end,
1737 &mode->htotal,
1738 &mode->vdisplay,
1739 &mode->vsync_start,
1740 &mode->vsync_end,
1741 &mode->vtotal, hsync, vsync) != 11)
1742 return -1;
1743
1744 mode->clock = fclock * 1000;
1745 if (strcmp(hsync, "+hsync") == 0)
1746 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1747 else if (strcmp(hsync, "-hsync") == 0)
1748 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1749 else
1750 return -1;
1751
1752 if (strcmp(vsync, "+vsync") == 0)
1753 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1754 else if (strcmp(vsync, "-vsync") == 0)
1755 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1756 else
1757 return -1;
1758
1759 return 0;
1760}
1761
1762static uint32_t
1763parse_transform(const char *transform, const char *output_name)
1764{
1765 static const struct { const char *name; uint32_t token; } names[] = {
1766 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1767 { "90", WL_OUTPUT_TRANSFORM_90 },
1768 { "180", WL_OUTPUT_TRANSFORM_180 },
1769 { "270", WL_OUTPUT_TRANSFORM_270 },
1770 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1771 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1772 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1773 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1774 };
1775 unsigned int i;
1776
1777 for (i = 0; i < ARRAY_LENGTH(names); i++)
1778 if (strcmp(names[i].name, transform) == 0)
1779 return names[i].token;
1780
1781 weston_log("Invalid transform \"%s\" for output %s\n",
1782 transform, output_name);
1783
1784 return WL_OUTPUT_TRANSFORM_NORMAL;
1785}
1786
Rob Bradford66bd9f52013-06-25 18:56:42 +01001787static void
1788setup_output_seat_constraint(struct drm_compositor *ec,
1789 struct weston_output *output,
1790 const char *s)
1791{
1792 if (strcmp(s, "") != 0) {
1793 struct udev_seat *seat;
1794
1795 seat = udev_seat_get_named(&ec->base, s);
1796 if (seat)
1797 seat->base.output = output;
1798
1799 if (seat && seat->base.pointer)
1800 weston_pointer_clamp(seat->base.pointer,
1801 &seat->base.pointer->x,
1802 &seat->base.pointer->y);
1803 }
1804}
1805
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001806static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001807create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001808 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001809 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001810 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001811{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001812 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001813 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1814 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001815 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001816 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001817 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001818 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001819 int i, width, height, scale;
1820 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001821 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001822 enum output_config config;
1823 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001824
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001825 i = find_crtc_for_connector(ec, resources, connector);
1826 if (i < 0) {
1827 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001828 return -1;
1829 }
1830
Peter Huttererf3d62272013-08-08 11:57:05 +10001831 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001832 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001833 return -1;
1834
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001835 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1836 output->base.make = "unknown";
1837 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001838 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001839 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001840
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001841 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1842 type_name = connector_type_names[connector->connector_type];
1843 else
1844 type_name = "UNKNOWN";
1845 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001846 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001847
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001848 section = weston_config_get_section(ec->base.config, "output", "name",
1849 output->base.name);
1850 weston_config_section_get_string(section, "mode", &s, "preferred");
1851 if (strcmp(s, "off") == 0)
1852 config = OUTPUT_CONFIG_OFF;
1853 else if (strcmp(s, "preferred") == 0)
1854 config = OUTPUT_CONFIG_PREFERRED;
1855 else if (strcmp(s, "current") == 0)
1856 config = OUTPUT_CONFIG_CURRENT;
1857 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1858 config = OUTPUT_CONFIG_MODE;
1859 else if (parse_modeline(s, &modeline) == 0)
1860 config = OUTPUT_CONFIG_MODELINE;
1861 else {
1862 weston_log("Invalid mode \"%s\" for output %s\n",
1863 s, output->base.name);
1864 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001865 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001866 free(s);
1867
1868 weston_config_section_get_int(section, "scale", &scale, 1);
1869 weston_config_section_get_string(section, "transform", &s, "normal");
1870 transform = parse_transform(s, output->base.name);
1871 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001872
Rob Bradford66bd9f52013-06-25 18:56:42 +01001873 weston_config_section_get_string(section, "seat", &s, "");
1874 setup_output_seat_constraint(ec, &output->base, s);
1875 free(s);
1876
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001877 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001878 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001879 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001880 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001881 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001882
Matt Roper361d2ad2011-08-29 13:52:23 -07001883 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001884 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001885
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001886 /* Get the current mode on the crtc that's currently driving
1887 * this connector. */
1888 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001889 memset(&crtc_mode, 0, sizeof crtc_mode);
1890 if (encoder != NULL) {
1891 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1892 drmModeFreeEncoder(encoder);
1893 if (crtc == NULL)
1894 goto err_free;
1895 if (crtc->mode_valid)
1896 crtc_mode = crtc->mode;
1897 drmModeFreeCrtc(crtc);
1898 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001899
David Herrmann0f0d54e2011-12-08 17:05:45 +01001900 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001901 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001902 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001903 goto err_free;
1904 }
1905
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001906 if (config == OUTPUT_CONFIG_OFF) {
1907 weston_log("Disabling output %s\n", output->base.name);
1908 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1909 0, 0, 0, 0, 0, NULL);
1910 goto err_free;
1911 }
1912
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001913 preferred = NULL;
1914 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001915 configured = NULL;
1916
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001917 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001918 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001919 width == drm_mode->base.width &&
1920 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001921 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001922 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001923 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001924 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001925 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001926 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001927
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001928 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001929 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001930 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001931 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001932 }
1933
Wang Quanxianacb805a2012-07-30 18:09:46 -04001934 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001935 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001936 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001937 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001938 }
1939
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001940 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001941 configured = current;
1942
Wang Quanxianacb805a2012-07-30 18:09:46 -04001943 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02001944 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001945 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02001946 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001947 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02001948 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001949 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02001950 output->base.current_mode = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001951
Hardeningff39efa2013-09-18 23:56:35 +02001952 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001953 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001954 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001955 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001956
Hardeningff39efa2013-09-18 23:56:35 +02001957 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001958
John Kåre Alsaker94659272012-11-13 19:10:18 +01001959 weston_output_init(&output->base, &ec->base, x, y,
1960 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001961 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001962
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001963 if (ec->use_pixman) {
1964 if (drm_output_init_pixman(output, ec) < 0) {
1965 weston_log("Failed to init output pixman state\n");
1966 goto err_output;
1967 }
1968 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001969 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001970 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001971 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001972
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001973 output->backlight = backlight_init(drm_device,
1974 connector->connector_type);
1975 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001976 weston_log("Initialized backlight, device %s\n",
1977 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001978 output->base.set_backlight = drm_set_backlight;
1979 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001980 } else {
1981 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001982 }
1983
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001984 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1985
Richard Hughes2b2092a2013-04-24 14:58:02 +01001986 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001987 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1988 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001989
Jonas Ådahle5a12252013-04-05 23:07:11 +02001990 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001991 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001992 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001993 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001994 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001995 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001996
Richard Hughese7299962013-05-01 21:52:12 +01001997 output->base.gamma_size = output->original_crtc->gamma_size;
1998 output->base.set_gamma = drm_output_set_gamma;
1999
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002000 weston_plane_init(&output->cursor_plane, 0, 0);
2001 weston_plane_init(&output->fb_plane, 0, 0);
2002
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002003 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2004 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2005 &ec->base.primary_plane);
2006
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002007 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002008 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002009 wl_list_for_each(m, &output->base.mode_list, link)
2010 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
2011 m->width, m->height, m->refresh / 1000.0,
2012 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2013 ", preferred" : "",
2014 m->flags & WL_OUTPUT_MODE_CURRENT ?
2015 ", current" : "",
2016 connector->count_modes == 0 ?
2017 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002018
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002019 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002020
John Kåre Alsaker94659272012-11-13 19:10:18 +01002021err_output:
2022 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002023err_free:
2024 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2025 base.link) {
2026 wl_list_remove(&drm_mode->base.link);
2027 free(drm_mode);
2028 }
2029
2030 drmModeFreeCrtc(output->original_crtc);
2031 ec->crtc_allocator &= ~(1 << output->crtc_id);
2032 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002033 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002034
David Herrmann0f0d54e2011-12-08 17:05:45 +01002035 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002036}
2037
Jesse Barnes58ef3792012-02-23 09:45:49 -05002038static void
2039create_sprites(struct drm_compositor *ec)
2040{
2041 struct drm_sprite *sprite;
2042 drmModePlaneRes *plane_res;
2043 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002044 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002045
2046 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2047 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002048 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002049 strerror(errno));
2050 return;
2051 }
2052
2053 for (i = 0; i < plane_res->count_planes; i++) {
2054 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2055 if (!plane)
2056 continue;
2057
Peter Huttererf3d62272013-08-08 11:57:05 +10002058 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002059 plane->count_formats));
2060 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002061 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002062 __func__);
2063 free(plane);
2064 continue;
2065 }
2066
Jesse Barnes58ef3792012-02-23 09:45:49 -05002067 sprite->possible_crtcs = plane->possible_crtcs;
2068 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002069 sprite->current = NULL;
2070 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002071 sprite->compositor = ec;
2072 sprite->count_formats = plane->count_formats;
2073 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002074 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002075 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002076 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002077 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2078 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002079
2080 wl_list_insert(&ec->sprite_list, &sprite->link);
2081 }
2082
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002083 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002084}
2085
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002086static void
2087destroy_sprites(struct drm_compositor *compositor)
2088{
2089 struct drm_sprite *sprite, *next;
2090 struct drm_output *output;
2091
2092 output = container_of(compositor->base.output_list.next,
2093 struct drm_output, base.link);
2094
2095 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2096 drmModeSetPlane(compositor->drm.fd,
2097 sprite->plane_id,
2098 output->crtc_id, 0, 0,
2099 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002100 drm_output_release_fb(output, sprite->current);
2101 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002102 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002103 free(sprite);
2104 }
2105}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002106
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002107static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002108create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002109 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002110{
2111 drmModeConnector *connector;
2112 drmModeRes *resources;
2113 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002114 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002115
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002116 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002117 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002118 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002119 return -1;
2120 }
2121
Jesse Barnes58ef3792012-02-23 09:45:49 -05002122 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002123 if (!ec->crtcs) {
2124 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002125 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002126 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002127
Rob Clark4339add2012-08-09 14:18:28 -05002128 ec->min_width = resources->min_width;
2129 ec->max_width = resources->max_width;
2130 ec->min_height = resources->min_height;
2131 ec->max_height = resources->max_height;
2132
Jesse Barnes58ef3792012-02-23 09:45:49 -05002133 ec->num_crtcs = resources->count_crtcs;
2134 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2135
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002136 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002137 connector = drmModeGetConnector(ec->drm.fd,
2138 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002139 if (connector == NULL)
2140 continue;
2141
2142 if (connector->connection == DRM_MODE_CONNECTED &&
2143 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002144 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002145 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002146 connector, x, y,
2147 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002148 drmModeFreeConnector(connector);
2149 continue;
2150 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002151
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002152 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002153 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002154 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002155 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002156
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002157 drmModeFreeConnector(connector);
2158 }
2159
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002160 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002161 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002162 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002163 return -1;
2164 }
2165
2166 drmModeFreeResources(resources);
2167
2168 return 0;
2169}
2170
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002171static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002172update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002173{
2174 drmModeConnector *connector;
2175 drmModeRes *resources;
2176 struct drm_output *output, *next;
2177 int x = 0, y = 0;
2178 int x_offset = 0, y_offset = 0;
2179 uint32_t connected = 0, disconnects = 0;
2180 int i;
2181
2182 resources = drmModeGetResources(ec->drm.fd);
2183 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002184 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002185 return;
2186 }
2187
2188 /* collect new connects */
2189 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002190 int connector_id = resources->connectors[i];
2191
2192 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002193 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002194 continue;
2195
David Herrmann7551cff2011-12-08 17:05:43 +01002196 if (connector->connection != DRM_MODE_CONNECTED) {
2197 drmModeFreeConnector(connector);
2198 continue;
2199 }
2200
Benjamin Franzke117483d2011-08-30 11:38:26 +02002201 connected |= (1 << connector_id);
2202
2203 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002204 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002205 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002206 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002207
2208 /* XXX: not yet needed, we die with 0 outputs */
2209 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002210 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002211 else
2212 x = 0;
2213 y = 0;
2214 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002215 connector, x, y,
2216 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002217 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002218
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002219 }
2220 drmModeFreeConnector(connector);
2221 }
2222 drmModeFreeResources(resources);
2223
2224 disconnects = ec->connector_allocator & ~connected;
2225 if (disconnects) {
2226 wl_list_for_each_safe(output, next, &ec->base.output_list,
2227 base.link) {
2228 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002229 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002230 output->base.x - x_offset,
2231 output->base.y - y_offset);
2232 }
2233
2234 if (disconnects & (1 << output->connector_id)) {
2235 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002236 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002237 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002238 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002239 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002240 }
2241 }
2242 }
2243
2244 /* FIXME: handle zero outputs, without terminating */
2245 if (ec->connector_allocator == 0)
2246 wl_display_terminate(ec->base.wl_display);
2247}
2248
2249static int
David Herrmannd7488c22012-03-11 20:05:21 +01002250udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002251{
David Herrmannd7488c22012-03-11 20:05:21 +01002252 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002253 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002254
2255 sysnum = udev_device_get_sysnum(device);
2256 if (!sysnum || atoi(sysnum) != ec->drm.id)
2257 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002258
David Herrmann6ac52db2012-03-11 20:05:22 +01002259 val = udev_device_get_property_value(device, "HOTPLUG");
2260 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002261 return 0;
2262
David Herrmann6ac52db2012-03-11 20:05:22 +01002263 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002264}
2265
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002266static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002267udev_drm_event(int fd, uint32_t mask, void *data)
2268{
2269 struct drm_compositor *ec = data;
2270 struct udev_device *event;
2271
2272 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002273
David Herrmannd7488c22012-03-11 20:05:21 +01002274 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002275 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002276
2277 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002278
2279 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002280}
2281
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002282static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002283drm_restore(struct weston_compositor *ec)
2284{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002285 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002286}
2287
2288static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002289drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002290{
2291 struct drm_compositor *d = (struct drm_compositor *) ec;
2292
Rob Bradfordd355b802013-05-31 18:09:55 +01002293 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002294
2295 wl_event_source_remove(d->udev_drm_source);
2296 wl_event_source_remove(d->drm_source);
2297
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002298 destroy_sprites(d);
2299
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002300 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002301
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002302 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002303
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002304 if (d->gbm)
2305 gbm_device_destroy(d->gbm);
2306
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002307 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002308
Rob Bradford45c15b82013-07-26 16:29:35 +01002309 close(d->drm.fd);
2310
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002311 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002312}
2313
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002314static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002315drm_compositor_set_modes(struct drm_compositor *compositor)
2316{
2317 struct drm_output *output;
2318 struct drm_mode *drm_mode;
2319 int ret;
2320
2321 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002322 if (!output->current) {
2323 /* If something that would cause the output to
2324 * switch mode happened while in another vt, we
2325 * might not have a current drm_fb. In that case,
2326 * schedule a repaint and let drm_output_repaint
2327 * handle setting the mode. */
2328 weston_output_schedule_repaint(&output->base);
2329 continue;
2330 }
2331
Hardeningff39efa2013-09-18 23:56:35 +02002332 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002333 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002334 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002335 &output->connector_id, 1,
2336 &drm_mode->mode_info);
2337 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002338 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002339 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002340 drm_mode->base.width, drm_mode->base.height,
2341 output->base.x, output->base.y);
2342 }
2343 }
2344}
2345
2346static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002347session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002348{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002349 struct weston_compositor *compositor = data;
2350 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002351 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002352 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002353
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002354 if (ec->base.session_active) {
2355 weston_log("activating session\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002356 compositor->focus = 1;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -07002357 if (ec->base.launcher == NULL && drmSetMaster(ec->drm.fd)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002358 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002359 wl_display_terminate(compositor->wl_display);
2360 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002361 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002362 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002363 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002364 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002365 } else {
2366 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002367 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002368
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002369 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002370 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002371 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002372
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002373 /* If we have a repaint scheduled (either from a
2374 * pending pageflip or the idle handler), make sure we
2375 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002376 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002377 * further attemps at repainting. When we switch
2378 * back, we schedule a repaint, which will process
2379 * pending frame callbacks. */
2380
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002381 wl_list_for_each(output, &ec->base.output_list, base.link) {
2382 output->base.repaint_needed = 0;
2383 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002384 }
2385
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002386 output = container_of(ec->base.output_list.next,
2387 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002388
2389 wl_list_for_each(sprite, &ec->sprite_list, link)
2390 drmModeSetPlane(ec->drm.fd,
2391 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002392 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002393 0, 0, 0, 0, 0, 0, 0, 0);
2394
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -07002395 if (ec->base.launcher == NULL && drmDropMaster(ec->drm.fd) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002396 weston_log("failed to drop master: %m\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002397 };
2398}
2399
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002400static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002401switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002402{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002403 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002404
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002405 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002406}
2407
David Herrmann0af066f2012-10-29 19:21:16 +01002408/*
2409 * Find primary GPU
2410 * Some systems may have multiple DRM devices attached to a single seat. This
2411 * function loops over all devices and tries to find a PCI device with the
2412 * boot_vga sysfs attribute set to 1.
2413 * If no such device is found, the first DRM device reported by udev is used.
2414 */
2415static struct udev_device*
2416find_primary_gpu(struct drm_compositor *ec, const char *seat)
2417{
2418 struct udev_enumerate *e;
2419 struct udev_list_entry *entry;
2420 const char *path, *device_seat, *id;
2421 struct udev_device *device, *drm_device, *pci;
2422
2423 e = udev_enumerate_new(ec->udev);
2424 udev_enumerate_add_match_subsystem(e, "drm");
2425 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2426
2427 udev_enumerate_scan_devices(e);
2428 drm_device = NULL;
2429 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2430 path = udev_list_entry_get_name(entry);
2431 device = udev_device_new_from_syspath(ec->udev, path);
2432 if (!device)
2433 continue;
2434 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2435 if (!device_seat)
2436 device_seat = default_seat;
2437 if (strcmp(device_seat, seat)) {
2438 udev_device_unref(device);
2439 continue;
2440 }
2441
2442 pci = udev_device_get_parent_with_subsystem_devtype(device,
2443 "pci", NULL);
2444 if (pci) {
2445 id = udev_device_get_sysattr_value(pci, "boot_vga");
2446 if (id && !strcmp(id, "1")) {
2447 if (drm_device)
2448 udev_device_unref(drm_device);
2449 drm_device = device;
2450 break;
2451 }
2452 }
2453
2454 if (!drm_device)
2455 drm_device = device;
2456 else
2457 udev_device_unref(device);
2458 }
2459
2460 udev_enumerate_unref(e);
2461 return drm_device;
2462}
2463
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002464static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002465planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002466{
2467 struct drm_compositor *c = data;
2468
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002469 switch (key) {
2470 case KEY_C:
2471 c->cursors_are_broken ^= 1;
2472 break;
2473 case KEY_V:
2474 c->sprites_are_broken ^= 1;
2475 break;
2476 case KEY_O:
2477 c->sprites_hidden ^= 1;
2478 break;
2479 default:
2480 break;
2481 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002482}
2483
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002484#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002485static void
2486recorder_frame_notify(struct wl_listener *listener, void *data)
2487{
2488 struct drm_output *output;
2489 struct drm_compositor *c;
2490 int fd, ret;
2491
2492 output = container_of(listener, struct drm_output,
2493 recorder_frame_listener);
2494 c = (struct drm_compositor *) output->base.compositor;
2495
2496 if (!output->recorder)
2497 return;
2498
2499 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2500 DRM_CLOEXEC, &fd);
2501 if (ret) {
2502 weston_log("[libva recorder] "
2503 "failed to create prime fd for front buffer\n");
2504 return;
2505 }
2506
2507 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002508}
2509
2510static void *
2511create_recorder(struct drm_compositor *c, int width, int height,
2512 const char *filename)
2513{
2514 int fd;
2515 drm_magic_t magic;
2516
2517 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2518 if (fd < 0)
2519 return NULL;
2520
2521 drmGetMagic(fd, &magic);
2522 drmAuthMagic(c->drm.fd, magic);
2523
2524 return vaapi_recorder_create(fd, width, height, filename);
2525}
2526
2527static void
2528recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2529 void *data)
2530{
2531 struct drm_compositor *c = data;
2532 struct drm_output *output;
2533 int width, height;
2534
2535 output = container_of(c->base.output_list.next,
2536 struct drm_output, base.link);
2537
2538 if (!output->recorder) {
Hardeningff39efa2013-09-18 23:56:35 +02002539 width = output->base.current_mode->width;
2540 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002541
2542 output->recorder =
2543 create_recorder(c, width, height, "capture.h264");
2544 if (!output->recorder) {
2545 weston_log("failed to create vaapi recorder\n");
2546 return;
2547 }
2548
2549 output->base.disable_planes++;
2550
2551 output->recorder_frame_listener.notify = recorder_frame_notify;
2552 wl_signal_add(&output->base.frame_signal,
2553 &output->recorder_frame_listener);
2554
2555 weston_output_schedule_repaint(&output->base);
2556
2557 weston_log("[libva recorder] initialized\n");
2558 } else {
2559 vaapi_recorder_destroy(output->recorder);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002560 output->recorder = NULL;
2561
2562 output->base.disable_planes--;
2563
2564 wl_list_remove(&output->recorder_frame_listener.link);
2565 weston_log("[libva recorder] done\n");
2566 }
2567}
2568#else
2569static void
2570recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2571 void *data)
2572{
2573 weston_log("Compiled without libva support\n");
2574}
2575#endif
2576
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002577static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002578drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002579 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002580 int *argc, char *argv[],
2581 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002582{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002583 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002584 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002585 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002586 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002587 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002588
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002589 weston_log("initializing drm backend\n");
2590
Peter Huttererf3d62272013-08-08 11:57:05 +10002591 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002592 if (ec == NULL)
2593 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002594
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002595 /* KMS support for sprites is not complete yet, so disable the
2596 * functionality for now. */
2597 ec->sprites_are_broken = 1;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07002598 ec->format = GBM_FORMAT_XRGB8888;
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002599 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002600
Daniel Stone725c2c32012-06-22 14:04:36 +01002601 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002602 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002603 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002604 goto err_base;
2605 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002606
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002607 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002608 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002609 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002610 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002611 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002612 goto err_compositor;
2613 }
2614
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002615 ec->udev = udev_new();
2616 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002617 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002618 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002619 }
2620
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002621 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002622 ec->session_listener.notify = session_notify;
2623 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002624
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002625 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002626 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002627 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002628 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002629 }
David Herrmann0af066f2012-10-29 19:21:16 +01002630 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002631
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002632 if (init_drm(ec, drm_device) < 0) {
2633 weston_log("failed to initialize kms\n");
2634 goto err_udev_dev;
2635 }
2636
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002637 if (ec->use_pixman) {
2638 if (init_pixman(ec) < 0) {
2639 weston_log("failed to initialize pixman renderer\n");
2640 goto err_udev_dev;
2641 }
2642 } else {
2643 if (init_egl(ec) < 0) {
2644 weston_log("failed to initialize egl\n");
2645 goto err_udev_dev;
2646 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002647 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002648
2649 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002650 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002651
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002652 ec->base.focus = 1;
2653
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002654 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002655
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002656 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002657 weston_compositor_add_key_binding(&ec->base, key,
2658 MODIFIER_CTRL | MODIFIER_ALT,
2659 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002660
Jesse Barnes58ef3792012-02-23 09:45:49 -05002661 wl_list_init(&ec->sprite_list);
2662 create_sprites(ec);
2663
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002664 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002665 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002666 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002667 }
2668
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002669 path = NULL;
2670
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002671 if (udev_input_init(&ec->input,
2672 &ec->base, ec->udev, param->seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002673 weston_log("failed to create input devices\n");
2674 goto err_sprite;
2675 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002676
2677 loop = wl_display_get_event_loop(ec->base.wl_display);
2678 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002679 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002680 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002681
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002682 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2683 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002684 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002685 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002686 }
2687 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2688 "drm", NULL);
2689 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002690 wl_event_loop_add_fd(loop,
2691 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002692 WL_EVENT_READABLE, udev_drm_event, ec);
2693
2694 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002695 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002696 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002697 }
2698
Daniel Stonea96b93c2012-06-22 14:04:37 +01002699 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002700
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002701 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002702 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002703 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002704 planes_binding, ec);
2705 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2706 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002707 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2708 recorder_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002709
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002710 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002711
2712err_udev_monitor:
2713 wl_event_source_remove(ec->udev_drm_source);
2714 udev_monitor_unref(ec->udev_monitor);
2715err_drm_source:
2716 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002717 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002718err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002719 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002720 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002721 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002722err_udev_dev:
2723 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002724err_launcher:
2725 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002726err_udev:
2727 udev_unref(ec->udev);
2728err_compositor:
2729 weston_compositor_shutdown(&ec->base);
2730err_base:
2731 free(ec);
2732 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002733}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002734
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002735WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002736backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002737 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002738{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002739 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002740
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002741 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002742 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2743 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2744 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002745 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002746 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002747 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002748
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002749 param.seat_id = default_seat;
2750
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002751 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002752
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002753 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002754}