blob: e32e4a85852ad0454f60ac94e187aea06e8c3f6f [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;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500159 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400160 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 *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500451drm_output_prepare_scanout_view(struct weston_output *_output,
452 struct weston_view *ev)
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 Ekstranda7af7042013-10-12 22:38:11 -0500457 struct weston_buffer *buffer = ev->surface->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
Jason Ekstranda7af7042013-10-12 22:38:11 -0500461 if (ev->geometry.x != output->base.x ||
462 ev->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 ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500466 output->base.transform != ev->surface->buffer_transform ||
467 ev->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
Jason Ekstranda7af7042013-10-12 22:38:11 -0500477 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500478 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300479 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400480 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300481 }
482
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500483 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300484 if (!output->next) {
485 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400486 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300487 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500488
Pekka Paalanende685b82012-12-04 15:58:12 +0200489 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500490
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400491 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500492}
493
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500494static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200495drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400496{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200497 struct drm_compositor *c =
498 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300499 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400500
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200501 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400502
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300503 bo = gbm_surface_lock_front_buffer(output->surface);
504 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200505 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400506 return;
507 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300508
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700509 output->next = drm_fb_get_from_bo(bo, c, c->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300510 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200511 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300512 gbm_surface_release_buffer(output->surface, bo);
513 return;
514 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400515}
516
517static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200518drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
519{
520 struct weston_compositor *ec = output->base.compositor;
521 pixman_region32_t total_damage, previous_damage;
522
523 pixman_region32_init(&total_damage);
524 pixman_region32_init(&previous_damage);
525
526 pixman_region32_copy(&previous_damage, damage);
527
528 pixman_region32_union(&total_damage, damage, &output->previous_damage);
529 pixman_region32_copy(&output->previous_damage, &previous_damage);
530
531 output->current_image ^= 1;
532
533 output->next = output->dumb[output->current_image];
534 pixman_renderer_output_set_buffer(&output->base,
535 output->image[output->current_image]);
536
537 ec->renderer->repaint_output(&output->base, &total_damage);
538
539 pixman_region32_fini(&total_damage);
540 pixman_region32_fini(&previous_damage);
541}
542
543static void
544drm_output_render(struct drm_output *output, pixman_region32_t *damage)
545{
546 struct drm_compositor *c =
547 (struct drm_compositor *) output->base.compositor;
548
549 if (c->use_pixman)
550 drm_output_render_pixman(output, damage);
551 else
552 drm_output_render_gl(output, damage);
553
554 pixman_region32_subtract(&c->base.primary_plane.damage,
555 &c->base.primary_plane.damage, damage);
556}
557
558static void
Richard Hughese7299962013-05-01 21:52:12 +0100559drm_output_set_gamma(struct weston_output *output_base,
560 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
561{
562 int rc;
563 struct drm_output *output = (struct drm_output *) output_base;
564 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
565
566 /* check */
567 if (output_base->gamma_size != size)
568 return;
569 if (!output->original_crtc)
570 return;
571
572 rc = drmModeCrtcSetGamma(compositor->drm.fd,
573 output->crtc_id,
574 size, r, g, b);
575 if (rc)
576 weston_log("set gamma failed: %m\n");
577}
578
David Herrmann1edf44c2013-10-22 17:11:26 +0200579static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500580drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400581 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100582{
583 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500584 struct drm_compositor *compositor =
585 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500586 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400587 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500588 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100589
Xiong Zhangabd5d472013-10-11 14:43:07 +0800590 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200591 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800592
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300593 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400594 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300595 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200596 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100597
Hardeningff39efa2013-09-18 23:56:35 +0200598 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300599 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400600 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300601 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400602 &output->connector_id, 1,
603 &mode->mode_info);
604 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200605 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200606 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400607 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300608 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200609 }
610
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500611 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300612 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500613 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200614 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200615 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500616 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100617
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300618 output->page_flip_pending = 1;
619
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400620 drm_output_set_cursor(output);
621
Jesse Barnes58ef3792012-02-23 09:45:49 -0500622 /*
623 * Now, update all the sprite surfaces
624 */
625 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200626 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500627 drmVBlank vbl = {
628 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
629 .request.sequence = 1,
630 };
631
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200632 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200633 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634 continue;
635
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200636 if (s->next && !compositor->sprites_hidden)
637 fb_id = s->next->fb_id;
638
Jesse Barnes58ef3792012-02-23 09:45:49 -0500639 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200640 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500641 s->dest_x, s->dest_y,
642 s->dest_w, s->dest_h,
643 s->src_x, s->src_y,
644 s->src_w, s->src_h);
645 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200646 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500647 ret, strerror(errno));
648
Rob Clark5ca1a472012-08-08 20:27:37 -0500649 if (output->pipe > 0)
650 vbl.request.type |= DRM_VBLANK_SECONDARY;
651
Jesse Barnes58ef3792012-02-23 09:45:49 -0500652 /*
653 * Queue a vblank signal so we know when the surface
654 * becomes active on the display or has been replaced.
655 */
656 vbl.request.signal = (unsigned long)s;
657 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
658 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200659 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500660 ret, strerror(errno));
661 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300662
663 s->output = output;
664 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500665 }
666
David Herrmann1edf44c2013-10-22 17:11:26 +0200667 return 0;
668
669err_pageflip:
670 if (output->next) {
671 drm_output_release_fb(output, output->next);
672 output->next = NULL;
673 }
674
675 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400676}
677
678static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200679drm_output_start_repaint_loop(struct weston_output *output_base)
680{
681 struct drm_output *output = (struct drm_output *) output_base;
682 struct drm_compositor *compositor = (struct drm_compositor *)
683 output_base->compositor;
684 uint32_t fb_id;
David Herrmann3c688c52013-10-22 17:11:25 +0200685 uint32_t msec;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300686 struct timespec ts;
687
Xiong Zhangabd5d472013-10-11 14:43:07 +0800688 if (output->destroy_pending)
689 return;
690
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300691 if (!output->current) {
692 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200693 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300694 }
695
696 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200697
698 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
699 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
700 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200701 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200702 }
David Herrmann3c688c52013-10-22 17:11:25 +0200703
704 return;
705
706finish_frame:
707 /* if we cannot page-flip, immediately finish frame */
708 clock_gettime(compositor->clock, &ts);
709 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
710 weston_output_finish_frame(output_base, msec);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200711}
712
713static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500714vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
715 void *data)
716{
717 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300718 struct drm_output *output = s->output;
719 uint32_t msecs;
720
721 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500722
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200723 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200724 s->current = s->next;
725 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300726
727 if (!output->page_flip_pending) {
728 msecs = sec * 1000 + usec / 1000;
729 weston_output_finish_frame(&output->base, msecs);
730 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500731}
732
733static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800734drm_output_destroy(struct weston_output *output_base);
735
736static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400737page_flip_handler(int fd, unsigned int frame,
738 unsigned int sec, unsigned int usec, void *data)
739{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200740 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400741 uint32_t msecs;
742
Jonas Ådahle5a12252013-04-05 23:07:11 +0200743 /* We don't set page_flip_pending on start_repaint_loop, in that case
744 * we just want to page flip to the current buffer to get an accurate
745 * timestamp */
746 if (output->page_flip_pending) {
747 drm_output_release_fb(output, output->current);
748 output->current = output->next;
749 output->next = NULL;
750 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300751
Jonas Ådahle5a12252013-04-05 23:07:11 +0200752 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400753
Xiong Zhangabd5d472013-10-11 14:43:07 +0800754 if (output->destroy_pending)
755 drm_output_destroy(&output->base);
756 else if (!output->vblank_pending) {
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300757 msecs = sec * 1000 + usec / 1000;
758 weston_output_finish_frame(&output->base, msecs);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300759
760 /* We can't call this from frame_notify, because the output's
761 * repaint needed flag is cleared just after that */
762 if (output->recorder)
763 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300764 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200765}
766
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500767static uint32_t
768drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500769 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500770{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500771 uint32_t i, format;
772
773 format = gbm_bo_get_format(bo);
774
775 if (format == GBM_FORMAT_ARGB8888) {
776 pixman_region32_t r;
777
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500778 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500779 ev->geometry.width,
780 ev->geometry.height);
781 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500782
783 if (!pixman_region32_not_empty(&r))
784 format = GBM_FORMAT_XRGB8888;
785
786 pixman_region32_fini(&r);
787 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500788
789 for (i = 0; i < s->count_formats; i++)
790 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500791 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500792
793 return 0;
794}
795
796static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500797drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500798{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500799 return !ev->transform.enabled ||
800 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801}
802
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400803static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500804drm_output_prepare_overlay_view(struct weston_output *output_base,
805 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500806{
807 struct weston_compositor *ec = output_base->compositor;
808 struct drm_compositor *c =(struct drm_compositor *) ec;
809 struct drm_sprite *s;
810 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500811 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500812 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200813 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500814 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400815 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500816
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200817 if (c->gbm == NULL)
818 return NULL;
819
Jason Ekstranda7af7042013-10-12 22:38:11 -0500820 if (ev->surface->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200821 return NULL;
822
Jason Ekstranda7af7042013-10-12 22:38:11 -0500823 if (ev->surface->buffer_scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200824 return NULL;
825
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500826 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400827 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500828
Jason Ekstranda7af7042013-10-12 22:38:11 -0500829 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400830 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300831
Jason Ekstranda7af7042013-10-12 22:38:11 -0500832 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400833 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500834
Jason Ekstranda7af7042013-10-12 22:38:11 -0500835 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200836 return NULL;
837
Jason Ekstranda7af7042013-10-12 22:38:11 -0500838 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500839 return NULL;
840
Jason Ekstranda7af7042013-10-12 22:38:11 -0500841 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400842 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500843
Jesse Barnes58ef3792012-02-23 09:45:49 -0500844 wl_list_for_each(s, &c->sprite_list, link) {
845 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
846 continue;
847
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200848 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500849 found = 1;
850 break;
851 }
852 }
853
854 /* No sprites available */
855 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400856 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500857
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400858 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500859 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700860 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400861 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400862 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400863
Jason Ekstranda7af7042013-10-12 22:38:11 -0500864 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500865 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200866 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400867 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500868 }
869
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200870 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200871 if (!s->next) {
872 gbm_bo_destroy(bo);
873 return NULL;
874 }
875
Jason Ekstranda7af7042013-10-12 22:38:11 -0500876 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500877
Jason Ekstranda7af7042013-10-12 22:38:11 -0500878 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400879 s->plane.x = box->x1;
880 s->plane.y = box->y1;
881
Jesse Barnes58ef3792012-02-23 09:45:49 -0500882 /*
883 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200884 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500885 * for us already).
886 */
887 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500888 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500889 &output_base->region);
890 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
891 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200892 tbox = weston_transformed_rect(output_base->width,
893 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200894 output_base->transform,
Hardeningff39efa2013-09-18 23:56:35 +0200895 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200896 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200897 s->dest_x = tbox.x1;
898 s->dest_y = tbox.y1;
899 s->dest_w = tbox.x2 - tbox.x1;
900 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500901 pixman_region32_fini(&dest_rect);
902
903 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500904 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500905 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500906 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400907
Jason Ekstranda7af7042013-10-12 22:38:11 -0500908 weston_view_from_global_fixed(ev,
909 wl_fixed_from_int(box->x1),
910 wl_fixed_from_int(box->y1),
911 &sx1, &sy1);
912 weston_view_from_global_fixed(ev,
913 wl_fixed_from_int(box->x2),
914 wl_fixed_from_int(box->y2),
915 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400916
917 if (sx1 < 0)
918 sx1 = 0;
919 if (sy1 < 0)
920 sy1 = 0;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500921 if (sx2 > wl_fixed_from_int(ev->geometry.width))
922 sx2 = wl_fixed_from_int(ev->geometry.width);
923 if (sy2 > wl_fixed_from_int(ev->geometry.height))
924 sy2 = wl_fixed_from_int(ev->geometry.height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400925
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200926 tbox.x1 = sx1;
927 tbox.y1 = sy1;
928 tbox.x2 = sx2;
929 tbox.y2 = sy2;
930
Jason Ekstranda7af7042013-10-12 22:38:11 -0500931 tbox = weston_transformed_rect(wl_fixed_from_int(ev->geometry.width),
932 wl_fixed_from_int(ev->geometry.height),
933 ev->surface->buffer_transform,
934 ev->surface->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200935
936 s->src_x = tbox.x1 << 8;
937 s->src_y = tbox.y1 << 8;
938 s->src_w = (tbox.x2 - tbox.x1) << 8;
939 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500940 pixman_region32_fini(&src_rect);
941
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400942 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500943}
944
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400945static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500946drm_output_prepare_cursor_view(struct weston_output *output_base,
947 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500948{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400949 struct drm_compositor *c =
950 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400951 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400952
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200953 if (c->gbm == NULL)
954 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200955 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
956 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500957 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400958 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500959 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400960 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500961 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400962 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500963 if (ev->surface->buffer_ref.buffer == NULL ||
964 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
965 ev->geometry.width > 64 || ev->geometry.height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400966 return NULL;
967
Jason Ekstranda7af7042013-10-12 22:38:11 -0500968 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400969
970 return &output->cursor_plane;
971}
972
973static void
974drm_output_set_cursor(struct drm_output *output)
975{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500976 struct weston_view *ev = output->cursor_view;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400977 struct drm_compositor *c =
978 (struct drm_compositor *) output->base.compositor;
979 EGLint handle, stride;
980 struct gbm_bo *bo;
981 uint32_t buf[64 * 64];
982 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400983 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500984
Jason Ekstranda7af7042013-10-12 22:38:11 -0500985 output->cursor_view = NULL;
986 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400987 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
988 return;
989 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500990
Jason Ekstranda7af7042013-10-12 22:38:11 -0500991 if (ev->surface->buffer_ref.buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +0200992 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400993 pixman_region32_fini(&output->cursor_plane.damage);
994 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400995 output->current_cursor ^= 1;
996 bo = output->cursor_bo[output->current_cursor];
997 memset(buf, 0, sizeof buf);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500998 stride = wl_shm_buffer_get_stride(ev->surface->buffer_ref.buffer->shm_buffer);
999 s = wl_shm_buffer_get_data(ev->surface->buffer_ref.buffer->shm_buffer);
1000 for (i = 0; i < ev->geometry.height; i++)
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001001 memcpy(buf + i * 64, s + i * stride,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001002 ev->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001003
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001004 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001005 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001006
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001007 handle = gbm_bo_get_handle(bo).s32;
1008 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -05001009 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001010 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001011 c->cursors_are_broken = 1;
1012 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001013 }
1014
Jason Ekstranda7af7042013-10-12 22:38:11 -05001015 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1016 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001017 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001018 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001019 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001020 c->cursors_are_broken = 1;
1021 }
1022
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001023 output->cursor_plane.x = x;
1024 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001025 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001026}
1027
Jesse Barnes58ef3792012-02-23 09:45:49 -05001028static void
1029drm_assign_planes(struct weston_output *output)
1030{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001031 struct drm_compositor *c =
1032 (struct drm_compositor *) output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001033 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001034 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001035 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001036
1037 /*
1038 * Find a surface for each sprite in the output using some heuristics:
1039 * 1) size
1040 * 2) frequency of update
1041 * 3) opacity (though some hw might support alpha blending)
1042 * 4) clipping (this can be fixed with color keys)
1043 *
1044 * The idea is to save on blitting since this should save power.
1045 * If we can get a large video surface on the sprite for example,
1046 * the main display surface may not need to update at all, and
1047 * the client buffer can be used directly for the sprite surface
1048 * as we do for flipping full screen surfaces.
1049 */
1050 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001051 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001052
1053 /* Flag all visible surfaces as keep_buffer = 1 */
1054 wl_list_for_each(ev, &c->base.view_list, link)
1055 ev->surface->keep_buffer = 1;
1056
1057 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001058 /* test whether this buffer can ever go into a plane:
1059 * non-shm, or small enough to be a cursor
1060 */
Jason Ekstranda7af7042013-10-12 22:38:11 -05001061 if (!ev->surface->buffer_ref.buffer ||
1062 (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) &&
1063 (ev->geometry.width > 64 || ev->geometry.height > 64)))
1064 ev->surface->keep_buffer = 0;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001065
Jesse Barnes58ef3792012-02-23 09:45:49 -05001066 pixman_region32_init(&surface_overlap);
1067 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001068 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001069
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001070 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001071 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001072 next_plane = primary;
1073 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001074 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001075 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001076 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001077 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001078 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001079 if (next_plane == NULL)
1080 next_plane = primary;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001081 weston_view_move_to_plane(ev, next_plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001082 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001083 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001084 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001085
Jesse Barnes58ef3792012-02-23 09:45:49 -05001086 pixman_region32_fini(&surface_overlap);
1087 }
1088 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001089}
1090
Matt Roper361d2ad2011-08-29 13:52:23 -07001091static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001092drm_output_fini_pixman(struct drm_output *output);
1093
1094static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001095drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001096{
1097 struct drm_output *output = (struct drm_output *) output_base;
1098 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001099 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001100 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001101
Xiong Zhangabd5d472013-10-11 14:43:07 +08001102 if (output->page_flip_pending) {
1103 output->destroy_pending = 1;
1104 weston_log("destroy output while page flip pending\n");
1105 return;
1106 }
1107
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001108 if (output->backlight)
1109 backlight_destroy(output->backlight);
1110
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001111 drmModeFreeProperty(output->dpms_prop);
1112
Matt Roper361d2ad2011-08-29 13:52:23 -07001113 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001114 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001115
1116 /* Restore original CRTC state */
1117 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001118 origcrtc->x, origcrtc->y,
1119 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001120 drmModeFreeCrtc(origcrtc);
1121
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001122 c->crtc_allocator &= ~(1 << output->crtc_id);
1123 c->connector_allocator &= ~(1 << output->connector_id);
1124
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001125 if (c->use_pixman) {
1126 drm_output_fini_pixman(output);
1127 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001128 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001129 gbm_surface_destroy(output->surface);
1130 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001131
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001132 weston_plane_release(&output->fb_plane);
1133 weston_plane_release(&output->cursor_plane);
1134
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001135 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001136 wl_list_remove(&output->base.link);
1137
Matt Roper361d2ad2011-08-29 13:52:23 -07001138 free(output);
1139}
1140
Alex Wub7b8bda2012-04-17 17:20:48 +08001141static struct drm_mode *
1142choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1143{
1144 struct drm_mode *tmp_mode = NULL, *mode;
1145
Hardeningff39efa2013-09-18 23:56:35 +02001146 if (output->base.current_mode->width == target_mode->width &&
1147 output->base.current_mode->height == target_mode->height &&
1148 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001149 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001150 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001151
1152 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1153 if (mode->mode_info.hdisplay == target_mode->width &&
1154 mode->mode_info.vdisplay == target_mode->height) {
1155 if (mode->mode_info.vrefresh == target_mode->refresh ||
1156 target_mode->refresh == 0) {
1157 return mode;
1158 } else if (!tmp_mode)
1159 tmp_mode = mode;
1160 }
1161 }
1162
1163 return tmp_mode;
1164}
1165
1166static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001167drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001168static int
1169drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001170
1171static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001172drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1173{
1174 struct drm_output *output;
1175 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001176 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001177
1178 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001179 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001180 return -1;
1181 }
1182
1183 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001184 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001185 return -1;
1186 }
1187
1188 ec = (struct drm_compositor *)output_base->compositor;
1189 output = (struct drm_output *)output_base;
1190 drm_mode = choose_mode (output, mode);
1191
1192 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001193 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001194 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001195 }
1196
Hardeningff39efa2013-09-18 23:56:35 +02001197 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001198 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001199
Hardeningff39efa2013-09-18 23:56:35 +02001200 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001201
Hardeningff39efa2013-09-18 23:56:35 +02001202 output->base.current_mode = &drm_mode->base;
1203 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001204 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1205
Alex Wub7b8bda2012-04-17 17:20:48 +08001206 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001207 drm_output_release_fb(output, output->current);
1208 drm_output_release_fb(output, output->next);
1209 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001210
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001211 if (ec->use_pixman) {
1212 drm_output_fini_pixman(output);
1213 if (drm_output_init_pixman(output, ec) < 0) {
1214 weston_log("failed to init output pixman state with "
1215 "new mode\n");
1216 return -1;
1217 }
1218 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001219 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001220 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001221
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001222 if (drm_output_init_egl(output, ec) < 0) {
1223 weston_log("failed to init output egl state with "
1224 "new mode");
1225 return -1;
1226 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001227 }
1228
Alex Wub7b8bda2012-04-17 17:20:48 +08001229 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001230}
1231
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001232static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001233on_drm_input(int fd, uint32_t mask, void *data)
1234{
1235 drmEventContext evctx;
1236
1237 memset(&evctx, 0, sizeof evctx);
1238 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1239 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001240 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001241 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001242
1243 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001244}
1245
1246static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001247init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001248{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001249 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001250 uint64_t cap;
1251 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001252
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001253 sysnum = udev_device_get_sysnum(device);
1254 if (sysnum)
1255 ec->drm.id = atoi(sysnum);
1256 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001257 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001258 return -1;
1259 }
1260
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001261 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001262 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001263 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001264 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001265 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001266 udev_device_get_devnode(device));
1267 return -1;
1268 }
1269
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001270 weston_log("using %s\n", filename);
1271
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001272 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001273 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001274
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001275 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1276 if (ret == 0 && cap == 1)
1277 ec->clock = CLOCK_MONOTONIC;
1278 else
1279 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001280
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001281 return 0;
1282}
1283
1284static int
1285init_egl(struct drm_compositor *ec)
1286{
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001287 EGLint format;
1288
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001289 gl_renderer = weston_load_module("gl-renderer.so",
1290 "gl_renderer_interface");
1291 if (!gl_renderer)
1292 return -1;
1293
1294 /* GBM will load a dri driver, but even though they need symbols from
1295 * libglapi, in some version of Mesa they are not linked to it. Since
1296 * only the gl-renderer module links to it, the call above won't make
1297 * these symbols globally available, and loading the DRI driver fails.
1298 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1299 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1300
Benjamin Franzke060cf802011-04-30 09:32:11 +02001301 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001302
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001303 if (!ec->gbm)
1304 return -1;
1305
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001306 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001307 if (gl_renderer->create(&ec->base, ec->gbm,
1308 gl_renderer->opaque_attribs, &format) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001309 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001310 return -1;
1311 }
1312
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001313 return 0;
1314}
1315
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001316static int
1317init_pixman(struct drm_compositor *ec)
1318{
1319 return pixman_renderer_init(&ec->base);
1320}
1321
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001322static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001323drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001324{
1325 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001326 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001327
1328 mode = malloc(sizeof *mode);
1329 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001330 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001331
1332 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001333 mode->base.width = info->hdisplay;
1334 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001335
1336 /* Calculate higher precision (mHz) refresh rate */
1337 refresh = (info->clock * 1000000LL / info->htotal +
1338 info->vtotal / 2) / info->vtotal;
1339
1340 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1341 refresh *= 2;
1342 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1343 refresh /= 2;
1344 if (info->vscan > 1)
1345 refresh /= info->vscan;
1346
1347 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001348 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001349
1350 if (info->type & DRM_MODE_TYPE_PREFERRED)
1351 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1352
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001353 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1354
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001355 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001356}
1357
1358static int
1359drm_subpixel_to_wayland(int drm_value)
1360{
1361 switch (drm_value) {
1362 default:
1363 case DRM_MODE_SUBPIXEL_UNKNOWN:
1364 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1365 case DRM_MODE_SUBPIXEL_NONE:
1366 return WL_OUTPUT_SUBPIXEL_NONE;
1367 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1368 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1369 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1370 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1371 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1372 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1373 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1374 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1375 }
1376}
1377
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001378/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001379static uint32_t
1380drm_get_backlight(struct drm_output *output)
1381{
1382 long brightness, max_brightness, norm;
1383
1384 brightness = backlight_get_brightness(output->backlight);
1385 max_brightness = backlight_get_max_brightness(output->backlight);
1386
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001387 /* convert it on a scale of 0 to 255 */
1388 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001389
1390 return (uint32_t) norm;
1391}
1392
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001393/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001394static void
1395drm_set_backlight(struct weston_output *output_base, uint32_t value)
1396{
1397 struct drm_output *output = (struct drm_output *) output_base;
1398 long max_brightness, new_brightness;
1399
1400 if (!output->backlight)
1401 return;
1402
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001403 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001404 return;
1405
1406 max_brightness = backlight_get_max_brightness(output->backlight);
1407
1408 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001409 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001410
1411 backlight_set_brightness(output->backlight, new_brightness);
1412}
1413
1414static drmModePropertyPtr
1415drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1416{
1417 drmModePropertyPtr props;
1418 int i;
1419
1420 for (i = 0; i < connector->count_props; i++) {
1421 props = drmModeGetProperty(fd, connector->props[i]);
1422 if (!props)
1423 continue;
1424
1425 if (!strcmp(props->name, name))
1426 return props;
1427
1428 drmModeFreeProperty(props);
1429 }
1430
1431 return NULL;
1432}
1433
1434static void
1435drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1436{
1437 struct drm_output *output = (struct drm_output *) output_base;
1438 struct weston_compositor *ec = output_base->compositor;
1439 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001440
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001441 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001442 return;
1443
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001444 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1445 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001446}
1447
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001448static const char *connector_type_names[] = {
1449 "None",
1450 "VGA",
1451 "DVI",
1452 "DVI",
1453 "DVI",
1454 "Composite",
1455 "TV",
1456 "LVDS",
1457 "CTV",
1458 "DIN",
1459 "DP",
1460 "HDMI",
1461 "HDMI",
1462 "TV",
1463 "eDP",
1464};
1465
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001466static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001467find_crtc_for_connector(struct drm_compositor *ec,
1468 drmModeRes *resources, drmModeConnector *connector)
1469{
1470 drmModeEncoder *encoder;
1471 uint32_t possible_crtcs;
1472 int i, j;
1473
1474 for (j = 0; j < connector->count_encoders; j++) {
1475 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1476 if (encoder == NULL) {
1477 weston_log("Failed to get encoder.\n");
1478 return -1;
1479 }
1480 possible_crtcs = encoder->possible_crtcs;
1481 drmModeFreeEncoder(encoder);
1482
1483 for (i = 0; i < resources->count_crtcs; i++) {
1484 if (possible_crtcs & (1 << i) &&
1485 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1486 return i;
1487 }
1488 }
1489
1490 return -1;
1491}
1492
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001493/* Init output state that depends on gl or gbm */
1494static int
1495drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1496{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001497 int i, flags;
1498
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001499 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001500 output->base.current_mode->width,
1501 output->base.current_mode->height,
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07001502 ec->format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001503 GBM_BO_USE_SCANOUT |
1504 GBM_BO_USE_RENDERING);
1505 if (!output->surface) {
1506 weston_log("failed to create gbm surface\n");
1507 return -1;
1508 }
1509
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001510 if (gl_renderer->output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001511 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001512 gbm_surface_destroy(output->surface);
1513 return -1;
1514 }
1515
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001516 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1517
1518 for (i = 0; i < 2; i++) {
1519 if (output->cursor_bo[i])
1520 continue;
1521
1522 output->cursor_bo[i] =
1523 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1524 flags);
1525 }
1526
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001527 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1528 weston_log("cursor buffers unavailable, using gl cursors\n");
1529 ec->cursors_are_broken = 1;
1530 }
1531
1532 return 0;
1533}
1534
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001535static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001536drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1537{
Hardeningff39efa2013-09-18 23:56:35 +02001538 int w = output->base.current_mode->width;
1539 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001540 unsigned int i;
1541
1542 /* FIXME error checking */
1543
1544 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001545 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001546 if (!output->dumb[i])
1547 goto err;
1548
1549 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001550 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001551 output->dumb[i]->map,
1552 output->dumb[i]->stride);
1553 if (!output->image[i])
1554 goto err;
1555 }
1556
1557 if (pixman_renderer_output_create(&output->base) < 0)
1558 goto err;
1559
1560 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001561 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001562
1563 return 0;
1564
1565err:
1566 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1567 if (output->dumb[i])
1568 drm_fb_destroy_dumb(output->dumb[i]);
1569 if (output->image[i])
1570 pixman_image_unref(output->image[i]);
1571
1572 output->dumb[i] = NULL;
1573 output->image[i] = NULL;
1574 }
1575
1576 return -1;
1577}
1578
1579static void
1580drm_output_fini_pixman(struct drm_output *output)
1581{
1582 unsigned int i;
1583
1584 pixman_renderer_output_destroy(&output->base);
1585 pixman_region32_fini(&output->previous_damage);
1586
1587 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1588 drm_fb_destroy_dumb(output->dumb[i]);
1589 pixman_image_unref(output->image[i]);
1590 output->dumb[i] = NULL;
1591 output->image[i] = NULL;
1592 }
1593}
1594
Richard Hughes2b2092a2013-04-24 14:58:02 +01001595static void
1596edid_parse_string(const uint8_t *data, char text[])
1597{
1598 int i;
1599 int replaced = 0;
1600
1601 /* this is always 12 bytes, but we can't guarantee it's null
1602 * terminated or not junk. */
1603 strncpy(text, (const char *) data, 12);
1604
1605 /* remove insane chars */
1606 for (i = 0; text[i] != '\0'; i++) {
1607 if (text[i] == '\n' ||
1608 text[i] == '\r') {
1609 text[i] = '\0';
1610 break;
1611 }
1612 }
1613
1614 /* ensure string is printable */
1615 for (i = 0; text[i] != '\0'; i++) {
1616 if (!isprint(text[i])) {
1617 text[i] = '-';
1618 replaced++;
1619 }
1620 }
1621
1622 /* if the string is random junk, ignore the string */
1623 if (replaced > 4)
1624 text[0] = '\0';
1625}
1626
1627#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1628#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1629#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1630#define EDID_OFFSET_DATA_BLOCKS 0x36
1631#define EDID_OFFSET_LAST_BLOCK 0x6c
1632#define EDID_OFFSET_PNPID 0x08
1633#define EDID_OFFSET_SERIAL 0x0c
1634
1635static int
1636edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1637{
1638 int i;
1639 uint32_t serial_number;
1640
1641 /* check header */
1642 if (length < 128)
1643 return -1;
1644 if (data[0] != 0x00 || data[1] != 0xff)
1645 return -1;
1646
1647 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1648 * /--08--\/--09--\
1649 * 7654321076543210
1650 * |\---/\---/\---/
1651 * R C1 C2 C3 */
1652 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1653 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1654 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1655 edid->pnp_id[3] = '\0';
1656
1657 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1658 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1659 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1660 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1661 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1662 if (serial_number > 0)
1663 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1664
1665 /* parse EDID data */
1666 for (i = EDID_OFFSET_DATA_BLOCKS;
1667 i <= EDID_OFFSET_LAST_BLOCK;
1668 i += 18) {
1669 /* ignore pixel clock data */
1670 if (data[i] != 0)
1671 continue;
1672 if (data[i+2] != 0)
1673 continue;
1674
1675 /* any useful blocks? */
1676 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1677 edid_parse_string(&data[i+5],
1678 edid->monitor_name);
1679 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1680 edid_parse_string(&data[i+5],
1681 edid->serial_number);
1682 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1683 edid_parse_string(&data[i+5],
1684 edid->eisa_id);
1685 }
1686 }
1687 return 0;
1688}
1689
1690static void
1691find_and_parse_output_edid(struct drm_compositor *ec,
1692 struct drm_output *output,
1693 drmModeConnector *connector)
1694{
1695 drmModePropertyBlobPtr edid_blob = NULL;
1696 drmModePropertyPtr property;
1697 int i;
1698 int rc;
1699
1700 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1701 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1702 if (!property)
1703 continue;
1704 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1705 !strcmp(property->name, "EDID")) {
1706 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1707 connector->prop_values[i]);
1708 }
1709 drmModeFreeProperty(property);
1710 }
1711 if (!edid_blob)
1712 return;
1713
1714 rc = edid_parse(&output->edid,
1715 edid_blob->data,
1716 edid_blob->length);
1717 if (!rc) {
1718 weston_log("EDID data '%s', '%s', '%s'\n",
1719 output->edid.pnp_id,
1720 output->edid.monitor_name,
1721 output->edid.serial_number);
1722 if (output->edid.pnp_id[0] != '\0')
1723 output->base.make = output->edid.pnp_id;
1724 if (output->edid.monitor_name[0] != '\0')
1725 output->base.model = output->edid.monitor_name;
1726 if (output->edid.serial_number[0] != '\0')
1727 output->base.serial_number = output->edid.serial_number;
1728 }
1729 drmModeFreePropertyBlob(edid_blob);
1730}
1731
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001732
1733
1734static int
1735parse_modeline(const char *s, drmModeModeInfo *mode)
1736{
1737 char hsync[16];
1738 char vsync[16];
1739 float fclock;
1740
1741 mode->type = DRM_MODE_TYPE_USERDEF;
1742 mode->hskew = 0;
1743 mode->vscan = 0;
1744 mode->vrefresh = 0;
1745 mode->flags = 0;
1746
Rob Bradford307e09e2013-07-26 16:29:40 +01001747 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001748 &fclock,
1749 &mode->hdisplay,
1750 &mode->hsync_start,
1751 &mode->hsync_end,
1752 &mode->htotal,
1753 &mode->vdisplay,
1754 &mode->vsync_start,
1755 &mode->vsync_end,
1756 &mode->vtotal, hsync, vsync) != 11)
1757 return -1;
1758
1759 mode->clock = fclock * 1000;
1760 if (strcmp(hsync, "+hsync") == 0)
1761 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1762 else if (strcmp(hsync, "-hsync") == 0)
1763 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1764 else
1765 return -1;
1766
1767 if (strcmp(vsync, "+vsync") == 0)
1768 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1769 else if (strcmp(vsync, "-vsync") == 0)
1770 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1771 else
1772 return -1;
1773
1774 return 0;
1775}
1776
1777static uint32_t
1778parse_transform(const char *transform, const char *output_name)
1779{
1780 static const struct { const char *name; uint32_t token; } names[] = {
1781 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1782 { "90", WL_OUTPUT_TRANSFORM_90 },
1783 { "180", WL_OUTPUT_TRANSFORM_180 },
1784 { "270", WL_OUTPUT_TRANSFORM_270 },
1785 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1786 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1787 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1788 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1789 };
1790 unsigned int i;
1791
1792 for (i = 0; i < ARRAY_LENGTH(names); i++)
1793 if (strcmp(names[i].name, transform) == 0)
1794 return names[i].token;
1795
1796 weston_log("Invalid transform \"%s\" for output %s\n",
1797 transform, output_name);
1798
1799 return WL_OUTPUT_TRANSFORM_NORMAL;
1800}
1801
Rob Bradford66bd9f52013-06-25 18:56:42 +01001802static void
1803setup_output_seat_constraint(struct drm_compositor *ec,
1804 struct weston_output *output,
1805 const char *s)
1806{
1807 if (strcmp(s, "") != 0) {
1808 struct udev_seat *seat;
1809
1810 seat = udev_seat_get_named(&ec->base, s);
1811 if (seat)
1812 seat->base.output = output;
1813
1814 if (seat && seat->base.pointer)
1815 weston_pointer_clamp(seat->base.pointer,
1816 &seat->base.pointer->x,
1817 &seat->base.pointer->y);
1818 }
1819}
1820
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001821static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001822create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001823 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001824 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001825 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001826{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001827 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001828 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1829 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001830 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001831 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001832 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001833 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001834 int i, width, height, scale;
1835 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001836 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001837 enum output_config config;
1838 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001839
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001840 i = find_crtc_for_connector(ec, resources, connector);
1841 if (i < 0) {
1842 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001843 return -1;
1844 }
1845
Peter Huttererf3d62272013-08-08 11:57:05 +10001846 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001847 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001848 return -1;
1849
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001850 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1851 output->base.make = "unknown";
1852 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001853 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001854 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001855
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001856 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1857 type_name = connector_type_names[connector->connector_type];
1858 else
1859 type_name = "UNKNOWN";
1860 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001861 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001862
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001863 section = weston_config_get_section(ec->base.config, "output", "name",
1864 output->base.name);
1865 weston_config_section_get_string(section, "mode", &s, "preferred");
1866 if (strcmp(s, "off") == 0)
1867 config = OUTPUT_CONFIG_OFF;
1868 else if (strcmp(s, "preferred") == 0)
1869 config = OUTPUT_CONFIG_PREFERRED;
1870 else if (strcmp(s, "current") == 0)
1871 config = OUTPUT_CONFIG_CURRENT;
1872 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1873 config = OUTPUT_CONFIG_MODE;
1874 else if (parse_modeline(s, &modeline) == 0)
1875 config = OUTPUT_CONFIG_MODELINE;
1876 else {
1877 weston_log("Invalid mode \"%s\" for output %s\n",
1878 s, output->base.name);
1879 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001880 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001881 free(s);
1882
1883 weston_config_section_get_int(section, "scale", &scale, 1);
1884 weston_config_section_get_string(section, "transform", &s, "normal");
1885 transform = parse_transform(s, output->base.name);
1886 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001887
Rob Bradford66bd9f52013-06-25 18:56:42 +01001888 weston_config_section_get_string(section, "seat", &s, "");
1889 setup_output_seat_constraint(ec, &output->base, s);
1890 free(s);
1891
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001892 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001893 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001894 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001895 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001896 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001897
Matt Roper361d2ad2011-08-29 13:52:23 -07001898 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001899 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001900
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001901 /* Get the current mode on the crtc that's currently driving
1902 * this connector. */
1903 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001904 memset(&crtc_mode, 0, sizeof crtc_mode);
1905 if (encoder != NULL) {
1906 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1907 drmModeFreeEncoder(encoder);
1908 if (crtc == NULL)
1909 goto err_free;
1910 if (crtc->mode_valid)
1911 crtc_mode = crtc->mode;
1912 drmModeFreeCrtc(crtc);
1913 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001914
David Herrmann0f0d54e2011-12-08 17:05:45 +01001915 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001916 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001917 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001918 goto err_free;
1919 }
1920
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001921 if (config == OUTPUT_CONFIG_OFF) {
1922 weston_log("Disabling output %s\n", output->base.name);
1923 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1924 0, 0, 0, 0, 0, NULL);
1925 goto err_free;
1926 }
1927
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001928 preferred = NULL;
1929 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001930 configured = NULL;
1931
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001932 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001933 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001934 width == drm_mode->base.width &&
1935 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001936 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001937 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001938 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001939 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001940 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001941 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001942
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001943 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001944 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001945 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001946 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001947 }
1948
Wang Quanxianacb805a2012-07-30 18:09:46 -04001949 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001950 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001951 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001952 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001953 }
1954
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001955 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001956 configured = current;
1957
Wang Quanxianacb805a2012-07-30 18:09:46 -04001958 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02001959 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001960 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02001961 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001962 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02001963 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001964 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02001965 output->base.current_mode = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001966
Hardeningff39efa2013-09-18 23:56:35 +02001967 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001968 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001969 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001970 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001971
Hardeningff39efa2013-09-18 23:56:35 +02001972 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001973
John Kåre Alsaker94659272012-11-13 19:10:18 +01001974 weston_output_init(&output->base, &ec->base, x, y,
1975 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001976 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001977
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001978 if (ec->use_pixman) {
1979 if (drm_output_init_pixman(output, ec) < 0) {
1980 weston_log("Failed to init output pixman state\n");
1981 goto err_output;
1982 }
1983 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001984 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001985 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001986 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001987
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001988 output->backlight = backlight_init(drm_device,
1989 connector->connector_type);
1990 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001991 weston_log("Initialized backlight, device %s\n",
1992 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001993 output->base.set_backlight = drm_set_backlight;
1994 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001995 } else {
1996 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001997 }
1998
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001999 wl_list_insert(ec->base.output_list.prev, &output->base.link);
2000
Richard Hughes2b2092a2013-04-24 14:58:02 +01002001 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002002 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2003 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002004
Jonas Ådahle5a12252013-04-05 23:07:11 +02002005 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002006 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002007 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002008 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002009 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002010 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002011
Richard Hughese7299962013-05-01 21:52:12 +01002012 output->base.gamma_size = output->original_crtc->gamma_size;
2013 output->base.set_gamma = drm_output_set_gamma;
2014
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002015 weston_plane_init(&output->cursor_plane, 0, 0);
2016 weston_plane_init(&output->fb_plane, 0, 0);
2017
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002018 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2019 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2020 &ec->base.primary_plane);
2021
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002022 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002023 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002024 wl_list_for_each(m, &output->base.mode_list, link)
2025 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
2026 m->width, m->height, m->refresh / 1000.0,
2027 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2028 ", preferred" : "",
2029 m->flags & WL_OUTPUT_MODE_CURRENT ?
2030 ", current" : "",
2031 connector->count_modes == 0 ?
2032 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002033
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002034 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002035
John Kåre Alsaker94659272012-11-13 19:10:18 +01002036err_output:
2037 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002038err_free:
2039 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2040 base.link) {
2041 wl_list_remove(&drm_mode->base.link);
2042 free(drm_mode);
2043 }
2044
2045 drmModeFreeCrtc(output->original_crtc);
2046 ec->crtc_allocator &= ~(1 << output->crtc_id);
2047 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002048 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002049
David Herrmann0f0d54e2011-12-08 17:05:45 +01002050 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002051}
2052
Jesse Barnes58ef3792012-02-23 09:45:49 -05002053static void
2054create_sprites(struct drm_compositor *ec)
2055{
2056 struct drm_sprite *sprite;
2057 drmModePlaneRes *plane_res;
2058 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002059 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002060
2061 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2062 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002063 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002064 strerror(errno));
2065 return;
2066 }
2067
2068 for (i = 0; i < plane_res->count_planes; i++) {
2069 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2070 if (!plane)
2071 continue;
2072
Peter Huttererf3d62272013-08-08 11:57:05 +10002073 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002074 plane->count_formats));
2075 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002076 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002077 __func__);
2078 free(plane);
2079 continue;
2080 }
2081
Jesse Barnes58ef3792012-02-23 09:45:49 -05002082 sprite->possible_crtcs = plane->possible_crtcs;
2083 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002084 sprite->current = NULL;
2085 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002086 sprite->compositor = ec;
2087 sprite->count_formats = plane->count_formats;
2088 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002089 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002090 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002091 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002092 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2093 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002094
2095 wl_list_insert(&ec->sprite_list, &sprite->link);
2096 }
2097
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002098 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002099}
2100
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002101static void
2102destroy_sprites(struct drm_compositor *compositor)
2103{
2104 struct drm_sprite *sprite, *next;
2105 struct drm_output *output;
2106
2107 output = container_of(compositor->base.output_list.next,
2108 struct drm_output, base.link);
2109
2110 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2111 drmModeSetPlane(compositor->drm.fd,
2112 sprite->plane_id,
2113 output->crtc_id, 0, 0,
2114 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002115 drm_output_release_fb(output, sprite->current);
2116 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002117 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002118 free(sprite);
2119 }
2120}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002121
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002122static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002123create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002124 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002125{
2126 drmModeConnector *connector;
2127 drmModeRes *resources;
2128 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002129 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002130
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002131 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002132 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002133 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002134 return -1;
2135 }
2136
Jesse Barnes58ef3792012-02-23 09:45:49 -05002137 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002138 if (!ec->crtcs) {
2139 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002140 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002141 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002142
Rob Clark4339add2012-08-09 14:18:28 -05002143 ec->min_width = resources->min_width;
2144 ec->max_width = resources->max_width;
2145 ec->min_height = resources->min_height;
2146 ec->max_height = resources->max_height;
2147
Jesse Barnes58ef3792012-02-23 09:45:49 -05002148 ec->num_crtcs = resources->count_crtcs;
2149 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2150
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002151 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002152 connector = drmModeGetConnector(ec->drm.fd,
2153 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002154 if (connector == NULL)
2155 continue;
2156
2157 if (connector->connection == DRM_MODE_CONNECTED &&
2158 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002159 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002160 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002161 connector, x, y,
2162 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002163 drmModeFreeConnector(connector);
2164 continue;
2165 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002166
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002167 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002168 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002169 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002170 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002171
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002172 drmModeFreeConnector(connector);
2173 }
2174
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002175 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002176 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002177 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002178 return -1;
2179 }
2180
2181 drmModeFreeResources(resources);
2182
2183 return 0;
2184}
2185
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002186static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002187update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002188{
2189 drmModeConnector *connector;
2190 drmModeRes *resources;
2191 struct drm_output *output, *next;
2192 int x = 0, y = 0;
2193 int x_offset = 0, y_offset = 0;
2194 uint32_t connected = 0, disconnects = 0;
2195 int i;
2196
2197 resources = drmModeGetResources(ec->drm.fd);
2198 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002199 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002200 return;
2201 }
2202
2203 /* collect new connects */
2204 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002205 int connector_id = resources->connectors[i];
2206
2207 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002208 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002209 continue;
2210
David Herrmann7551cff2011-12-08 17:05:43 +01002211 if (connector->connection != DRM_MODE_CONNECTED) {
2212 drmModeFreeConnector(connector);
2213 continue;
2214 }
2215
Benjamin Franzke117483d2011-08-30 11:38:26 +02002216 connected |= (1 << connector_id);
2217
2218 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002219 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002220 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002221 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002222
2223 /* XXX: not yet needed, we die with 0 outputs */
2224 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002225 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002226 else
2227 x = 0;
2228 y = 0;
2229 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002230 connector, x, y,
2231 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002232 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002233
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002234 }
2235 drmModeFreeConnector(connector);
2236 }
2237 drmModeFreeResources(resources);
2238
2239 disconnects = ec->connector_allocator & ~connected;
2240 if (disconnects) {
2241 wl_list_for_each_safe(output, next, &ec->base.output_list,
2242 base.link) {
2243 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002244 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002245 output->base.x - x_offset,
2246 output->base.y - y_offset);
2247 }
2248
2249 if (disconnects & (1 << output->connector_id)) {
2250 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002251 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002252 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002253 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002254 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002255 }
2256 }
2257 }
2258
2259 /* FIXME: handle zero outputs, without terminating */
2260 if (ec->connector_allocator == 0)
2261 wl_display_terminate(ec->base.wl_display);
2262}
2263
2264static int
David Herrmannd7488c22012-03-11 20:05:21 +01002265udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002266{
David Herrmannd7488c22012-03-11 20:05:21 +01002267 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002268 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002269
2270 sysnum = udev_device_get_sysnum(device);
2271 if (!sysnum || atoi(sysnum) != ec->drm.id)
2272 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002273
David Herrmann6ac52db2012-03-11 20:05:22 +01002274 val = udev_device_get_property_value(device, "HOTPLUG");
2275 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002276 return 0;
2277
David Herrmann6ac52db2012-03-11 20:05:22 +01002278 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002279}
2280
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002281static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002282udev_drm_event(int fd, uint32_t mask, void *data)
2283{
2284 struct drm_compositor *ec = data;
2285 struct udev_device *event;
2286
2287 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002288
David Herrmannd7488c22012-03-11 20:05:21 +01002289 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002290 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002291
2292 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002293
2294 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002295}
2296
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002297static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002298drm_restore(struct weston_compositor *ec)
2299{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002300 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002301}
2302
2303static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002304drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002305{
2306 struct drm_compositor *d = (struct drm_compositor *) ec;
2307
Rob Bradfordd355b802013-05-31 18:09:55 +01002308 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002309
2310 wl_event_source_remove(d->udev_drm_source);
2311 wl_event_source_remove(d->drm_source);
2312
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002313 destroy_sprites(d);
2314
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002315 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002316
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002317 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002318
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002319 if (d->gbm)
2320 gbm_device_destroy(d->gbm);
2321
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002322 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002323
Rob Bradford45c15b82013-07-26 16:29:35 +01002324 close(d->drm.fd);
2325
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002326 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002327}
2328
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002329static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002330drm_compositor_set_modes(struct drm_compositor *compositor)
2331{
2332 struct drm_output *output;
2333 struct drm_mode *drm_mode;
2334 int ret;
2335
2336 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002337 if (!output->current) {
2338 /* If something that would cause the output to
2339 * switch mode happened while in another vt, we
2340 * might not have a current drm_fb. In that case,
2341 * schedule a repaint and let drm_output_repaint
2342 * handle setting the mode. */
2343 weston_output_schedule_repaint(&output->base);
2344 continue;
2345 }
2346
Hardeningff39efa2013-09-18 23:56:35 +02002347 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002348 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002349 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002350 &output->connector_id, 1,
2351 &drm_mode->mode_info);
2352 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002353 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002354 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002355 drm_mode->base.width, drm_mode->base.height,
2356 output->base.x, output->base.y);
2357 }
2358 }
2359}
2360
2361static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002362session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002363{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002364 struct weston_compositor *compositor = data;
2365 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002366 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002367 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002368
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002369 if (ec->base.session_active) {
2370 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002371 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002372 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002373 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002374 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002375 } else {
2376 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002377 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002378
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002379 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002380 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002381
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002382 /* If we have a repaint scheduled (either from a
2383 * pending pageflip or the idle handler), make sure we
2384 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002385 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002386 * further attemps at repainting. When we switch
2387 * back, we schedule a repaint, which will process
2388 * pending frame callbacks. */
2389
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002390 wl_list_for_each(output, &ec->base.output_list, base.link) {
2391 output->base.repaint_needed = 0;
2392 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002393 }
2394
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002395 output = container_of(ec->base.output_list.next,
2396 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002397
2398 wl_list_for_each(sprite, &ec->sprite_list, link)
2399 drmModeSetPlane(ec->drm.fd,
2400 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002401 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002402 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002403 };
2404}
2405
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002406static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002407switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002408{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002409 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002410
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002411 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002412}
2413
David Herrmann0af066f2012-10-29 19:21:16 +01002414/*
2415 * Find primary GPU
2416 * Some systems may have multiple DRM devices attached to a single seat. This
2417 * function loops over all devices and tries to find a PCI device with the
2418 * boot_vga sysfs attribute set to 1.
2419 * If no such device is found, the first DRM device reported by udev is used.
2420 */
2421static struct udev_device*
2422find_primary_gpu(struct drm_compositor *ec, const char *seat)
2423{
2424 struct udev_enumerate *e;
2425 struct udev_list_entry *entry;
2426 const char *path, *device_seat, *id;
2427 struct udev_device *device, *drm_device, *pci;
2428
2429 e = udev_enumerate_new(ec->udev);
2430 udev_enumerate_add_match_subsystem(e, "drm");
2431 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2432
2433 udev_enumerate_scan_devices(e);
2434 drm_device = NULL;
2435 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2436 path = udev_list_entry_get_name(entry);
2437 device = udev_device_new_from_syspath(ec->udev, path);
2438 if (!device)
2439 continue;
2440 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2441 if (!device_seat)
2442 device_seat = default_seat;
2443 if (strcmp(device_seat, seat)) {
2444 udev_device_unref(device);
2445 continue;
2446 }
2447
2448 pci = udev_device_get_parent_with_subsystem_devtype(device,
2449 "pci", NULL);
2450 if (pci) {
2451 id = udev_device_get_sysattr_value(pci, "boot_vga");
2452 if (id && !strcmp(id, "1")) {
2453 if (drm_device)
2454 udev_device_unref(drm_device);
2455 drm_device = device;
2456 break;
2457 }
2458 }
2459
2460 if (!drm_device)
2461 drm_device = device;
2462 else
2463 udev_device_unref(device);
2464 }
2465
2466 udev_enumerate_unref(e);
2467 return drm_device;
2468}
2469
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002470static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002471planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002472{
2473 struct drm_compositor *c = data;
2474
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002475 switch (key) {
2476 case KEY_C:
2477 c->cursors_are_broken ^= 1;
2478 break;
2479 case KEY_V:
2480 c->sprites_are_broken ^= 1;
2481 break;
2482 case KEY_O:
2483 c->sprites_hidden ^= 1;
2484 break;
2485 default:
2486 break;
2487 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002488}
2489
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002490#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002491static void
2492recorder_frame_notify(struct wl_listener *listener, void *data)
2493{
2494 struct drm_output *output;
2495 struct drm_compositor *c;
2496 int fd, ret;
2497
2498 output = container_of(listener, struct drm_output,
2499 recorder_frame_listener);
2500 c = (struct drm_compositor *) output->base.compositor;
2501
2502 if (!output->recorder)
2503 return;
2504
2505 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2506 DRM_CLOEXEC, &fd);
2507 if (ret) {
2508 weston_log("[libva recorder] "
2509 "failed to create prime fd for front buffer\n");
2510 return;
2511 }
2512
2513 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002514}
2515
2516static void *
2517create_recorder(struct drm_compositor *c, int width, int height,
2518 const char *filename)
2519{
2520 int fd;
2521 drm_magic_t magic;
2522
2523 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2524 if (fd < 0)
2525 return NULL;
2526
2527 drmGetMagic(fd, &magic);
2528 drmAuthMagic(c->drm.fd, magic);
2529
2530 return vaapi_recorder_create(fd, width, height, filename);
2531}
2532
2533static void
2534recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2535 void *data)
2536{
2537 struct drm_compositor *c = data;
2538 struct drm_output *output;
2539 int width, height;
2540
2541 output = container_of(c->base.output_list.next,
2542 struct drm_output, base.link);
2543
2544 if (!output->recorder) {
Hardeningff39efa2013-09-18 23:56:35 +02002545 width = output->base.current_mode->width;
2546 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002547
2548 output->recorder =
2549 create_recorder(c, width, height, "capture.h264");
2550 if (!output->recorder) {
2551 weston_log("failed to create vaapi recorder\n");
2552 return;
2553 }
2554
2555 output->base.disable_planes++;
2556
2557 output->recorder_frame_listener.notify = recorder_frame_notify;
2558 wl_signal_add(&output->base.frame_signal,
2559 &output->recorder_frame_listener);
2560
2561 weston_output_schedule_repaint(&output->base);
2562
2563 weston_log("[libva recorder] initialized\n");
2564 } else {
2565 vaapi_recorder_destroy(output->recorder);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002566 output->recorder = NULL;
2567
2568 output->base.disable_planes--;
2569
2570 wl_list_remove(&output->recorder_frame_listener.link);
2571 weston_log("[libva recorder] done\n");
2572 }
2573}
2574#else
2575static void
2576recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2577 void *data)
2578{
2579 weston_log("Compiled without libva support\n");
2580}
2581#endif
2582
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002583static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002584drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002585 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002586 int *argc, char *argv[],
2587 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002588{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002589 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002590 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002591 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002592 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002593 const char *path;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002594 char *s;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002595 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002596
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002597 weston_log("initializing drm backend\n");
2598
Peter Huttererf3d62272013-08-08 11:57:05 +10002599 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002600 if (ec == NULL)
2601 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002602
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002603 /* KMS support for sprites is not complete yet, so disable the
2604 * functionality for now. */
2605 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002606
2607 section = weston_config_get_section(config, "core", NULL, NULL);
2608 weston_config_section_get_string(section,
2609 "gbm-format", &s, "xrgb8888");
2610 if (strcmp(s, "xrgb8888") == 0)
2611 ec->format = GBM_FORMAT_XRGB8888;
2612 else if (strcmp(s, "rgb565") == 0)
2613 ec->format = GBM_FORMAT_RGB565;
2614 else if (strcmp(s, "xrgb2101010") == 0)
2615 ec->format = GBM_FORMAT_XRGB2101010;
2616 else {
2617 weston_log("fatal: unrecognized pixel format: %s\n", s);
2618 free(s);
2619 goto err_base;
2620 }
2621 free(s);
2622
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002623 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002624
Daniel Stone725c2c32012-06-22 14:04:36 +01002625 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002626 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002627 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002628 goto err_base;
2629 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002630
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002631 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002632 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
2633 param->seat_id);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002634 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002635 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002636 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002637 goto err_compositor;
2638 }
2639
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002640 ec->udev = udev_new();
2641 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002642 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002643 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002644 }
2645
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002646 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002647 ec->session_listener.notify = session_notify;
2648 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002649
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002650 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002651 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002652 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002653 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002654 }
David Herrmann0af066f2012-10-29 19:21:16 +01002655 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002656
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002657 if (init_drm(ec, drm_device) < 0) {
2658 weston_log("failed to initialize kms\n");
2659 goto err_udev_dev;
2660 }
2661
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002662 if (ec->use_pixman) {
2663 if (init_pixman(ec) < 0) {
2664 weston_log("failed to initialize pixman renderer\n");
2665 goto err_udev_dev;
2666 }
2667 } else {
2668 if (init_egl(ec) < 0) {
2669 weston_log("failed to initialize egl\n");
2670 goto err_udev_dev;
2671 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002672 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002673
2674 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002675 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002676
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002677 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002678
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002679 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002680 weston_compositor_add_key_binding(&ec->base, key,
2681 MODIFIER_CTRL | MODIFIER_ALT,
2682 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002683
Jesse Barnes58ef3792012-02-23 09:45:49 -05002684 wl_list_init(&ec->sprite_list);
2685 create_sprites(ec);
2686
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002687 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002688 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002689 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002690 }
2691
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002692 path = NULL;
2693
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002694 if (udev_input_init(&ec->input,
2695 &ec->base, ec->udev, param->seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002696 weston_log("failed to create input devices\n");
2697 goto err_sprite;
2698 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002699
2700 loop = wl_display_get_event_loop(ec->base.wl_display);
2701 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002702 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002703 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002704
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002705 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2706 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002707 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002708 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002709 }
2710 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2711 "drm", NULL);
2712 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002713 wl_event_loop_add_fd(loop,
2714 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002715 WL_EVENT_READABLE, udev_drm_event, ec);
2716
2717 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002718 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002719 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002720 }
2721
Daniel Stonea96b93c2012-06-22 14:04:37 +01002722 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002723
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002724 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002725 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002726 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002727 planes_binding, ec);
2728 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2729 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002730 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2731 recorder_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002732
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002733 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002734
2735err_udev_monitor:
2736 wl_event_source_remove(ec->udev_drm_source);
2737 udev_monitor_unref(ec->udev_monitor);
2738err_drm_source:
2739 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002740 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002741err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002742 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002743 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002744 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002745err_udev_dev:
2746 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002747err_launcher:
2748 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002749err_udev:
2750 udev_unref(ec->udev);
2751err_compositor:
2752 weston_compositor_shutdown(&ec->base);
2753err_base:
2754 free(ec);
2755 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002756}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002757
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002758WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002759backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002760 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002761{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002762 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002763
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002764 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002765 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2766 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2767 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002768 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002769 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002770 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002771
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002772 param.seat_id = default_seat;
2773
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002774 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002775
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002776 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002777}